Skip to content

Commit

Permalink
add packagevariantset controller
Browse files Browse the repository at this point in the history
  • Loading branch information
natasha41575 committed Jan 23, 2023
1 parent dc44dbd commit 9dd1910
Show file tree
Hide file tree
Showing 15 changed files with 1,641 additions and 14 deletions.
8 changes: 4 additions & 4 deletions internal/fnruntime/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ func SelectInput(input []*yaml.RNode, selectors, exclusions []kptfilev1.Selector
} else {
for _, node := range input {
for _, selector := range selectors {
if isMatch(node, selector) {
if IsMatch(node, selector) {
selectedInput = append(selectedInput, node)
}
}
Expand All @@ -160,7 +160,7 @@ func SelectInput(input []*yaml.RNode, selectors, exclusions []kptfilev1.Selector
for _, node := range selectedInput {
matchesExclusion := false
for _, exclusion := range exclusions {
if !exclusion.IsEmpty() && isMatch(node, exclusion) {
if !exclusion.IsEmpty() && IsMatch(node, exclusion) {
matchesExclusion = true
break
}
Expand All @@ -172,8 +172,8 @@ func SelectInput(input []*yaml.RNode, selectors, exclusions []kptfilev1.Selector
return filteredInput, nil
}

// isMatch returns true if the resource matches input selection criteria
func isMatch(node *yaml.RNode, selector kptfilev1.Selector) bool {
// IsMatch returns true if the resource matches input selection criteria
func IsMatch(node *yaml.RNode, selector kptfilev1.Selector) bool {
// keep expanding with new selectors
return nameMatch(node, selector) && namespaceMatch(node, selector) &&
kindMatch(node, selector) && apiVersionMatch(node, selector) &&
Expand Down
2 changes: 1 addition & 1 deletion internal/fnruntime/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ spec:
t.Run(tc.name, func(t *testing.T) {
node, err := yaml.Parse(tc.input)
assert.NoError(t, err)
actual := isMatch(node, tc.selector)
actual := IsMatch(node, tc.selector)
assert.Equal(t, tc.expected, actual)
})
}
Expand Down
2 changes: 1 addition & 1 deletion porch/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ TEST_GIT_SERVER_IMAGE ?= test-git-server
# Only enable a subset of reconcilers in porch controllers by default. Use the RECONCILERS
# env variable to specify a specific list of reconcilers or use
# RECONCILERS=* to enable all known reconcilers.
ALL_RECONCILERS="rootsyncsets,remoterootsyncsets,workloadidentitybindings,rootsyncdeployments,functiondiscovery,packagevariants,rootsyncrollouts"
ALL_RECONCILERS="rootsyncsets,remoterootsyncsets,workloadidentitybindings,rootsyncdeployments,functiondiscovery,packagevariants,packagevariantsets,rootsyncrollouts"
ifndef RECONCILERS
ENABLED_RECONCILERS="rootsyncsets,remoterootsyncsets,workloadidentitybindings,functiondiscovery"
else
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
# Copyright 2023 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.8.0
creationTimestamp: null
name: packagevariantsets.config.porch.kpt.dev
spec:
group: config.porch.kpt.dev
names:
kind: PackageVariantSet
listKind: PackageVariantSetList
plural: packagevariantsets
singular: packagevariantset
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: PackageVariantSet represents an upstream package revision and
a way to target specific downstream repositories where a variant of the
upstream package should be created.
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: PackageVariantSetSpec defines the desired state of PackageVariantSet
properties:
adoptionPolicy:
type: string
deletionPolicy:
type: string
targets:
items:
properties:
objects:
description: 'option 3: a selector against a set of arbitrary
objects'
properties:
repoName:
properties:
fromField:
type: string
value:
type: string
type: object
selectors:
items:
properties:
annotations:
additionalProperties:
type: string
description: Annotations on the target resources
type: object
apiVersion:
description: APIVersion of the target resources
type: string
kind:
description: Kind of the target resources
type: string
labels:
additionalProperties:
type: string
description: Labels on the target resources
type: object
name:
description: Name of the target resources
type: string
namespace:
description: Namespace of the target resources
type: string
type: object
type: array
type: object
package:
description: 'option 1: an explicit repo/package name pair'
properties:
name:
type: string
repo:
type: string
type: object
packageName:
description: For options 2 and 3, PackageName specifies how
to create the name of the package variant
properties:
baseName:
properties:
fromField:
type: string
value:
type: string
type: object
namePrefix:
properties:
fromField:
type: string
value:
type: string
type: object
nameSuffix:
properties:
fromField:
type: string
value:
type: string
type: object
type: object
repositories:
additionalProperties:
type: string
description: 'option 2: a label selector against a set of repositories'
type: object
type: object
type: array
upstream:
properties:
package:
properties:
name:
type: string
repo:
type: string
type: object
ref:
type: string
revision:
type: string
type: object
type: object
status:
description: PackageVariantSetStatus defines the observed state of PackageVariantSet
properties:
validationErrors:
items:
type: string
type: array
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
2 changes: 2 additions & 0 deletions porch/controllers/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import (
"github.com/GoogleContainerTools/kpt/porch/controllers/functiondiscovery"
"github.com/GoogleContainerTools/kpt/porch/controllers/klippy/pkg/controllers/klippy"
"github.com/GoogleContainerTools/kpt/porch/controllers/packagevariants/pkg/controllers/packagevariant"
"github.com/GoogleContainerTools/kpt/porch/controllers/packagevariantsets/pkg/controllers/packagevariantset"
"github.com/GoogleContainerTools/kpt/porch/controllers/remoterootsyncsets/pkg/controllers/remoterootsyncset"
"github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncdeployments/pkg/controllers/rootsyncdeployment"
"github.com/GoogleContainerTools/kpt/porch/controllers/rootsyncrollouts/pkg/controllers/rootsyncrollout"
Expand All @@ -54,6 +55,7 @@ import (
var (
reconcilers = map[string]Reconciler{
"packagevariants": &packagevariant.PackageVariantReconciler{},
"packagevariantsets": &packagevariantset.PackageVariantSetReconciler{},
"rootsyncsets": &rootsyncset.RootSyncSetReconciler{},
"remoterootsyncsets": &remoterootsyncset.RemoteRootSyncSetReconciler{},
"workloadidentitybindings": &workloadidentitybinding.WorkloadIdentityBindingReconciler{},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ const (

DeletionPolicyDelete DeletionPolicy = "delete"
DeletionPolicyOrphan DeletionPolicy = "orphan"

Finalizer = "config.porch.kpt.dev/finalizer"
)

// PackageVariantSpec defines the desired state of PackageVariant
Expand All @@ -72,6 +74,7 @@ type Downstream struct {

// PackageVariantStatus defines the observed state of PackageVariant
type PackageVariantStatus struct {
// TODO: Move this to conditions.
ValidationErrors []string `json:"validationErrors,omitempty"`
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import (
"k8s.io/klog/v2"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
"sigs.k8s.io/controller-runtime/pkg/source"
Expand Down Expand Up @@ -69,6 +70,36 @@ func (r *PackageVariantReconciler) Reconcile(ctx context.Context, req ctrl.Reque
return ctrl.Result{}, nil
}

if !pv.ObjectMeta.DeletionTimestamp.IsZero() {
// This object is being deleted, so we need to make sure the packagerevisions owned by this object
// are deleted. Normally, garbage collection can handle this, but we have a special case here because
// (a) we cannot delete published packagerevisions and instead have to propose deletion of them
// (b) we may want to orphan packagerevisions instead of deleting them.
for _, pr := range prList.Items {
if r.hasOurOwnerReference(pv, pr.OwnerReferences) {
r.deleteOrOrphan(ctx, &pr, pv)
if porchapi.LifecycleIsPublished(pr.Spec.Lifecycle) {
// orphan published package revisions so that the GC does not automatically delete it
r.orphanPackageRevision(ctx, &pr, pv)
}
}
}
// Remove our finalizer from the list and update it.
controllerutil.RemoveFinalizer(pv, api.Finalizer)
if err := r.Update(ctx, pv); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to update %s after delete finalizer: %w", req.Name, err)
}
return ctrl.Result{}, nil
}

// the object is not being deleted, so let's ensure that our finalizer is here
if !controllerutil.ContainsFinalizer(pv, api.Finalizer) {
controllerutil.AddFinalizer(pv, api.Finalizer)
if err := r.Update(ctx, pv); err != nil {
return ctrl.Result{}, fmt.Errorf("failed to update %s after add finalizer: %w", req.Name, err)
}
}

if errs := validatePackageVariant(pv); len(errs) > 0 {
pv.Status.ValidationErrors = nil
for _, validationErr := range errs {
Expand Down Expand Up @@ -351,25 +382,27 @@ func (r *PackageVariantReconciler) deleteOrOrphan(ctx context.Context,
r.deletePackageRevision(ctx, pr)
case api.DeletionPolicyOrphan:
klog.Infoln(fmt.Sprintf("package variant %q is orphaning package revision %q", pv.Name, pr.Name))
pr.ObjectMeta.OwnerReferences = r.orphanPackageRevision(pr.OwnerReferences, pv.UID)
if err := r.Client.Update(ctx, pr); err != nil {
klog.Errorf("error orphaning package revision: %v", err)
}
r.orphanPackageRevision(ctx, pr, pv)
default:
// this should never happen, because the pv should already be validated beforehand
klog.Errorf("invalid deletion policy %s", pv.Spec.DeletionPolicy)
}
}

func (r *PackageVariantReconciler) orphanPackageRevision(currentOwners []metav1.OwnerReference,
pvUID types.UID) []metav1.OwnerReference {
func (r *PackageVariantReconciler) orphanPackageRevision(ctx context.Context,
pr *porchapi.PackageRevision,
pv *api.PackageVariant) {
currentOwners := pr.OwnerReferences
var newOwners []metav1.OwnerReference
for _, owner := range currentOwners {
if owner.UID != pvUID {
if owner.UID != pv.UID {
newOwners = append(newOwners, owner)
}
}
return newOwners
pr.ObjectMeta.OwnerReferences = newOwners
if err := r.Client.Update(ctx, pr); err != nil {
klog.Errorf("error orphaning package revision: %v", err)
}
}

func (r *PackageVariantReconciler) deletePackageRevision(ctx context.Context, pr *porchapi.PackageRevision) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package v1alpha1 contains API Schema definitions for the config.porch.kpt.dev v1alpha1 API group
// +kubebuilder:object:generate=true
// +groupName=config.porch.kpt.dev
package v1alpha1

import (
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/scheme"
)

//go:generate go run sigs.k8s.io/controller-tools/cmd/[email protected] object object:headerFile="../../../../scripts/boilerplate.go.txt" paths="./..."

var (
// GroupVersion is group version used to register these objects
GroupVersion = schema.GroupVersion{Group: "config.porch.kpt.dev", Version: "v1alpha1"}

// SchemeBuilder is used to add go types to the GroupVersionKind scheme
SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion}

// AddToScheme adds the types in this group-version to the given scheme.
AddToScheme = SchemeBuilder.AddToScheme
)
Loading

0 comments on commit 9dd1910

Please sign in to comment.