constellation/cli/internal/cloudcmd/clients_test.go

483 lines
15 KiB
Go

package cloudcmd
import (
"context"
"errors"
"strconv"
"testing"
azurecl "github.com/edgelesssys/constellation/cli/internal/azure/client"
gcpcl "github.com/edgelesssys/constellation/cli/internal/gcp/client"
"github.com/edgelesssys/constellation/internal/azureshared"
"github.com/edgelesssys/constellation/internal/cloud/cloudprovider"
"github.com/edgelesssys/constellation/internal/cloud/cloudtypes"
"github.com/edgelesssys/constellation/internal/gcpshared"
"github.com/edgelesssys/constellation/internal/state"
"go.uber.org/goleak"
)
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"),
)
}
type fakeAzureClient struct {
workers cloudtypes.Instances
controlPlanes cloudtypes.Instances
resourceGroup string
name string
uid string
location string
subscriptionID string
tenantID string
subnetID string
loadBalancerName string
controlPlaneScaleSet string
workerScaleSet string
networkSecurityGroup string
adAppObjectID string
}
func (c *fakeAzureClient) GetState() (state.ConstellationState, error) {
stat := state.ConstellationState{
CloudProvider: cloudprovider.Azure.String(),
AzureWorkers: c.workers,
AzureControlPlane: c.controlPlanes,
Name: c.name,
UID: c.uid,
AzureResourceGroup: c.resourceGroup,
AzureLocation: c.location,
AzureSubscription: c.subscriptionID,
AzureTenant: c.tenantID,
AzureSubnet: c.subnetID,
AzureNetworkSecurityGroup: c.networkSecurityGroup,
AzureWorkersScaleSet: c.workerScaleSet,
AzureControlPlanesScaleSet: c.controlPlaneScaleSet,
AzureADAppObjectID: c.adAppObjectID,
}
return stat, nil
}
func (c *fakeAzureClient) SetState(stat state.ConstellationState) error {
c.workers = stat.AzureWorkers
c.controlPlanes = stat.AzureControlPlane
c.name = stat.Name
c.uid = stat.UID
c.resourceGroup = stat.AzureResourceGroup
c.location = stat.AzureLocation
c.subscriptionID = stat.AzureSubscription
c.tenantID = stat.AzureTenant
c.subnetID = stat.AzureSubnet
c.networkSecurityGroup = stat.AzureNetworkSecurityGroup
c.workerScaleSet = stat.AzureWorkersScaleSet
c.controlPlaneScaleSet = stat.AzureControlPlanesScaleSet
c.adAppObjectID = stat.AzureADAppObjectID
return nil
}
func (c *fakeAzureClient) CreateApplicationInsight(ctx context.Context) error {
return nil
}
func (c *fakeAzureClient) CreateResourceGroup(ctx context.Context) error {
c.resourceGroup = "resource-group"
return nil
}
func (c *fakeAzureClient) CreateVirtualNetwork(ctx context.Context) error {
c.subnetID = "subnet"
return nil
}
func (c *fakeAzureClient) CreateExternalLoadBalancer(ctx context.Context) error {
c.loadBalancerName = "loadBalancer"
return nil
}
func (c *fakeAzureClient) CreateSecurityGroup(ctx context.Context, input azurecl.NetworkSecurityGroupInput) error {
c.networkSecurityGroup = "network-security-group"
return nil
}
func (c *fakeAzureClient) CreateInstances(ctx context.Context, input azurecl.CreateInstancesInput) error {
c.controlPlaneScaleSet = "controlplanes-scale-set"
c.workerScaleSet = "workers-scale-set"
c.workers = make(cloudtypes.Instances)
for i := 0; i < input.CountWorkers; i++ {
id := "id-" + strconv.Itoa(i)
c.workers[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
c.controlPlanes = make(cloudtypes.Instances)
for i := 0; i < input.CountControlPlanes; i++ {
id := "id-" + strconv.Itoa(i)
c.controlPlanes[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
return nil
}
// TODO: deprecate as soon as scale sets are available.
func (c *fakeAzureClient) CreateInstancesVMs(ctx context.Context, input azurecl.CreateInstancesInput) error {
c.workers = make(cloudtypes.Instances)
for i := 0; i < input.CountWorkers; i++ {
id := "id-" + strconv.Itoa(i)
c.workers[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
c.controlPlanes = make(cloudtypes.Instances)
for i := 0; i < input.CountControlPlanes; i++ {
id := "id-" + strconv.Itoa(i)
c.controlPlanes[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
return nil
}
func (c *fakeAzureClient) CreateServicePrincipal(ctx context.Context) (string, error) {
c.adAppObjectID = "00000000-0000-0000-0000-000000000001"
return azureshared.ApplicationCredentials{
ClientID: "client-id",
ClientSecret: "client-secret",
}.ToCloudServiceAccountURI(), nil
}
func (c *fakeAzureClient) TerminateResourceGroup(ctx context.Context) error {
if c.resourceGroup == "" {
return nil
}
c.workers = nil
c.controlPlanes = nil
c.resourceGroup = ""
c.subnetID = ""
c.networkSecurityGroup = ""
c.workerScaleSet = ""
c.controlPlaneScaleSet = ""
return nil
}
func (c *fakeAzureClient) TerminateServicePrincipal(ctx context.Context) error {
if c.adAppObjectID == "" {
return nil
}
c.adAppObjectID = ""
return nil
}
type stubAzureClient struct {
terminateResourceGroupCalled bool
terminateServicePrincipalCalled bool
getStateErr error
setStateErr error
createApplicationInsightErr error
createResourceGroupErr error
createVirtualNetworkErr error
createSecurityGroupErr error
createLoadBalancerErr error
createInstancesErr error
createServicePrincipalErr error
terminateResourceGroupErr error
terminateServicePrincipalErr error
}
func (c *stubAzureClient) GetState() (state.ConstellationState, error) {
return state.ConstellationState{}, c.getStateErr
}
func (c *stubAzureClient) SetState(state.ConstellationState) error {
return c.setStateErr
}
func (c *stubAzureClient) CreateExternalLoadBalancer(ctx context.Context) error {
return c.createLoadBalancerErr
}
func (c *stubAzureClient) CreateApplicationInsight(ctx context.Context) error {
return c.createApplicationInsightErr
}
func (c *stubAzureClient) CreateResourceGroup(ctx context.Context) error {
return c.createResourceGroupErr
}
func (c *stubAzureClient) CreateVirtualNetwork(ctx context.Context) error {
return c.createVirtualNetworkErr
}
func (c *stubAzureClient) CreateSecurityGroup(ctx context.Context, input azurecl.NetworkSecurityGroupInput) error {
return c.createSecurityGroupErr
}
func (c *stubAzureClient) CreateInstances(ctx context.Context, input azurecl.CreateInstancesInput) error {
return c.createInstancesErr
}
// TODO: deprecate as soon as scale sets are available.
func (c *stubAzureClient) CreateInstancesVMs(ctx context.Context, input azurecl.CreateInstancesInput) error {
return c.createInstancesErr
}
func (c *stubAzureClient) CreateServicePrincipal(ctx context.Context) (string, error) {
return azureshared.ApplicationCredentials{
ClientID: "00000000-0000-0000-0000-000000000000",
ClientSecret: "secret",
}.ToCloudServiceAccountURI(), c.createServicePrincipalErr
}
func (c *stubAzureClient) TerminateResourceGroup(ctx context.Context) error {
c.terminateResourceGroupCalled = true
return c.terminateResourceGroupErr
}
func (c *stubAzureClient) TerminateServicePrincipal(ctx context.Context) error {
c.terminateServicePrincipalCalled = true
return c.terminateServicePrincipalErr
}
type fakeGcpClient struct {
workers cloudtypes.Instances
controlPlanes cloudtypes.Instances
workerInstanceGroup string
controlPlaneInstanceGroup string
controlPlaneTemplate string
workerTemplate string
network string
subnetwork string
firewalls []string
project string
uid string
name string
zone string
serviceAccount string
// loadbalancer
healthCheck string
backendService string
forwardingRule string
}
func (c *fakeGcpClient) GetState() (state.ConstellationState, error) {
stat := state.ConstellationState{
CloudProvider: cloudprovider.GCP.String(),
GCPWorkers: c.workers,
GCPControlPlanes: c.controlPlanes,
GCPWorkerInstanceGroup: c.workerInstanceGroup,
GCPControlPlaneInstanceGroup: c.controlPlaneInstanceGroup,
GCPWorkerInstanceTemplate: c.workerTemplate,
GCPControlPlaneInstanceTemplate: c.controlPlaneTemplate,
GCPNetwork: c.network,
GCPSubnetwork: c.subnetwork,
GCPFirewalls: c.firewalls,
GCPBackendService: c.backendService,
GCPHealthCheck: c.healthCheck,
GCPForwardingRule: c.forwardingRule,
GCPProject: c.project,
Name: c.name,
UID: c.uid,
GCPZone: c.zone,
GCPServiceAccount: c.serviceAccount,
}
return stat, nil
}
func (c *fakeGcpClient) SetState(stat state.ConstellationState) error {
c.workers = stat.GCPWorkers
c.controlPlanes = stat.GCPControlPlanes
c.workerInstanceGroup = stat.GCPWorkerInstanceGroup
c.controlPlaneInstanceGroup = stat.GCPControlPlaneInstanceGroup
c.workerTemplate = stat.GCPWorkerInstanceTemplate
c.controlPlaneTemplate = stat.GCPControlPlaneInstanceTemplate
c.network = stat.GCPNetwork
c.subnetwork = stat.GCPSubnetwork
c.firewalls = stat.GCPFirewalls
c.project = stat.GCPProject
c.name = stat.Name
c.uid = stat.UID
c.zone = stat.GCPZone
c.serviceAccount = stat.GCPServiceAccount
c.healthCheck = stat.GCPHealthCheck
c.backendService = stat.GCPBackendService
c.forwardingRule = stat.GCPForwardingRule
return nil
}
func (c *fakeGcpClient) CreateVPCs(ctx context.Context) error {
c.network = "network"
c.subnetwork = "subnetwork"
return nil
}
func (c *fakeGcpClient) CreateFirewall(ctx context.Context, input gcpcl.FirewallInput) error {
if c.network == "" {
return errors.New("client has not network")
}
for _, rule := range input.Ingress {
c.firewalls = append(c.firewalls, rule.Name)
}
return nil
}
func (c *fakeGcpClient) CreateInstances(ctx context.Context, input gcpcl.CreateInstancesInput) error {
c.controlPlaneInstanceGroup = "controlplane-group"
c.workerInstanceGroup = "workers-group"
c.workerTemplate = "worker-template"
c.controlPlaneTemplate = "controlplane-template"
c.workers = make(cloudtypes.Instances)
for i := 0; i < input.CountWorkers; i++ {
id := "id-" + strconv.Itoa(i)
c.workers[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
c.controlPlanes = make(cloudtypes.Instances)
for i := 0; i < input.CountControlPlanes; i++ {
id := "id-" + strconv.Itoa(i)
c.controlPlanes[id] = cloudtypes.Instance{PublicIP: "192.0.2.1", PrivateIP: "192.0.2.1"}
}
return nil
}
func (c *fakeGcpClient) CreateServiceAccount(ctx context.Context, input gcpcl.ServiceAccountInput) (string, error) {
c.serviceAccount = "service-account@" + c.project + ".iam.gserviceaccount.com"
return gcpshared.ServiceAccountKey{
Type: "service_account",
ProjectID: c.project,
PrivateKeyID: "key-id",
PrivateKey: "-----BEGIN PRIVATE KEY-----\nprivate-key\n-----END PRIVATE KEY-----\n",
ClientEmail: c.serviceAccount,
ClientID: "client-id",
AuthURI: "https://accounts.google.com/o/oauth2/auth",
TokenURI: "https://accounts.google.com/o/oauth2/token",
AuthProviderX509CertURL: "https://www.googleapis.com/oauth2/v1/certs",
ClientX509CertURL: "https://www.googleapis.com/robot/v1/metadata/x509/service-account-email",
}.ToCloudServiceAccountURI(), nil
}
func (c *fakeGcpClient) CreateLoadBalancer(ctx context.Context) error {
c.healthCheck = "health-check"
c.backendService = "backend-service"
c.forwardingRule = "forwarding-rule"
return nil
}
func (c *fakeGcpClient) TerminateFirewall(ctx context.Context) error {
if len(c.firewalls) == 0 {
return nil
}
c.firewalls = nil
return nil
}
func (c *fakeGcpClient) TerminateVPCs(context.Context) error {
if len(c.firewalls) != 0 {
return errors.New("client has firewalls, which must be deleted first")
}
c.network = ""
c.subnetwork = ""
return nil
}
func (c *fakeGcpClient) TerminateInstances(context.Context) error {
c.workerTemplate = ""
c.controlPlaneTemplate = ""
c.workerInstanceGroup = ""
c.controlPlaneInstanceGroup = ""
c.workers = nil
c.controlPlanes = nil
return nil
}
func (c *fakeGcpClient) TerminateServiceAccount(context.Context) error {
c.serviceAccount = ""
return nil
}
func (c *fakeGcpClient) TerminateLoadBalancer(context.Context) error {
c.healthCheck = ""
c.backendService = ""
c.forwardingRule = ""
return nil
}
func (c *fakeGcpClient) Close() error {
return nil
}
type stubGcpClient struct {
terminateFirewallCalled bool
terminateInstancesCalled bool
terminateVPCsCalled bool
terminateServiceAccountCalled bool
closeCalled bool
getStateErr error
setStateErr error
createVPCsErr error
createFirewallErr error
createInstancesErr error
createServiceAccountErr error
createLoadBalancerErr error
terminateFirewallErr error
terminateVPCsErr error
terminateInstancesErr error
terminateServiceAccountErr error
terminateLoadBalancerErr error
closeErr error
}
func (c *stubGcpClient) GetState() (state.ConstellationState, error) {
return state.ConstellationState{}, c.getStateErr
}
func (c *stubGcpClient) SetState(state.ConstellationState) error {
return c.setStateErr
}
func (c *stubGcpClient) CreateVPCs(ctx context.Context) error {
return c.createVPCsErr
}
func (c *stubGcpClient) CreateFirewall(ctx context.Context, input gcpcl.FirewallInput) error {
return c.createFirewallErr
}
func (c *stubGcpClient) CreateInstances(ctx context.Context, input gcpcl.CreateInstancesInput) error {
return c.createInstancesErr
}
func (c *stubGcpClient) CreateServiceAccount(ctx context.Context, input gcpcl.ServiceAccountInput) (string, error) {
return gcpshared.ServiceAccountKey{}.ToCloudServiceAccountURI(), c.createServiceAccountErr
}
func (c *stubGcpClient) CreateLoadBalancer(ctx context.Context) error {
return c.createLoadBalancerErr
}
func (c *stubGcpClient) TerminateFirewall(ctx context.Context) error {
c.terminateFirewallCalled = true
return c.terminateFirewallErr
}
func (c *stubGcpClient) TerminateVPCs(context.Context) error {
c.terminateVPCsCalled = true
return c.terminateVPCsErr
}
func (c *stubGcpClient) TerminateInstances(context.Context) error {
c.terminateInstancesCalled = true
return c.terminateInstancesErr
}
func (c *stubGcpClient) TerminateServiceAccount(context.Context) error {
c.terminateServiceAccountCalled = true
return c.terminateServiceAccountErr
}
func (c *stubGcpClient) TerminateLoadBalancer(context.Context) error {
return c.terminateLoadBalancerErr
}
func (c *stubGcpClient) Close() error {
c.closeCalled = true
return c.closeErr
}