1 package services
2
3 import (
4 "context"
5 "encoding/json"
6 "strings"
7 "time"
8
9 secretmanagerpb "cloud.google.com/go/secretmanager/apiv1/secretmanagerpb"
10 _ "github.com/doug-martin/goqu/v9/dialect/mysql"
11
12 gcperror "edge-infra.dev/pkg/edge/api/apierror/gcp"
13 "edge-infra.dev/pkg/edge/api/clients"
14 "edge-infra.dev/pkg/edge/api/graph/mapper"
15 "edge-infra.dev/pkg/edge/api/graph/model"
16 "edge-infra.dev/pkg/edge/api/types"
17 "edge-infra.dev/pkg/edge/api/utils"
18 workloadApi "edge-infra.dev/pkg/edge/constants/api/workload"
19 secretMgrApi "edge-infra.dev/pkg/lib/gcp/secretmanager"
20 gcputils "edge-infra.dev/pkg/lib/gcp/utils"
21 )
22
23 const PlatformSecret = "platform"
24 const EdgeOwner = "edge"
25
26
27 type GCPService interface {
28 GetZones(ctx context.Context) ([]*string, error)
29 GetGKEVersions(ctx context.Context, zone string) ([]*string, error)
30 GetMachineTypes(ctx context.Context, zone string) ([]*model.MachineTypeInfo, error)
31 AddSecret(ctx context.Context, name, owner, t string, secrets []*model.KeyValues, projectID string, workload *string, expireAt *time.Time) error
32 GetMachineType(ctx context.Context, zone string, machineType string) (*model.MachineTypeInfo, error)
33 GetSecrets(ctx context.Context, name *string, owner, t *string, getValues bool, projectID string) ([]*model.SecretManagerResponse, error)
34 DeleteSecret(ctx context.Context, name string, projectID string) (bool, error)
35 }
36
37 type gcpService struct {
38 GcpClientService GcpClientService
39 TopLevelProjectID string
40 BigQueryClient clients.BQClient
41 }
42
43 func (s *gcpService) GetZones(ctx context.Context) ([]*string, error) {
44 computeClient, err := s.GcpClientService.GetComputeClient(ctx, s.TopLevelProjectID)
45 if err != nil {
46 return nil, gcperror.Wrap(err)
47 }
48 zoneList, err := computeClient.GetZones(ctx)
49 if err != nil {
50 return nil, gcperror.Wrap(err)
51 }
52 return mapper.ToZones(zoneList), nil
53 }
54
55 func (s *gcpService) GetGKEVersions(ctx context.Context, zone string) ([]*string, error) {
56 containerClient, err := s.GcpClientService.GetContainerClient(ctx, s.TopLevelProjectID)
57 if err != nil {
58 return nil, gcperror.Wrap(err)
59 }
60 serverConfig, err := containerClient.GetServerConfig(ctx, zone)
61 if err != nil {
62 return nil, gcperror.Wrap(err)
63 }
64 return mapper.ToGkeVersions(serverConfig.ValidMasterVersions), nil
65 }
66
67 func (s *gcpService) GetMachineTypes(ctx context.Context, zone string) ([]*model.MachineTypeInfo, error) {
68 computeClient, err := s.GcpClientService.GetComputeClient(ctx, s.TopLevelProjectID)
69 if err != nil {
70 return nil, gcperror.Wrap(err)
71 }
72 machineList, err := computeClient.GetMachineTypes(ctx, zone)
73 if err != nil {
74 return nil, gcperror.Wrap(err)
75 }
76 return mapper.ToMachineTypes(machineList), nil
77 }
78
79 func (s *gcpService) GetMachineType(ctx context.Context, zone string, machineType string) (*model.MachineTypeInfo, error) {
80 computeClient, err := s.GcpClientService.GetComputeClient(ctx, s.TopLevelProjectID)
81 if err != nil {
82 return nil, gcperror.Wrap(err)
83 }
84 machineTypeInfo, err := computeClient.GetMachineType(ctx, zone, machineType)
85 if err != nil {
86 return nil, gcperror.Wrap(err)
87 }
88 return mapper.ToMachineType(machineTypeInfo), nil
89 }
90
91 func (s *gcpService) AddSecret(ctx context.Context, name, owner, t string, secrets []*model.KeyValues, projectID string, workload *string, expireAt *time.Time) error {
92 secretService, err := s.GcpClientService.GetSecretClient(ctx, projectID)
93 if err != nil {
94 return gcperror.Wrap(err)
95 }
96 defer gcputils.CloseConnection(ctx, secretService)
97 m := make(map[string]string)
98 for _, s := range secrets {
99 m[s.Key] = s.Value
100 }
101 strSecret, err := json.Marshal(m)
102 if err != nil {
103 return err
104 }
105 labels := map[string]string{
106 secretMgrApi.SecretLabel: string(workloadApi.Tenant),
107 secretMgrApi.SecretTypeLabel: t,
108 secretMgrApi.SecretOwnerLabel: owner,
109 }
110 if !utils.IsNullOrEmpty(workload) {
111
112 labels[secretMgrApi.SecretNamespaceSelectorLabel] = *workload
113 }
114 err = secretService.AddSecret(ctx, name, strSecret, labels, false, expireAt, "")
115 if err != nil {
116 return gcperror.Wrap(err)
117 }
118 return nil
119 }
120
121 func (s *gcpService) GetSecrets(ctx context.Context, name *string, owner, t *string, getValues bool, projectID string) ([]*model.SecretManagerResponse, error) {
122 secretService, err := s.GcpClientService.GetSecretClient(ctx, projectID)
123 if err != nil {
124 return nil, gcperror.Wrap(err)
125 }
126 defer gcputils.CloseConnection(ctx, secretService)
127 secretsMap, err := getSecrets(ctx, name, owner, t, secretService)
128 if err != nil {
129 return nil, gcperror.Wrap(err)
130 }
131 res, err := mapSecretManagerToModel(ctx, secretsMap, getValues, secretService)
132 if err != nil {
133 return nil, gcperror.Wrap(err)
134 }
135 return res, nil
136 }
137
138 func getSecrets(ctx context.Context, name, owner, t *string, secretService types.SecretManagerService) ([]*secretmanagerpb.Secret, error) {
139 var secrets []*secretmanagerpb.Secret
140 var err error
141 if name != nil {
142 secret, err := secretService.GetSecret(ctx, *name)
143 if err != nil {
144 return nil, err
145 }
146 secrets = []*secretmanagerpb.Secret{secret}
147 } else {
148 secrets, err = secretService.ListSecrets(ctx, "")
149 if err != nil {
150 return nil, err
151 }
152 }
153 return secretManagerSecretsFiltered(secrets, t, owner), nil
154 }
155
156 func (s *gcpService) DeleteSecret(ctx context.Context, name string, projectID string) (bool, error) {
157 secretService, err := s.GcpClientService.GetSecretClient(ctx, projectID)
158 if err != nil {
159 return false, gcperror.Wrap(err)
160 }
161 defer gcputils.CloseConnection(ctx, secretService)
162 err = secretService.DeleteSecret(ctx, name)
163 if err != nil {
164 return false, gcperror.Wrap(err)
165 }
166 return true, nil
167 }
168
169 func mapSecretManagerToModel(ctx context.Context, secrets []*secretmanagerpb.Secret, getValues bool, secretService types.SecretManagerService) ([]*model.SecretManagerResponse, error) {
170 result := []*model.SecretManagerResponse{}
171 for _, secret := range secrets {
172 var updated *string
173 var kv []*model.KeyValuesOutput
174 name := getSecretName(secret.Name)
175 if getValues {
176 secretValue, err := secretService.GetLatestSecretValue(ctx, name)
177 if err != nil {
178 return nil, err
179 }
180 secretInfo, err := secretService.GetLatestSecretValueInfo(ctx, name)
181 if err != nil {
182 return nil, err
183 }
184 var keyMap map[string]string
185 err = json.Unmarshal(secretValue, &keyMap)
186 if err != nil {
187 kv = []*model.KeyValuesOutput{{Key: name, Value: string(secretValue)}}
188 } else {
189 for k, v := range keyMap {
190 kv = append(kv, &model.KeyValuesOutput{Key: k, Value: v})
191 }
192 }
193 u := secretInfo.CreateTime.AsTime().Format(mapper.TimeFormat)
194 updated = &u
195 }
196 result = append(result, secretManagerToModel(name, secretService.GetProjectID(), secret, updated, kv))
197 }
198 return result, nil
199 }
200
201 func getSecretName(val string) string {
202 return val[strings.LastIndex(val, "/")+1:]
203 }
204
205 func secretManagerSecretsFiltered(secrets []*secretmanagerpb.Secret, filterType, owner *string) []*secretmanagerpb.Secret {
206 var filteredSecrets []*secretmanagerpb.Secret
207 for _, s := range secrets {
208 if filterType != nil {
209 if t, ok := s.Labels[secretMgrApi.SecretTypeLabel]; ok {
210 if *filterType != t {
211 continue
212 }
213 } else {
214 continue
215 }
216 }
217 if owner != nil {
218 if o, ok := s.Labels[secretMgrApi.SecretOwnerLabel]; ok {
219 if *owner != o {
220 continue
221 }
222 } else {
223 continue
224 }
225 }
226
227 filteredSecrets = append(filteredSecrets, s)
228 }
229 return filteredSecrets
230 }
231
232 func secretManagerToModel(name string, organization string, secret *secretmanagerpb.Secret, updated *string, kv []*model.KeyValuesOutput) *model.SecretManagerResponse {
233 var typ *string
234 w := PlatformSecret
235 o := EdgeOwner
236 workload := &w
237 owner := &o
238 if t, ok := secret.Labels[secretMgrApi.SecretTypeLabel]; ok {
239 typ = &t
240 }
241 if w, ok := secret.Labels[secretMgrApi.SecretLabel]; ok {
242 workload = &w
243 }
244 if o, ok := secret.Labels[secretMgrApi.SecretOwnerLabel]; ok {
245 owner = &o
246 }
247
248 created := secret.CreateTime.AsTime().Format(mapper.TimeFormat)
249 return &model.SecretManagerResponse{
250 Name: name,
251 Project: organization,
252 Created: &created,
253 Updated: updated,
254 Values: kv,
255 Type: typ,
256 Workload: workload,
257 Owner: owner,
258 }
259 }
260
261 func NewGcpService(gcpClientService GcpClientService, topLevelProjectId string, bqClient clients.BQClient) *gcpService {
262 return &gcpService{
263 GcpClientService: gcpClientService,
264 TopLevelProjectID: topLevelProjectId,
265 BigQueryClient: bqClient,
266 }
267 }
268
View as plain text