Skip to content

Commit af24fad

Browse files
committed
feat: generate Dockerfile from declarative plugin
We need to copy the channels directory in the Dockerfile, particularly now that we're running with non-root permissions and it is no longer a one-liner. Signed-off-by: Vivek Singh <[email protected]>
1 parent 958ac27 commit af24fad

File tree

14 files changed

+204
-30
lines changed

14 files changed

+204
-30
lines changed

.github/workflows/apidiff.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ jobs:
2121
with:
2222
go-version: '1.17'
2323
- name: Execute go-apidiff
24-
uses: joelanford/go-apidiff@v0.1.0
24+
uses: joelanford/go-apidiff@v0.2.0
2525
with:
2626
compare-imports: true
2727
print-compatible: true

pkg/plugins/golang/declarative/v1/api.go

Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,20 @@ package v1
1919
import (
2020
"errors"
2121
"fmt"
22-
"path/filepath"
23-
24-
"github.com/spf13/afero"
2522

2623
"sigs.k8s.io/kubebuilder/v3/pkg/config"
2724
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
2825
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
2926
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
3027
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
31-
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1/internal/templates"
28+
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1/scaffolds"
3229
goPluginV2 "sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/v2"
3330
)
3431

3532
const (
3633
// kbDeclarativePattern is the sigs.k8s.io/kubebuilder-declarative-pattern version
3734
kbDeclarativePatternForV2 = "v0.0.0-20200522144838-848d48e5b073"
3835
kbDeclarativePatternForV3 = "fea7e5cc701290589ec20ef4d9c0629d08b5307d"
39-
40-
exampleManifestVersion = "0.0.1"
4136
)
4237

