Skip to content

Commit d2255fe

Browse files
author
Mengqi Yu
committed
move scaffold pkg from controller-tools
1 parent 7c492d0 commit d2255fe

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+4589
-15
lines changed

cmd/kubebuilder/api.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ import (
2828
"github.com/spf13/cobra"
2929
flag "github.com/spf13/pflag"
3030

31-
"sigs.k8s.io/controller-tools/pkg/scaffold"
32-
"sigs.k8s.io/controller-tools/pkg/scaffold/controller"
33-
"sigs.k8s.io/controller-tools/pkg/scaffold/input"
34-
"sigs.k8s.io/controller-tools/pkg/scaffold/resource"
3531
"sigs.k8s.io/kubebuilder/cmd/kubebuilder/util"
32+
"sigs.k8s.io/kubebuilder/pkg/scaffold"
33+
"sigs.k8s.io/kubebuilder/pkg/scaffold/controller"
34+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
35+
"sigs.k8s.io/kubebuilder/pkg/scaffold/resource"
3636
)
3737

3838
type apiOptions struct {

cmd/kubebuilder/init_project.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,11 @@ import (
2929
"github.com/spf13/cobra"
3030
flag "github.com/spf13/pflag"
3131

32-
"sigs.k8s.io/controller-tools/pkg/scaffold"
33-
"sigs.k8s.io/controller-tools/pkg/scaffold/input"
34-
"sigs.k8s.io/controller-tools/pkg/scaffold/manager"
35-
"sigs.k8s.io/controller-tools/pkg/scaffold/project"
3632
"sigs.k8s.io/kubebuilder/cmd/kubebuilder/util"
33+
"sigs.k8s.io/kubebuilder/pkg/scaffold"
34+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
35+
"sigs.k8s.io/kubebuilder/pkg/scaffold/manager"
36+
"sigs.k8s.io/kubebuilder/pkg/scaffold/project"
3737
)
3838

3939
func newInitProjectCmd() *cobra.Command {

cmd/kubebuilder/vendor_update.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@ import (
2020
"log"
2121

2222
"github.com/spf13/cobra"
23-
"sigs.k8s.io/controller-tools/pkg/scaffold"
24-
"sigs.k8s.io/controller-tools/pkg/scaffold/input"
25-
"sigs.k8s.io/controller-tools/pkg/scaffold/project"
23+
"sigs.k8s.io/kubebuilder/pkg/scaffold"
24+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
25+
"sigs.k8s.io/kubebuilder/pkg/scaffold/project"
2626
)
2727

2828
func newVendorUpdateCmd() *cobra.Command {

cmd/kubebuilder/webhook.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ import (
2727

2828
"k8s.io/apimachinery/pkg/api/meta"
2929
"k8s.io/apimachinery/pkg/runtime/schema"
30-
"sigs.k8s.io/controller-tools/pkg/scaffold"
31-
"sigs.k8s.io/controller-tools/pkg/scaffold/input"
32-
"sigs.k8s.io/controller-tools/pkg/scaffold/resource"
33-
"sigs.k8s.io/controller-tools/pkg/scaffold/webhook"
30+
"sigs.k8s.io/kubebuilder/pkg/scaffold"
31+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
32+
"sigs.k8s.io/kubebuilder/pkg/scaffold/resource"
33+
"sigs.k8s.io/kubebuilder/pkg/scaffold/webhook"
3434
)
3535

3636
func newWebhookCmd() *cobra.Command {

pkg/scaffold/controller/add.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controller
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
"strings"
23+
24+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
25+
"sigs.k8s.io/kubebuilder/pkg/scaffold/resource"
26+
)
27+
28+
var _ input.File = &AddController{}
29+
30+
// AddController scaffolds adds a new Controller.
31+
type AddController struct {
32+
input.Input
33+
34+
// Resource is a resource in the API group
35+
Resource *resource.Resource
36+
}
37+
38+
// GetInput implements input.File
39+
func (a *AddController) GetInput() (input.Input, error) {
40+
if a.Path == "" {
41+
a.Path = filepath.Join("pkg", "controller", fmt.Sprintf(
42+
"add_%s.go", strings.ToLower(a.Resource.Kind)))
43+
}
44+
a.TemplateBody = addControllerTemplate
45+
return a.Input, nil
46+
}
47+
48+
var addControllerTemplate = `{{ .Boilerplate }}
49+
50+
package controller
51+
52+
import (
53+
"{{ .Repo }}/pkg/controller/{{ lower .Resource.Kind }}"
54+
)
55+
56+
func init() {
57+
// AddToManagerFuncs is a list of functions to create controllers and add them to a manager.
58+
AddToManagerFuncs = append(AddToManagerFuncs, {{ lower .Resource.Kind }}.Add)
59+
}
60+
`

pkg/scaffold/controller/controller.go

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
/*
2+
Copyright 2018 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package controller
18+
19+
import (
20+
"fmt"
21+
"os"
22+
"path"
23+
"path/filepath"
24+
"strings"
25+
26+
"github.com/markbates/inflect"
27+
"sigs.k8s.io/kubebuilder/pkg/scaffold/input"
28+
"sigs.k8s.io/kubebuilder/pkg/scaffold/resource"
29+
)
30+
31+
// Controller scaffolds a Controller for a Resource
32+
type Controller struct {
33+
input.Input
34+
35+
// Resource is the Resource to make the Controller for
36+
Resource *resource.Resource
37+
38+
// ResourcePackage is the package of the Resource
39+
ResourcePackage string
40+
41+
// Plural is the plural lowercase of kind
42+
Plural string
43+
44+
// Is the Group + "." + Domain for the Resource
45+
GroupDomain string
46+
}
47+
48+
// GetInput implements input.File
49+
func (a *Controller) GetInput() (input.Input, error) {
50+
// Use the k8s.io/api package for core resources
51+
coreGroups := map[string]string{
52+
"apps": "",
53+
"admissionregistration": "k8s.io",
54+
"apiextensions": "k8s.io",
55+
"authentication": "k8s.io",
56+
"autoscaling": "",
57+
"batch": "",
58+
"certificates": "k8s.io",
59+
"core": "",
60+
"extensions": "",
61+
"metrics": "k8s.io",
62+
"policy": "",
63+
"rbac.authorization": "k8s.io",
64+
"storage": "k8s.io",
65+
}
66+
67+
a.ResourcePackage, a.GroupDomain = getResourceInfo(coreGroups, a.Resource, a.Input)
68+
69+
if a.Plural == "" {
70+
rs := inflect.NewDefaultRuleset()
71+
a.Plural = rs.Pluralize(strings.ToLower(a.Resource.Kind))
72+
}
73+
74+
if a.Path == "" {
75+
a.Path = filepath.Join("pkg", "controller",
76+
strings.ToLower(a.Resource.Kind),
77+
strings.ToLower(a.Resource.Kind)+"_controller.go")
78+
}
79+
a.TemplateBody = controllerTemplate
80+
a.Input.IfExistsAction = input.Error
81+
return a.Input, nil
82+
}
83+
84+
func getResourceInfo(coreGroups map[string]string, r *resource.Resource, in input.Input) (resourcePackage, groupDomain string) {
85+
resourcePath := filepath.Join("pkg", "apis", r.Group, r.Version,
86+
fmt.Sprintf("%s_types.go", strings.ToLower(r.Kind)))
87+
if _, err := os.Stat(resourcePath); os.IsNotExist(err) {
88+
if domain, found := coreGroups[r.Group]; found {
89+
resourcePackage := path.Join("k8s.io", "api")
90+
groupDomain = r.Group
91+
if domain != "" {
92+
groupDomain = r.Group + "." + domain
93+
}
94+
return resourcePackage, groupDomain
95+
}
96+
// TODO: need to support '--resource-pkg-path' flag for specifying resourcePath
97+
}
98+
return path.Join(in.Repo, "pkg", "apis"), r.Group + "." + in.Domain
99+
}
100+
101+
var controllerTemplate = `{{ .Boilerplate }}
102+
103+
package {{ lower .Resource.Kind }}
104+
105+
import (
106+
{{ if .Resource.CreateExampleReconcileBody }} "context"
107+
"log"
108+
"reflect"
109+
110+
appsv1 "k8s.io/api/apps/v1"
111+
corev1 "k8s.io/api/core/v1"
112+
"k8s.io/apimachinery/pkg/api/errors"
113+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
114+
"k8s.io/apimachinery/pkg/runtime/schema"
115+
"k8s.io/apimachinery/pkg/runtime"
116+
"k8s.io/apimachinery/pkg/types"
117+
"sigs.k8s.io/controller-runtime/pkg/client"
118+
"sigs.k8s.io/controller-runtime/pkg/controller"
119+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
120+
"sigs.k8s.io/controller-runtime/pkg/handler"
121+
"sigs.k8s.io/controller-runtime/pkg/manager"
122+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
123+
"sigs.k8s.io/controller-runtime/pkg/source"
124+
{{ .Resource.Group}}{{ .Resource.Version }} "{{ .ResourcePackage }}/{{ .Resource.Group}}/{{ .Resource.Version }}"
125+
{{ else }} "context"
126+
127+
appsv1 "k8s.io/api/apps/v1"
128+
"k8s.io/apimachinery/pkg/api/errors"
129+
"sigs.k8s.io/controller-runtime/pkg/client"
130+
"sigs.k8s.io/controller-runtime/pkg/controller"
131+
"sigs.k8s.io/controller-runtime/pkg/handler"
132+
"sigs.k8s.io/controller-runtime/pkg/manager"
133+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
134+
"sigs.k8s.io/controller-runtime/pkg/source"
135+
{{ .Resource.Group}}{{ .Resource.Version }} "{{ .ResourcePackage }}/{{ .Resource.Group}}/{{ .Resource.Version }}"
136+
{{ end -}}
137+
)
138+
139+
/**
140+
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
141+
* business logic. Delete these comments after modifying this file.*
142+
*/
143+
144+
// Add creates a new {{ .Resource.Kind }} Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller
145+
// and Start it when the Manager is Started.
146+
// USER ACTION REQUIRED: update cmd/manager/main.go to call this {{ .Resource.Group}}.Add(mgr) to install this Controller
147+
func Add(mgr manager.Manager) error {
148+
return add(mgr, newReconciler(mgr))
149+
}
150+
151+
// newReconciler returns a new reconcile.Reconciler
152+
func newReconciler(mgr manager.Manager) reconcile.Reconciler {
153+
return &Reconcile{{ .Resource.Kind }}{Client: mgr.GetClient(), scheme: mgr.GetScheme()}
154+
}
155+
156+
// add adds a new Controller to mgr with r as the reconcile.Reconciler
157+
func add(mgr manager.Manager, r reconcile.Reconciler) error {
158+
// Create a new controller
159+
c, err := controller.New("{{ lower .Resource.Kind }}-controller", mgr, controller.Options{Reconciler: r})
160+
if err != nil {
161+
return err
162+
}
163+
164+
// Watch for changes to {{ .Resource.Kind }}
165+
err = c.Watch(&source.Kind{Type: &{{ .Resource.Group}}{{ .Resource.Version }}.{{ .Resource.Kind }}{}}, &handler.EnqueueRequestForObject{})
166+
if err != nil {
167+
return err
168+
}
169+
170+
// TODO(user): Modify this to be the types you create
171+
// Uncomment watch a Deployment created by {{ .Resource.Kind }} - change this for objects you create
172+
err = c.Watch(&source.Kind{Type: &appsv1.Deployment{}}, &handler.EnqueueRequestForOwner{
173+
IsController: true,
174+
OwnerType: &{{ .Resource.Group}}{{ .Resource.Version }}.{{ .Resource.Kind }}{},
175+
})
176+
if err != nil {
177+
return err
178+
}
179+
180+
return nil
181+
}
182+
183+
var _ reconcile.Reconciler = &Reconcile{{ .Resource.Kind }}{}
184+
185+
// Reconcile{{ .Resource.Kind }} reconciles a {{ .Resource.Kind }} object
186+
type Reconcile{{ .Resource.Kind }} struct {
187+
client.Client
188+
scheme *runtime.Scheme
189+
}
190+
191+
// Reconcile reads that state of the cluster for a {{ .Resource.Kind }} object and makes changes based on the state read
192+
// and what is in the {{ .Resource.Kind }}.Spec
193+
// TODO(user): Modify this Reconcile function to implement your Controller logic. The scaffolding writes
194+
// a Deployment as an example
195+
{{ if .Resource.CreateExampleReconcileBody -}}
196+
// Automatically generate RBAC rules to allow the Controller to read and write Deployments
197+
// +kubebuilder:rbac:groups=apps,resources=deployments,verbs=get;list;watch;create;update;patch;delete
198+
{{ end -}}
199+
// +kubebuilder:rbac:groups={{.GroupDomain}},resources={{ .Plural }},verbs=get;list;watch;create;update;patch;delete
200+
func (r *Reconcile{{ .Resource.Kind }}) Reconcile(request reconcile.Request) (reconcile.Result, error) {
201+
// Fetch the {{ .Resource.Kind }} instance
202+
instance := &{{ .Resource.Group}}{{ .Resource.Version }}.{{ .Resource.Kind }}{}
203+
err := r.Get(context.TODO(), request.NamespacedName, instance)
204+
if err != nil {
205+
if errors.IsNotFound(err) {
206+
// Object not found, return. Created objects are automatically garbage collected.
207+
// For additional cleanup logic use finalizers.
208+
return reconcile.Result{}, nil
209+
}
210+
// Error reading the object - requeue the request.
211+
return reconcile.Result{}, err
212+
}
213+
214+
{{ if .Resource.CreateExampleReconcileBody -}}
215+
// TODO(user): Change this to be the object type created by your controller
216+
// Define the desired Deployment object
217+
deploy := &appsv1.Deployment{
218+
ObjectMeta: metav1.ObjectMeta{
219+
Name: instance.Name + "-deployment",
220+
Namespace: {{ if .Resource.Namespaced}}instance.Namespace{{ else }}"default"{{ end }},
221+
},
222+
Spec: appsv1.DeploymentSpec{
223+
Selector: &metav1.LabelSelector{
224+
MatchLabels: map[string]string{"deployment": instance.Name + "-deployment"},
225+
},
226+
Template: corev1.PodTemplateSpec{
227+
ObjectMeta: metav1.ObjectMeta{Labels: map[string]string{"deployment": instance.Name + "-deployment"}},
228+
Spec: corev1.PodSpec{
229+
Containers: []corev1.Container{
230+
{
231+
Name: "nginx",
232+
Image: "nginx",
233+
},
234+
},
235+
},
236+
},
237+
},
238+
}
239+
if err := controllerutil.SetControllerReference(instance, deploy, r.scheme); err != nil {
240+
return reconcile.Result{}, err
241+
}
242+
243+
// TODO(user): Change this for the object type created by your controller
244+
// Check if the Deployment already exists
245+
found := &appsv1.Deployment{}
246+
err = r.Get(context.TODO(), types.NamespacedName{Name: deploy.Name, Namespace: deploy.Namespace}, found)
247+
if err != nil && errors.IsNotFound(err) {
248+
log.Printf("Creating Deployment %s/%s\n", deploy.Namespace, deploy.Name)
249+
err = r.Create(context.TODO(), deploy)
250+
if err != nil {
251+
return reconcile.Result{}, err
252+
}
253+
} else if err != nil {
254+
return reconcile.Result{}, err
255+
}
256+
257+
// TODO(user): Change this for the object type created by your controller
258+
// Update the found object and write the result back if there are any changes
259+
if !reflect.DeepEqual(deploy.Spec, found.Spec) {
260+
found.Spec = deploy.Spec
261+
log.Printf("Updating Deployment %s/%s\n", deploy.Namespace, deploy.Name)
262+
err = r.Update(context.TODO(), found)
263+
if err != nil {
264+
return reconcile.Result{}, err
265+
}
266+
}
267+
{{ end -}}
268+
269+
return reconcile.Result{}, nil
270+
}
271+
`

0 commit comments

Comments
 (0)