github.com/Venafi/vcert/v5@v5.10.2/pkg/webclient/cloudproviders/cloudproviders.go (about) 1 package cloudproviders 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 9 "github.com/Khan/genqlient/graphql" 10 "github.com/Venafi/vcert/v5/pkg/domain" 11 "github.com/Venafi/vcert/v5/pkg/util" 12 ) 13 14 //go:generate go run -mod=mod github.com/Khan/genqlient genqlient.yaml 15 16 type CloudProvidersClient struct { 17 graphqlClient graphql.Client 18 } 19 20 func NewCloudProvidersClient(url string, httpClient *http.Client) *CloudProvidersClient { 21 return &CloudProvidersClient{ 22 graphqlClient: graphql.NewClient(url, httpClient), 23 } 24 } 25 26 func (c *CloudProvidersClient) GetCloudProvider(ctx context.Context, request domain.GetCloudProviderRequest) (*domain.CloudProvider, error) { 27 if request.Name == "" { 28 return nil, fmt.Errorf("cloud provider name cannot be empty") 29 } 30 31 status := cloudProviderStatusFromDomain(request.Status) 32 providerType := cloudProviderTypeFromDomain(request.Type) 33 34 resp, err := GetCloudProviders(ctx, c.graphqlClient, status, providerType, request.Name) 35 if err != nil { 36 return nil, fmt.Errorf("failed to retrieve Cloud Provider with name %s: %w", request.Name, err) 37 } 38 if resp == nil || resp.GetCloudProviders() == nil || len(resp.GetCloudProviders().GetNodes()) != 1 { 39 return nil, fmt.Errorf("could not find Cloud Provider with name %s", request.Name) 40 } 41 42 cp := resp.GetCloudProviders().GetNodes()[0] 43 44 statusDetails := "" 45 if cp.GetStatusDetails() != nil { 46 statusDetails = *cp.GetStatusDetails() 47 } 48 49 return &domain.CloudProvider{ 50 ID: cp.GetId(), 51 Name: cp.GetName(), 52 Type: cp.GetType().toDomain(), 53 Status: cp.GetStatus().toDomain(), 54 StatusDetails: statusDetails, 55 KeystoresCount: cp.GetKeystoresCount(), 56 }, nil 57 } 58 59 func (c *CloudProvidersClient) GetCloudKeystore(ctx context.Context, request domain.GetCloudKeystoreRequest) (*domain.CloudKeystore, error) { 60 if request.CloudKeystoreID == nil { 61 if request.CloudKeystoreName == nil || (request.CloudProviderID == nil && request.CloudProviderName == nil) { 62 return nil, fmt.Errorf("following combinations are accepted for provisioning: keystore ID, or both provider Name and keystore Name, or both provider ID and keystore Name") 63 } 64 } 65 66 resp, err := GetCloudKeystores(ctx, c.graphqlClient, request.CloudKeystoreID, request.CloudKeystoreName, request.CloudProviderID, request.CloudProviderName) 67 msg := util.GetKeystoreOptionsString(request.CloudProviderID, request.CloudKeystoreID, request.CloudProviderName, request.CloudKeystoreName) 68 if err != nil { 69 return nil, fmt.Errorf("failed to retrieve Cloud Keystore with %s: %w", msg, err) 70 } 71 72 if resp == nil || resp.GetCloudKeystores() == nil { 73 return nil, fmt.Errorf("could not find keystore with %s", msg) 74 } 75 76 if len(resp.GetCloudKeystores().GetNodes()) != 1 { 77 return nil, fmt.Errorf("could not find keystore with with %s", msg) 78 } 79 80 ck := resp.GetCloudKeystores().GetNodes()[0] 81 82 return &domain.CloudKeystore{ 83 ID: ck.GetId(), 84 Name: ck.GetName(), 85 Type: ck.GetType().toDomain(), 86 MachineIdentitiesCount: ck.GetMachineIdentitiesCount(), 87 }, nil 88 } 89 90 func (c *CloudProvidersClient) GetMachineIdentity(ctx context.Context, request domain.GetCloudMachineIdentityRequest) (*domain.CloudMachineIdentity, error) { 91 if request.MachineIdentityID == nil { 92 return nil, fmt.Errorf("machine identity ID missing") 93 } 94 95 resp, err := GetMachineIdentities(ctx, c.graphqlClient, request.KeystoreID, request.MachineIdentityID, request.Fingerprints, request.NewlyDiscovered, request.Metadata) 96 if err != nil { 97 return nil, fmt.Errorf("failed to retrieve cloud machine identity with id %s: %w", *request.MachineIdentityID, err) 98 } 99 if len(resp.GetCloudMachineIdentities().GetNodes()) != 1 { 100 return nil, fmt.Errorf("could not find cloud machine identity with with ID %s", *request.MachineIdentityID) 101 } 102 103 mi := resp.GetCloudMachineIdentities().GetNodes()[0] 104 105 return mi.toDomain() 106 } 107 108 func (c *CloudProvidersClient) DeleteMachineIdentity(ctx context.Context, id string) (bool, error) { 109 if id == "" { 110 return false, fmt.Errorf("machine identity ID missing") 111 } 112 resp, err := DeleteMachineIdentities(ctx, c.graphqlClient, []string{id}) 113 if err != nil { 114 return false, fmt.Errorf("failed to delete machine identity with id %s: %w", id, err) 115 } 116 return resp.GetDeleteCloudMachineIdentities(), nil 117 } 118 119 func (c *CloudProvidersClient) ProvisionCertificate(ctx context.Context, certificateID string, cloudKeystoreID string, wsClientID string, options *CertificateProvisioningOptionsInput) (*domain.ProvisioningResponse, error) { 120 if certificateID == "" { 121 return nil, fmt.Errorf("certificateID cannot be empty") 122 } 123 if cloudKeystoreID == "" { 124 return nil, fmt.Errorf("cloudKeystoreID cannot be empty") 125 } 126 if wsClientID == "" { 127 return nil, fmt.Errorf("wsClientID cannot be empty") 128 } 129 resp, err := ProvisionCertificate(ctx, c.graphqlClient, certificateID, cloudKeystoreID, wsClientID, options) 130 if err != nil { 131 return nil, fmt.Errorf("failed to provision certificate with certificate ID %s, keystore ID %s and websocket ID %s: %w", certificateID, cloudKeystoreID, wsClientID, err) 132 } 133 134 if resp == nil || resp.GetProvisionToCloudKeystore() == nil { 135 return nil, fmt.Errorf("failed to provision certificate with certificate ID %s, keystore ID %s and websocket ID %s", certificateID, cloudKeystoreID, wsClientID) 136 } 137 138 return &domain.ProvisioningResponse{ 139 WorkflowId: resp.GetProvisionToCloudKeystore().GetWorkflowId(), 140 WorkflowName: resp.GetProvisionToCloudKeystore().GetWorkflowName(), 141 }, nil 142 } 143 144 func (c *CloudProvidersClient) ProvisionCertificateToMachineIdentity(ctx context.Context, certificateID *string, machineIdentityID string, wsClientID string) (*domain.ProvisioningResponse, error) { 145 if machineIdentityID == "" { 146 return nil, fmt.Errorf("machineIdentityID cannot be empty") 147 } 148 if wsClientID == "" { 149 return nil, fmt.Errorf("wsClientID cannot be empty") 150 } 151 152 certID := "nil" 153 if certificateID != nil { 154 certID = *certificateID 155 } 156 157 resp, err := ProvisionCertificateToMachineIdentity(ctx, c.graphqlClient, machineIdentityID, wsClientID, certificateID) 158 if err != nil { 159 return nil, fmt.Errorf("failed to provision certificate with ID %s, to machine identity with ID %s: %w", certID, machineIdentityID, err) 160 } 161 162 if resp == nil || resp.GetProvisionToCloudMachineIdentity() == nil { 163 return nil, fmt.Errorf("failed to provision certificate with ID %s, to machine identity with ID %s", certID, machineIdentityID) 164 } 165 166 return &domain.ProvisioningResponse{ 167 WorkflowId: resp.GetProvisionToCloudMachineIdentity().GetWorkflowId(), 168 WorkflowName: resp.GetProvisionToCloudMachineIdentity().GetWorkflowName(), 169 }, nil 170 } 171 172 func (v *GetMachineIdentitiesCloudMachineIdentitiesMachineIdentityConnectionNodesMachineIdentity) toDomain() (*domain.CloudMachineIdentity, error) { 173 providerID := "" 174 if v.CloudProviderId != nil { 175 providerID = *v.CloudProviderId 176 } 177 keystoreName := "" 178 if v.CloudKeystoreName != nil { 179 keystoreName = *v.CloudKeystoreName 180 } 181 providerName := "" 182 if v.CloudProviderName != nil { 183 providerName = *v.CloudProviderName 184 } 185 statusDetails := "" 186 if v.StatusDetails != nil { 187 statusDetails = *v.StatusDetails 188 } 189 metadata, err := v.metadataToDomain() 190 if err != nil { 191 return nil, fmt.Errorf("failed to parse cloud certificate metadata: %w", err) 192 } 193 194 return &domain.CloudMachineIdentity{ 195 ID: v.Id, 196 CloudKeystoreID: v.CloudKeystoreId, 197 CloudKeystoreName: keystoreName, 198 CloudProviderID: providerID, 199 CloudProviderName: providerName, 200 CertificateID: v.CertificateId, 201 Metadata: metadata, 202 Status: v.Status.toDomain(), 203 StatusDetails: statusDetails, 204 }, nil 205 } 206 207 func (mis MachineIdentityStatus) toDomain() domain.MachineIdentityStatus { 208 switch mis { 209 case MachineIdentityStatusNew: 210 return domain.MachineIdentityStatusNew 211 case MachineIdentityStatusPending: 212 return domain.MachineIdentityStatusPending 213 case MachineIdentityStatusInstalled: 214 return domain.MachineIdentityStatusInstalled 215 case MachineIdentityStatusDiscovered: 216 return domain.MachineIdentityStatusDiscovered 217 case MachineIdentityStatusValidated: 218 return domain.MachineIdentityStatusValidated 219 case MachineIdentityStatusMissing: 220 return domain.MachineIdentityStatusMissing 221 case MachineIdentityStatusFailed: 222 return domain.MachineIdentityStatusFailed 223 default: 224 return domain.MachineIdentityStatusUnknown 225 } 226 } 227 228 func (v *GetMachineIdentitiesCloudMachineIdentitiesMachineIdentityConnectionNodesMachineIdentity) metadataToDomain() (*domain.CertificateCloudMetadata, error) { 229 if v.Metadata == nil { 230 return nil, nil 231 } 232 m := *v.Metadata 233 234 data, err := json.Marshal(m) 235 if err != nil { 236 return nil, fmt.Errorf("failed to marshal cloud certificate metadata: %w", err) 237 } 238 239 values := make(map[string]interface{}) 240 err = json.Unmarshal(data, &values) 241 if err != nil { 242 return nil, fmt.Errorf("failed to unmarshal cloud certificate metadata: %w", err) 243 } 244 245 certMetadata := domain.NewCertificateCloudMetadata(values) 246 return &certMetadata, nil 247 } 248 249 func (v CloudProviderStatus) toDomain() domain.CloudProviderStatus { 250 switch v { 251 case CloudProviderStatusValidated: 252 return domain.CloudProviderStatusValidated 253 case CloudProviderStatusNotValidated: 254 return domain.CloudProviderStatusNotValidated 255 default: 256 return domain.CloudProviderStatusUnknown 257 } 258 } 259 260 func cloudProviderStatusFromDomain(status domain.CloudProviderStatus) *CloudProviderStatus { 261 switch status { 262 case domain.CloudProviderStatusValidated: 263 cpStatus := CloudProviderStatusValidated 264 return &cpStatus 265 case domain.CloudProviderStatusNotValidated: 266 cpStatus := CloudProviderStatusNotValidated 267 return &cpStatus 268 default: 269 return nil 270 } 271 } 272 273 func (v CloudProviderType) toDomain() domain.CloudProviderType { 274 switch v { 275 case CloudProviderTypeAws: 276 return domain.CloudProviderTypeAWS 277 case CloudProviderTypeAzure: 278 return domain.CloudProviderTypeAzure 279 case CloudProviderTypeGcp: 280 return domain.CloudProviderTypeGCP 281 default: 282 return domain.CloudProviderTypeUnknown 283 } 284 } 285 286 func cloudProviderTypeFromDomain(providerType domain.CloudProviderType) *CloudProviderType { 287 switch providerType { 288 case domain.CloudProviderTypeAWS: 289 cpType := CloudProviderTypeAws 290 return &cpType 291 case domain.CloudProviderTypeAzure: 292 cpType := CloudProviderTypeAzure 293 return &cpType 294 case domain.CloudProviderTypeGCP: 295 cpType := CloudProviderTypeGcp 296 return &cpType 297 default: 298 return nil 299 } 300 } 301 302 func (v CloudKeystoreType) toDomain() domain.CloudKeystoreType { 303 switch v { 304 case CloudKeystoreTypeAcm: 305 return domain.CloudKeystoreTypeACM 306 case CloudKeystoreTypeAkv: 307 return domain.CloudKeystoreTypeAKV 308 case CloudKeystoreTypeGcm: 309 return domain.CloudKeystoreTypeGCM 310 default: 311 return domain.CloudKeystoreTypeUnknown 312 } 313 }