4338
var _ plugin.CreateAPISubcommand = &createAPISubcommand{}
@@ -97,27 +92,17 @@ func (p *createAPISubcommand) InjectResource(res *resource.Resource) error {
9792
func (p *createAPISubcommand) Scaffold(fs machinery.Filesystem) error {
9893
fmt.Println("updating scaffold with declarative pattern...")
9994

100-
// Load the boilerplate
101-
bp, err := afero.ReadFile(fs.FS, filepath.Join("hack", "boilerplate.go.txt"))
95+
scaffolder := scaffolds.NewAPIScaffolder(p.config, *p.resource)
96+
scaffolder.InjectFS(fs)
97+
err := scaffolder.Scaffold()
10298
if err != nil {
103-
return fmt.Errorf("error updating scaffold: unable to load boilerplate: %w", err)
99+
return err
104100
}
105-
boilerplate := string(bp)
106-
107-
// Initialize the machinery.Scaffold that will write the files to disk
108-
scaffold := machinery.NewScaffold(fs,
109-
machinery.WithConfig(p.config),
110-
machinery.WithBoilerplate(boilerplate),
111-
machinery.WithResource(p.resource),
112-
)
113-
114-
if err := scaffold.Execute(
115-
&templates.Types{},
116-
&templates.Controller{},
117-
&templates.Channel{ManifestVersion: exampleManifestVersion},
118-
&templates.Manifest{ManifestVersion: exampleManifestVersion},
119-
); err != nil {
120-
return fmt.Errorf("error updating scaffold: %w", err)
101+
102+
// Update Dockerfile
103+
err = updateDockerfile()
104+
if err != nil {
105+
return err
121106
}
122107

123108
// Track the resources following a declarative approach
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
Copyright 2021 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 v1
18+
19+
import (
20+
"fmt"
21+
"io/ioutil"
22+
"path/filepath"
23+
"strings"
24+
25+
"sigs.k8s.io/kubebuilder/v3/pkg/config"
26+
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
27+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin"
28+
"sigs.k8s.io/kubebuilder/v3/pkg/plugin/util"
29+
)
30+
31+
var _ plugin.InitSubcommand = &initSubcommand{}
32+
33+
type initSubcommand struct {
34+
config config.Config
35+
}
36+
37+
func (p *initSubcommand) InjectConfig(c config.Config) error {
38+
p.config = c
39+
40+
return nil
41+
}
42+
43+
func (p *initSubcommand) Scaffold(fs machinery.Filesystem) error {
44+
err := updateDockerfile()
45+
if err != nil {
46+
return err
47+
}
48+
return nil
49+
}
50+
51+
// updateDockerfile will add channels staging required for declarative plugin
52+
func updateDockerfile() error {
53+
fmt.Println("updating Dockerfile to add channels/ directory in the image")
54+
managerFile := filepath.Join("Dockerfile")
55+
56+
// nolint:lll
57+
err := insertCodeIfDoesNotExist(managerFile,
58+
"COPY controllers/ controllers/",
59+
"\n# https://github.com/kubernetes-sigs/kubebuilder-declarative-pattern/blob/master/docs/addon/walkthrough/README.md#adding-a-manifest\n# Stage channels and make readable\nCOPY channels/ /channels/\nRUN chmod -R a+rx /channels/")
60+
if err != nil {
61+
return err
62+
}
63+
64+
err = insertCodeIfDoesNotExist(managerFile,
65+
"COPY --from=builder /workspace/manager .",
66+
"\n# copy channels\nCOPY --from=builder /channels /channels\n")
67+
if err != nil {
68+
return err
69+
}
70+
return nil
71+
}
72+
73+
// insertCodeIfDoesNotExist insert code if it does not already exists
74+
func insertCodeIfDoesNotExist(filename, target, code string) error {
75+
// false positive
76+
// nolint:gosec
77+
contents, err := ioutil.ReadFile(filename)
78+
if err != nil {
79+
return err
80+
}
81+
82+
idx := strings.Index(string(contents), code)
83+
if idx != -1 {
84+
return nil
85+
}
86+
87+
return util.InsertCode(filename, target, code)
88+
}

pkg/plugins/golang/declarative/v1/plugin.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ var _ plugin.CreateAPI = Plugin{}
3737

3838
// Plugin implements the plugin.Full interface
3939
type Plugin struct {
40+
initSubcommand
4041
createAPISubcommand
4142
}
4243

@@ -49,6 +50,9 @@ func (Plugin) Version() plugin.Version { return pluginVersion }
4950
// SupportedProjectVersions returns an array with all project versions supported by the plugin
5051
func (Plugin) SupportedProjectVersions() []config.Version { return supportedProjectVersions }
5152

53+
// GetInitSubcommand will return the subcommand which is responsible for initializing and common scaffolding
54+
func (p Plugin) GetInitSubcommand() plugin.InitSubcommand { return &p.initSubcommand }
55+
5256
// GetCreateAPISubcommand will return the subcommand which is responsible for scaffolding apis
5357
func (p Plugin) GetCreateAPISubcommand() plugin.CreateAPISubcommand { return &p.createAPISubcommand }
5458

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*
2+
Copyright 2022 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 scaffolds
18+
19+
import (
20+
"fmt"
21+
"path/filepath"
22+
23+
"github.com/spf13/afero"
24+
"sigs.k8s.io/kubebuilder/v3/pkg/config"
25+
"sigs.k8s.io/kubebuilder/v3/pkg/machinery"
26+
"sigs.k8s.io/kubebuilder/v3/pkg/model/resource"
27+
"sigs.k8s.io/kubebuilder/v3/pkg/plugins"
28+
"sigs.k8s.io/kubebuilder/v3/pkg/plugins/golang/declarative/v1/scaffolds/internal/templates"
29+
)
30+
31+
const (
32+
exampleManifestVersion = "0.0.1"
33+
)
34+
35+
var _ plugins.Scaffolder = &apiScaffolder{}
36+
37+
type apiScaffolder struct {
38+
config config.Config
39+
resource resource.Resource
40+
41+
// fs is the filesystem that will be used by the scaffolder
42+
fs machinery.Filesystem
43+
}
44+
45+
// NewAPIScaffolder returns a new Scaffolder for declarative
46+
func NewAPIScaffolder(config config.Config, res resource.Resource) plugins.Scaffolder {
47+
return &apiScaffolder{
48+
config: config,
49+
resource: res,
50+
}
51+
}
52+
53+
// InjectFS implements cmdutil.Scaffolder
54+
func (s *apiScaffolder) InjectFS(fs machinery.Filesystem) {
55+
s.fs = fs
56+
}
57+
58+
// Scaffold implements cmdutil.Scaffolder
59+
func (s *apiScaffolder) Scaffold() error {
60+
// Load the boilerplate
61+
boilerplate, err := afero.ReadFile(s.fs.FS, filepath.Join("hack", "boilerplate.go.txt"))
62+
if err != nil {
63+
return fmt.Errorf("error updating scaffold: unable to load boilerplate: %w", err)
64+
}
65+
66+
// Initialize the machinery.Scaffold that will write the files to disk
67+
scaffold := machinery.NewScaffold(s.fs,
68+
machinery.WithConfig(s.config),
69+
machinery.WithBoilerplate(string(boilerplate)),
70+
machinery.WithResource(&s.resource),
71+
)
72+
73+
err = scaffold.Execute(
74+
&templates.Types{},
75+
&templates.Controller{},
76+
&templates.Channel{ManifestVersion: exampleManifestVersion},
77+
&templates.Manifest{ManifestVersion: exampleManifestVersion},
78+
)
79+
if err != nil {
80+
return fmt.Errorf("error updating scaffold: %w", err)
81+
}
82+
return nil
83+
}

pkg/plugins/golang/v2/scaffolds/internal/templates/dockerfile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ COPY api/ api/
5555
COPY controllers/ controllers/
5656
5757
# Build
58-
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GO111MODULE=on go build -a -o manager main.go
58+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -a -o manager main.go
5959
6060
# Use distroless as minimal base image to package the manager binary
6161
# Refer to https://github.com/GoogleContainerTools/distroless for more details

0 commit comments

Comments
 (0)