1 package resolver
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "net/http"
8 "testing"
9
10 "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
11
12 "edge-infra.dev/pkg/edge/api/graph/model"
13 seeding "edge-infra.dev/pkg/edge/api/graph/test"
14 "edge-infra.dev/pkg/edge/api/middleware"
15 "edge-infra.dev/pkg/edge/api/mocks"
16 "edge-infra.dev/pkg/edge/api/types"
17 "edge-infra.dev/pkg/edge/constants"
18 "edge-infra.dev/pkg/edge/k8objectsutils"
19 "edge-infra.dev/pkg/lib/runtime/version"
20 "edge-infra.dev/pkg/sds/clustersecrets/breakglass"
21 "edge-infra.dev/pkg/sds/clustersecrets/grub"
22
23 "github.com/golang/mock/gomock"
24 "github.com/stretchr/testify/assert"
25 corev1 "k8s.io/api/core/v1"
26 )
27
28 var testKeyValues = []*model.KeyValuesOutput{
29 {
30 Key: "",
31 Value: "docker config vals",
32 },
33 }
34 var DockerPullSM = []*model.SecretManagerResponse{{
35 Name: "name",
36 Project: "project",
37 Values: testKeyValues,
38 }}
39 var terminalBootstrapConfig = `ack_bootstrap: true
40 first_node: true
41 grub_hash: sensitiveGrubHash
42 grub_user: recovery
43 hostname: testNode
44 ncr-edge:
45 bootstrap-payload:
46 clusterCaHash: sensitiveClusterHash
47 clusterEdgeId: d2eda5c6-7dc5-4b38-9ea1-136756887628
48 edge-infra-version: 0.20.7
49 parameters:
50 api-endpoint: https://dev1.edge-preprod.dev/api/v2
51 cluster-edge-id: d2eda5c6-7dc5-4b38-9ea1-136756887628
52 organization: edge-org
53 upload-ca-hash: /etc/kubernetes/pki/ca.crt
54 token: sesitiveBootstrapToken
55 pod_subnet: x.x.x.x/x
56 role: controlplane
57 service_subnet: x.x.x.x/x
58 vip_address: x.x.x.x
59 zylevel0_hash: 'sensitiveHash123'`
60
61 var sanitizedTerminalBootstrapConfig = `ack_bootstrap: true
62 first_node: true
63 grub_hash: ******************
64 grub_user: ******************
65 hostname: testNode
66 ncr-edge:
67 bootstrap-payload:
68 clusterCaHash: ******************
69 clusterEdgeId: d2eda5c6-7dc5-4b38-9ea1-136756887628
70 edge-infra-version: 0.20.7
71 parameters:
72 api-endpoint: https://dev1.edge-preprod.dev/api/v2
73 cluster-edge-id: d2eda5c6-7dc5-4b38-9ea1-136756887628
74 organization: edge-org
75 upload-ca-hash: /etc/kubernetes/pki/ca.crt
76 token: ******************
77 pod_subnet: x.x.x.x/x
78 role: controlplane
79 service_subnet: x.x.x.x/x
80 vip_address: x.x.x.x
81 zylevel0_hash: ******************`
82
83 var edgeOSVersion = "1.10.0"
84
85 func TestGetBootrapperRoles(t *testing.T) {
86 ls := getRoleForLumper(false)
87 assert.Equal(t, 1, len(ls))
88 ls = getRoleForLumper(true)
89 assert.Equal(t, 2, len(ls))
90 }
91
92 func TestSanitizeTerminalBootstrapConfig(t *testing.T) {
93 sanitized := sanitizeTerminalBootstrapConfig(terminalBootstrapConfig)
94 assert.Equal(t, sanitizedTerminalBootstrapConfig, sanitized)
95 }
96
97 func TestGetDockerPullSecret(t *testing.T) {
98 mock := gomock.NewController(t)
99 service := mocks.NewMockGCPService(mock)
100 service.EXPECT().
101 GetSecrets(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
102 Return(DockerPullSM, nil).AnyTimes()
103
104 r := &Resolver{GCPService: service, Config: &types.Config{Bff: types.BffConfig{TopLevelProjectID: "test"}}}
105 secret, err := r.getDockerPullSecret(context.Background(), "lumper-system")
106 assert.NoError(t, err)
107 k8sSec := corev1.Secret{}
108 err = json.Unmarshal([]byte(secret), &k8sSec)
109 assert.NoError(t, err)
110 assert.Equal(t, "lumper-system", k8sSec.Namespace)
111 assert.Equal(t, constants.EdgeDockerSecret, k8sSec.Name)
112 assert.Equal(t, corev1.SecretTypeDockerConfigJson, k8sSec.Type)
113 val, ok := k8sSec.Data[corev1.DockerConfigJsonKey]
114 assert.Equal(t, true, ok)
115 assert.Equal(t, []byte("docker config vals"), val)
116 }
117
118 func TestBeginTerminalBootstrap(t *testing.T) {
119 mock := gomock.NewController(t)
120
121 mockGCP := mocks.NewMockGcpClientService(mock)
122 mockSecretManager := mocks.NewMockSecretManagerService(mock)
123 mockGCP.EXPECT().GetSecretClient(gomock.Any(), gomock.Any()).Return(mockSecretManager, nil).AnyTimes()
124
125 cluster := seeding.Clusters[0].ConvertToModel()
126
127 grubSecret, _ := grub.New("")
128 grubBytes, _ := grubSecret.ToBytes()
129 breakglassSecret, _ := breakglass.New("")
130 breakglassBytes, _ := breakglassSecret.ToBytes()
131
132 mockSecretManager.EXPECT().GetLatestSecretValueInfo(gomock.Any(), k8objectsutils.NameWithPrefix(breakglass.HashedSecretName, cluster.ClusterEdgeID)).Return(&secretmanagerpb.SecretVersion{Name: "projects/*/secrets/*/versions/1"}, nil).AnyTimes()
133 mockSecretManager.EXPECT().GetLatestSecretValueInfo(gomock.Any(), k8objectsutils.NameWithPrefix(grub.HashedSecretName, cluster.ClusterEdgeID)).Return(&secretmanagerpb.SecretVersion{Name: "projects/*/secrets/*/versions/1"}, nil).AnyTimes()
134 mockSecretManager.EXPECT().GetSecretVersionValue(gomock.Any(), k8objectsutils.NameWithPrefix(breakglass.HashedSecretName, cluster.ClusterEdgeID), "1").Return(breakglassBytes, nil).AnyTimes()
135 mockSecretManager.EXPECT().GetSecretVersionValue(gomock.Any(), k8objectsutils.NameWithPrefix(grub.HashedSecretName, cluster.ClusterEdgeID), "1").Return(grubBytes, nil).AnyTimes()
136 mockSecretManager.EXPECT().GetSecretVersionValue(gomock.Any(), k8objectsutils.NameWithPrefix(breakglass.PlainSecretName, cluster.ClusterEdgeID), "hashedVersion-1").Return([]byte(breakglassSecret.Plain()), nil).AnyTimes()
137 mockSecretManager.EXPECT().GetSecretVersionValue(gomock.Any(), k8objectsutils.NameWithPrefix(grub.PlainSecretName, cluster.ClusterEdgeID), "hashedVersion-1").Return([]byte(grubSecret.Plain()), nil).AnyTimes()
138
139 gcpService := mocks.NewMockGCPService(mock)
140 gcpService.EXPECT().
141 GetSecrets(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
142 Return(DockerPullSM, nil).AnyTimes()
143 gcpService.EXPECT().
144 AddSecret(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
145 Return(nil).AnyTimes()
146 gcpService.EXPECT().
147 DeleteSecret(gomock.Any(), gomock.Any(), gomock.Any()).Return(true, nil).AnyTimes()
148
149 terminal := seeding.Terminals[0].ConvertToModel()
150 terminal.Interfaces = []*model.TerminalInterface{seeding.TerminalInterfaces[0].ConvertToModel()}
151 terminal.Interfaces[0].Addresses = []*model.TerminalAddress{seeding.TerminalAddresses[0].ConvertToModel()}
152 terminalService := mocks.NewMockTerminalService(mock)
153 activationCodeService := mocks.NewMockActivationCode(mock)
154 terminalService.EXPECT().GetTerminal(gomock.Any(), gomock.Any(), gomock.Any()).Return(&terminal, nil).AnyTimes()
155
156 bannerService := mocks.NewMockBannerService(mock)
157 bannerService.EXPECT().GetClusterInfraInfo(gomock.Any(), gomock.Any()).Return(&model.Cluster{ClusterEdgeID: "resr"}, nil).AnyTimes()
158 bannerService.EXPECT().GetBanner(gomock.Any(), gomock.Any()).Return(&model.Banner{}, nil).AnyTimes()
159
160 clusterConfig := model.ClusterConfig{ClusterEdgeID: seeding.ClusterConfig[0].ClusterEdgeID}
161 for _, config := range seeding.ClusterConfig {
162 clusterConfig, _ = config.ConvertToModel(clusterConfig)
163 }
164 terminalService.EXPECT().
165 GetTerminalBootstrapConfig(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Eq("testEdgeAPIURL.dev")).
166 Return("cluster-config", nil).AnyTimes()
167
168 activationCodeService.EXPECT().MarkUsed(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
169
170 storeClusterService := mocks.NewMockStoreClusterService(mock)
171 storeClusterService.EXPECT().GetCluster(gomock.Any(), gomock.Any()).Return(&cluster, nil).AnyTimes()
172 storeClusterService.EXPECT().GetClusterByClusterEdgeID(gomock.Any(), gomock.Any()).Return(types.Cluster{}, nil).AnyTimes()
173
174 tenant := model.Tenant{}
175 tenantService := mocks.NewMockTenantService(mock)
176 tenantService.EXPECT().GetTenantByBannerID(gomock.Any(), gomock.Any()).Return(&tenant, nil).AnyTimes()
177
178 compatibilityService := mocks.NewMockCompatibilityService(mock)
179 artifactCompatibility := model.ArtifactCompatibility{
180 Artifact: &model.ArtifactVersion{
181 Name: "store",
182 Version: version.New().SemVer,
183 },
184 NthIndex: 2,
185 CompatibleArtifacts: []*model.ArtifactVersion{
186 {
187 Name: "edge-os",
188 Version: "1.10",
189 },
190 },
191 }
192 compatibilityService.EXPECT().GetArtifactVersionCompatibility(gomock.Any(), gomock.Any(), gomock.Any()).Return(&artifactCompatibility, nil).AnyTimes()
193 clusterNetworkServices := []*model.ClusterNetworkServiceInfo{}
194 storeClusterService.EXPECT().GetClusterNetworkServices(gomock.Any(), gomock.Any()).Return(clusterNetworkServices, nil).AnyTimes()
195
196 clusterConfigService := mocks.NewMockClusterConfigService(mock)
197 clusterConfigService.EXPECT().GetClusterConfig(gomock.Any(), gomock.Any()).Return(&clusterConfig, nil).AnyTimes()
198
199 secretService := mocks.NewMockSecretService(mock)
200 secretService.EXPECT().
201 DeleteExternalSecret(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
202 Return(nil).AnyTimes()
203
204 bootstrapService := mocks.NewMockBootstrapService(mock)
205 bootstrapService.EXPECT().CreateClusterBootstrapTokenEntry(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
206
207 clusterCaHash := "cluster-ca-hash"
208 registrationService := mocks.NewMockRegistrationService(mock)
209 registrationService.EXPECT().ClusterCaHash(gomock.Any(), gomock.Any()).Return(clusterCaHash, nil).AnyTimes()
210
211 r := &Resolver{
212 GCPService: gcpService,
213 Config: &types.Config{
214 EdgeAPIEndpoint: "testEdgeAPIURL.dev",
215 Bff: types.BffConfig{TopLevelProjectID: "test"},
216 },
217 TerminalService: terminalService,
218 StoreClusterService: storeClusterService,
219 TenantService: tenantService,
220 ClusterConfigService: clusterConfigService,
221 SecretService: secretService,
222 RegistrationService: registrationService,
223 BootstrapService: bootstrapService,
224 CompatibilityService: compatibilityService,
225 GCPClientService: mockGCP,
226 ActivationCodeService: activationCodeService,
227 BannerService: bannerService,
228 }
229 qr := queryResolver{r}
230
231 ctx := context.WithValue(context.Background(), middleware.TerminalIDCtxKey, terminal.TerminalID)
232 ctx = context.WithValue(ctx, middleware.EdgeAPIEndpointCtxKey, "mockEdgeAPIURL.dev")
233 terminalBootstrap, err := qr.beginTerminalBootstrap(ctx, nil, nil)
234 assert.NoError(t, err)
235 assert.Equal(t, "cluster-config", terminalBootstrap.Configuration)
236
237 terminalBootstrap, err = qr.beginTerminalBootstrap(ctx, []string{"fa:79:6a:6c:38:bb"}, &edgeOSVersion)
238 expectedErr := fmt.Sprintf(`status code %d: the MAC address of this terminal does not match the MAC registered for this activation
239 code - please check the activation code and try again`, http.StatusBadRequest)
240 assert.EqualError(t, err, expectedErr)
241 assert.Nil(t, terminalBootstrap)
242
243 terminalBootstrap, err = qr.beginTerminalBootstrap(ctx, []string{"fa:79:6a:6c:38:bb", "00:00:5e:00:53:af"}, &edgeOSVersion)
244 assert.NoError(t, err)
245 assert.Equal(t, "cluster-config", terminalBootstrap.Configuration)
246 }
247
View as plain text