@@ -18,27 +18,30 @@ limitations under the License.
18
18
package kubernetesversions
19
19
20
20
import (
21
+ "bytes"
21
22
_ "embed"
22
23
"errors"
24
+ "fmt"
25
+ "io/ioutil"
23
26
"os"
24
27
"os/exec"
25
28
"path"
29
+ "strings"
30
+ "text/template"
26
31
27
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
- cabpkv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1alpha4"
29
- kcpv1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1alpha4"
32
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
30
33
"sigs.k8s.io/cluster-api/test/framework"
31
34
"sigs.k8s.io/yaml"
32
35
)
33
36
34
- const yamlSeparator = "\n ---\n "
35
-
36
37
var (
37
- //go:embed data/kustomization.yaml
38
- kustomizationYamlBytes []byte
39
-
40
- //go:embed data/debian_injection_script.envsubst.sh
38
+ //go:embed data/debian_injection_script.envsubst.sh.tpl
41
39
debianInjectionScriptBytes string
40
+
41
+ debianInjectionScriptTemplate = template .Must (template .New ("" ).Parse (debianInjectionScriptBytes ))
42
+
43
+ //go:embed data/kustomization.yaml
44
+ kustomizationYAMLBytes string
42
45
)
43
46
44
47
type GenerateCIArtifactsInjectedTemplateForDebianInput struct {
@@ -88,18 +91,34 @@ func GenerateCIArtifactsInjectedTemplateForDebian(input GenerateCIArtifactsInjec
88
91
89
92
kustomizedTemplate := path .Join (templateDir , "cluster-template-conformance-ci-artifacts.yaml" )
90
93
91
- if err := os .WriteFile (path .Join (overlayDir , "kustomization.yaml" ), kustomizationYamlBytes , 0o600 ); err != nil {
94
+ if err := ioutil .WriteFile (path .Join (overlayDir , "kustomization.yaml" ), [] byte ( kustomizationYAMLBytes ) , 0o600 ); err != nil {
92
95
return "" , err
93
96
}
94
97
95
- kustomizeVersions , err := generateKustomizeVersionsYaml (input .KubeadmControlPlaneName , input .KubeadmConfigTemplateName , input .KubeadmConfigName )
98
+ var debianInjectionScriptControlPlaneBytes bytes.Buffer
99
+ if err := debianInjectionScriptTemplate .Execute (& debianInjectionScriptControlPlaneBytes , map [string ]bool {"IsControlPlaneMachine" : true }); err != nil {
100
+ return "" , err
101
+ }
102
+ patch , err := generateInjectScriptJSONPatch (input .SourceTemplate , "KubeadmControlPlane" , input .KubeadmControlPlaneName , "/spec/kubeadmConfigSpec" , "/usr/local/bin/ci-artifacts.sh" , debianInjectionScriptControlPlaneBytes .String ())
96
103
if err != nil {
97
104
return "" , err
98
105
}
106
+ if err := os .WriteFile (path .Join (overlayDir , "kubeadmcontrolplane-patch.yaml" ), patch , 0o600 ); err != nil {
107
+ return "" , err
108
+ }
99
109
100
- if err := os .WriteFile (path .Join (overlayDir , "kustomizeversions.yaml" ), kustomizeVersions , 0o600 ); err != nil {
110
+ var debianInjectionScriptWorkerBytes bytes.Buffer
111
+ if err := debianInjectionScriptTemplate .Execute (& debianInjectionScriptWorkerBytes , map [string ]bool {"IsControlPlaneMachine" : false }); err != nil {
101
112
return "" , err
102
113
}
114
+ patch , err = generateInjectScriptJSONPatch (input .SourceTemplate , "KubeadmConfigTemplate" , input .KubeadmConfigTemplateName , "/spec/template/spec" , "/usr/local/bin/ci-artifacts.sh" , debianInjectionScriptWorkerBytes .String ())
115
+ if err != nil {
116
+ return "" , err
117
+ }
118
+ if err := os .WriteFile (path .Join (overlayDir , "kubeadmconfigtemplate-patch.yaml" ), patch , 0o600 ); err != nil {
119
+ return "" , err
120
+ }
121
+
103
122
if err := os .WriteFile (path .Join (overlayDir , "ci-artifacts-source-template.yaml" ), input .SourceTemplate , 0o600 ); err != nil {
104
123
return "" , err
105
124
}
@@ -117,91 +136,89 @@ func GenerateCIArtifactsInjectedTemplateForDebian(input GenerateCIArtifactsInjec
117
136
return kustomizedTemplate , nil
118
137
}
119
138
120
- func generateKustomizeVersionsYaml (kcpName , kubeadmTemplateName , kubeadmConfigName string ) ([]byte , error ) {
121
- kcp := generateKubeadmControlPlane (kcpName )
122
- kubeadm := generateKubeadmConfigTemplate (kubeadmTemplateName )
123
- kcpYaml , err := yaml .Marshal (kcp )
124
- if err != nil {
125
- return nil , err
126
- }
127
- kubeadmYaml , err := yaml .Marshal (kubeadm )
128
- if err != nil {
129
- return nil , err
130
- }
131
- fileStr := string (kcpYaml ) + yamlSeparator + string (kubeadmYaml )
132
- if kubeadmConfigName == "" {
133
- return []byte (fileStr ), nil
134
- }
139
+ type jsonPatch struct {
140
+ Op string `json:"op"`
141
+ Path string `json:"path"`
142
+ Value interface {} `json:"value"`
143
+ }
135
144
136
- kubeadmConfig := generateKubeadmConfig (kubeadmConfigName )
137
- kubeadmConfigYaml , err := yaml .Marshal (kubeadmConfig )
145
+ // generateInjectScriptJSONPatch generates a JSON patch which injects a script
146
+ // * objectKind: is the kind of the object we want to inject the script into
147
+ // * objectName: is the name of the object we want to inject the script into
148
+ // * jsonPatchPathPrefix: is the prefix of the 'files' and `preKubeadmCommands` arrays where we append the script
149
+ // * scriptPath: is the path where the script will be stored at
150
+ // * scriptContent: content of the script.
151
+ func generateInjectScriptJSONPatch (sourceTemplate []byte , objectKind , objectName , jsonPatchPathPrefix , scriptPath , scriptContent string ) ([]byte , error ) {
152
+ filesPathExists , preKubeadmCommandsPathExists , err := checkIfArraysAlreadyExist (sourceTemplate , objectKind , objectName , jsonPatchPathPrefix )
138
153
if err != nil {
139
154
return nil , err
140
155
}
141
- fileStr = fileStr + yamlSeparator + string (kubeadmConfigYaml )
142
156
143
- return []byte (fileStr ), nil
144
- }
145
-
146
- func generateKubeadmConfigTemplate (name string ) * cabpkv1.KubeadmConfigTemplate {
147
- kubeadmSpec := generateKubeadmConfigSpec ()
148
- return & cabpkv1.KubeadmConfigTemplate {
149
- TypeMeta : metav1.TypeMeta {
150
- Kind : "KubeadmConfigTemplate" ,
151
- APIVersion : cabpkv1 .GroupVersion .String (),
152
- },
153
- ObjectMeta : metav1.ObjectMeta {
154
- Name : name ,
157
+ var patches []jsonPatch
158
+ if ! filesPathExists {
159
+ patches = append (patches , jsonPatch {
160
+ Op : "add" ,
161
+ Path : fmt .Sprintf ("%s/files" , jsonPatchPathPrefix ),
162
+ Value : []interface {}{},
163
+ })
164
+ }
165
+ patches = append (patches , jsonPatch {
166
+ Op : "add" ,
167
+ Path : fmt .Sprintf ("%s/files/-" , jsonPatchPathPrefix ),
168
+ Value : map [string ]string {
169
+ "content" : scriptContent ,
170
+ "owner" : "root:root" ,
171
+ "path" : scriptPath ,
172
+ "permissions" : "0750" ,
155
173
},
156
- Spec : cabpkv1.KubeadmConfigTemplateSpec {
157
- Template : cabpkv1.KubeadmConfigTemplateResource {
158
- Spec : * kubeadmSpec ,
159
- },
160
- },
161
- }
174
+ })
175
+ if ! preKubeadmCommandsPathExists {
176
+ patches = append (patches , jsonPatch {
177
+ Op : "add" ,
178
+ Path : fmt .Sprintf ("%s/preKubeadmCommands" , jsonPatchPathPrefix ),
179
+ Value : []string {},
180
+ })
181
+ }
182
+ patches = append (patches , jsonPatch {
183
+ Op : "add" ,
184
+ Path : fmt .Sprintf ("%s/preKubeadmCommands/-" , jsonPatchPathPrefix ),
185
+ Value : scriptPath ,
186
+ })
187
+
188
+ return yaml .Marshal (patches )
162
189
}
163
190
164
- func generateKubeadmConfig (name string ) * cabpkv1.KubeadmConfig {
165
- kubeadmSpec := generateKubeadmConfigSpec ()
166
- return & cabpkv1.KubeadmConfig {
167
- TypeMeta : metav1.TypeMeta {
168
- Kind : "KubeadmConfig" ,
169
- APIVersion : kcpv1 .GroupVersion .String (),
170
- },
171
- ObjectMeta : metav1.ObjectMeta {
172
- Name : name ,
173
- },
174
- Spec : * kubeadmSpec ,
175
- }
176
- }
177
-
178
- func generateKubeadmControlPlane (name string ) * kcpv1.KubeadmControlPlane {
179
- kubeadmSpec := generateKubeadmConfigSpec ()
180
- return & kcpv1.KubeadmControlPlane {
181
- TypeMeta : metav1.TypeMeta {
182
- Kind : "KubeadmControlPlane" ,
183
- APIVersion : kcpv1 .GroupVersion .String (),
184
- },
185
- ObjectMeta : metav1.ObjectMeta {
186
- Name : name ,
187
- },
188
- Spec : kcpv1.KubeadmControlPlaneSpec {
189
- KubeadmConfigSpec : * kubeadmSpec ,
190
- Version : "${KUBERNETES_VERSION}" ,
191
- },
192
- }
193
- }
194
-
195
- func generateKubeadmConfigSpec () * cabpkv1.KubeadmConfigSpec {
196
- return & cabpkv1.KubeadmConfigSpec {
197
- Files : []cabpkv1.File {
198
- {
199
- Path : "/usr/local/bin/ci-artifacts.sh" ,
200
- Content : debianInjectionScriptBytes ,
201
- Owner : "root:root" ,
202
- Permissions : "0750" ,
203
- },
204
- },
205
- PreKubeadmCommands : []string {"/usr/local/bin/ci-artifacts.sh" },
206
- }
191
+ // checkIfArraysAlreadyExist check is the 'files' and 'preKubeadmCommands' arrays already exist below jsonPatchPathPrefix.
192
+ func checkIfArraysAlreadyExist (sourceTemplate []byte , objectKind , objectName , jsonPatchPathPrefix string ) (bool , bool , error ) {
193
+ yamlDocs := strings .Split (string (sourceTemplate ), "---" )
194
+ for _ , yamlDoc := range yamlDocs {
195
+ if yamlDoc == "" {
196
+ continue
197
+ }
198
+ var obj unstructured.Unstructured
199
+ if err := yaml .Unmarshal ([]byte (yamlDoc ), & obj ); err != nil {
200
+ return false , false , err
201
+ }
202
+
203
+ if obj .GetKind () != objectKind {
204
+ continue
205
+ }
206
+ if obj .GetName () != objectName {
207
+ continue
208
+ }
209
+
210
+ pathSplit := strings .Split (strings .TrimPrefix (jsonPatchPathPrefix , "/" ), "/" )
211
+ filesPath := append (pathSplit , "files" )
212
+ preKubeadmCommandsPath := append (pathSplit , "preKubeadmCommands" )
213
+ _ , filesPathExists , err := unstructured .NestedFieldCopy (obj .Object , filesPath ... )
214
+ if err != nil {
215
+ return false , false , err
216
+ }
217
+ _ , preKubeadmCommandsPathExists , err := unstructured .NestedFieldCopy (obj .Object , preKubeadmCommandsPath ... )
218
+ if err != nil {
219
+ return false , false , err
220
+ }
221
+ return filesPathExists , preKubeadmCommandsPathExists , nil
222
+ }
223
+ return false , false , fmt .Errorf ("could not find document with kind %q and name %q" , objectKind , objectName )
207
224
}
0 commit comments