15
15
package cmd
16
16
17
17
import (
18
+ "bytes"
18
19
"fmt"
20
+ "io/ioutil"
21
+ "log"
19
22
"os"
20
23
"os/exec"
21
24
25
+ "github.com/operator-framework/operator-sdk/commands/operator-sdk/cmd/cmdutil"
22
26
cmdError "github.com/operator-framework/operator-sdk/commands/operator-sdk/error"
27
+ "github.com/operator-framework/operator-sdk/pkg/generator"
23
28
29
+ "github.com/ghodss/yaml"
24
30
"github.com/spf13/cobra"
25
31
)
26
32
33
+ var (
34
+ namespacedManBuild string
35
+ globalManBuild string
36
+ rbacManBuild string
37
+ testLocationBuild string
38
+ enableTests bool
39
+ )
40
+
27
41
func NewBuildCmd () * cobra.Command {
28
- return & cobra.Command {
42
+ buildCmd := & cobra.Command {
29
43
Use : "build <image>" ,
30
44
Short : "Compiles code and builds artifacts" ,
31
45
Long : `The operator-sdk build command compiles the code, builds the executables,
@@ -42,6 +56,74 @@ For example:
42
56
` ,
43
57
Run : buildFunc ,
44
58
}
59
+ buildCmd .Flags ().BoolVarP (& enableTests , "enable-tests" , "e" , false , "Enable in-cluster testing by adding test binary to the image" )
60
+ buildCmd .Flags ().StringVarP (& testLocationBuild , "test-location" , "t" , "./test/e2e" , "Location of tests" )
61
+ buildCmd .Flags ().StringVarP (& namespacedManBuild , "namespaced" , "n" , "" , "Path of namespaced resources for tests" )
62
+ buildCmd .Flags ().StringVarP (& globalManBuild , "global" , "g" , "deploy/crd.yaml" , "Path of global resources for tests" )
63
+ buildCmd .Flags ().StringVarP (& rbacManBuild , "rbac" , "r" , "deploy/rbac.yaml" , "Path of global resources for tests" )
64
+ return buildCmd
65
+ }
66
+
67
+ func parseRoles (yamlFile []byte ) ([]byte , error ) {
68
+ res := make ([]byte , 0 )
69
+ yamlSplit := bytes .Split (yamlFile , []byte ("\n ---\n " ))
70
+ for _ , yamlSpec := range yamlSplit {
71
+ yamlMap := make (map [string ]interface {})
72
+ err := yaml .Unmarshal (yamlSpec , & yamlMap )
73
+ if err != nil {
74
+ return nil , err
75
+ }
76
+ if yamlMap ["kind" ].(string ) == "Role" {
77
+ ruleBytes , err := yaml .Marshal (yamlMap ["rules" ])
78
+ if err != nil {
79
+ return nil , err
80
+ }
81
+ res = append (res , ruleBytes ... )
82
+ }
83
+ }
84
+ return res , nil
85
+ }
86
+
87
+ func verifyDeploymentImage (yamlFile []byte , imageName string ) string {
88
+ warningMessages := ""
89
+ yamlSplit := bytes .Split (yamlFile , []byte ("\n ---\n " ))
90
+ for _ , yamlSpec := range yamlSplit {
91
+ yamlMap := make (map [string ]interface {})
92
+ err := yaml .Unmarshal (yamlSpec , & yamlMap )
93
+ if err != nil {
94
+ fmt .Printf ("WARNING: Could not unmarshal yaml namespaced spec" )
95
+ return ""
96
+ }
97
+ if yamlMap ["kind" ].(string ) == "Deployment" {
98
+ // this is ugly and hacky; we should probably make this cleaner
99
+ nestedMap , ok := yamlMap ["spec" ].(map [string ]interface {})
100
+ if ! ok {
101
+ continue
102
+ }
103
+ nestedMap , ok = nestedMap ["template" ].(map [string ]interface {})
104
+ if ! ok {
105
+ continue
106
+ }
107
+ nestedMap , ok = nestedMap ["spec" ].(map [string ]interface {})
108
+ if ! ok {
109
+ continue
110
+ }
111
+ containersArray , ok := nestedMap ["containers" ].([]interface {})
112
+ if ! ok {
113
+ continue
114
+ }
115
+ for _ , item := range containersArray {
116
+ image , ok := item .(map [string ]interface {})["image" ].(string )
117
+ if ! ok {
118
+ continue
119
+ }
120
+ if image != imageName {
121
+ warningMessages = fmt .Sprintf ("%s\n WARNING: Namespace manifest contains a deployment with image %v, which does not match the name of the image being built: %v" , warningMessages , image , imageName )
122
+ }
123
+ }
124
+ }
125
+ }
126
+ return warningMessages
45
127
}
46
128
47
129
const (
@@ -56,18 +138,73 @@ func buildFunc(cmd *cobra.Command, args []string) {
56
138
}
57
139
58
140
bcmd := exec .Command (build )
141
+ bcmd .Env = append (os .Environ (), fmt .Sprintf ("TEST_LOCATION=%v" , testLocationBuild ))
142
+ bcmd .Env = append (bcmd .Env , fmt .Sprintf ("ENABLE_TESTS=%v" , enableTests ))
59
143
o , err := bcmd .CombinedOutput ()
60
144
if err != nil {
61
145
cmdError .ExitWithError (cmdError .ExitError , fmt .Errorf ("failed to build: (%v)" , string (o )))
62
146
}
63
147
fmt .Fprintln (os .Stdout , string (o ))
64
148
149
+ namespacedRolesBytes := make ([]byte , 0 )
150
+ genWarning := ""
65
151
image := args [0 ]
152
+ if enableTests {
153
+ if namespacedManBuild == "" {
154
+ os .Mkdir ("deploy/test" , os .FileMode (int (0775 )))
155
+ namespacedManBuild = "deploy/test/namespace-manifests.yaml"
156
+ rbac , err := ioutil .ReadFile ("deploy/rbac.yaml" )
157
+ if err != nil {
158
+ log .Fatalf ("could not find rbac manifest: %v" , err )
159
+ }
160
+ operator , err := ioutil .ReadFile ("deploy/operator.yaml" )
161
+ if err != nil {
162
+ log .Fatalf ("could not find operator manifest: %v" , err )
163
+ }
164
+ combined := append (rbac , []byte ("\n ---\n " )... )
165
+ combined = append (combined , operator ... )
166
+ err = ioutil .WriteFile (namespacedManBuild , combined , os .FileMode (int (0664 )))
167
+ if err != nil {
168
+ log .Fatalf ("could not create temporary namespaced manifest file: %v" , err )
169
+ }
170
+ defer func () {
171
+ err := os .Remove (namespacedManBuild )
172
+ if err != nil {
173
+ log .Fatalf ("could not delete temporary namespace manifest file" )
174
+ }
175
+ }()
176
+ }
177
+ namespacedBytes , err := ioutil .ReadFile (namespacedManBuild )
178
+ if err != nil {
179
+ log .Fatalf ("could not read rbac manifest: %v" , err )
180
+ }
181
+ namespacedRolesBytes , err = parseRoles (namespacedBytes )
182
+ if err != nil {
183
+ log .Fatalf ("could not parse namespaced manifest file for rbac roles: %v" , err )
184
+ }
185
+ genWarning = verifyDeploymentImage (namespacedBytes , image )
186
+ global , err := ioutil .ReadFile (globalManBuild )
187
+ if err != nil {
188
+ cmdError .ExitWithError (cmdError .ExitError , fmt .Errorf ("failed to read global manifest: (%v)" , err ))
189
+ }
190
+ c := cmdutil .GetConfig ()
191
+ if err = generator .RenderTestYaml (c , string (global ), string (namespacedRolesBytes ), image ); err != nil {
192
+ cmdError .ExitWithError (cmdError .ExitError , fmt .Errorf ("failed to generate deploy/test-gen.yaml: (%v)" , err ))
193
+ }
194
+ os .Link ("tmp/build/dockerfiles/Dockerfile_Tests" , "tmp/build/Dockerfile" )
195
+ } else {
196
+ os .Link ("tmp/build/dockerfiles/Dockerfile_Standard" , "tmp/build/Dockerfile" )
197
+ }
198
+ defer os .Remove ("tmp/build/Dockerfile" )
66
199
dbcmd := exec .Command (dockerBuild )
67
200
dbcmd .Env = append (os .Environ (), fmt .Sprintf ("IMAGE=%v" , image ))
201
+ dbcmd .Env = append (dbcmd .Env , fmt .Sprintf ("NAMESPACEDMAN=%v" , namespacedManBuild ))
68
202
o , err = dbcmd .CombinedOutput ()
69
203
if err != nil {
70
204
cmdError .ExitWithError (cmdError .ExitError , fmt .Errorf ("failed to output build image %v: (%v)" , image , string (o )))
71
205
}
72
206
fmt .Fprintln (os .Stdout , string (o ))
207
+ if genWarning != "" {
208
+ fmt .Printf ("%s\n " , genWarning )
209
+ }
73
210
}
0 commit comments