diff --git a/generated_golden.sh b/generated_golden.sh index 1b2443b7bb4..8a83a937feb 100755 --- a/generated_golden.sh +++ b/generated_golden.sh @@ -67,6 +67,7 @@ scaffold_test_project() { $kb create webhook --group crew --version v1 --kind Captain --defaulting --programmatic-validation $kb create api --group crew --version v1 --kind FirstMate --controller=true --resource=true --make=false $kb create webhook --group crew --version v1 --kind FirstMate --conversion + $kb create api --group crew --version v1 --kind Admiral --controller=true --resource=true --namespaced=false --make=false # TODO(droot): Adding a second group is a valid test case and kubebuilder is expected to report an error in this case. It # doesn't do that currently so leaving it commented so that we can enable it later. # $kb create api --group ship --version v1beta1 --kind Frigate --example=false --controller=true --resource=true --make=false diff --git a/pkg/scaffold/v2/types.go b/pkg/scaffold/v2/types.go index 24366cca8f3..17a3356870b 100644 --- a/pkg/scaffold/v2/types.go +++ b/pkg/scaffold/v2/types.go @@ -75,6 +75,7 @@ type {{.Resource.Kind}}Status struct { } // +kubebuilder:object:root=true +{{ if not .Resource.Namespaced }} // +kubebuilder:resource:scope=Cluster {{ end }} // {{.Resource.Kind}} is the Schema for the {{ .Resource.Resource }} API type {{.Resource.Kind}} struct { diff --git a/testdata/project-v2/PROJECT b/testdata/project-v2/PROJECT index cf393d4ed16..f866d89dc89 100644 --- a/testdata/project-v2/PROJECT +++ b/testdata/project-v2/PROJECT @@ -8,3 +8,6 @@ resources: - group: crew version: v1 kind: FirstMate +- group: crew + version: v1 + kind: Admiral diff --git a/testdata/project-v2/api/v1/admiral_types.go b/testdata/project-v2/api/v1/admiral_types.go new file mode 100644 index 00000000000..2fc3c728301 --- /dev/null +++ b/testdata/project-v2/api/v1/admiral_types.go @@ -0,0 +1,61 @@ +/* +Copyright 2019 The Kubernetes authors. + +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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! +// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. + +// AdmiralSpec defines the desired state of Admiral +type AdmiralSpec struct { + // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// AdmiralStatus defines the observed state of Admiral +type AdmiralStatus struct { + // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster + // Important: Run "make" to regenerate code after modifying this file +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster + +// Admiral is the Schema for the admirals API +type Admiral struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec AdmiralSpec `json:"spec,omitempty"` + Status AdmiralStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// AdmiralList contains a list of Admiral +type AdmiralList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []Admiral `json:"items"` +} + +func init() { + SchemeBuilder.Register(&Admiral{}, &AdmiralList{}) +} diff --git a/testdata/project-v2/api/v1/zz_generated.deepcopy.go b/testdata/project-v2/api/v1/zz_generated.deepcopy.go index cc2c50f293c..75068713cd8 100644 --- a/testdata/project-v2/api/v1/zz_generated.deepcopy.go +++ b/testdata/project-v2/api/v1/zz_generated.deepcopy.go @@ -24,6 +24,95 @@ import ( "k8s.io/apimachinery/pkg/runtime" ) +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Admiral) DeepCopyInto(out *Admiral) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Admiral. +func (in *Admiral) DeepCopy() *Admiral { + if in == nil { + return nil + } + out := new(Admiral) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Admiral) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmiralList) DeepCopyInto(out *AdmiralList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Admiral, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmiralList. +func (in *AdmiralList) DeepCopy() *AdmiralList { + if in == nil { + return nil + } + out := new(AdmiralList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *AdmiralList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmiralSpec) DeepCopyInto(out *AdmiralSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmiralSpec. +func (in *AdmiralSpec) DeepCopy() *AdmiralSpec { + if in == nil { + return nil + } + out := new(AdmiralSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AdmiralStatus) DeepCopyInto(out *AdmiralStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AdmiralStatus. +func (in *AdmiralStatus) DeepCopy() *AdmiralStatus { + if in == nil { + return nil + } + out := new(AdmiralStatus) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Captain) DeepCopyInto(out *Captain) { *out = *in diff --git a/testdata/project-v2/config/crd/bases/crew.testproject.org_admirals.yaml b/testdata/project-v2/config/crd/bases/crew.testproject.org_admirals.yaml new file mode 100644 index 00000000000..08a6ede151c --- /dev/null +++ b/testdata/project-v2/config/crd/bases/crew.testproject.org_admirals.yaml @@ -0,0 +1,46 @@ + +--- +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + creationTimestamp: null + name: admirals.crew.testproject.org +spec: + group: crew.testproject.org + names: + kind: Admiral + plural: admirals + scope: Cluster + validation: + openAPIV3Schema: + description: Admiral is the Schema for the admirals API + 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/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/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: AdmiralSpec defines the desired state of Admiral + type: object + status: + description: AdmiralStatus defines the observed state of Admiral + type: object + type: object + versions: + - name: v1 + served: true + storage: true +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/testdata/project-v2/config/crd/kustomization.yaml b/testdata/project-v2/config/crd/kustomization.yaml index 2ccf34d0288..63799882c02 100644 --- a/testdata/project-v2/config/crd/kustomization.yaml +++ b/testdata/project-v2/config/crd/kustomization.yaml @@ -4,6 +4,7 @@ resources: - bases/crew.testproject.org_captains.yaml - bases/crew.testproject.org_firstmates.yaml +- bases/crew.testproject.org_admirals.yaml # +kubebuilder:scaffold:crdkustomizeresource patches: @@ -11,12 +12,14 @@ patches: # patches here are for enabling the conversion webhook for each CRD #- patches/webhook_in_captains.yaml #- patches/webhook_in_firstmates.yaml +#- patches/webhook_in_admirals.yaml # +kubebuilder:scaffold:crdkustomizewebhookpatch # [CERTMANAGER] To enable webhook, uncomment all the sections with [CERTMANAGER] prefix. # patches here are for enabling the CA injection for each CRD #- patches/cainjection_in_captains.yaml #- patches/cainjection_in_firstmates.yaml +#- patches/cainjection_in_admirals.yaml # +kubebuilder:scaffold:crdkustomizecainjectionpatch # the following config is for teaching kustomize how to do kustomization for CRDs. diff --git a/testdata/project-v2/config/crd/patches/cainjection_in_admirals.yaml b/testdata/project-v2/config/crd/patches/cainjection_in_admirals.yaml new file mode 100644 index 00000000000..232dee80fb3 --- /dev/null +++ b/testdata/project-v2/config/crd/patches/cainjection_in_admirals.yaml @@ -0,0 +1,8 @@ +# The following patch adds a directive for certmanager to inject CA into the CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + annotations: + certmanager.k8s.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME) + name: admirals.crew.testproject.org diff --git a/testdata/project-v2/config/crd/patches/webhook_in_admirals.yaml b/testdata/project-v2/config/crd/patches/webhook_in_admirals.yaml new file mode 100644 index 00000000000..2b9bf612404 --- /dev/null +++ b/testdata/project-v2/config/crd/patches/webhook_in_admirals.yaml @@ -0,0 +1,17 @@ +# The following patch enables conversion webhook for CRD +# CRD conversion requires k8s 1.13 or later. +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: admirals.crew.testproject.org +spec: + conversion: + strategy: Webhook + webhookClientConfig: + # this is "\n" used as a placeholder, otherwise it will be rejected by the apiserver for being blank, + # but we're going to set it later using the cert-manager (or potentially a patch if not using cert-manager) + caBundle: Cg== + service: + namespace: system + name: webhook-service + path: /convert diff --git a/testdata/project-v2/config/rbac/role.yaml b/testdata/project-v2/config/rbac/role.yaml index 40bb6acd137..76c829a9128 100644 --- a/testdata/project-v2/config/rbac/role.yaml +++ b/testdata/project-v2/config/rbac/role.yaml @@ -26,6 +26,26 @@ rules: - get - patch - update +- apiGroups: + - crew.testproject.org + resources: + - admirals + verbs: + - create + - delete + - get + - list + - patch + - update + - watch +- apiGroups: + - crew.testproject.org + resources: + - admirals/status + verbs: + - get + - patch + - update - apiGroups: - crew.testproject.org resources: diff --git a/testdata/project-v2/config/samples/crew_v1_admiral.yaml b/testdata/project-v2/config/samples/crew_v1_admiral.yaml new file mode 100644 index 00000000000..0fd9ae039ef --- /dev/null +++ b/testdata/project-v2/config/samples/crew_v1_admiral.yaml @@ -0,0 +1,7 @@ +apiVersion: crew.testproject.org/v1 +kind: Admiral +metadata: + name: admiral-sample +spec: + # Add fields here + foo: bar diff --git a/testdata/project-v2/controllers/admiral_controller.go b/testdata/project-v2/controllers/admiral_controller.go new file mode 100644 index 00000000000..a05401a5b34 --- /dev/null +++ b/testdata/project-v2/controllers/admiral_controller.go @@ -0,0 +1,51 @@ +/* +Copyright 2019 The Kubernetes authors. + +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 controllers + +import ( + "context" + + "github.com/go-logr/logr" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + + crewv1 "sigs.k8s.io/kubebuilder/testdata/project-v2/api/v1" +) + +// AdmiralReconciler reconciles a Admiral object +type AdmiralReconciler struct { + client.Client + Log logr.Logger +} + +// +kubebuilder:rbac:groups=crew.testproject.org,resources=admirals,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=crew.testproject.org,resources=admirals/status,verbs=get;update;patch + +func (r *AdmiralReconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { + _ = context.Background() + _ = r.Log.WithValues("admiral", req.NamespacedName) + + // your logic here + + return ctrl.Result{}, nil +} + +func (r *AdmiralReconciler) SetupWithManager(mgr ctrl.Manager) error { + return ctrl.NewControllerManagedBy(mgr). + For(&crewv1.Admiral{}). + Complete(r) +} diff --git a/testdata/project-v2/controllers/suite_test.go b/testdata/project-v2/controllers/suite_test.go index 24cf9102047..2f64f89096f 100644 --- a/testdata/project-v2/controllers/suite_test.go +++ b/testdata/project-v2/controllers/suite_test.go @@ -68,6 +68,9 @@ var _ = BeforeSuite(func(done Done) { err = crewv1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) + err = crewv1.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + err = corev1.AddToScheme(scheme.Scheme) Expect(err).NotTo(HaveOccurred()) diff --git a/testdata/project-v2/main.go b/testdata/project-v2/main.go index 5ea59ea6907..0b040421298 100644 --- a/testdata/project-v2/main.go +++ b/testdata/project-v2/main.go @@ -86,6 +86,13 @@ func main() { setupLog.Error(err, "unable to create webhook", "webhook", "FirstMate") os.Exit(1) } + if err = (&controllers.AdmiralReconciler{ + Client: mgr.GetClient(), + Log: ctrl.Log.WithName("controllers").WithName("Admiral"), + }).SetupWithManager(mgr); err != nil { + setupLog.Error(err, "unable to create controller", "controller", "Admiral") + os.Exit(1) + } if err = (&controllers.NamespaceReconciler{ Client: mgr.GetClient(), Log: ctrl.Log.WithName("controllers").WithName("Namespace"),