1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package main
20
21 import (
22 "context"
23 "encoding/json"
24 "fmt"
25 "io/ioutil"
26 "log"
27 "path"
28 "strings"
29
30 "github.com/ghodss/yaml"
31 appsv1 "k8s.io/api/apps/v1"
32 corev1 "k8s.io/api/core/v1"
33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
35 "sigs.k8s.io/kubebuilder-declarative-pattern/pkg/patterns/declarative/pkg/manifest"
36
37 corev1beta1 "github.com/GoogleCloudPlatform/k8s-config-connector/operator/pkg/apis/core/v1beta1"
38 "github.com/GoogleCloudPlatform/k8s-config-connector/operator/pkg/k8s"
39 cnrmmanifest "github.com/GoogleCloudPlatform/k8s-config-connector/operator/pkg/manifest"
40 "github.com/GoogleCloudPlatform/k8s-config-connector/operator/pkg/test/util/paths"
41 )
42
43 const (
44 fileMode = 0600
45 outputFilename = "image_configmap.yaml"
46 outputDir = "config/gke-addon"
47 )
48
49 func main() {
50 ctx := context.Background()
51 cc := &corev1beta1.ConfigConnector{
52 Spec: corev1beta1.ConfigConnectorSpec{
53 Mode: k8s.NamespacedMode,
54 GoogleServiceAccount: "someGSA",
55 },
56 }
57 operatorSrcRoot := paths.GetOperatorSrcRootOrLogFatal()
58 r := cnrmmanifest.NewLocalRepository(path.Join(operatorSrcRoot, "channels"))
59 channel, err := r.LoadChannel(ctx, k8s.StableChannel)
60 if err != nil {
61 log.Fatalf("error loading %v channel: %v", k8s.StableChannel, err)
62 }
63 version, err := channel.Latest(ctx, cc.ComponentName())
64 if err != nil {
65 log.Fatalf("error resolving the version to deploy: %v", err)
66 }
67 if version == nil {
68 log.Fatalf("could not find the latest version in channel %v", k8s.StableChannel)
69 }
70
71 manifestStrs, err := r.LoadManifest(ctx, cc.ComponentName(), version.Version, cc)
72 if err != nil {
73 log.Fatalf("error loading manifest for package %v of version %v: %v", version.Package, version.Version, err)
74 }
75 objects := make([]*manifest.Object, 0)
76 for _, str := range manifestStrs {
77 m, err := manifest.ParseObjects(ctx, str)
78 if err != nil {
79 log.Fatalf("parsing manifest: %v", err)
80 }
81 objects = append(objects, m.Items...)
82 }
83
84 namespacedStrs, err := r.LoadNamespacedComponents(ctx, cc.ComponentName(), version.Version)
85 if err != nil {
86 log.Fatalf("error loading namespaced components for package %v of version %v: %v", version.Package, version.Version, err)
87 }
88 for _, str := range namespacedStrs {
89 m, err := manifest.ParseObjects(ctx, str)
90 if err != nil {
91 log.Fatalf("parsing manifest: %v", err)
92 }
93 objects = append(objects, m.Items...)
94 }
95
96 cm := corev1.ConfigMap{
97 TypeMeta: metav1.TypeMeta{
98 Kind: "ConfigMap",
99 APIVersion: "v1",
100 },
101 ObjectMeta: metav1.ObjectMeta{
102 Name: "config-images",
103 Namespace: k8s.OperatorSystemNamespace,
104 Labels: map[string]string{
105 "addonmanager.kubernetes.io/mode": "Reconcile",
106 "cnrm.cloud.google.com/operator-system": "true",
107 },
108 Annotations: map[string]string{
109 "components.gke.io/image-map": "Images deployed by operator",
110 },
111 },
112 Data: make(map[string]string, 0),
113 }
114
115 for _, obj := range objects {
116
117 if obj.Kind == "StatefulSet" && strings.Contains(obj.GetName(), "cnrm-controller-manager") {
118 image, err := extractImageFromStatefulSet(obj.UnstructuredObject(), "manager")
119 if err != nil {
120 log.Fatalf("error resolving manager image: %v", err)
121 }
122 cm.Data["cnrm.controller"] = image
123 }
124
125 if obj.Kind == "StatefulSet" && obj.GetName() == "cnrm-deletiondefender" {
126 image, err := extractImageFromStatefulSet(obj.UnstructuredObject(), "deletiondefender")
127 if err != nil {
128 log.Fatalf("error resolving manager image: %v", err)
129 }
130 cm.Data["cnrm.deletiondefender"] = image
131 }
132
133 if obj.Kind == "StatefulSet" && obj.GetName() == "cnrm-unmanaged-detector" {
134 image, err := extractImageFromStatefulSet(obj.UnstructuredObject(), "unmanageddetector")
135 if err != nil {
136 log.Fatalf("error resolving manager image: %v", err)
137 }
138 cm.Data["cnrm.unmanageddetector"] = image
139 }
140
141 if obj.Kind == "Deployment" && obj.GetName() == "cnrm-webhook-manager" {
142 image, err := extractImageFromDeployment(obj.UnstructuredObject(), "webhook")
143 if err != nil {
144 log.Fatalf("error resolving webhook image: %v", err)
145 }
146 cm.Data["cnrm.webhook"] = image
147 }
148
149 if obj.Kind == "Deployment" && obj.GetName() == "cnrm-resource-stats-recorder" {
150 image, err := extractImageFromDeployment(obj.UnstructuredObject(), "recorder")
151 if err != nil {
152 log.Fatalf("error resolving recorder image: %v", err)
153 }
154 cm.Data["cnrm.recorder"] = image
155 }
156
157 if obj.Kind == "Deployment" && obj.GetName() == "cnrm-resource-stats-recorder" {
158 image, err := extractImageFromDeployment(obj.UnstructuredObject(), "prom-to-sd")
159 if err != nil {
160 log.Fatalf("error resolving prom-to-sd sidecar image: %v", err)
161 }
162 cm.Data["prom-to-sd"] = image
163 }
164 }
165 outputFilepath := path.Join(operatorSrcRoot, outputDir, outputFilename)
166 if err := outputConfigMapToFile(&cm, outputFilepath); err != nil {
167 log.Fatalf("error writing ConfigMap %v to file: %v", cm, err)
168 }
169 log.Println("successfully generated the image_configmaps.yaml")
170 }
171
172 func extractImageFromStatefulSet(obj *unstructured.Unstructured, containerName string) (string, error) {
173 b, err := obj.MarshalJSON()
174 if err != nil {
175 return "", err
176 }
177 ss := &appsv1.StatefulSet{}
178 if err := json.Unmarshal(b, ss); err != nil {
179 return "", err
180 }
181
182 for _, container := range ss.Spec.Template.Spec.Containers {
183 if container.Name == containerName {
184 return container.Image, nil
185 }
186 }
187 return "", fmt.Errorf("could not find container with name %v in StatefulSet %v", containerName, obj.GetName())
188 }
189
190 func extractImageFromDeployment(obj *unstructured.Unstructured, containerName string) (string, error) {
191 b, err := obj.MarshalJSON()
192 if err != nil {
193 return "", err
194 }
195 ss := &appsv1.Deployment{}
196 if err := json.Unmarshal(b, ss); err != nil {
197 return "", err
198 }
199
200 for _, container := range ss.Spec.Template.Spec.Containers {
201 if container.Name == containerName {
202 return container.Image, nil
203 }
204 }
205 return "", fmt.Errorf("could not find container with name %v in Deployment %v", containerName, obj.GetName())
206 }
207
208 func outputConfigMapToFile(crd *corev1.ConfigMap, outputFilepath string) error {
209 crdBytes, err := yaml.Marshal(crd)
210 if err != nil {
211 return err
212 }
213 if err := ioutil.WriteFile(outputFilepath, crdBytes, fileMode); err != nil {
214 return err
215 }
216 return nil
217 }
218
View as plain text