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  }