diff --git a/cli/internal/gcp/autoscaling_node_group.go b/cli/internal/gcp/autoscaling_node_group.go deleted file mode 100644 index c8b6384a4..000000000 --- a/cli/internal/gcp/autoscaling_node_group.go +++ /dev/null @@ -1,13 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package gcp - -import "fmt" - -func AutoscalingNodeGroup(project string, zone string, nodeInstanceGroup string, min int, max int) string { - return fmt.Sprintf("%d:%d:https://www.googleapis.com/compute/v1/projects/%s/zones/%s/instanceGroups/%s", min, max, project, zone, nodeInstanceGroup) -} diff --git a/cli/internal/gcp/autoscaling_node_group_test.go b/cli/internal/gcp/autoscaling_node_group_test.go deleted file mode 100644 index 0292379bb..000000000 --- a/cli/internal/gcp/autoscaling_node_group_test.go +++ /dev/null @@ -1,25 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package gcp - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "go.uber.org/goleak" -) - -func TestMain(m *testing.M) { - goleak.VerifyTestMain(m) -} - -func TestAutoscalingNodeGroup(t *testing.T) { - assert := assert.New(t) - nodeGroups := AutoscalingNodeGroup("some-project", "some-zone", "some-group", 0, 100) - wantNodeGroups := "0:100:https://www.googleapis.com/compute/v1/projects/some-project/zones/some-zone/instanceGroups/some-group" - assert.Equal(wantNodeGroups, nodeGroups) -} diff --git a/cli/internal/gcp/client/api.go b/cli/internal/gcp/client/api.go deleted file mode 100644 index f3d6319fe..000000000 --- a/cli/internal/gcp/client/api.go +++ /dev/null @@ -1,158 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - - "github.com/googleapis/gax-go/v2" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - adminpb "google.golang.org/genproto/googleapis/iam/admin/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" -) - -type instanceAPI interface { - Close() error - List(ctx context.Context, req *computepb.ListInstancesRequest, - opts ...gax.CallOption) InstanceIterator -} - -type operationRegionAPI interface { - Close() error - Wait(ctx context.Context, req *computepb.WaitRegionOperationRequest, - opts ...gax.CallOption) (*computepb.Operation, error) -} - -type operationZoneAPI interface { - Close() error - Wait(ctx context.Context, req *computepb.WaitZoneOperationRequest, - opts ...gax.CallOption) (*computepb.Operation, error) -} - -type operationGlobalAPI interface { - Close() error - Wait(ctx context.Context, req *computepb.WaitGlobalOperationRequest, - opts ...gax.CallOption) (*computepb.Operation, error) -} - -type firewallsAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertFirewallRequest, - opts ...gax.CallOption) (Operation, error) -} - -type forwardingRulesAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, - opts ...gax.CallOption) (Operation, error) - Get(ctx context.Context, req *computepb.GetGlobalForwardingRuleRequest, - opts ...gax.CallOption) (*computepb.ForwardingRule, error) - SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, - opts ...gax.CallOption) (Operation, error) -} - -type backendServicesAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, - opts ...gax.CallOption) (Operation, error) -} - -type healthChecksAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, - opts ...gax.CallOption) (Operation, error) -} - -type targetTCPProxiesAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, - opts ...gax.CallOption) (Operation, error) -} - -type networksAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertNetworkRequest, - opts ...gax.CallOption) (Operation, error) -} - -type subnetworksAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, - opts ...gax.CallOption) (Operation, error) -} - -type instanceTemplateAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, - opts ...gax.CallOption) (Operation, error) -} - -type instanceGroupManagersAPI interface { - Close() error - Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, - opts ...gax.CallOption) (Operation, error) - Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, - opts ...gax.CallOption) (Operation, error) - ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, - opts ...gax.CallOption) ManagedInstanceIterator -} - -type iamAPI interface { - Close() error - CreateServiceAccount(ctx context.Context, req *adminpb.CreateServiceAccountRequest, - opts ...gax.CallOption) (*adminpb.ServiceAccount, error) - CreateServiceAccountKey(ctx context.Context, req *adminpb.CreateServiceAccountKeyRequest, - opts ...gax.CallOption) (*adminpb.ServiceAccountKey, error) - DeleteServiceAccount(ctx context.Context, req *adminpb.DeleteServiceAccountRequest, - opts ...gax.CallOption) error -} - -type projectsAPI interface { - Close() error - GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, - opts ...gax.CallOption) (*iampb.Policy, error) - SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, - opts ...gax.CallOption) (*iampb.Policy, error) -} - -type addressesAPI interface { - Close() error - Insert(ctx context.Context, req *computepb.InsertGlobalAddressRequest, - opts ...gax.CallOption) (Operation, error) - Get(ctx context.Context, req *computepb.GetGlobalAddressRequest, - opts ...gax.CallOption) (*computepb.Address, error) - Delete(ctx context.Context, req *computepb.DeleteGlobalAddressRequest, - opts ...gax.CallOption) (Operation, error) -} - -type Operation interface { - Proto() *computepb.Operation -} - -type ManagedInstanceIterator interface { - Next() (*computepb.ManagedInstance, error) -} - -type InstanceIterator interface { - Next() (*computepb.Instance, error) -} diff --git a/cli/internal/gcp/client/api_test.go b/cli/internal/gcp/client/api_test.go deleted file mode 100644 index 6af12f0ab..000000000 --- a/cli/internal/gcp/client/api_test.go +++ /dev/null @@ -1,576 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - - "github.com/googleapis/gax-go/v2" - "google.golang.org/api/iterator" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" - "google.golang.org/protobuf/proto" -) - -type stubOperation struct { - *computepb.Operation -} - -func (o *stubOperation) Proto() *computepb.Operation { - return o.Operation -} - -type stubInstanceAPI struct { - listIterator *stubInstanceIterator -} - -func (a stubInstanceAPI) Close() error { - return nil -} - -func (a stubInstanceAPI) List(ctx context.Context, req *computepb.ListInstancesRequest, - opts ...gax.CallOption, -) InstanceIterator { - return a.listIterator -} - -type stubInstanceIterator struct { - instances []*computepb.Instance - nextErr error - - internalCounter int -} - -func (i *stubInstanceIterator) Next() (*computepb.Instance, error) { - if i.nextErr != nil { - return nil, i.nextErr - } - if i.internalCounter >= len(i.instances) { - i.internalCounter = 0 - return nil, iterator.Done - } - resp := i.instances[i.internalCounter] - i.internalCounter++ - return resp, nil -} - -type stubOperationZoneAPI struct { - waitErr error -} - -func (a stubOperationZoneAPI) Close() error { - return nil -} - -func (a stubOperationZoneAPI) Wait(ctx context.Context, req *computepb.WaitZoneOperationRequest, - opts ...gax.CallOption, -) (*computepb.Operation, error) { - if a.waitErr != nil { - return nil, a.waitErr - } - return &computepb.Operation{ - Status: computepb.Operation_DONE.Enum(), - }, nil -} - -type stubOperationRegionAPI struct { - waitErr error -} - -func (a stubOperationRegionAPI) Close() error { - return nil -} - -func (a stubOperationRegionAPI) Wait(ctx context.Context, req *computepb.WaitRegionOperationRequest, - opts ...gax.CallOption, -) (*computepb.Operation, error) { - if a.waitErr != nil { - return nil, a.waitErr - } - return &computepb.Operation{ - Status: computepb.Operation_DONE.Enum(), - }, nil -} - -type stubOperationGlobalAPI struct { - waitErr error -} - -func (a stubOperationGlobalAPI) Close() error { - return nil -} - -func (a stubOperationGlobalAPI) Wait(ctx context.Context, req *computepb.WaitGlobalOperationRequest, - opts ...gax.CallOption, -) (*computepb.Operation, error) { - if a.waitErr != nil { - return nil, a.waitErr - } - return &computepb.Operation{ - Status: computepb.Operation_DONE.Enum(), - }, nil -} - -type stubFirewallsAPI struct { - deleteErr error - insertErr error -} - -func (a stubFirewallsAPI) Close() error { - return nil -} - -func (a stubFirewallsAPI) Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubFirewallsAPI) Insert(ctx context.Context, req *computepb.InsertFirewallRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubNetworksAPI struct { - insertErr error - deleteErr error -} - -func (a stubNetworksAPI) Close() error { - return nil -} - -func (a stubNetworksAPI) Insert(ctx context.Context, req *computepb.InsertNetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubNetworksAPI) Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubSubnetworksAPI struct { - insertErr error - deleteErr error -} - -func (a stubSubnetworksAPI) Close() error { - return nil -} - -func (a stubSubnetworksAPI) Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - Region: proto.String("region"), - }, - }, nil -} - -func (a stubSubnetworksAPI) Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - Region: proto.String("region"), - }, - }, nil -} - -type stubBackendServicesAPI struct { - insertErr error - deleteErr error -} - -func (a stubBackendServicesAPI) Close() error { - return nil -} - -func (a stubBackendServicesAPI) Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubBackendServicesAPI) Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubTargetTCPProxiesAPI struct { - insertErr error - deleteErr error -} - -func (a stubTargetTCPProxiesAPI) Close() error { - return nil -} - -func (a stubTargetTCPProxiesAPI) Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubTargetTCPProxiesAPI) Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubForwardingRulesAPI struct { - insertErr error - deleteErr error - getErr error - setLabelErr error - forwardingRule *computepb.ForwardingRule -} - -func (a stubForwardingRulesAPI) Close() error { - return nil -} - -func (a stubForwardingRulesAPI) Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubForwardingRulesAPI) Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubForwardingRulesAPI) Get(ctx context.Context, req *computepb.GetGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (*computepb.ForwardingRule, error) { - if a.getErr != nil { - return nil, a.getErr - } - return a.forwardingRule, nil -} - -func (a stubForwardingRulesAPI) SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.setLabelErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubHealthChecksAPI struct { - insertErr error - deleteErr error -} - -func (a stubHealthChecksAPI) Close() error { - return nil -} - -func (a stubHealthChecksAPI) Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubHealthChecksAPI) Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubInstanceTemplateAPI struct { - deleteErr error - insertErr error -} - -func (a stubInstanceTemplateAPI) Close() error { - return nil -} - -func (a stubInstanceTemplateAPI) Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubInstanceTemplateAPI) Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -type stubInstanceGroupManagersAPI struct { - listIterator *stubManagedInstanceIterator - - deleteErr error - insertErr error -} - -func (a stubInstanceGroupManagersAPI) Close() error { - return nil -} - -func (a stubInstanceGroupManagersAPI) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Zone: proto.String("zone"), - Name: proto.String("name"), - }, - }, nil -} - -func (a stubInstanceGroupManagersAPI) Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, - opts ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Zone: proto.String("zone"), - Name: proto.String("name"), - }, - }, nil -} - -func (a stubInstanceGroupManagersAPI) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, - opts ...gax.CallOption, -) ManagedInstanceIterator { - return a.listIterator -} - -type stubProjectsAPI struct { - getPolicyErr error - setPolicyErr error -} - -func (a stubProjectsAPI) Close() error { - return nil -} - -func (a stubProjectsAPI) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { - if a.getPolicyErr != nil { - return nil, a.getPolicyErr - } - return &iampb.Policy{ - Version: 3, - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{ - "member", - }, - }, - }, - Etag: []byte("etag"), - }, nil -} - -func (a stubProjectsAPI) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, opts ...gax.CallOption) (*iampb.Policy, error) { - if a.setPolicyErr != nil { - return nil, a.setPolicyErr - } - return &iampb.Policy{ - Version: 3, - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{ - "member", - }, - }, - }, - Etag: []byte("etag"), - }, nil -} - -type stubManagedInstanceIterator struct { - instances []*computepb.ManagedInstance - nextErr error - - internalCounter int -} - -func (i *stubManagedInstanceIterator) Next() (*computepb.ManagedInstance, error) { - if i.nextErr != nil { - return nil, i.nextErr - } - if i.internalCounter >= len(i.instances) { - i.internalCounter = 0 - return nil, iterator.Done - } - resp := i.instances[i.internalCounter] - i.internalCounter++ - return resp, nil -} - -type stubAddressesAPI struct { - insertErr error - getAddr *string - getErr error - deleteErr error -} - -func (a stubAddressesAPI) Insert(context.Context, *computepb.InsertGlobalAddressRequest, - ...gax.CallOption, -) (Operation, error) { - if a.insertErr != nil { - return nil, a.insertErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubAddressesAPI) Get(ctx context.Context, req *computepb.GetGlobalAddressRequest, - opts ...gax.CallOption, -) (*computepb.Address, error) { - return &computepb.Address{Address: a.getAddr}, a.getErr -} - -func (a stubAddressesAPI) Delete(context.Context, *computepb.DeleteGlobalAddressRequest, - ...gax.CallOption, -) (Operation, error) { - if a.deleteErr != nil { - return nil, a.deleteErr - } - return &stubOperation{ - &computepb.Operation{ - Name: proto.String("name"), - }, - }, nil -} - -func (a stubAddressesAPI) Close() error { - return nil -} diff --git a/cli/internal/gcp/client/client.go b/cli/internal/gcp/client/client.go deleted file mode 100644 index b44d4e1b7..000000000 --- a/cli/internal/gcp/client/client.go +++ /dev/null @@ -1,394 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "crypto/rand" - "errors" - "math/big" - "net/http" - "strings" - - compute "cloud.google.com/go/compute/apiv1" - admin "cloud.google.com/go/iam/admin/apiv1" - resourcemanager "cloud.google.com/go/resourcemanager/apiv3" - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes" - "github.com/edgelesssys/constellation/v2/internal/state" - "go.uber.org/multierr" - "google.golang.org/api/googleapi" -) - -// Client is a client for the Google Compute Engine. -type Client struct { - instanceAPI - operationRegionAPI - operationZoneAPI - operationGlobalAPI - networksAPI - subnetworksAPI - firewallsAPI - forwardingRulesAPI - backendServicesAPI - healthChecksAPI - targetTCPProxiesAPI - instanceTemplateAPI - instanceGroupManagersAPI - iamAPI - projectsAPI - addressesAPI - - workers cloudtypes.Instances - controlPlanes cloudtypes.Instances - - workerInstanceGroup string - controlPlaneInstanceGroup string - controlPlaneTemplate string - workerTemplate string - network string - subnetwork string - secondarySubnetworkRange string - firewalls []string - name string - project string - uid string - zone string - region string - - // loadbalancer - loadbalancerIP string - loadbalancerIPname string - loadbalancers []*loadBalancer -} - -// NewFromDefault creates an uninitialized client. -func NewFromDefault(ctx context.Context) (*Client, error) { - var closers []closer - insAPI, err := compute.NewInstancesRESTClient(ctx) - if err != nil { - return nil, err - } - closers = append(closers, insAPI) - opZoneAPI, err := compute.NewZoneOperationsRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, opZoneAPI) - opRegionAPI, err := compute.NewRegionOperationsRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, opRegionAPI) - opGlobalAPI, err := compute.NewGlobalOperationsRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, opGlobalAPI) - netAPI, err := compute.NewNetworksRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, netAPI) - subnetAPI, err := compute.NewSubnetworksRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, subnetAPI) - fwAPI, err := compute.NewFirewallsRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, subnetAPI) - forwardingRulesAPI, err := compute.NewGlobalForwardingRulesRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, forwardingRulesAPI) - backendServicesAPI, err := compute.NewBackendServicesRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, backendServicesAPI) - targetTCPProxiesAPI, err := compute.NewTargetTcpProxiesRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, targetTCPProxiesAPI) - targetPoolsAPI, err := compute.NewTargetPoolsRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, targetPoolsAPI) - healthChecksAPI, err := compute.NewHealthChecksRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, healthChecksAPI) - templAPI, err := compute.NewInstanceTemplatesRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, templAPI) - groupAPI, err := compute.NewInstanceGroupManagersRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, groupAPI) - iamAPI, err := admin.NewIamClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, iamAPI) - projectsAPI, err := resourcemanager.NewProjectsClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - closers = append(closers, projectsAPI) - addressesAPI, err := compute.NewGlobalAddressesRESTClient(ctx) - if err != nil { - _ = closeAll(closers) - return nil, err - } - - return &Client{ - instanceAPI: &instanceClient{insAPI}, - operationRegionAPI: opRegionAPI, - operationZoneAPI: opZoneAPI, - operationGlobalAPI: opGlobalAPI, - networksAPI: &networksClient{netAPI}, - subnetworksAPI: &subnetworksClient{subnetAPI}, - firewallsAPI: &firewallsClient{fwAPI}, - forwardingRulesAPI: &forwardingRulesClient{forwardingRulesAPI}, - backendServicesAPI: &backendServicesClient{backendServicesAPI}, - targetTCPProxiesAPI: &targetTCPProxiesClient{targetTCPProxiesAPI}, - healthChecksAPI: &healthChecksClient{healthChecksAPI}, - instanceTemplateAPI: &instanceTemplateClient{templAPI}, - instanceGroupManagersAPI: &instanceGroupManagersClient{groupAPI}, - iamAPI: &iamClient{iamAPI}, - projectsAPI: &projectsClient{projectsAPI}, - addressesAPI: &addressesClient{addressesAPI}, - workers: make(cloudtypes.Instances), - controlPlanes: make(cloudtypes.Instances), - }, nil -} - -// NewInitialized creates an initialized client. -func NewInitialized(ctx context.Context, project, zone, region, name string) (*Client, error) { - client, err := NewFromDefault(ctx) - if err != nil { - return nil, err - } - err = client.init(project, zone, region, name) - return client, err -} - -// Close closes the client's connection. -func (c *Client) Close() error { - closers := []closer{ - c.instanceAPI, - c.operationRegionAPI, - c.operationZoneAPI, - c.operationGlobalAPI, - c.networksAPI, - c.subnetworksAPI, - c.firewallsAPI, - c.forwardingRulesAPI, - c.backendServicesAPI, - c.healthChecksAPI, - c.instanceTemplateAPI, - c.instanceGroupManagersAPI, - c.iamAPI, - c.projectsAPI, - c.addressesAPI, - } - return closeAll(closers) -} - -// init initializes the client. -func (c *Client) init(project, zone, region, name string) error { - c.project = project - c.zone = zone - c.name = name - c.region = region - - uid, err := c.generateUID() - if err != nil { - return err - } - c.uid = uid - return nil -} - -// GetState returns the state of the client as ConstellationState. -func (c *Client) GetState() state.ConstellationState { - stat := state.ConstellationState{ - Name: c.name, - UID: c.uid, - CloudProvider: cloudprovider.GCP.String(), - LoadBalancerIP: c.loadbalancerIP, - GCPProject: c.project, - GCPZone: c.zone, - GCPRegion: c.region, - GCPWorkerInstances: c.workers, - GCPWorkerInstanceGroup: c.workerInstanceGroup, - GCPWorkerInstanceTemplate: c.workerTemplate, - GCPControlPlaneInstances: c.controlPlanes, - GCPControlPlaneInstanceGroup: c.controlPlaneInstanceGroup, - GCPControlPlaneInstanceTemplate: c.controlPlaneTemplate, - GCPFirewalls: c.firewalls, - GCPNetwork: c.network, - GCPSubnetwork: c.subnetwork, - GCPLoadbalancerIPname: c.loadbalancerIPname, - } - for _, lb := range c.loadbalancers { - stat.GCPLoadbalancers = append(stat.GCPLoadbalancers, lb.name) - } - return stat -} - -// SetState sets the state of the client to the handed ConstellationState. -func (c *Client) SetState(stat state.ConstellationState) { - c.workers = stat.GCPWorkerInstances - c.controlPlanes = stat.GCPControlPlaneInstances - c.workerInstanceGroup = stat.GCPWorkerInstanceGroup - c.controlPlaneInstanceGroup = stat.GCPControlPlaneInstanceGroup - c.project = stat.GCPProject - c.zone = stat.GCPZone - c.region = stat.GCPRegion - c.name = stat.Name - c.uid = stat.UID - c.firewalls = stat.GCPFirewalls - c.network = stat.GCPNetwork - c.subnetwork = stat.GCPSubnetwork - c.workerTemplate = stat.GCPWorkerInstanceTemplate - c.controlPlaneTemplate = stat.GCPControlPlaneInstanceTemplate - c.loadbalancerIPname = stat.GCPLoadbalancerIPname - c.loadbalancerIP = stat.LoadBalancerIP - for _, lbName := range stat.GCPLoadbalancers { - lb := &loadBalancer{ - name: lbName, - hasForwardingRules: true, - hasBackendService: true, - hasHealthCheck: true, - hasTargetTCPProxy: true, - } - c.loadbalancers = append(c.loadbalancers, lb) - } -} - -func (c *Client) generateUID() (string, error) { - letters := []byte("abcdefghijklmnopqrstuvwxyz0123456789") - - const uidLen = 5 - uid := make([]byte, uidLen) - for i := 0; i < uidLen; i++ { - n, err := rand.Int(rand.Reader, big.NewInt(int64(len(letters)))) - if err != nil { - return "", err - } - uid[i] = letters[n.Int64()] - } - return string(uid), nil -} - -// buildInstanceName returns a formatted name string. -// The names are joined with a '-'. -// If names is empty, the returned value is c.name + "-" + c.uid. -func (c *Client) buildResourceName(names ...string) string { - builder := strings.Builder{} - - builder.WriteString(c.name) - builder.WriteRune('-') - for _, name := range names { - builder.WriteString(name) - builder.WriteRune('-') - } - builder.WriteString(c.uid) - - return builder.String() -} - -func (c *Client) resourceURI(scope resourceScope, resourceType, resourceName string) string { - const baseURI = "https://www.googleapis.com/compute/v1/projects/" - - builder := strings.Builder{} - - builder.WriteString(baseURI) - builder.WriteString(c.project) - - switch scope { - case scopeGlobal: - builder.WriteString("/global/") - case scopeRegion: - builder.WriteString("/regions/") - builder.WriteString(c.region) - builder.WriteRune('/') - case scopeZone: - builder.WriteString("/zones/") - builder.WriteString(c.zone) - builder.WriteRune('/') - default: - panic("unknown scope") - } - - builder.WriteString(resourceType) - builder.WriteRune('/') - builder.WriteString(resourceName) - - return builder.String() -} - -type resourceScope string - -const ( - scopeGlobal resourceScope = "global" - scopeRegion resourceScope = "region" - scopeZone resourceScope = "zone" -) - -type closer interface { - Close() error -} - -// closeAll closes all closers, even if an error occurs. -// -// Errors are collected and a composed error is returned. -func closeAll(closers []closer) error { - // Since this function is intended to be deferred, it will always call all - // close operations, even if a previous operation failed. The if multiple - // errors occur, the returned error will be composed of the error messages - // of those errors. - var err error - for _, closer := range closers { - err = multierr.Append(err, closer.Close()) - } - return err -} - -func isNotFoundError(err error) bool { - var gAPIErr *googleapi.Error - if !errors.As(err, &gAPIErr) { - return false - } - return gAPIErr.Code == http.StatusNotFound -} diff --git a/cli/internal/gcp/client/client_test.go b/cli/internal/gcp/client/client_test.go deleted file mode 100644 index e5842dd53..000000000 --- a/cli/internal/gcp/client/client_test.go +++ /dev/null @@ -1,259 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "errors" - "net/http" - "testing" - - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes" - "github.com/edgelesssys/constellation/v2/internal/state" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "go.uber.org/goleak" - "google.golang.org/api/googleapi" -) - -func TestMain(m *testing.M) { - goleak.VerifyTestMain(m, - // https://github.com/census-instrumentation/opencensus-go/issues/1262 - goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"), - ) -} - -func TestSetGetState(t *testing.T) { - state := state.ConstellationState{ - CloudProvider: cloudprovider.GCP.String(), - GCPWorkerInstances: cloudtypes.Instances{ - "id-1": { - PublicIP: "ip1", - PrivateIP: "ip2", - }, - }, - GCPControlPlaneInstances: cloudtypes.Instances{ - "id-1": { - PublicIP: "ip3", - PrivateIP: "ip4", - }, - }, - GCPWorkerInstanceGroup: "group-id", - GCPControlPlaneInstanceGroup: "group-id", - GCPProject: "proj-id", - GCPZone: "zone-id", - GCPRegion: "region-id", - Name: "name", - UID: "uid", - LoadBalancerIP: "ip5", - GCPNetwork: "net-id", - GCPSubnetwork: "subnet-id", - GCPFirewalls: []string{"fw-1", "fw-2"}, - GCPWorkerInstanceTemplate: "temp-id", - GCPControlPlaneInstanceTemplate: "temp-id", - GCPLoadbalancers: []string{"lb-1", "lb-2"}, - } - - t.Run("SetState", func(t *testing.T) { - assert := assert.New(t) - - client := Client{} - client.SetState(state) - assert.Equal(state.GCPWorkerInstances, client.workers) - assert.Equal(state.GCPControlPlaneInstances, client.controlPlanes) - assert.Equal(state.GCPWorkerInstanceGroup, client.workerInstanceGroup) - assert.Equal(state.GCPControlPlaneInstanceGroup, client.controlPlaneInstanceGroup) - assert.Equal(state.GCPProject, client.project) - assert.Equal(state.GCPZone, client.zone) - assert.Equal(state.Name, client.name) - assert.Equal(state.UID, client.uid) - assert.Equal(state.GCPNetwork, client.network) - assert.Equal(state.GCPFirewalls, client.firewalls) - assert.Equal(state.GCPControlPlaneInstanceTemplate, client.controlPlaneTemplate) - assert.Equal(state.GCPWorkerInstanceTemplate, client.workerTemplate) - assert.Equal(state.LoadBalancerIP, client.loadbalancerIP) - for _, lb := range client.loadbalancers { - assert.Contains(state.GCPLoadbalancers, lb.name) - assert.True(lb.hasBackendService) - assert.True(lb.hasHealthCheck) - assert.True(lb.hasForwardingRules) - } - }) - - t.Run("GetState", func(t *testing.T) { - assert := assert.New(t) - - client := Client{ - workers: state.GCPWorkerInstances, - controlPlanes: state.GCPControlPlaneInstances, - workerInstanceGroup: state.GCPWorkerInstanceGroup, - controlPlaneInstanceGroup: state.GCPControlPlaneInstanceGroup, - project: state.GCPProject, - zone: state.GCPZone, - region: state.GCPRegion, - name: state.Name, - uid: state.UID, - network: state.GCPNetwork, - subnetwork: state.GCPSubnetwork, - firewalls: state.GCPFirewalls, - workerTemplate: state.GCPWorkerInstanceTemplate, - controlPlaneTemplate: state.GCPControlPlaneInstanceTemplate, - loadbalancerIP: state.LoadBalancerIP, - loadbalancerIPname: state.GCPLoadbalancerIPname, - } - for _, lbName := range state.GCPLoadbalancers { - client.loadbalancers = append(client.loadbalancers, &loadBalancer{name: lbName}) - } - - stat := client.GetState() - - assert.Equal(state, stat) - }) -} - -func TestBuildResourceName(t *testing.T) { - testCases := map[string]struct { - clientUID string - clientName string - names []string - wantName string - }{ - "no names": { - clientUID: "uid", - clientName: "name", - wantName: "name-uid", - }, - "one name": { - clientUID: "uid", - clientName: "name", - names: []string{"foo"}, - wantName: "name-foo-uid", - }, - "two names": { - clientUID: "uid", - clientName: "name", - names: []string{"foo", "bar"}, - wantName: "name-foo-bar-uid", - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - client := Client{ - name: tc.clientName, - uid: tc.clientUID, - } - - name := client.buildResourceName(tc.names...) - - assert.Equal(tc.wantName, name) - }) - } -} - -func TestResourceURI(t *testing.T) { - testCases := map[string]struct { - scope resourceScope - resourceType string - resourceName string - wantURI string - }{ - "global resource": { - scope: scopeGlobal, - resourceType: "healthChecks", - resourceName: "name", - wantURI: "https://www.googleapis.com/compute/v1/projects/project/global/healthChecks/name", - }, - "regional resource": { - scope: scopeRegion, - resourceType: "healthChecks", - resourceName: "name", - wantURI: "https://www.googleapis.com/compute/v1/projects/project/regions/region/healthChecks/name", - }, - "zonal resource": { - scope: scopeZone, - resourceType: "instanceGroups", - resourceName: "name", - wantURI: "https://www.googleapis.com/compute/v1/projects/project/zones/zone/instanceGroups/name", - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - client := Client{ - project: "project", - zone: "zone", - region: "region", - } - - uri := client.resourceURI(tc.scope, tc.resourceType, tc.resourceName) - - assert.Equal(tc.wantURI, uri) - }) - } -} - -func TestInit(t *testing.T) { - assert := assert.New(t) - require := require.New(t) - - client := Client{} - require.NoError(client.init("project", "zone", "region", "name")) - assert.Equal("project", client.project) - assert.Equal("zone", client.zone) - assert.Equal("region", client.region) - assert.Equal("name", client.name) -} - -func TestCloseAll(t *testing.T) { - assert := assert.New(t) - - closers := []closer{&someCloser{}, &someCloser{}, &someCloser{}} - assert.NoError(closeAll(closers)) - for _, c := range closers { - assert.True(c.(*someCloser).closed) - } - - someErr := errors.New("failed") - closers = []closer{&someCloser{}, &someCloser{closeErr: someErr}, &someCloser{}} - assert.Error(closeAll(closers)) - for _, c := range closers { - assert.True(c.(*someCloser).closed) - } -} - -type someCloser struct { - closeErr error - closed bool -} - -func (c *someCloser) Close() error { - c.closed = true - return c.closeErr -} - -func TestIsNotFoundError(t *testing.T) { - testCases := map[string]struct { - err error - result bool - }{ - "not found error": {err: &googleapi.Error{Code: http.StatusNotFound}, result: true}, - "nil error": {err: nil, result: false}, - "other error": {err: errors.New("failed"), result: false}, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - assert.Equal(tc.result, isNotFoundError(tc.err)) - }) - } -} diff --git a/cli/internal/gcp/client/gcpwrappers.go b/cli/internal/gcp/client/gcpwrappers.go deleted file mode 100644 index eb0bc2860..000000000 --- a/cli/internal/gcp/client/gcpwrappers.go +++ /dev/null @@ -1,297 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - - compute "cloud.google.com/go/compute/apiv1" - admin "cloud.google.com/go/iam/admin/apiv1" - resourcemanager "cloud.google.com/go/resourcemanager/apiv3" - "github.com/googleapis/gax-go/v2" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - adminpb "google.golang.org/genproto/googleapis/iam/admin/v1" - iampb "google.golang.org/genproto/googleapis/iam/v1" -) - -type instanceClient struct { - *compute.InstancesClient -} - -func (c *instanceClient) Close() error { - return c.InstancesClient.Close() -} - -func (c *instanceClient) List(ctx context.Context, req *computepb.ListInstancesRequest, - opts ...gax.CallOption, -) InstanceIterator { - return c.InstancesClient.List(ctx, req) -} - -type firewallsClient struct { - *compute.FirewallsClient -} - -func (c *firewallsClient) Close() error { - return c.FirewallsClient.Close() -} - -func (c *firewallsClient) Delete(ctx context.Context, req *computepb.DeleteFirewallRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.FirewallsClient.Delete(ctx, req) -} - -func (c *firewallsClient) Insert(ctx context.Context, req *computepb.InsertFirewallRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.FirewallsClient.Insert(ctx, req) -} - -type forwardingRulesClient struct { - *compute.GlobalForwardingRulesClient -} - -func (c *forwardingRulesClient) Close() error { - return c.GlobalForwardingRulesClient.Close() -} - -func (c *forwardingRulesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.GlobalForwardingRulesClient.Delete(ctx, req) -} - -func (c *forwardingRulesClient) Insert(ctx context.Context, req *computepb.InsertGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.GlobalForwardingRulesClient.Insert(ctx, req) -} - -func (c *forwardingRulesClient) Get(ctx context.Context, req *computepb.GetGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (*computepb.ForwardingRule, error) { - return c.GlobalForwardingRulesClient.Get(ctx, req) -} - -func (c *forwardingRulesClient) SetLabels(ctx context.Context, req *computepb.SetLabelsGlobalForwardingRuleRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.GlobalForwardingRulesClient.SetLabels(ctx, req) -} - -type backendServicesClient struct { - *compute.BackendServicesClient -} - -func (c *backendServicesClient) Close() error { - return c.BackendServicesClient.Close() -} - -func (c *backendServicesClient) Insert(ctx context.Context, req *computepb.InsertBackendServiceRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.BackendServicesClient.Insert(ctx, req) -} - -func (c *backendServicesClient) Delete(ctx context.Context, req *computepb.DeleteBackendServiceRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.BackendServicesClient.Delete(ctx, req) -} - -type targetTCPProxiesClient struct { - *compute.TargetTcpProxiesClient -} - -func (c *targetTCPProxiesClient) Close() error { - return c.TargetTcpProxiesClient.Close() -} - -func (c *targetTCPProxiesClient) Delete(ctx context.Context, req *computepb.DeleteTargetTcpProxyRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.TargetTcpProxiesClient.Delete(ctx, req) -} - -func (c *targetTCPProxiesClient) Insert(ctx context.Context, req *computepb.InsertTargetTcpProxyRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.TargetTcpProxiesClient.Insert(ctx, req) -} - -type healthChecksClient struct { - *compute.HealthChecksClient -} - -func (c *healthChecksClient) Close() error { - return c.HealthChecksClient.Close() -} - -func (c *healthChecksClient) Delete(ctx context.Context, req *computepb.DeleteHealthCheckRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.HealthChecksClient.Delete(ctx, req) -} - -func (c *healthChecksClient) Insert(ctx context.Context, req *computepb.InsertHealthCheckRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.HealthChecksClient.Insert(ctx, req) -} - -type networksClient struct { - *compute.NetworksClient -} - -func (c *networksClient) Close() error { - return c.NetworksClient.Close() -} - -func (c *networksClient) Insert(ctx context.Context, req *computepb.InsertNetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.NetworksClient.Insert(ctx, req) -} - -func (c *networksClient) Delete(ctx context.Context, req *computepb.DeleteNetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.NetworksClient.Delete(ctx, req) -} - -type subnetworksClient struct { - *compute.SubnetworksClient -} - -func (c *subnetworksClient) Close() error { - return c.SubnetworksClient.Close() -} - -func (c *subnetworksClient) Insert(ctx context.Context, req *computepb.InsertSubnetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.SubnetworksClient.Insert(ctx, req) -} - -func (c *subnetworksClient) Delete(ctx context.Context, req *computepb.DeleteSubnetworkRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.SubnetworksClient.Delete(ctx, req) -} - -type instanceTemplateClient struct { - *compute.InstanceTemplatesClient -} - -func (c *instanceTemplateClient) Close() error { - return c.InstanceTemplatesClient.Close() -} - -func (c *instanceTemplateClient) Delete(ctx context.Context, req *computepb.DeleteInstanceTemplateRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.InstanceTemplatesClient.Delete(ctx, req) -} - -func (c *instanceTemplateClient) Insert(ctx context.Context, req *computepb.InsertInstanceTemplateRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.InstanceTemplatesClient.Insert(ctx, req) -} - -type instanceGroupManagersClient struct { - *compute.InstanceGroupManagersClient -} - -func (c *instanceGroupManagersClient) Close() error { - return c.InstanceGroupManagersClient.Close() -} - -func (c *instanceGroupManagersClient) Delete(ctx context.Context, req *computepb.DeleteInstanceGroupManagerRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.InstanceGroupManagersClient.Delete(ctx, req) -} - -func (c *instanceGroupManagersClient) Insert(ctx context.Context, req *computepb.InsertInstanceGroupManagerRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.InstanceGroupManagersClient.Insert(ctx, req) -} - -func (c *instanceGroupManagersClient) ListManagedInstances(ctx context.Context, req *computepb.ListManagedInstancesInstanceGroupManagersRequest, - opts ...gax.CallOption, -) ManagedInstanceIterator { - return c.InstanceGroupManagersClient.ListManagedInstances(ctx, req) -} - -type iamClient struct { - *admin.IamClient -} - -func (c *iamClient) Close() error { - return c.IamClient.Close() -} - -func (c *iamClient) CreateServiceAccount(ctx context.Context, req *adminpb.CreateServiceAccountRequest, - opts ...gax.CallOption, -) (*adminpb.ServiceAccount, error) { - return c.IamClient.CreateServiceAccount(ctx, req) -} - -func (c *iamClient) CreateServiceAccountKey(ctx context.Context, req *adminpb.CreateServiceAccountKeyRequest, - opts ...gax.CallOption, -) (*adminpb.ServiceAccountKey, error) { - return c.IamClient.CreateServiceAccountKey(ctx, req) -} - -func (c *iamClient) DeleteServiceAccount(ctx context.Context, req *adminpb.DeleteServiceAccountRequest, - opts ...gax.CallOption, -) error { - return c.IamClient.DeleteServiceAccount(ctx, req) -} - -type projectsClient struct { - *resourcemanager.ProjectsClient -} - -func (c *projectsClient) Close() error { - return c.ProjectsClient.Close() -} - -func (c *projectsClient) GetIamPolicy(ctx context.Context, req *iampb.GetIamPolicyRequest, - opts ...gax.CallOption, -) (*iampb.Policy, error) { - return c.ProjectsClient.GetIamPolicy(ctx, req) -} - -func (c *projectsClient) SetIamPolicy(ctx context.Context, req *iampb.SetIamPolicyRequest, - opts ...gax.CallOption, -) (*iampb.Policy, error) { - return c.ProjectsClient.SetIamPolicy(ctx, req) -} - -type addressesClient struct { - *compute.GlobalAddressesClient -} - -func (c *addressesClient) Insert(ctx context.Context, req *computepb.InsertGlobalAddressRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.GlobalAddressesClient.Insert(ctx, req) -} - -func (c *addressesClient) Delete(ctx context.Context, req *computepb.DeleteGlobalAddressRequest, - opts ...gax.CallOption, -) (Operation, error) { - return c.GlobalAddressesClient.Delete(ctx, req) -} - -func (c *addressesClient) Close() error { - return c.GlobalAddressesClient.Close() -} diff --git a/cli/internal/gcp/client/instances.go b/cli/internal/gcp/client/instances.go deleted file mode 100644 index 41644f1f8..000000000 --- a/cli/internal/gcp/client/instances.go +++ /dev/null @@ -1,454 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "fmt" - "strconv" - "strings" - "time" - - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes" - "github.com/edgelesssys/constellation/v2/internal/constants" - "github.com/edgelesssys/constellation/v2/internal/role" - "google.golang.org/api/iterator" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - "google.golang.org/protobuf/proto" -) - -// CreateInstances creates instances (virtual machines) on Google Compute Engine. -// -// A separate managed instance group is created for control planes and workers, the function -// waits until the instances are up and stores the public and private IPs of the instances -// in the client. If the client's network must be set before instances can be created. -func (c *Client) CreateInstances(ctx context.Context, input CreateInstancesInput) error { - if c.network == "" { - return errors.New("client has no network") - } - ops := []Operation{} - - enableSerialConsole := strconv.FormatBool(input.EnableSerialConsole) - - workerTemplateInput := insertInstanceTemplateInput{ - Name: c.buildResourceName("worker"), - Network: c.network, - SecondarySubnetworkRangeName: c.secondarySubnetworkRange, - Subnetwork: c.subnetwork, - EnableSerialConsole: enableSerialConsole, - ImageID: input.ImageID, - InstanceType: input.InstanceType, - StateDiskSizeGB: int64(input.StateDiskSizeGB), - StateDiskType: input.StateDiskType, - Role: role.Worker.String(), - KubeEnv: input.KubeEnv, - Project: c.project, - Zone: c.zone, - Region: c.region, - UID: c.uid, - } - op, err := c.insertInstanceTemplate(ctx, workerTemplateInput) - if err != nil { - return fmt.Errorf("inserting instanceTemplate: %w", err) - } - ops = append(ops, op) - c.workerTemplate = workerTemplateInput.Name - - controlPlaneTemplateInput := insertInstanceTemplateInput{ - Name: c.buildResourceName("control-plane"), - Network: c.network, - Subnetwork: c.subnetwork, - SecondarySubnetworkRangeName: c.secondarySubnetworkRange, - EnableSerialConsole: enableSerialConsole, - ImageID: input.ImageID, - InstanceType: input.InstanceType, - StateDiskSizeGB: int64(input.StateDiskSizeGB), - StateDiskType: input.StateDiskType, - Role: role.ControlPlane.String(), - KubeEnv: input.KubeEnv, - Project: c.project, - Zone: c.zone, - Region: c.region, - UID: c.uid, - } - op, err = c.insertInstanceTemplate(ctx, controlPlaneTemplateInput) - if err != nil { - return fmt.Errorf("inserting instanceTemplate: %w", err) - } - ops = append(ops, op) - c.controlPlaneTemplate = controlPlaneTemplateInput.Name - if err := c.waitForOperations(ctx, ops); err != nil { - return err - } - ops = []Operation{} - - controlPlaneGroupInput := instanceGroupManagerInput{ - Count: input.CountControlPlanes, - Name: strings.Join([]string{c.name, "control-plane", c.uid}, "-"), - NamedPorts: []*computepb.NamedPort{ - {Name: proto.String("kubernetes"), Port: proto.Int32(constants.KubernetesPort)}, - {Name: proto.String("debugd"), Port: proto.Int32(constants.DebugdPort)}, - {Name: proto.String("bootstrapper"), Port: proto.Int32(constants.BootstrapperPort)}, - {Name: proto.String("verify"), Port: proto.Int32(constants.VerifyServiceNodePortGRPC)}, - {Name: proto.String("konnectivity"), Port: proto.Int32(constants.KonnectivityPort)}, - {Name: proto.String("recovery"), Port: proto.Int32(constants.RecoveryPort)}, - }, - Template: c.controlPlaneTemplate, - UID: c.uid, - Project: c.project, - Zone: c.zone, - } - op, err = c.insertInstanceGroupManger(ctx, controlPlaneGroupInput) - if err != nil { - return fmt.Errorf("inserting instanceGroupManager: %w", err) - } - ops = append(ops, op) - c.controlPlaneInstanceGroup = controlPlaneGroupInput.Name - - workerGroupInput := instanceGroupManagerInput{ - Count: input.CountWorkers, - Name: strings.Join([]string{c.name, "worker", c.uid}, "-"), - Template: c.workerTemplate, - UID: c.uid, - Project: c.project, - Zone: c.zone, - } - op, err = c.insertInstanceGroupManger(ctx, workerGroupInput) - if err != nil { - return fmt.Errorf("inserting instanceGroupManager: %w", err) - } - ops = append(ops, op) - c.workerInstanceGroup = workerGroupInput.Name - - if err := c.waitForOperations(ctx, ops); err != nil { - return err - } - - if err := c.waitForInstanceGroupScaling(ctx, c.workerInstanceGroup); err != nil { - return fmt.Errorf("waiting for instanceGroupScaling: %w", err) - } - - if err := c.waitForInstanceGroupScaling(ctx, c.controlPlaneInstanceGroup); err != nil { - return fmt.Errorf("waiting for instanceGroupScaling: %w", err) - } - - if err := c.getInstanceIPs(ctx, c.workerInstanceGroup, c.workers); err != nil { - return fmt.Errorf("getting instanceIPs: %w", err) - } - if err := c.getInstanceIPs(ctx, c.controlPlaneInstanceGroup, c.controlPlanes); err != nil { - return fmt.Errorf("getting instanceIPs: %w", err) - } - return nil -} - -// TerminateInstances terminates the clients instances. -func (c *Client) TerminateInstances(ctx context.Context) error { - ops := []Operation{} - if c.workerInstanceGroup != "" { - op, err := c.deleteInstanceGroupManager(ctx, c.workerInstanceGroup) - if err != nil && !isNotFoundError(err) { - return fmt.Errorf("deleting instanceGroupManager '%s': %w", c.workerInstanceGroup, err) - } - if err == nil { - ops = append(ops, op) - } - c.workerInstanceGroup = "" - c.workers = make(cloudtypes.Instances) - } - - if c.controlPlaneInstanceGroup != "" { - op, err := c.deleteInstanceGroupManager(ctx, c.controlPlaneInstanceGroup) - if err != nil && !isNotFoundError(err) { - return fmt.Errorf("deleting instanceGroupManager '%s': %w", c.controlPlaneInstanceGroup, err) - } - if err == nil { - ops = append(ops, op) - } - c.controlPlaneInstanceGroup = "" - c.controlPlanes = make(cloudtypes.Instances) - } - if err := c.waitForOperations(ctx, ops); err != nil { - return err - } - ops = []Operation{} - - if c.workerTemplate != "" { - op, err := c.deleteInstanceTemplate(ctx, c.workerTemplate) - if err != nil && !isNotFoundError(err) { - return fmt.Errorf("deleting instanceTemplate: %w", err) - } - if err == nil { - ops = append(ops, op) - } - c.workerTemplate = "" - } - if c.controlPlaneTemplate != "" { - op, err := c.deleteInstanceTemplate(ctx, c.controlPlaneTemplate) - if err != nil && !isNotFoundError(err) { - return fmt.Errorf("deleting instanceTemplate: %w", err) - } - if err == nil { - ops = append(ops, op) - } - c.controlPlaneTemplate = "" - } - return c.waitForOperations(ctx, ops) -} - -func (c *Client) insertInstanceTemplate(ctx context.Context, input insertInstanceTemplateInput) (Operation, error) { - req := input.insertInstanceTemplateRequest() - return c.instanceTemplateAPI.Insert(ctx, req) -} - -func (c *Client) deleteInstanceTemplate(ctx context.Context, name string) (Operation, error) { - req := &computepb.DeleteInstanceTemplateRequest{ - InstanceTemplate: name, - Project: c.project, - } - return c.instanceTemplateAPI.Delete(ctx, req) -} - -func (c *Client) insertInstanceGroupManger(ctx context.Context, input instanceGroupManagerInput) (Operation, error) { - req := input.InsertInstanceGroupManagerRequest() - return c.instanceGroupManagersAPI.Insert(ctx, &req) -} - -func (c *Client) deleteInstanceGroupManager(ctx context.Context, instanceGroupManagerName string) (Operation, error) { - req := &computepb.DeleteInstanceGroupManagerRequest{ - InstanceGroupManager: instanceGroupManagerName, - Project: c.project, - Zone: c.zone, - } - return c.instanceGroupManagersAPI.Delete(ctx, req) -} - -func (c *Client) waitForInstanceGroupScaling(ctx context.Context, groupID string) error { - for { - if err := ctx.Err(); err != nil { - return err - } - listReq := &computepb.ListManagedInstancesInstanceGroupManagersRequest{ - InstanceGroupManager: groupID, - Project: c.project, - Zone: c.zone, - } - it := c.instanceGroupManagersAPI.ListManagedInstances(ctx, listReq) - for { - resp, err := it.Next() - if errors.Is(err, iterator.Done) { - return nil - } - if err != nil { - return err - } - if resp.CurrentAction == nil { - return errors.New("currentAction is nil") - } - if *resp.CurrentAction != computepb.ManagedInstance_NONE.String() { - time.Sleep(5 * time.Second) - break - } - } - } -} - -// getInstanceIPs requests the IPs of the client's instances. -func (c *Client) getInstanceIPs(ctx context.Context, groupID string, list cloudtypes.Instances) error { - req := &computepb.ListInstancesRequest{ - Filter: proto.String("name=" + groupID + "*"), - Project: c.project, - Zone: c.zone, - } - it := c.instanceAPI.List(ctx, req) - for { - resp, err := it.Next() - if errors.Is(err, iterator.Done) { - return nil - } - if err != nil { - return err - } - if resp.Name == nil { - return errors.New("instance name is nil pointer") - } - if len(resp.NetworkInterfaces) == 0 { - return errors.New("network interface is empty") - } - if resp.NetworkInterfaces[0].NetworkIP == nil { - return errors.New("networkIP is nil") - } - if len(resp.NetworkInterfaces[0].AccessConfigs) == 0 { - return errors.New("access configs is empty") - } - if resp.NetworkInterfaces[0].AccessConfigs[0].NatIP == nil { - return errors.New("natIP is nil") - } - instance := cloudtypes.Instance{ - PrivateIP: *resp.NetworkInterfaces[0].NetworkIP, - PublicIP: *resp.NetworkInterfaces[0].AccessConfigs[0].NatIP, - } - list[*resp.Name] = instance - } -} - -type instanceGroupManagerInput struct { - Count int - Name string - NamedPorts []*computepb.NamedPort - Template string - Project string - Zone string - UID string -} - -func (i *instanceGroupManagerInput) InsertInstanceGroupManagerRequest() computepb.InsertInstanceGroupManagerRequest { - return computepb.InsertInstanceGroupManagerRequest{ - InstanceGroupManagerResource: &computepb.InstanceGroupManager{ - BaseInstanceName: proto.String(i.Name), - NamedPorts: i.NamedPorts, - InstanceTemplate: proto.String("projects/" + i.Project + "/global/instanceTemplates/" + i.Template), - Name: proto.String(i.Name), - TargetSize: proto.Int32(int32(i.Count)), - }, - Project: i.Project, - Zone: i.Zone, - } -} - -// CreateInstancesInput is the input for a CreatInstances operation. -type CreateInstancesInput struct { - EnableSerialConsole bool - CountWorkers int - CountControlPlanes int - ImageID string - InstanceType string - StateDiskSizeGB int - StateDiskType string - KubeEnv string -} - -type insertInstanceTemplateInput struct { - Name string - Network string - Subnetwork string - SecondarySubnetworkRangeName string - EnableSerialConsole string - ImageID string - InstanceType string - StateDiskSizeGB int64 - StateDiskType string - Role string - KubeEnv string - Project string - Zone string - Region string - UID string -} - -func (i insertInstanceTemplateInput) insertInstanceTemplateRequest() *computepb.InsertInstanceTemplateRequest { - req := computepb.InsertInstanceTemplateRequest{ - InstanceTemplateResource: &computepb.InstanceTemplate{ - Description: proto.String("This instance belongs to a Constellation cluster."), - Name: proto.String(i.Name), - Properties: &computepb.InstanceProperties{ - ConfidentialInstanceConfig: &computepb.ConfidentialInstanceConfig{ - EnableConfidentialCompute: proto.Bool(true), - }, - Description: proto.String("This instance belongs to a Constellation cluster."), - Disks: []*computepb.AttachedDisk{ - { - InitializeParams: &computepb.AttachedDiskInitializeParams{ - DiskSizeGb: proto.Int64(10), - SourceImage: proto.String(i.ImageID), - }, - AutoDelete: proto.Bool(true), - Boot: proto.Bool(true), - Mode: proto.String(computepb.AttachedDisk_READ_WRITE.String()), - }, - { - InitializeParams: &computepb.AttachedDiskInitializeParams{ - DiskSizeGb: proto.Int64(i.StateDiskSizeGB), - DiskType: proto.String(i.StateDiskType), - }, - AutoDelete: proto.Bool(true), - DeviceName: proto.String("state-disk"), - Mode: proto.String(computepb.AttachedDisk_READ_WRITE.String()), - Type: proto.String(computepb.AttachedDisk_PERSISTENT.String()), - }, - }, - MachineType: proto.String(i.InstanceType), - Metadata: &computepb.Metadata{ - Items: []*computepb.Items{ - { - Key: proto.String("kube-env"), - Value: proto.String(i.KubeEnv), - }, - { - Key: proto.String("constellation-uid"), - Value: proto.String(i.UID), - }, - { - Key: proto.String("constellation-role"), - Value: proto.String(i.Role), - }, - { - Key: proto.String("serial-port-enable"), - Value: proto.String(i.EnableSerialConsole), - }, - }, - }, - NetworkInterfaces: []*computepb.NetworkInterface{ - { - Network: proto.String("projects/" + i.Project + "/global/networks/" + i.Network), - Subnetwork: proto.String("regions/" + i.Region + "/subnetworks/" + i.Subnetwork), - AccessConfigs: []*computepb.AccessConfig{ - {Type: proto.String(computepb.AccessConfig_ONE_TO_ONE_NAT.String())}, - }, - }, - }, - Scheduling: &computepb.Scheduling{ - OnHostMaintenance: proto.String(computepb.Scheduling_TERMINATE.String()), - }, - ServiceAccounts: []*computepb.ServiceAccount{ - { - Scopes: []string{ - "https://www.googleapis.com/auth/compute", - "https://www.googleapis.com/auth/servicecontrol", - "https://www.googleapis.com/auth/service.management.readonly", - "https://www.googleapis.com/auth/devstorage.read_only", - "https://www.googleapis.com/auth/logging.write", - "https://www.googleapis.com/auth/monitoring.write", - "https://www.googleapis.com/auth/trace.append", - }, - }, - }, - ShieldedInstanceConfig: &computepb.ShieldedInstanceConfig{ - EnableIntegrityMonitoring: proto.Bool(true), - EnableSecureBoot: proto.Bool(true), - EnableVtpm: proto.Bool(true), - }, - Tags: &computepb.Tags{ - Items: []string{"constellation-" + i.UID}, - }, - }, - }, - Project: i.Project, - } - - // if there is an secondary IP range defined, we use it as an alias IP range - if i.SecondarySubnetworkRangeName != "" { - req.InstanceTemplateResource.Properties.NetworkInterfaces[0].AliasIpRanges = []*computepb.AliasIpRange{ - { - IpCidrRange: proto.String("/24"), - SubnetworkRangeName: proto.String(i.SecondarySubnetworkRangeName), - }, - } - } - - return &req -} diff --git a/cli/internal/gcp/client/instances_test.go b/cli/internal/gcp/client/instances_test.go deleted file mode 100644 index 3ebc3fbe0..000000000 --- a/cli/internal/gcp/client/instances_test.go +++ /dev/null @@ -1,285 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "net/http" - "testing" - - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes" - "github.com/stretchr/testify/assert" - "google.golang.org/api/googleapi" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - "google.golang.org/protobuf/proto" -) - -func TestCreateInstances(t *testing.T) { - testInstances := []*computepb.Instance{ - { - Name: proto.String("instance-name-1"), - NetworkInterfaces: []*computepb.NetworkInterface{ - { - AccessConfigs: []*computepb.AccessConfig{ - {NatIP: proto.String("public-ip")}, - }, - NetworkIP: proto.String("private-ip"), - }, - }, - }, - { - Name: proto.String("instance-name-2"), - NetworkInterfaces: []*computepb.NetworkInterface{ - { - AccessConfigs: []*computepb.AccessConfig{ - {NatIP: proto.String("public-ip")}, - }, - NetworkIP: proto.String("private-ip"), - }, - }, - }, - } - testManagedInstances := []*computepb.ManagedInstance{ - {CurrentAction: proto.String(computepb.ManagedInstance_NONE.String())}, - {CurrentAction: proto.String(computepb.ManagedInstance_NONE.String())}, - } - testInput := CreateInstancesInput{ - CountControlPlanes: 3, - CountWorkers: 4, - ImageID: "img", - InstanceType: "n2d-standard-4", - KubeEnv: "kube-env", - } - someErr := errors.New("failed") - - testCases := map[string]struct { - instanceAPI instanceAPI - operationZoneAPI operationZoneAPI - operationGlobalAPI operationGlobalAPI - instanceTemplateAPI instanceTemplateAPI - instanceGroupManagersAPI instanceGroupManagersAPI - input CreateInstancesInput - network string - wantErr bool - }{ - "successful create": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{instances: testManagedInstances}}, - network: "network", - input: testInput, - }, - "failed no network": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{waitErr: someErr}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{instances: testManagedInstances}}, - input: testInput, - wantErr: true, - }, - "failed wait zonal op": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{waitErr: someErr}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{instances: testManagedInstances}}, - network: "network", - input: testInput, - wantErr: true, - }, - "failed wait global op": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{instances: testManagedInstances}}, - network: "network", - input: testInput, - wantErr: true, - }, - "failed insert template": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{insertErr: someErr}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{instances: testManagedInstances}}, - input: testInput, - network: "network", - wantErr: true, - }, - "failed insert instanceGroupManager": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{insertErr: someErr}, - network: "network", - input: testInput, - wantErr: true, - }, - "failed instanceGroupManager iterator": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{instances: testInstances}}, - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{nextErr: someErr}}, - network: "network", - input: testInput, - wantErr: true, - }, - "failed instance iterator": { - instanceAPI: stubInstanceAPI{listIterator: &stubInstanceIterator{nextErr: someErr}}, - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{listIterator: &stubManagedInstanceIterator{instances: testManagedInstances}}, - network: "network", - input: testInput, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - network: tc.network, - subnetwork: "subnetwork", - secondarySubnetworkRange: "secondary-range", - instanceAPI: tc.instanceAPI, - operationZoneAPI: tc.operationZoneAPI, - operationGlobalAPI: tc.operationGlobalAPI, - instanceTemplateAPI: tc.instanceTemplateAPI, - instanceGroupManagersAPI: tc.instanceGroupManagersAPI, - workers: make(cloudtypes.Instances), - controlPlanes: make(cloudtypes.Instances), - } - - if tc.wantErr { - assert.Error(client.CreateInstances(ctx, tc.input)) - } else { - assert.NoError(client.CreateInstances(ctx, tc.input)) - assert.Equal([]string{"public-ip", "public-ip"}, client.workers.PublicIPs()) - assert.Equal([]string{"private-ip", "private-ip"}, client.workers.PrivateIPs()) - assert.Equal([]string{"public-ip", "public-ip"}, client.controlPlanes.PublicIPs()) - assert.Equal([]string{"private-ip", "private-ip"}, client.controlPlanes.PrivateIPs()) - assert.NotNil(client.workerInstanceGroup) - assert.NotNil(client.controlPlaneInstanceGroup) - assert.NotNil(client.controlPlaneTemplate) - assert.NotNil(client.workerTemplate) - } - }) - } -} - -func TestTerminateInstances(t *testing.T) { - someErr := errors.New("failed") - notFoundErr := &googleapi.Error{Code: http.StatusNotFound} - - testCases := map[string]struct { - operationZoneAPI operationZoneAPI - operationGlobalAPI operationGlobalAPI - instanceTemplateAPI instanceTemplateAPI - instanceGroupManagersAPI instanceGroupManagersAPI - - missingWorkerInstanceGroup bool - wantErr bool - }{ - "successful terminate": { - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{}, - }, - "successful terminate with missing worker instance group": { - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{}, - missingWorkerInstanceGroup: true, - }, - "instances not found": { - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{deleteErr: notFoundErr}, - }, - "templates not found": { - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{deleteErr: notFoundErr}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{}, - }, - "fail delete instanceGroupManager": { - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{deleteErr: someErr}, - wantErr: true, - }, - "fail delete instanceTemplate": { - operationZoneAPI: stubOperationZoneAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - instanceTemplateAPI: stubInstanceTemplateAPI{deleteErr: someErr}, - instanceGroupManagersAPI: stubInstanceGroupManagersAPI{}, - wantErr: true, - }, - } - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - operationZoneAPI: tc.operationZoneAPI, - operationGlobalAPI: tc.operationGlobalAPI, - instanceTemplateAPI: tc.instanceTemplateAPI, - instanceGroupManagersAPI: tc.instanceGroupManagersAPI, - workers: cloudtypes.Instances{"worker-id-1": cloudtypes.Instance{}, "worker-id-2": cloudtypes.Instance{}}, - controlPlanes: cloudtypes.Instances{"controlplane-id-1": cloudtypes.Instance{}}, - firewalls: []string{"firewall-1", "firewall-2"}, - network: "network-id-1", - workerInstanceGroup: "workerInstanceGroup-id-1", - controlPlaneInstanceGroup: "controlplaneInstanceGroup-id-1", - workerTemplate: "template-id-1", - controlPlaneTemplate: "template-id-1", - } - if tc.missingWorkerInstanceGroup { - client.workerInstanceGroup = "" - client.workers = cloudtypes.Instances{} - } - - if tc.wantErr { - assert.Error(client.TerminateInstances(ctx)) - } else { - assert.NoError(client.TerminateInstances(ctx)) - assert.Nil(client.workers.PublicIPs()) - assert.Nil(client.workers.PrivateIPs()) - assert.Nil(client.controlPlanes.PublicIPs()) - assert.Nil(client.controlPlanes.PrivateIPs()) - assert.Empty(client.workerInstanceGroup) - assert.Empty(client.controlPlaneInstanceGroup) - assert.Empty(client.controlPlaneTemplate) - assert.Empty(client.workerTemplate) - } - }) - } -} diff --git a/cli/internal/gcp/client/loadbalancer.go b/cli/internal/gcp/client/loadbalancer.go deleted file mode 100644 index bec9a0ef4..000000000 --- a/cli/internal/gcp/client/loadbalancer.go +++ /dev/null @@ -1,493 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "fmt" - "strconv" - - "github.com/edgelesssys/constellation/v2/internal/constants" - "go.uber.org/multierr" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - "google.golang.org/protobuf/proto" -) - -type loadBalancer struct { - name string - - // For creation. - ip string - frontendPort int - backendPortName string - healthCheck computepb.HealthCheck_Type - label bool - - // For resource management. - hasHealthCheck bool - hasBackendService bool - hasForwardingRules bool - hasTargetTCPProxy bool -} - -// CreateLoadBalancers creates all necessary load balancers. -func (c *Client) CreateLoadBalancers(ctx context.Context, isDebugCluster bool) error { - if err := c.createIPAddr(ctx); err != nil { - return fmt.Errorf("creating load balancer IP address: %w", err) - } - - // - // LoadBalancer definitions. - // - // LoadBalancers added here also need to be referenced in instances.go:*Client.CreateInstances - - c.loadbalancers = append(c.loadbalancers, &loadBalancer{ - name: c.buildResourceName("kube"), - ip: c.loadbalancerIP, - frontendPort: constants.KubernetesPort, - backendPortName: "kubernetes", - healthCheck: computepb.HealthCheck_HTTPS, - label: true, // Label, so bootstrapper can find kube-apiserver. - }) - - c.loadbalancers = append(c.loadbalancers, &loadBalancer{ - name: c.buildResourceName("boot"), - ip: c.loadbalancerIPname, - frontendPort: constants.BootstrapperPort, - backendPortName: "bootstrapper", - healthCheck: computepb.HealthCheck_TCP, - }) - - c.loadbalancers = append(c.loadbalancers, &loadBalancer{ - name: c.buildResourceName("verify"), - ip: c.loadbalancerIPname, - frontendPort: constants.VerifyServiceNodePortGRPC, - backendPortName: "verify", - healthCheck: computepb.HealthCheck_TCP, - }) - - c.loadbalancers = append(c.loadbalancers, &loadBalancer{ - name: c.buildResourceName("konnectivity"), - ip: c.loadbalancerIPname, - frontendPort: constants.KonnectivityPort, - backendPortName: "konnectivity", - healthCheck: computepb.HealthCheck_TCP, - }) - - c.loadbalancers = append(c.loadbalancers, &loadBalancer{ - name: c.buildResourceName("recovery"), - ip: c.loadbalancerIPname, - frontendPort: constants.RecoveryPort, - backendPortName: "recovery", - healthCheck: computepb.HealthCheck_TCP, - }) - - // Only create when the debug cluster flag is set in the Constellation config - if isDebugCluster { - c.loadbalancers = append(c.loadbalancers, &loadBalancer{ - name: c.buildResourceName("debugd"), - ip: c.loadbalancerIPname, - frontendPort: constants.DebugdPort, - backendPortName: "debugd", - healthCheck: computepb.HealthCheck_TCP, - }) - } - - // Load balancer creation. - - errC := make(chan error) - createLB := func(ctx context.Context, lb *loadBalancer) { - errC <- c.createLoadBalancer(ctx, lb) - } - - for _, lb := range c.loadbalancers { - go createLB(ctx, lb) - } - - var err error - for i := 0; i < len(c.loadbalancers); i++ { - err = multierr.Append(err, <-errC) - } - - return err -} - -// createLoadBalancer creates a load balancer. -func (c *Client) createLoadBalancer(ctx context.Context, lb *loadBalancer) error { - if err := c.createHealthCheck(ctx, lb); err != nil { - return fmt.Errorf("creating health checks: %w", err) - } - if err := c.createBackendService(ctx, lb); err != nil { - return fmt.Errorf("creating backend services: %w", err) - } - if err := c.createTargetTCPProxy(ctx, lb); err != nil { - return fmt.Errorf("creating target TCP proxies: %w", err) - } - if err := c.createForwardingRules(ctx, lb); err != nil { - return fmt.Errorf("creating forwarding rules: %w", err) - } - return nil -} - -func (c *Client) createHealthCheck(ctx context.Context, lb *loadBalancer) error { - req := &computepb.InsertHealthCheckRequest{ - Project: c.project, - HealthCheckResource: &computepb.HealthCheck{ - Name: proto.String(lb.name), - Type: proto.String(computepb.HealthCheck_Type_name[int32(lb.healthCheck)]), - CheckIntervalSec: proto.Int32(1), - TimeoutSec: proto.Int32(1), - }, - } - switch lb.healthCheck { - case computepb.HealthCheck_HTTPS: - req.HealthCheckResource.HttpsHealthCheck = newHealthCheckHTTPS(lb.frontendPort) - case computepb.HealthCheck_TCP: - req.HealthCheckResource.TcpHealthCheck = newHealthCheckTCP(lb.frontendPort) - } - resp, err := c.healthChecksAPI.Insert(ctx, req) - if err != nil { - return fmt.Errorf("inserting health check: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return fmt.Errorf("waiting for health check creation: %w", err) - } - - lb.hasHealthCheck = true - return nil -} - -func (c *Client) createBackendService(ctx context.Context, lb *loadBalancer) error { - req := &computepb.InsertBackendServiceRequest{ - Project: c.project, - BackendServiceResource: &computepb.BackendService{ - Name: proto.String(lb.name), - Protocol: proto.String(computepb.BackendService_Protocol_name[int32(computepb.BackendService_TCP)]), - LoadBalancingScheme: proto.String(computepb.BackendService_LoadBalancingScheme_name[int32(computepb.BackendService_EXTERNAL)]), - HealthChecks: []string{c.resourceURI(scopeGlobal, "healthChecks", lb.name)}, - PortName: proto.String(lb.backendPortName), - Backends: []*computepb.Backend{ - { - BalancingMode: proto.String(computepb.Backend_BalancingMode_name[int32(computepb.Backend_UTILIZATION)]), - Group: proto.String(c.resourceURI(scopeZone, "instanceGroups", c.controlPlaneInstanceGroup)), - }, - }, - }, - } - resp, err := c.backendServicesAPI.Insert(ctx, req) - if err != nil { - return fmt.Errorf("inserting backend services: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return fmt.Errorf("waiting for backend services creation: %w", err) - } - - lb.hasBackendService = true - return nil -} - -func (c *Client) createForwardingRules(ctx context.Context, lb *loadBalancer) error { - req := &computepb.InsertGlobalForwardingRuleRequest{ - Project: c.project, - ForwardingRuleResource: &computepb.ForwardingRule{ - Name: proto.String(lb.name), - IPAddress: proto.String(c.resourceURI(scopeGlobal, "addresses", c.loadbalancerIPname)), - IPProtocol: proto.String(computepb.ForwardingRule_IPProtocolEnum_name[int32(computepb.ForwardingRule_TCP)]), - LoadBalancingScheme: proto.String(computepb.ForwardingRule_LoadBalancingScheme_name[int32(computepb.ForwardingRule_EXTERNAL)]), - PortRange: proto.String(strconv.Itoa(lb.frontendPort)), - - Target: proto.String(c.resourceURI(scopeGlobal, "targetTcpProxies", lb.name)), - }, - } - resp, err := c.forwardingRulesAPI.Insert(ctx, req) - if err != nil { - return fmt.Errorf("inserting forwarding rules: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return err - } - lb.hasForwardingRules = true - - if lb.label { - return c.labelLoadBalancer(ctx, lb.name) - } - return nil -} - -// labelLoadBalancer labels a load balancer (its forwarding rules) so that it can be found by applications in the cluster. -func (c *Client) labelLoadBalancer(ctx context.Context, name string) error { - forwardingRule, err := c.forwardingRulesAPI.Get(ctx, &computepb.GetGlobalForwardingRuleRequest{ - Project: c.project, - ForwardingRule: name, - }) - if err != nil { - return fmt.Errorf("getting forwarding rule: %w", err) - } - if forwardingRule.LabelFingerprint == nil { - return fmt.Errorf("forwarding rule %s has no label fingerprint", name) - } - - resp, err := c.forwardingRulesAPI.SetLabels(ctx, &computepb.SetLabelsGlobalForwardingRuleRequest{ - Project: c.project, - Resource: name, - GlobalSetLabelsRequestResource: &computepb.GlobalSetLabelsRequest{ - Labels: map[string]string{"constellation-uid": c.uid}, - LabelFingerprint: forwardingRule.LabelFingerprint, - }, - }) - if err != nil { - return fmt.Errorf("setting forwarding rule labels: %w", err) - } - - return c.waitForOperations(ctx, []Operation{resp}) -} - -func (c *Client) createTargetTCPProxy(ctx context.Context, lb *loadBalancer) error { - req := &computepb.InsertTargetTcpProxyRequest{ - Project: c.project, - TargetTcpProxyResource: &computepb.TargetTcpProxy{ - Name: proto.String(lb.name), - Service: proto.String(c.resourceURI(scopeGlobal, "backendServices", lb.name)), - }, - } - resp, err := c.targetTCPProxiesAPI.Insert(ctx, req) - if err != nil { - return fmt.Errorf("inserting target tcp proxy: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return err - } - lb.hasTargetTCPProxy = true - return nil -} - -// TerminateLoadBalancers terminates all load balancers. -func (c *Client) TerminateLoadBalancers(ctx context.Context) error { - errC := make(chan error) - - terminateLB := func(ctx context.Context, lb *loadBalancer) { - errC <- c.terminateLoadBalancer(ctx, lb) - } - - for _, lb := range c.loadbalancers { - go terminateLB(ctx, lb) - } - - var err error - for i := 0; i < len(c.loadbalancers); i++ { - err = multierr.Append(err, <-errC) - } - if err != nil && !isNotFoundError(err) { - return err - } - - if err := c.deleteIPAddr(ctx); err != nil { - return fmt.Errorf("deleting load balancer IP address: %w", err) - } - - c.loadbalancers = nil - return nil -} - -// terminateLoadBalancer removes the load balancer and its associated resources. -func (c *Client) terminateLoadBalancer(ctx context.Context, lb *loadBalancer) error { - if lb == nil { - return nil - } - if lb.name == "" { - return errors.New("load balancer name is empty") - } - - if lb.hasForwardingRules { - if err := c.terminateForwadingRules(ctx, lb); err != nil { - return fmt.Errorf("terminating forwarding rules: %w", err) - } - } - - if lb.hasTargetTCPProxy { - if err := c.terminateTargetTCPProxy(ctx, lb); err != nil { - return fmt.Errorf("terminating target tcp proxy: %w", err) - } - } - - if lb.hasBackendService { - if err := c.terminateBackendService(ctx, lb); err != nil { - return fmt.Errorf("terminating backend services: %w", err) - } - } - - if lb.hasHealthCheck { - if err := c.terminateHealthCheck(ctx, lb); err != nil { - return fmt.Errorf("terminating health checks: %w", err) - } - } - - lb.name = "" - return nil -} - -func (c *Client) terminateForwadingRules(ctx context.Context, lb *loadBalancer) error { - resp, err := c.forwardingRulesAPI.Delete(ctx, &computepb.DeleteGlobalForwardingRuleRequest{ - Project: c.project, - ForwardingRule: lb.name, - }) - if isNotFoundError(err) { - lb.hasForwardingRules = false - return nil - } - if err != nil { - return fmt.Errorf("deleting forwarding rules: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return err - } - - lb.hasForwardingRules = false - return nil -} - -func (c *Client) terminateTargetTCPProxy(ctx context.Context, lb *loadBalancer) error { - resp, err := c.targetTCPProxiesAPI.Delete(ctx, &computepb.DeleteTargetTcpProxyRequest{ - Project: c.project, - TargetTcpProxy: lb.name, - }) - if isNotFoundError(err) { - lb.hasTargetTCPProxy = false - return nil - } - if err != nil { - return fmt.Errorf("deleting target tcp proxy: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return err - } - - lb.hasTargetTCPProxy = false - return nil -} - -func (c *Client) terminateBackendService(ctx context.Context, lb *loadBalancer) error { - resp, err := c.backendServicesAPI.Delete(ctx, &computepb.DeleteBackendServiceRequest{ - Project: c.project, - BackendService: lb.name, - }) - if isNotFoundError(err) { - lb.hasBackendService = false - return nil - } - if err != nil { - return fmt.Errorf("deleting backend services: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return err - } - - lb.hasBackendService = false - return nil -} - -func (c *Client) terminateHealthCheck(ctx context.Context, lb *loadBalancer) error { - resp, err := c.healthChecksAPI.Delete(ctx, &computepb.DeleteHealthCheckRequest{ - Project: c.project, - HealthCheck: lb.name, - }) - if isNotFoundError(err) { - lb.hasHealthCheck = false - return nil - } - if err != nil { - return fmt.Errorf("deleting health checks: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{resp}); err != nil { - return err - } - - lb.hasHealthCheck = false - return nil -} - -func (c *Client) createIPAddr(ctx context.Context) error { - ipName := c.buildResourceName() - insertReq := &computepb.InsertGlobalAddressRequest{ - Project: c.project, - AddressResource: &computepb.Address{ - Name: proto.String(ipName), - }, - } - op, err := c.addressesAPI.Insert(ctx, insertReq) - if err != nil { - return fmt.Errorf("inserting address: %w", err) - } - if err := c.waitForOperations(ctx, []Operation{op}); err != nil { - return err - } - c.loadbalancerIPname = ipName - - getReq := &computepb.GetGlobalAddressRequest{ - Project: c.project, - Address: c.loadbalancerIPname, - } - addr, err := c.addressesAPI.Get(ctx, getReq) - if err != nil { - return fmt.Errorf("getting address: %w", err) - } - if addr.Address == nil { - return fmt.Errorf("address response without address: %q", addr) - } - - c.loadbalancerIP = *addr.Address - return nil -} - -func (c *Client) deleteIPAddr(ctx context.Context) error { - if c.loadbalancerIPname == "" { - return nil - } - - req := &computepb.DeleteGlobalAddressRequest{ - Project: c.project, - Address: c.loadbalancerIPname, - } - op, err := c.addressesAPI.Delete(ctx, req) - if isNotFoundError(err) { - c.loadbalancerIPname = "" - return nil - } - if err != nil { - return fmt.Errorf("deleting address: %w", err) - } - - if err := c.waitForOperations(ctx, []Operation{op}); err != nil { - return err - } - - c.loadbalancerIPname = "" - return nil -} - -func newHealthCheckHTTPS(port int) *computepb.HTTPSHealthCheck { - return &computepb.HTTPSHealthCheck{ - Host: proto.String(""), - Port: proto.Int32(int32(port)), - RequestPath: proto.String("/readyz"), - } -} - -func newHealthCheckTCP(port int) *computepb.TCPHealthCheck { - return &computepb.TCPHealthCheck{ - Port: proto.Int32(int32(port)), - } -} diff --git a/cli/internal/gcp/client/loadbalancer_test.go b/cli/internal/gcp/client/loadbalancer_test.go deleted file mode 100644 index 42ba2bc3f..000000000 --- a/cli/internal/gcp/client/loadbalancer_test.go +++ /dev/null @@ -1,750 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "fmt" - "net/http" - "testing" - - "github.com/stretchr/testify/assert" - "google.golang.org/api/googleapi" - "google.golang.org/genproto/googleapis/cloud/compute/v1" - "google.golang.org/protobuf/proto" -) - -func TestCreateLoadBalancers(t *testing.T) { - someErr := errors.New("failed") - forwardingRule := &compute.ForwardingRule{LabelFingerprint: proto.String("fingerprint")} - - testCases := map[string]struct { - addrAPI addressesAPI - healthAPI healthChecksAPI - backendAPI backendServicesAPI - proxyAPI targetTCPProxiesAPI - forwardAPI forwardingRulesAPI - operationAPI operationGlobalAPI - isDebugCluster bool - wantErr bool - }{ - "successful create": { - addrAPI: &stubAddressesAPI{getAddr: proto.String("192.0.2.1")}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{}, - proxyAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{forwardingRule: forwardingRule}, - operationAPI: stubOperationGlobalAPI{}, - }, - "successful create (debug cluster)": { - addrAPI: &stubAddressesAPI{getAddr: proto.String("192.0.2.1")}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{}, - proxyAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{forwardingRule: forwardingRule}, - operationAPI: stubOperationGlobalAPI{}, - isDebugCluster: true, - }, - "createIPAddr fails": { - addrAPI: &stubAddressesAPI{insertErr: someErr}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{}, - proxyAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{forwardingRule: forwardingRule}, - operationAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - "createLB fails": { - addrAPI: &stubAddressesAPI{}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{insertErr: someErr}, - proxyAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{forwardingRule: forwardingRule}, - operationAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - "createTcpProxy fails": { - addrAPI: &stubAddressesAPI{getAddr: proto.String("192.0.2.1")}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{}, - proxyAPI: &stubTargetTCPProxiesAPI{insertErr: someErr}, - forwardAPI: &stubForwardingRulesAPI{forwardingRule: forwardingRule}, - operationAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - addressesAPI: tc.addrAPI, - targetTCPProxiesAPI: tc.proxyAPI, - healthChecksAPI: tc.healthAPI, - backendServicesAPI: tc.backendAPI, - forwardingRulesAPI: tc.forwardAPI, - operationGlobalAPI: tc.operationAPI, - } - - err := client.CreateLoadBalancers(ctx, tc.isDebugCluster) - - // In case we expect an error, check for the error and continue otherwise. - if tc.wantErr { - assert.Error(err) - return - } - - // If we don't expect an error, check if the resources have been successfully created. - assert.NoError(err) - assert.NotEmpty(client.loadbalancerIPname) - - var foundDebugdLB bool - for _, lb := range client.loadbalancers { - // Expect load balancer name to have the format of "name-serviceName-uid" which is what buildResourceName does currently. - if lb.name == fmt.Sprintf("%s-debugd-%s", client.name, client.uid) { - foundDebugdLB = true - break - } - } - - if tc.isDebugCluster { - assert.Equal(6, len(client.loadbalancers)) - assert.True(foundDebugdLB, "debugd loadbalancer not found in debug-mode") - } else { - assert.Equal(5, len(client.loadbalancers)) - assert.False(foundDebugdLB, "debugd loadbalancer found in non-debug mode") - } - }) - } -} - -func TestCreateLoadBalancer(t *testing.T) { - someErr := errors.New("failed") - testCases := map[string]struct { - operationGlobalAPI operationGlobalAPI - healthChecksAPI healthChecksAPI - backendServicesAPI backendServicesAPI - forwardingRulesAPI forwardingRulesAPI - targetTCPProxiesAPI targetTCPProxiesAPI - wantErr bool - wantLB *loadBalancer - }{ - "successful create": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{forwardingRule: &compute.ForwardingRule{LabelFingerprint: proto.String("fingerprint")}}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - hasHealthCheck: true, - hasTargetTCPProxy: true, - hasBackendService: true, - hasForwardingRules: true, - }, - }, - "successful create with label": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{forwardingRule: &compute.ForwardingRule{LabelFingerprint: proto.String("fingerprint")}}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - label: true, - hasHealthCheck: true, - hasTargetTCPProxy: true, - hasBackendService: true, - hasForwardingRules: true, - }, - }, - "CreateLoadBalancer fails when getting forwarding rule": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{getErr: someErr}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - label: true, - hasHealthCheck: true, - hasTargetTCPProxy: true, - hasBackendService: true, - hasForwardingRules: true, - }, - }, - "CreateLoadBalancer fails when label fingerprint is missing": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{forwardingRule: &compute.ForwardingRule{}}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - label: true, - hasHealthCheck: true, - hasTargetTCPProxy: true, - hasBackendService: true, - hasForwardingRules: true, - }, - }, - "CreateLoadBalancer fails when creating health check": { - healthChecksAPI: stubHealthChecksAPI{insertErr: someErr}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{forwardingRule: &compute.ForwardingRule{LabelFingerprint: proto.String("fingerprint")}}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - hasHealthCheck: false, - hasTargetTCPProxy: false, - hasBackendService: false, - hasForwardingRules: false, - }, - }, - "CreateLoadBalancer fails when creating backend service": { - healthChecksAPI: stubHealthChecksAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - backendServicesAPI: stubBackendServicesAPI{insertErr: someErr}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - hasHealthCheck: true, - hasBackendService: false, - hasTargetTCPProxy: false, - hasForwardingRules: false, - }, - }, - "CreateLoadBalancer fails when creating forwarding rule": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{insertErr: someErr}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - hasHealthCheck: true, - hasBackendService: true, - hasTargetTCPProxy: true, - hasForwardingRules: false, - }, - }, - "CreateLoadBalancer fails when creating target proxy rule": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{insertErr: someErr}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - hasHealthCheck: true, - hasBackendService: true, - hasForwardingRules: false, - }, - }, - "CreateLoadBalancer fails when waiting on operation": { - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{forwardingRule: &compute.ForwardingRule{LabelFingerprint: proto.String("fingerprint")}}, - operationGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - frontendPort: 1234, - backendPortName: "testport", - hasHealthCheck: false, - hasBackendService: false, - hasForwardingRules: false, - }, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - backendServicesAPI: tc.backendServicesAPI, - forwardingRulesAPI: tc.forwardingRulesAPI, - targetTCPProxiesAPI: tc.targetTCPProxiesAPI, - healthChecksAPI: tc.healthChecksAPI, - operationGlobalAPI: tc.operationGlobalAPI, - } - lb := &loadBalancer{ - name: tc.wantLB.name, - frontendPort: tc.wantLB.frontendPort, - backendPortName: tc.wantLB.backendPortName, - label: tc.wantLB.label, - } - - err := client.createLoadBalancer(ctx, lb) - - if tc.wantErr { - assert.Error(err) - assert.Equal(tc.wantLB, lb) - } else { - assert.NoError(err) - assert.Equal(tc.wantLB, lb) - } - }) - } -} - -func TestTerminateLoadbalancers(t *testing.T) { - someErr := errors.New("failed") - newRunningLB := func() *loadBalancer { - return &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: true, - hasTargetTCPProxy: true, - hasForwardingRules: true, - } - } - - testCases := map[string]struct { - addrAPI addressesAPI - healthAPI healthChecksAPI - backendAPI backendServicesAPI - targetAPI targetTCPProxiesAPI - forwardAPI forwardingRulesAPI - opGlobalAPI operationGlobalAPI - wantErr bool - }{ - "successful terminate": { - addrAPI: &stubAddressesAPI{}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{}, - targetAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - }, - "deleteIPAddr fails": { - addrAPI: &stubAddressesAPI{deleteErr: someErr}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{}, - targetAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - "deleteLB fails": { - addrAPI: &stubAddressesAPI{}, - healthAPI: &stubHealthChecksAPI{}, - backendAPI: &stubBackendServicesAPI{deleteErr: someErr}, - targetAPI: &stubTargetTCPProxiesAPI{}, - forwardAPI: &stubForwardingRulesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - addressesAPI: tc.addrAPI, - healthChecksAPI: tc.healthAPI, - backendServicesAPI: tc.backendAPI, - targetTCPProxiesAPI: tc.targetAPI, - forwardingRulesAPI: tc.forwardAPI, - operationGlobalAPI: tc.opGlobalAPI, - loadbalancerIPname: "loadbalancerIPid", - loadbalancers: []*loadBalancer{ - newRunningLB(), - newRunningLB(), - newRunningLB(), - }, - } - - err := client.TerminateLoadBalancers(ctx) - - if tc.wantErr { - assert.Error(err) - } else { - assert.NoError(err) - assert.Empty(client.loadbalancerIPname) - assert.Nil(client.loadbalancers) - } - }) - } -} - -func TestTerminateLoadBalancer(t *testing.T) { - someErr := errors.New("failed") - notFoundErr := &googleapi.Error{Code: http.StatusNotFound} - newRunningLB := func() *loadBalancer { - return &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasTargetTCPProxy: true, - hasBackendService: true, - hasForwardingRules: true, - } - } - - testCases := map[string]struct { - lb *loadBalancer - opGlobalAPI operationGlobalAPI - healthChecksAPI healthChecksAPI - backendServicesAPI backendServicesAPI - targetTCPProxiesAPI targetTCPProxiesAPI - forwardingRulesAPI forwardingRulesAPI - wantErr bool - wantLB *loadBalancer - }{ - "successful terminate": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{}, - }, - "terminate partially created loadbalancer": { - lb: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: true, - hasForwardingRules: false, - }, - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{deleteErr: someErr}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{}, - }, - "terminate partially created loadbalancer 2": { - lb: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: false, - hasForwardingRules: false, - }, - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{deleteErr: someErr}, - forwardingRulesAPI: stubForwardingRulesAPI{deleteErr: someErr}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{}, - }, - "no-op for nil loadbalancer": { - lb: nil, - }, - "health check not found": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{deleteErr: notFoundErr}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{}, - }, - "backend service not found": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{deleteErr: notFoundErr}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{}, - }, - "forwarding rules not found": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{deleteErr: notFoundErr}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantLB: &loadBalancer{}, - }, - "fails for loadbalancer without name": { - lb: &loadBalancer{}, - wantErr: true, - wantLB: &loadBalancer{}, - }, - "fails when deleting health check": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{deleteErr: someErr}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: false, - hasForwardingRules: false, - hasTargetTCPProxy: false, - }, - }, - "fails when deleting backend service": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{deleteErr: someErr}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: true, - hasForwardingRules: false, - hasTargetTCPProxy: false, - }, - }, - "fails when deleting forwarding rule": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{deleteErr: someErr}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: true, - hasForwardingRules: true, - hasTargetTCPProxy: true, - }, - }, - "fails when deleting tcp proxy rule": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{deleteErr: someErr}, - opGlobalAPI: stubOperationGlobalAPI{}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: true, - hasForwardingRules: false, - hasTargetTCPProxy: true, - }, - }, - "fails when waiting on operation": { - lb: newRunningLB(), - healthChecksAPI: stubHealthChecksAPI{}, - backendServicesAPI: stubBackendServicesAPI{}, - forwardingRulesAPI: stubForwardingRulesAPI{}, - targetTCPProxiesAPI: stubTargetTCPProxiesAPI{}, - opGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - wantErr: true, - wantLB: &loadBalancer{ - name: "name", - hasHealthCheck: true, - hasBackendService: true, - hasForwardingRules: true, - hasTargetTCPProxy: true, - }, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - backendServicesAPI: tc.backendServicesAPI, - forwardingRulesAPI: tc.forwardingRulesAPI, - healthChecksAPI: tc.healthChecksAPI, - targetTCPProxiesAPI: tc.targetTCPProxiesAPI, - operationGlobalAPI: tc.opGlobalAPI, - } - - err := client.terminateLoadBalancer(ctx, tc.lb) - - if tc.wantErr { - assert.Error(err) - assert.Equal(tc.wantLB, tc.lb) - } else { - assert.NoError(err) - assert.Equal(tc.wantLB, tc.lb) - } - }) - } -} - -func TestCreateIPAddr(t *testing.T) { - someErr := errors.New("failed") - - testCases := map[string]struct { - addrAPI addressesAPI - opAPI operationGlobalAPI - wantErr bool - }{ - "successful create": { - addrAPI: stubAddressesAPI{getAddr: proto.String("test-ip")}, - opAPI: stubOperationGlobalAPI{}, - }, - "insert fails": { - addrAPI: stubAddressesAPI{insertErr: someErr}, - opAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - "get fails": { - addrAPI: stubAddressesAPI{getErr: someErr}, - opAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - "get address nil": { - addrAPI: stubAddressesAPI{getAddr: nil}, - opAPI: stubOperationGlobalAPI{}, - wantErr: true, - }, - "wait fails": { - addrAPI: stubAddressesAPI{}, - opAPI: stubOperationGlobalAPI{waitErr: someErr}, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - addressesAPI: tc.addrAPI, - operationGlobalAPI: tc.opAPI, - } - - err := client.createIPAddr(ctx) - - if tc.wantErr { - assert.Error(err) - } else { - assert.NoError(err) - assert.Equal("test-ip", client.loadbalancerIP) - assert.Equal("name-uid", client.loadbalancerIPname) - } - }) - } -} - -func TestDeleteIPAddr(t *testing.T) { - someErr := errors.New("failed") - notFoundErr := &googleapi.Error{Code: http.StatusNotFound} - - testCases := map[string]struct { - addrAPI addressesAPI - opAPI operationGlobalAPI - addrID string - wantErr bool - }{ - "successful delete": { - addrAPI: stubAddressesAPI{}, - opAPI: stubOperationGlobalAPI{}, - addrID: "name", - }, - "not found": { - addrAPI: stubAddressesAPI{deleteErr: notFoundErr}, - opAPI: stubOperationGlobalAPI{}, - addrID: "name", - }, - "empty is no-op": { - addrAPI: stubAddressesAPI{}, - opAPI: stubOperationGlobalAPI{}, - }, - "delete fails": { - addrAPI: stubAddressesAPI{deleteErr: someErr}, - opAPI: stubOperationGlobalAPI{}, - addrID: "name", - wantErr: true, - }, - "wait fails": { - addrAPI: stubAddressesAPI{}, - opAPI: stubOperationGlobalAPI{waitErr: someErr}, - addrID: "name", - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - addressesAPI: tc.addrAPI, - operationGlobalAPI: tc.opAPI, - loadbalancerIPname: tc.addrID, - } - - err := client.deleteIPAddr(ctx) - - if tc.wantErr { - assert.Error(err) - } else { - assert.NoError(err) - assert.Empty(client.loadbalancerIPname) - } - }) - } -} diff --git a/cli/internal/gcp/client/network.go b/cli/internal/gcp/client/network.go deleted file mode 100644 index 609c5bdae..000000000 --- a/cli/internal/gcp/client/network.go +++ /dev/null @@ -1,231 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes" - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" - "google.golang.org/protobuf/proto" -) - -const ( - SubnetCIDR = "192.168.178.0/24" - SubnetExtCIDR = "10.10.0.0/16" -) - -// CreateFirewall creates a set of firewall rules for the client's network. -// -// The client must have a VPC network to set firewall rules. -func (c *Client) CreateFirewall(ctx context.Context, input FirewallInput) error { - if c.network == "" { - return errors.New("client has not network") - } - firewallRules, err := input.Ingress.GCP() - if err != nil { - return err - } - var ops []Operation - for _, rule := range firewallRules { - c.firewalls = append(c.firewalls, rule.GetName()) - - rule.Network = proto.String("global/networks/" + c.network) - rule.Name = proto.String(rule.GetName() + "-" + c.uid) - req := &computepb.InsertFirewallRequest{ - FirewallResource: rule, - Project: c.project, - } - resp, err := c.firewallsAPI.Insert(ctx, req) - if err != nil { - return err - } - if resp.Proto().Name == nil { - return errors.New("operation name is nil") - } - ops = append(ops, resp) - } - return c.waitForOperations(ctx, ops) -} - -// TerminateFirewall deletes firewall rules from the client's network. -// -// The client must have a VPC network to set firewall rules. -func (c *Client) TerminateFirewall(ctx context.Context) error { - if len(c.firewalls) == 0 { - return nil - } - var ops []Operation - for _, name := range c.firewalls { - ruleName := name + "-" + c.uid - req := &computepb.DeleteFirewallRequest{ - Firewall: ruleName, - Project: c.project, - } - resp, err := c.firewallsAPI.Delete(ctx, req) - if isNotFoundError(err) { - continue - } - if err != nil { - return err - } - if resp.Proto().Name == nil { - return errors.New("operation name is nil") - } - ops = append(ops, resp) - } - if err := c.waitForOperations(ctx, ops); err != nil { - return err - } - c.firewalls = []string{} - return nil -} - -// FirewallInput defines firewall rules to be set. -type FirewallInput struct { - Ingress cloudtypes.Firewall - Egress cloudtypes.Firewall -} - -// CreateVPCs creates all necessary VPC networks. -func (c *Client) CreateVPCs(ctx context.Context) error { - c.network = c.buildResourceName() - - op, err := c.createVPC(ctx, c.network) - if err != nil { - return err - } - if err := c.waitForOperations(ctx, []Operation{op}); err != nil { - return err - } - - if err := c.createSubnets(ctx); err != nil { - return err - } - - return nil -} - -// createVPC creates a VPC network. -func (c *Client) createVPC(ctx context.Context, name string) (Operation, error) { - req := &computepb.InsertNetworkRequest{ - NetworkResource: &computepb.Network{ - AutoCreateSubnetworks: proto.Bool(false), - Description: proto.String("Constellation VPC"), - Name: proto.String(name), - }, - Project: c.project, - } - return c.networksAPI.Insert(ctx, req) -} - -// TerminateVPCs terminates all VPC networks. -// -// If the any network has firewall rules, these must be terminated first. -func (c *Client) TerminateVPCs(ctx context.Context) error { - if len(c.firewalls) != 0 { - return errors.New("client has firewalls, which must be deleted first") - } - - if err := c.terminateSubnet(ctx); err != nil { - return err - } - - if err := c.terminateVPC(ctx); err != nil { - return err - } - - return nil -} - -// terminateVPC terminates a VPC network. -// -// If the network has firewall rules, these must be terminated first. -func (c *Client) terminateVPC(ctx context.Context) error { - if c.network == "" { - return nil - } - - req := &computepb.DeleteNetworkRequest{ - Project: c.project, - Network: c.network, - } - op, err := c.networksAPI.Delete(ctx, req) - if err != nil && !isNotFoundError(err) { - return err - } - if isNotFoundError(err) { - c.network = "" - return nil - } - - if err := c.waitForOperations(ctx, []Operation{op}); err != nil { - return err - } - - c.network = "" - return nil -} - -func (c *Client) createSubnets(ctx context.Context) error { - c.subnetwork = "node-net-" + c.uid - c.secondarySubnetworkRange = "net-ext" + c.uid - - op, err := c.createSubnet(ctx, c.subnetwork, c.network, c.secondarySubnetworkRange) - if err != nil { - return err - } - - return c.waitForOperations(ctx, []Operation{op}) -} - -func (c *Client) createSubnet(ctx context.Context, name, network, secondaryRangeName string) (Operation, error) { - req := &computepb.InsertSubnetworkRequest{ - Project: c.project, - Region: c.region, - SubnetworkResource: &computepb.Subnetwork{ - IpCidrRange: proto.String(SubnetCIDR), - Name: proto.String(name), - Network: proto.String("projects/" + c.project + "/global/networks/" + network), - SecondaryIpRanges: []*computepb.SubnetworkSecondaryRange{ - { - RangeName: proto.String(secondaryRangeName), - IpCidrRange: proto.String(SubnetExtCIDR), - }, - }, - }, - } - return c.subnetworksAPI.Insert(ctx, req) -} - -func (c *Client) terminateSubnet(ctx context.Context) error { - if c.subnetwork == "" { - return nil - } - - req := &computepb.DeleteSubnetworkRequest{ - Project: c.project, - Region: c.region, - Subnetwork: c.subnetwork, - } - op, err := c.subnetworksAPI.Delete(ctx, req) - if err != nil && !isNotFoundError(err) { - return err - } - if isNotFoundError(err) { - c.subnetwork = "" - return nil - } - - if err := c.waitForOperations(ctx, []Operation{op}); err != nil { - return err - } - - c.subnetwork = "" - return nil -} diff --git a/cli/internal/gcp/client/network_test.go b/cli/internal/gcp/client/network_test.go deleted file mode 100644 index 3087cb099..000000000 --- a/cli/internal/gcp/client/network_test.go +++ /dev/null @@ -1,357 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "net/http" - "testing" - - "github.com/edgelesssys/constellation/v2/internal/cloud/cloudtypes" - "github.com/stretchr/testify/assert" - "google.golang.org/api/googleapi" -) - -func TestCreateVPCs(t *testing.T) { - someErr := errors.New("failed") - - testCases := map[string]struct { - operationGlobalAPI operationGlobalAPI - operationRegionAPI operationRegionAPI - networksAPI networksAPI - subnetworksAPI subnetworksAPI - wantErr bool - }{ - "successful create": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - }, - "failed wait global op": { - operationGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - wantErr: true, - }, - "failed wait region op": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{waitErr: someErr}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - wantErr: true, - }, - "failed insert networks": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{insertErr: someErr}, - subnetworksAPI: stubSubnetworksAPI{}, - wantErr: true, - }, - "failed insert subnetworks": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{insertErr: someErr}, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - operationGlobalAPI: tc.operationGlobalAPI, - operationRegionAPI: tc.operationRegionAPI, - networksAPI: tc.networksAPI, - subnetworksAPI: tc.subnetworksAPI, - workers: make(cloudtypes.Instances), - controlPlanes: make(cloudtypes.Instances), - } - - if tc.wantErr { - assert.Error(client.CreateVPCs(ctx)) - } else { - assert.NoError(client.CreateVPCs(ctx)) - assert.NotNil(client.network) - } - }) - } -} - -func TestTerminateVPCs(t *testing.T) { - someErr := errors.New("failed") - notFoundErr := &googleapi.Error{Code: http.StatusNotFound} - - testCases := map[string]struct { - operationGlobalAPI operationGlobalAPI - operationRegionAPI operationRegionAPI - networksAPI networksAPI - subnetworksAPI subnetworksAPI - firewalls []string - subnetwork string - network string - wantErr bool - }{ - "successful terminate": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - }, - "subnetwork empty": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "", - network: "network-id-1", - }, - "network empty": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "subnetwork-id-1", - network: "", - }, - "subnetwork not found": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{deleteErr: notFoundErr}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - }, - "network not found": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{deleteErr: notFoundErr}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - }, - "failed wait global op": { - operationGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - wantErr: true, - }, - "failed delete networks": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{deleteErr: someErr}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - wantErr: true, - }, - "failed delete subnetworks": { - operationGlobalAPI: stubOperationGlobalAPI{}, - operationRegionAPI: stubOperationRegionAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{deleteErr: someErr}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - wantErr: true, - }, - "must delete firewalls first": { - firewalls: []string{"firewall-1", "firewall-2"}, - operationRegionAPI: stubOperationRegionAPI{}, - operationGlobalAPI: stubOperationGlobalAPI{}, - networksAPI: stubNetworksAPI{}, - subnetworksAPI: stubSubnetworksAPI{}, - subnetwork: "subnetwork-id-1", - network: "network-id-1", - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - operationGlobalAPI: tc.operationGlobalAPI, - operationRegionAPI: tc.operationRegionAPI, - networksAPI: tc.networksAPI, - subnetworksAPI: tc.subnetworksAPI, - firewalls: tc.firewalls, - network: tc.network, - subnetwork: tc.subnetwork, - } - - if tc.wantErr { - assert.Error(client.TerminateVPCs(ctx)) - } else { - assert.NoError(client.TerminateVPCs(ctx)) - assert.Empty(client.network) - assert.Empty(client.subnetwork) - } - }) - } -} - -func TestCreateFirewall(t *testing.T) { - someErr := errors.New("failed") - testFirewallInput := FirewallInput{ - Ingress: cloudtypes.Firewall{ - cloudtypes.FirewallRule{ - Name: "test-1", - Description: "test-1 description", - Protocol: "tcp", - IPRange: "192.0.2.0/24", - FromPort: 9000, - }, - cloudtypes.FirewallRule{ - Name: "test-2", - Description: "test-2 description", - Protocol: "udp", - IPRange: "192.0.2.0/24", - FromPort: 51820, - }, - }, - Egress: cloudtypes.Firewall{}, - } - - testCases := map[string]struct { - network string - operationGlobalAPI operationGlobalAPI - firewallsAPI firewallsAPI - firewallInput FirewallInput - wantErr bool - }{ - "successful create": { - network: "network", - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{}, - }, - "failed wait global op": { - network: "network", - operationGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - firewallsAPI: stubFirewallsAPI{}, - wantErr: true, - }, - "failed insert networks": { - network: "network", - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{insertErr: someErr}, - wantErr: true, - }, - "no network set": { - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{}, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - network: tc.network, - operationGlobalAPI: tc.operationGlobalAPI, - firewallsAPI: tc.firewallsAPI, - } - - if tc.wantErr { - assert.Error(client.CreateFirewall(ctx, testFirewallInput)) - } else { - assert.NoError(client.CreateFirewall(ctx, testFirewallInput)) - assert.ElementsMatch([]string{"test-1", "test-2"}, client.firewalls) - } - }) - } -} - -func TestTerminateFirewall(t *testing.T) { - someErr := errors.New("failed") - notFoundErr := &googleapi.Error{Code: http.StatusNotFound} - - testCases := map[string]struct { - operationGlobalAPI operationGlobalAPI - firewallsAPI firewallsAPI - firewalls []string - wantErr bool - }{ - "successful terminate": { - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{}, - firewalls: []string{"firewall-1", "firewall-2"}, - }, - "successful terminate when no firewall exists": { - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{}, - firewalls: []string{}, - }, - "successful terminate when firewall not found": { - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{deleteErr: notFoundErr}, - firewalls: []string{"firewall-1", "firewall-2"}, - }, - "failed to wait on global operation": { - operationGlobalAPI: stubOperationGlobalAPI{waitErr: someErr}, - firewallsAPI: stubFirewallsAPI{}, - firewalls: []string{"firewall-1", "firewall-2"}, - wantErr: true, - }, - "failed to delete firewalls": { - operationGlobalAPI: stubOperationGlobalAPI{}, - firewallsAPI: stubFirewallsAPI{deleteErr: someErr}, - firewalls: []string{"firewall-1", "firewall-2"}, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - firewalls: tc.firewalls, - operationGlobalAPI: tc.operationGlobalAPI, - firewallsAPI: tc.firewallsAPI, - } - - if tc.wantErr { - assert.Error(client.TerminateFirewall(ctx)) - } else { - assert.NoError(client.TerminateFirewall(ctx)) - assert.Empty(client.firewalls) - } - }) - } -} diff --git a/cli/internal/gcp/client/operation.go b/cli/internal/gcp/client/operation.go deleted file mode 100644 index a1c0cadc8..000000000 --- a/cli/internal/gcp/client/operation.go +++ /dev/null @@ -1,116 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "fmt" - - computepb "google.golang.org/genproto/googleapis/cloud/compute/v1" -) - -// waitForOperations waits until every operation in the opIDs slice is -// done or returns the first occurring error. -func (c *Client) waitForOperations(ctx context.Context, ops []Operation) error { - for _, op := range ops { - switch { - case op.Proto() == nil: - return errors.New("proto of operation is nil") - case op.Proto().Zone != nil: - if err := c.waitForZoneOperation(ctx, op); err != nil { - return err - } - case op.Proto().Region != nil: - if err := c.waitForRegionOperation(ctx, op); err != nil { - return err - } - default: - if err := c.waitForGlobalOperation(ctx, op); err != nil { - return err - } - } - } - return nil -} - -func (c *Client) waitForGlobalOperation(ctx context.Context, op Operation) error { - for { - if err := ctx.Err(); err != nil { - return err - } - if op.Proto().Name == nil { - return errors.New("operation name is nil") - } - waitReq := &computepb.WaitGlobalOperationRequest{ - Operation: *op.Proto().Name, - Project: c.project, - } - zoneOp, err := c.operationGlobalAPI.Wait(ctx, waitReq) - if err != nil { - return fmt.Errorf("unable to wait for the operation: %w", err) - } - if *zoneOp.Status.Enum() == computepb.Operation_DONE { - if opErr := zoneOp.Error; opErr != nil { - return fmt.Errorf("operation failed: %s", opErr.String()) - } - return nil - } - } -} - -func (c *Client) waitForZoneOperation(ctx context.Context, op Operation) error { - for { - if err := ctx.Err(); err != nil { - return err - } - if op.Proto().Name == nil { - return errors.New("operation name is nil") - } - waitReq := &computepb.WaitZoneOperationRequest{ - Operation: *op.Proto().Name, - Project: c.project, - Zone: c.zone, - } - zoneOp, err := c.operationZoneAPI.Wait(ctx, waitReq) - if err != nil { - return fmt.Errorf("unable to wait for the operation: %w", err) - } - if *zoneOp.Status.Enum() == computepb.Operation_DONE { - if opErr := zoneOp.Error; opErr != nil { - return fmt.Errorf("operation failed: %s", opErr.String()) - } - return nil - } - } -} - -func (c *Client) waitForRegionOperation(ctx context.Context, op Operation) error { - for { - if err := ctx.Err(); err != nil { - return err - } - if op.Proto().Name == nil { - return errors.New("operation name is nil") - } - waitReq := &computepb.WaitRegionOperationRequest{ - Operation: *op.Proto().Name, - Project: c.project, - Region: c.region, - } - regionOp, err := c.operationRegionAPI.Wait(ctx, waitReq) - if err != nil { - return fmt.Errorf("unable to wait for the operation: %w", err) - } - if *regionOp.Status.Enum() == computepb.Operation_DONE { - if opErr := regionOp.Error; opErr != nil { - return fmt.Errorf("operation failed: %s", opErr.String()) - } - return nil - } - } -} diff --git a/cli/internal/gcp/client/project.go b/cli/internal/gcp/client/project.go deleted file mode 100644 index da2cb4f17..000000000 --- a/cli/internal/gcp/client/project.go +++ /dev/null @@ -1,77 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "fmt" - - iampb "google.golang.org/genproto/googleapis/iam/v1" -) - -// addIAMPolicyBindings adds a GCP service account to roles specified in the input. -func (c *Client) addIAMPolicyBindings(ctx context.Context, input AddIAMPolicyBindingInput) error { - getReq := &iampb.GetIamPolicyRequest{ - Resource: "projects/" + c.project, - } - policy, err := c.projectsAPI.GetIamPolicy(ctx, getReq) - if err != nil { - return fmt.Errorf("retrieving current iam policy: %w", err) - } - for _, binding := range input.Bindings { - addIAMPolicy(policy, binding) - } - setReq := &iampb.SetIamPolicyRequest{ - Resource: "projects/" + c.project, - Policy: policy, - } - if _, err := c.projectsAPI.SetIamPolicy(ctx, setReq); err != nil { - return fmt.Errorf("setting new iam policy: %w", err) - } - return nil -} - -// PolicyBinding is a GCP IAM policy binding. -type PolicyBinding struct { - ServiceAccount string - Role string -} - -// addIAMPolicy inserts policy binding for service account and role to an existing iam policy. -func addIAMPolicy(policy *iampb.Policy, policyBinding PolicyBinding) { - var binding *iampb.Binding - for _, existingBinding := range policy.Bindings { - if existingBinding.Role == policyBinding.Role && existingBinding.Condition == nil { - binding = existingBinding - break - } - } - if binding == nil { - binding = &iampb.Binding{ - Role: policyBinding.Role, - } - policy.Bindings = append(policy.Bindings, binding) - } - - // add service account to role, if not already a member - member := "serviceAccount:" + policyBinding.ServiceAccount - var alreadyMember bool - for _, existingMember := range binding.Members { - if member == existingMember { - alreadyMember = true - break - } - } - if !alreadyMember { - binding.Members = append(binding.Members, member) - } -} - -// AddIAMPolicyBindingInput is the input for an AddIAMPolicyBinding operation. -type AddIAMPolicyBindingInput struct { - Bindings []PolicyBinding -} diff --git a/cli/internal/gcp/client/project_test.go b/cli/internal/gcp/client/project_test.go deleted file mode 100644 index 956cc5f61..000000000 --- a/cli/internal/gcp/client/project_test.go +++ /dev/null @@ -1,183 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package client - -import ( - "context" - "errors" - "testing" - - "github.com/stretchr/testify/assert" - iampb "google.golang.org/genproto/googleapis/iam/v1" - "google.golang.org/protobuf/proto" -) - -func TestAddIAMPolicyBindings(t *testing.T) { - someErr := errors.New("someErr") - - testCases := map[string]struct { - projectsAPI stubProjectsAPI - input AddIAMPolicyBindingInput - wantErr bool - }{ - "successful set without new bindings": { - input: AddIAMPolicyBindingInput{ - Bindings: []PolicyBinding{}, - }, - }, - "successful set with bindings": { - input: AddIAMPolicyBindingInput{ - Bindings: []PolicyBinding{ - { - ServiceAccount: "service-account", - Role: "role", - }, - }, - }, - }, - "retrieving iam policy fails": { - projectsAPI: stubProjectsAPI{ - getPolicyErr: someErr, - }, - wantErr: true, - }, - "setting iam policy fails": { - projectsAPI: stubProjectsAPI{ - setPolicyErr: someErr, - }, - wantErr: true, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - ctx := context.Background() - client := Client{ - project: "project", - zone: "zone", - name: "name", - uid: "uid", - projectsAPI: tc.projectsAPI, - } - - err := client.addIAMPolicyBindings(ctx, tc.input) - if tc.wantErr { - assert.Error(err) - } else { - assert.NoError(err) - } - }) - } -} - -func TestAddIAMPolicy(t *testing.T) { - testCases := map[string]struct { - binding PolicyBinding - policy *iampb.Policy - wantErr bool - wantPolicy *iampb.Policy - }{ - "successful on empty policy": { - binding: PolicyBinding{ - ServiceAccount: "service-account", - Role: "role", - }, - policy: &iampb.Policy{ - Bindings: []*iampb.Binding{}, - }, - wantPolicy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{"serviceAccount:service-account"}, - }, - }, - }, - }, - "successful on existing policy with different role": { - binding: PolicyBinding{ - ServiceAccount: "service-account", - Role: "role", - }, - policy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "other-role", - Members: []string{"other-member"}, - }, - }, - }, - wantPolicy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "other-role", - Members: []string{"other-member"}, - }, - { - Role: "role", - Members: []string{"serviceAccount:service-account"}, - }, - }, - }, - }, - "successful on existing policy with existing role": { - binding: PolicyBinding{ - ServiceAccount: "service-account", - Role: "role", - }, - policy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{"other-member"}, - }, - }, - }, - wantPolicy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{"other-member", "serviceAccount:service-account"}, - }, - }, - }, - }, - "already a member": { - binding: PolicyBinding{ - ServiceAccount: "service-account", - Role: "role", - }, - policy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{"serviceAccount:service-account"}, - }, - }, - }, - wantPolicy: &iampb.Policy{ - Bindings: []*iampb.Binding{ - { - Role: "role", - Members: []string{"serviceAccount:service-account"}, - }, - }, - }, - }, - } - - for name, tc := range testCases { - t.Run(name, func(t *testing.T) { - assert := assert.New(t) - - addIAMPolicy(tc.policy, tc.binding) - assert.True(proto.Equal(tc.wantPolicy, tc.policy)) - }) - } -} diff --git a/cli/internal/gcp/kube_env.go b/cli/internal/gcp/kube_env.go deleted file mode 100644 index 1c5466ef6..000000000 --- a/cli/internal/gcp/kube_env.go +++ /dev/null @@ -1,10 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package gcp - -// KubeEnv contains placeholder values required by cluster-autoscaler. -var KubeEnv = `AUTOSCALER_ENV_VARS: kube_reserved=cpu=1060m,memory=1019Mi,ephemeral-storage=41Gi;node_labels=;os=linux;os_distribution=cos;evictionHard=` diff --git a/internal/state/state.go b/internal/state/state.go index 304702956..cbf294bbe 100644 --- a/internal/state/state.go +++ b/internal/state/state.go @@ -17,21 +17,6 @@ type ConstellationState struct { CloudProvider string `json:"cloudprovider,omitempty"` LoadBalancerIP string `json:"bootstrapperhost,omitempty"` - GCPWorkerInstances cloudtypes.Instances `json:"gcpworkers,omitempty"` - GCPControlPlaneInstances cloudtypes.Instances `json:"gcpcontrolplanes,omitempty"` - GCPWorkerInstanceGroup string `json:"gcpworkerinstancegroup,omitempty"` - GCPControlPlaneInstanceGroup string `json:"gcpcontrolplaneinstancegroup,omitempty"` - GCPWorkerInstanceTemplate string `json:"gcpworkerinstancetemplate,omitempty"` - GCPControlPlaneInstanceTemplate string `json:"gcpcontrolplaneinstancetemplate,omitempty"` - GCPNetwork string `json:"gcpnetwork,omitempty"` - GCPSubnetwork string `json:"gcpsubnetwork,omitempty"` - GCPFirewalls []string `json:"gcpfirewalls,omitempty"` - GCPLoadbalancerIPname string `json:"gcploadbalanceripid,omitempty"` - GCPLoadbalancers []string `json:"gcploadbalancers,omitempty"` - GCPProject string `json:"gcpproject,omitempty"` - GCPZone string `json:"gcpzone,omitempty"` - GCPRegion string `json:"gcpregion,omitempty"` - AzureWorkerInstances cloudtypes.Instances `json:"azureworkers,omitempty"` AzureControlPlaneInstances cloudtypes.Instances `json:"azurecontrolplanes,omitempty"` AzureResourceGroup string `json:"azureresourcegroup,omitempty"`