Skip to content

Commit a660be5

Browse files
committed
cmd: add render subcommand to be used by openshift/installer
to add the rolebindingrestriction crd as a bootstrap manifest Signed-off-by: Bryce Palmer <[email protected]>
1 parent d52377c commit a660be5

File tree

4 files changed

+171
-2
lines changed

4 files changed

+171
-2
lines changed

cmd/authentication-operator/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55

66
"github.com/openshift/cluster-authentication-operator/pkg/cmd/mom"
77
"github.com/openshift/cluster-authentication-operator/pkg/cmd/operator"
8+
"github.com/openshift/cluster-authentication-operator/pkg/cmd/render"
89
"github.com/spf13/cobra"
910
"k8s.io/cli-runtime/pkg/genericiooptions"
1011
"k8s.io/component-base/cli"
@@ -34,6 +35,7 @@ func NewAuthenticationOperatorCommand() *cobra.Command {
3435
cmd.AddCommand(mom.NewApplyConfigurationCommand(ioStreams))
3536
cmd.AddCommand(mom.NewInputResourcesCommand(ioStreams))
3637
cmd.AddCommand(mom.NewOutputResourcesCommand(ioStreams))
38+
cmd.AddCommand(render.NewRender())
3739

3840
return cmd
3941
}

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,13 @@ require (
1212
github.com/openshift/library-go v0.0.0-20250113163708-355465391f40
1313
github.com/openshift/multi-operator-manager v0.0.0-20241205181422-20aa3906b99d
1414
github.com/spf13/cobra v1.8.1
15+
github.com/spf13/pflag v1.0.5
1516
github.com/stretchr/testify v1.9.0
1617
go.etcd.io/etcd/client/v3 v3.5.14
1718
golang.org/x/net v0.29.0
1819
gopkg.in/yaml.v2 v2.4.0
1920
k8s.io/api v0.31.1
21+
k8s.io/apiextensions-apiserver v0.31.1
2022
k8s.io/apimachinery v0.31.1
2123
k8s.io/apiserver v0.31.1
2224
k8s.io/cli-runtime v0.31.1
@@ -81,7 +83,6 @@ require (
8183
github.com/robfig/cron v1.2.0 // indirect
8284
github.com/shopspring/decimal v1.3.1 // indirect
8385
github.com/sirupsen/logrus v1.9.3 // indirect
84-
github.com/spf13/pflag v1.0.5 // indirect
8586
github.com/stoewer/go-strcase v1.2.0 // indirect
8687
github.com/x448/float16 v0.8.4 // indirect
8788
go.etcd.io/etcd/api/v3 v3.5.14 // indirect
@@ -113,7 +114,6 @@ require (
113114
gopkg.in/inf.v0 v0.9.1 // indirect
114115
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
115116
gopkg.in/yaml.v3 v3.0.1 // indirect
116-
k8s.io/apiextensions-apiserver v0.31.1 // indirect
117117
k8s.io/kms v0.31.1 // indirect
118118
k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect
119119
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.30.3 // indirect

pkg/cmd/render/render.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
package render
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"path/filepath"
7+
8+
"github.com/openshift/cluster-authentication-operator/bindata"
9+
"github.com/spf13/cobra"
10+
"github.com/spf13/pflag"
11+
)
12+
13+
type Permission os.FileMode
14+
15+
const (
16+
PermissionDirectoryDefault Permission = 0755
17+
PermissionFileDefault Permission = 0644
18+
)
19+
20+
type AssetsFunc func(name string) ([]byte, error)
21+
22+
type RenderOptions struct {
23+
AssetOutputDir string
24+
Assets AssetsFunc
25+
AssetsToRender []string
26+
}
27+
28+
func (ro *RenderOptions) AddFlags(fs *pflag.FlagSet) {
29+
fs.StringVar(&ro.AssetOutputDir, "asset-output-dir", ro.AssetOutputDir, "Output path for rendered manifests.")
30+
}
31+
32+
func (ro *RenderOptions) Run() error {
33+
err := os.MkdirAll(ro.AssetOutputDir, os.FileMode(PermissionDirectoryDefault))
34+
if err != nil {
35+
return fmt.Errorf("creating asset-output-dir: %w", err)
36+
}
37+
38+
for _, assetToRender := range ro.AssetsToRender {
39+
asset, err := ro.Assets(assetToRender)
40+
if err != nil {
41+
return fmt.Errorf("getting asset %q to be rendered: %w", assetToRender, err)
42+
}
43+
44+
filename := filepath.Join(ro.AssetOutputDir, filepath.Base(assetToRender))
45+
err = os.WriteFile(filename, asset, os.FileMode(PermissionFileDefault))
46+
if err != nil {
47+
return fmt.Errorf("rendering asset %q to file %q: %w ", assetToRender, filename, err)
48+
}
49+
}
50+
51+
return nil
52+
}
53+
54+
// NewRender returns a cobra command responsible
55+
// for rendering bootstrap manifests required by the
56+
// cluster-authentication-operator
57+
func NewRender() *cobra.Command {
58+
renderOpts := &RenderOptions{
59+
Assets: bindata.Asset,
60+
AssetsToRender: []string{
61+
"oauth-openshift/authorization.openshift.io_rolebindingrestrictions.yaml",
62+
},
63+
}
64+
65+
renderCmd := &cobra.Command{
66+
Use: "render",
67+
Short: "render bootstrap manifests",
68+
RunE: func(cmd *cobra.Command, args []string) error {
69+
return renderOpts.Run()
70+
},
71+
}
72+
73+
renderOpts.AddFlags(renderCmd.Flags())
74+
75+
return renderCmd
76+
}

pkg/cmd/render/render_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
package render_test
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"io"
7+
"os"
8+
"path/filepath"
9+
"strings"
10+
"testing"
11+
12+
"github.com/openshift/cluster-authentication-operator/pkg/cmd/render"
13+
)
14+
15+
func TestRenderOptionsRun(t *testing.T) {
16+
type testcase struct {
17+
name string
18+
assets render.AssetsFunc
19+
assetsToRender []string
20+
expectedErr error
21+
expectedAssets map[string][]byte
22+
}
23+
24+
testcases := []testcase{
25+
{
26+
name: "asset-output-dir can be created, fetching asset fails, error",
27+
assets: func(name string) ([]byte, error) {
28+
return nil, errors.New("boom")
29+
},
30+
assetsToRender: []string{
31+
"foobar",
32+
},
33+
expectedAssets: make(map[string][]byte),
34+
expectedErr: errors.New("getting asset \"foobar\" to be rendered:"),
35+
},
36+
{
37+
name: "asset-output-dir can be created, fetching asset successful, no error, manifest rendered successfully",
38+
assets: func(name string) ([]byte, error) {
39+
return []byte("baz"), nil
40+
},
41+
assetsToRender: []string{
42+
"foobar",
43+
},
44+
expectedAssets: map[string][]byte{
45+
"foobar": []byte("baz"),
46+
},
47+
expectedErr: nil,
48+
},
49+
}
50+
51+
for _, tc := range testcases {
52+
t.Run(tc.name, func(t *testing.T) {
53+
tempDir := t.TempDir()
54+
renderOpts := &render.RenderOptions{
55+
AssetOutputDir: tempDir,
56+
Assets: tc.assets,
57+
AssetsToRender: tc.assetsToRender,
58+
}
59+
err := renderOpts.Run()
60+
switch {
61+
case err != nil && tc.expectedErr != nil:
62+
if !strings.Contains(err.Error(), tc.expectedErr.Error()) {
63+
t.Fatalf("received error %q does not contain expected error substring %q", err.Error(), tc.expectedErr.Error())
64+
}
65+
case err != nil && tc.expectedErr == nil:
66+
t.Fatalf("received unexpected error %v", err)
67+
case err == nil && tc.expectedErr != nil:
68+
t.Fatalf("expected and error containing substring %q but did not receive an error", tc.expectedErr.Error())
69+
}
70+
71+
for path, contents := range tc.expectedAssets {
72+
file, err := os.Open(filepath.Join(tempDir, path))
73+
if err != nil {
74+
if os.IsNotExist(err) {
75+
t.Fatalf("expected rendered manifest %q to exist in filesystem but it does not", path)
76+
}
77+
t.Fatalf("received unexpected error when checking for existence of rendered manifest %q in filesystem: %v", path, err)
78+
}
79+
80+
fileContents, err := io.ReadAll(file)
81+
if err != nil {
82+
t.Fatalf("received unexpected error when reading contents of file %q: %v", path, err)
83+
}
84+
85+
if !bytes.Equal(fileContents, contents) {
86+
t.Fatalf("contents for rendered manifest %q do not match the expected. Rendered contents: %v, expected: %v", path, string(fileContents), string(contents))
87+
}
88+
}
89+
})
90+
}
91+
}

0 commit comments

Comments
 (0)