Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add two tasks to create and destroy VM stacks in Azure #958

Merged
merged 16 commits into from
Jul 19, 2024
6 changes: 6 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ integration-testing:
rules:
- when: on_success
before_script:
# Setup Azure credentials. Uncomment once the resources are ready
# - export AZURE_CLIENT_ID=$(aws ssm get-parameter --region us-east-1 --name ci.test-infra-definitions.azure_client_id --with-decryption --query "Parameter.Value" --out text)
# - export AZURE_CLIENT_SECRET=$(aws ssm get-parameter --region us-east-1 --name ci.test-infra-definitions.azure_client_secret --with-decryption --query "Parameter.Value" --out text)
# - export AZURE_TENANT_ID=$(aws ssm get-parameter --region us-east-1 --name ci.test-infra-definitions.azure_tenant_id --with-decryption --query "Parameter.Value" --out text)
# - export AZURE_SUBSCRIPTION_ID=$(aws ssm get-parameter --region us-east-1 --name ci.test-infra-definitions.azure_subscription_id --with-decryption --query "Parameter.Value" --out text)
# - az login --service-principal -u "$AZURE_CLIENT_ID" -p "$AZURE_CLIENT_SECRET" --tenant "$AZURE_TENANT_ID" > /dev/null
# Setup AWS Credentials
- mkdir -p ~/.aws
- aws ssm get-parameter --region us-east-1 --name ci.test-infra-definitions.agent-qa-profile --with-decryption --query "Parameter.Value" --out text >> ~/.aws/config
Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,14 @@ Available tasks:
create-docker Create a docker environment.
create-ecs Create a new ECS environment.
create-eks Create a new EKS environment. It lasts around 20 minutes.
create-vm Create a new virtual machine on the cloud.
aws.create-vm Create a new virtual machine on aws.
az.create-vm Create a new virtual machine on azure.
destroy-aks Destroy a AKS environment created with invoke create-aks.
destroy-docker Destroy an environment created by invoke create_docker.
destroy-ecs Destroy a ECS environment created with invoke create-ecs.
destroy-eks Destroy a EKS environment created with invoke create-eks.
aws.destroy-vm Destroy a virtual machine on aws.
az.destroy-vm Destroy a virtual machine on azure.
```

Run any `-h` on any of the available tasks for more information
Expand Down
38 changes: 32 additions & 6 deletions integration-tests/invoke_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,32 +49,58 @@ func TestInvokes(t *testing.T) {
require.NotEmpty(t, tmpConfig.ConfigParams.AWS.TeamTag)

// Subtests
t.Run("invoke-vm", func(t *testing.T) {

// Uncomment once the resources will be created
//t.Run("az.create-vm", func(t *testing.T) {
// t.Parallel()
// testAzureInvokeVM(t, tmpConfigFile, *workingDir)
//})

t.Run("aws.create-vm", func(t *testing.T) {
t.Parallel()
testInvokeVM(t, tmpConfigFile, *workingDir)
testAwsInvokeVM(t, tmpConfigFile, *workingDir)
})

t.Run("invoke-docker-vm", func(t *testing.T) {
t.Parallel()
testInvokeDockerVM(t, tmpConfigFile, *workingDir)
})

t.Run("invoke-kind", func(t *testing.T) {
t.Parallel()
testInvokeKind(t, tmpConfigFile, *workingDir)
})
}

func testInvokeVM(t *testing.T, tmpConfigFile string, workingDirectory string) {
//func testAzureInvokeVM(t *testing.T, tmpConfigFile string, workingDirectory string) {
// t.Helper()
//
// stackName := fmt.Sprintf("az-invoke-vm-%s", os.Getenv("CI_PIPELINE_ID"))
// t.Log("creating vm")
// createCmd := exec.Command("invoke", "az.create-vm", "--no-interactive", "--stack-name", stackName, "--config-path", tmpConfigFile, "--account", "agent-qa")
// createCmd.Dir = workingDirectory
// createOutput, err := createCmd.Output()
// assert.NoError(t, err, "Error found creating vm: %s", string(createOutput))
//
// t.Log("destroying vm")
// destroyCmd := exec.Command("invoke", "az.destroy-vm", "--yes", "--no-clean-known-hosts", "--stack-name", stackName, "--config-path", tmpConfigFile)
// destroyCmd.Dir = workingDirectory
// destroyOutput, err := destroyCmd.Output()
// require.NoError(t, err, "Error found destroying stack: %s", string(destroyOutput))
//}

func testAwsInvokeVM(t *testing.T, tmpConfigFile string, workingDirectory string) {
t.Helper()

stackName := fmt.Sprintf("invoke-vm-%s", os.Getenv("CI_PIPELINE_ID"))
stackName := fmt.Sprintf("aws-invoke-vm-%s", os.Getenv("CI_PIPELINE_ID"))
t.Log("creating vm")
createCmd := exec.Command("invoke", "create-vm", "--no-interactive", "--stack-name", stackName, "--config-path", tmpConfigFile, "--use-fakeintake")
createCmd := exec.Command("invoke", "aws.create-vm", "--no-interactive", "--stack-name", stackName, "--config-path", tmpConfigFile, "--use-fakeintake")
createCmd.Dir = workingDirectory
createOutput, err := createCmd.Output()
assert.NoError(t, err, "Error found creating vm: %s", string(createOutput))

t.Log("destroying vm")
destroyCmd := exec.Command("invoke", "destroy-vm", "--yes", "--no-clean-known-hosts", "--stack-name", stackName, "--config-path", tmpConfigFile)
destroyCmd := exec.Command("invoke", "aws.destroy-vm", "--yes", "--no-clean-known-hosts", "--stack-name", stackName, "--config-path", tmpConfigFile)
destroyCmd.Dir = workingDirectory
destroyOutput, err := destroyCmd.Output()
require.NoError(t, err, "Error found destroying stack: %s", string(destroyOutput))
Expand Down
37 changes: 12 additions & 25 deletions resources/azure/compute/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ const (
AdminUsername = "azureuser"
)

func NewLinuxInstance(e azure.Environment, name, imageUrn, instanceType string, userData pulumi.StringPtrInput) (*compute.VirtualMachine, *network.PublicIPAddress, *network.NetworkInterface, error) {
func NewLinuxInstance(e azure.Environment, name, imageUrn, instanceType string, userData pulumi.StringPtrInput) (*compute.VirtualMachine, *network.NetworkInterface, error) {
sshPublicKey, err := utils.GetSSHPublicKey(e.DefaultPublicKeyPath())
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

linuxOsProfile := compute.OSProfileArgs{
Expand All @@ -45,13 +45,13 @@ func NewLinuxInstance(e azure.Environment, name, imageUrn, instanceType string,
return newVMInstance(e, name, imageUrn, instanceType, linuxOsProfile)
}

func NewWindowsInstance(e azure.Environment, name, imageUrn, instanceType string, userData, firstLogonCommand pulumi.StringPtrInput) (*compute.VirtualMachine, *network.PublicIPAddress, *network.NetworkInterface, pulumi.StringOutput, error) {
func NewWindowsInstance(e azure.Environment, name, imageUrn, instanceType string, userData, firstLogonCommand pulumi.StringPtrInput) (*compute.VirtualMachine, *network.NetworkInterface, pulumi.StringOutput, error) {
windowsAdminPassword, err := random.NewRandomPassword(e.Ctx(), e.Namer.ResourceName(name, "admin-password"), &random.RandomPasswordArgs{
Length: pulumi.Int(20),
Special: pulumi.Bool(true),
})
if err != nil {
return nil, nil, nil, pulumi.StringOutput{}, err
return nil, nil, pulumi.StringOutput{}, err
}

windowsOsProfile := compute.OSProfileArgs{
Expand All @@ -74,28 +74,18 @@ func NewWindowsInstance(e azure.Environment, name, imageUrn, instanceType string
}
}

vm, publicIP, nw, err := newVMInstance(e, name, imageUrn, instanceType, windowsOsProfile)
vm, nw, err := newVMInstance(e, name, imageUrn, instanceType, windowsOsProfile)
if err != nil {
return nil, nil, nil, pulumi.StringOutput{}, err
return nil, nil, pulumi.StringOutput{}, err
}

return vm, publicIP, nw, windowsAdminPassword.Result, nil
return vm, nw, windowsAdminPassword.Result, nil
}

func newVMInstance(e azure.Environment, name, imageUrn, instanceType string, osProfile compute.OSProfilePtrInput) (*compute.VirtualMachine, *network.PublicIPAddress, *network.NetworkInterface, error) {
func newVMInstance(e azure.Environment, name, imageUrn, instanceType string, osProfile compute.OSProfilePtrInput) (*compute.VirtualMachine, *network.NetworkInterface, error) {
vmImageRef, err := parseImageReferenceURN(imageUrn)
if err != nil {
return nil, nil, nil, err
}

publicIP, err := network.NewPublicIPAddress(e.Ctx(), e.Namer.ResourceName(name), &network.PublicIPAddressArgs{
PublicIpAddressName: e.Namer.DisplayName(math.MaxInt, pulumi.String(name)),
ResourceGroupName: pulumi.String(e.DefaultResourceGroup()),
PublicIPAllocationMethod: pulumi.String(network.IPAllocationMethodStatic),
Tags: e.ResourcesTags(),
}, e.WithProviders(config.ProviderAzure))
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

nwInt, err := network.NewNetworkInterface(e.Ctx(), e.Namer.ResourceName(name), &network.NetworkInterfaceArgs{
Expand All @@ -108,15 +98,12 @@ func newVMInstance(e azure.Environment, name, imageUrn, instanceType string, osP
Id: pulumi.String(e.DefaultSubnet()),
},
PrivateIPAllocationMethod: pulumi.String(network.IPAllocationMethodDynamic),
PublicIPAddress: network.PublicIPAddressTypeArgs{
Id: publicIP.ID(),
},
},
},
Tags: e.ResourcesTags(),
}, e.WithProviders(config.ProviderAzure))
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

vm, err := compute.NewVirtualMachine(e.Ctx(), e.Namer.ResourceName(name), &compute.VirtualMachineArgs{
Expand Down Expand Up @@ -148,8 +135,8 @@ func newVMInstance(e azure.Environment, name, imageUrn, instanceType string, osP
Tags: e.ResourcesTags(),
}, e.WithProviders(config.ProviderAzure))
if err != nil {
return nil, nil, nil, err
return nil, nil, err
}

return vm, publicIP, nwInt, nil
return vm, nwInt, nil
}
1 change: 1 addition & 0 deletions resources/azure/environment.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func NewEnvironment(ctx *pulumi.Context) (Environment, error) {
DisablePulumiPartnerId: pulumi.BoolPtr(true),
SubscriptionId: pulumi.StringPtr(env.envDefault.azure.subscriptionID),
TenantId: pulumi.StringPtr(env.envDefault.azure.tenantID),
Location: pulumi.StringPtr(env.envDefault.azure.location),
})
if err != nil {
return Environment{}, err
Expand Down
51 changes: 50 additions & 1 deletion resources/azure/environmentDefaults.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package azure

const (
sandboxEnv = "az/sandbox"
sandboxEnv = "az/sandbox"
agentSandboxEnv = "az/agent-sandbox"
agentQaEnv = "az/agent-qa"
)

type environmentDefault struct {
Expand All @@ -12,6 +14,7 @@ type environmentDefault struct {
type azureProvider struct {
tenantID string
subscriptionID string
location string
}

type ddInfra struct {
Expand All @@ -32,6 +35,10 @@ func getEnvironmentDefault(envName string) environmentDefault {
switch envName {
case sandboxEnv:
return sandboxDefault()
case agentSandboxEnv:
return agentSandboxDefault()
case agentQaEnv:
return agentQaDefault()
default:
panic("Unknown environment: " + envName)
}
Expand All @@ -56,3 +63,45 @@ func sandboxDefault() environmentDefault {
},
}
}

func agentSandboxDefault() environmentDefault {
return environmentDefault{
azure: azureProvider{
tenantID: "cc0b82f3-7c2e-400b-aec3-40a3d720505b",
subscriptionID: "9972cab2-9e99-419b-a683-86bfa77b3df1",
location: "West US 2",
},
ddInfra: ddInfra{
defaultResourceGroup: "dd-agent-sandbox",
defaultVNet: "/subscriptions/9972cab2-9e99-419b-a683-86bfa77b3df1/resourceGroups/dd-agent-sandbox/providers/Microsoft.Network/virtualNetworks/dd-agent-sandbox",
defaultSubnet: "/subscriptions/9972cab2-9e99-419b-a683-86bfa77b3df1/resourceGroups/dd-agent-sandbox/providers/Microsoft.Network/virtualNetworks/dd-agent-sandbox/subnets/dd-agent-sandbox-private",
defaultSecurityGroup: "/subscriptions/9972cab2-9e99-419b-a683-86bfa77b3df1/resourceGroups/dd-agent-sandbox/providers/Microsoft.Network/networkSecurityGroups/appgategreen",
defaultInstanceType: "Standard_D2a_v4", // Allows nested virtualization for kata runtimes
defaultARMInstanceType: "Standard_D4ps_v5", // No azure arm instance supports nested virtualization
aks: ddInfraAks{
linuxKataNodeGroup: true,
},
},
}
}

func agentQaDefault() environmentDefault {
return environmentDefault{
azure: azureProvider{
tenantID: "cc0b82f3-7c2e-400b-aec3-40a3d720505b",
subscriptionID: "c767177d-c6fc-47d3-a87e-3ab195f5b99e",
location: "West US 2",
},
ddInfra: ddInfra{
defaultResourceGroup: "dd-agent-sandbox",
defaultVNet: "/subscriptions/9972cab2-9e99-419b-a683-86bfa77b3df1/resourceGroups/dd-agent-sandbox/providers/Microsoft.Network/virtualNetworks/dd-agent-sandbox",
defaultSubnet: "/subscriptions/9972cab2-9e99-419b-a683-86bfa77b3df1/resourceGroups/dd-agent-sandbox/providers/Microsoft.Network/virtualNetworks/dd-agent-sandbox/subnets/dd-agent-sandbox-private",
defaultSecurityGroup: "/subscriptions/9972cab2-9e99-419b-a683-86bfa77b3df1/resourceGroups/dd-agent-sandbox/providers/Microsoft.Network/networkSecurityGroups/appgategreen",
defaultInstanceType: "Standard_D2a_v4", // Allows nested virtualization for kata runtimes
defaultARMInstanceType: "Standard_D4ps_v5", // No azure arm instance supports nested virtualization
aks: ddInfraAks{
linuxKataNodeGroup: true,
},
},
}
}
17 changes: 12 additions & 5 deletions scenarios/azure/compute/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func NewVM(e azure.Environment, name string, params ...VMOption) (*remote.Host,
}

// Default missing parameters
if err = defaultVMArgs(vmArgs); err != nil {
if err = defaultVMArgs(e, vmArgs); err != nil {
return nil, err
}

Expand All @@ -40,9 +40,9 @@ func NewVM(e azure.Environment, name string, params ...VMOption) (*remote.Host,
var nwIface *network.NetworkInterface

if vmArgs.osInfo.Family() == os.LinuxFamily {
_, _, nwIface, err = compute.NewLinuxInstance(e, c.Name(), imageInfo.urn, vmArgs.instanceType, pulumi.StringPtr(vmArgs.userData))
_, nwIface, err = compute.NewLinuxInstance(e, c.Name(), imageInfo.urn, vmArgs.instanceType, pulumi.StringPtr(vmArgs.userData))
} else if vmArgs.osInfo.Family() == os.WindowsFamily {
_, _, nwIface, _, err = compute.NewWindowsInstance(e, c.Name(), imageInfo.urn, vmArgs.instanceType, pulumi.StringPtr(vmArgs.userData), nil)
_, nwIface, _, err = compute.NewWindowsInstance(e, c.Name(), imageInfo.urn, vmArgs.instanceType, pulumi.StringPtr(vmArgs.userData), nil)
} else {
return fmt.Errorf("unsupported OS family %v", vmArgs.osInfo.Family())
}
Expand All @@ -62,9 +62,16 @@ func NewVM(e azure.Environment, name string, params ...VMOption) (*remote.Host,
})
}

func defaultVMArgs(vmArgs *vmArgs) error {
func defaultVMArgs(e azure.Environment, vmArgs *vmArgs) error {
if vmArgs.osInfo == nil {
vmArgs.osInfo = &os.UbuntuDefault
vmArgs.osInfo = &os.WindowsDefault
}

if vmArgs.instanceType == "" {
vmArgs.instanceType = e.DefaultInstanceType()
if vmArgs.osInfo.Architecture == os.ARM64Arch {
vmArgs.instanceType = e.DefaultARMInstanceType()
}
}

return nil
Expand Down
28 changes: 17 additions & 11 deletions tasks/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from invoke.collection import Collection

import tasks.aws as aws
import tasks.az as azure
import tasks.ci as ci
import tasks.setup as setup
import tasks.test as test
Expand All @@ -15,22 +17,26 @@
from .vm import create_vm, destroy_vm

ns = Collection()
ns.add_task(create_vm) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_vm) # pyright: ignore [reportArgumentType]

ns.add_task(check_s3_image_exists) # pyright: ignore [reportArgumentType]
ns.add_task(create_aks) # pyright: ignore [reportArgumentType]
ns.add_task(create_docker) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_docker) # pyright: ignore [reportArgumentType]
ns.add_task(create_ecs) # pyright: ignore [reportArgumentType]
ns.add_task(create_eks) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_eks) # pyright: ignore [reportArgumentType]
ns.add_task(create_aks) # pyright: ignore [reportArgumentType]
ns.add_task(create_installer_lab) # pyright: ignore [reportArgumentType]
ns.add_task(create_kind) # pyright: ignore [reportArgumentType]
ns.add_task(create_vm) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_aks) # pyright: ignore [reportArgumentType]
ns.add_task(create_ecs) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_docker) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_ecs) # pyright: ignore [reportArgumentType]
ns.add_task(create_kind) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_eks) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_installer_lab) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_kind) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_vm) # pyright: ignore [reportArgumentType]
ns.add_task(retry_job) # pyright: ignore [reportArgumentType]
ns.add_task(check_s3_image_exists) # pyright: ignore [reportArgumentType]

ns.add_collection(aws) # pyright: ignore [reportArgumentType]
ns.add_collection(azure) # pyright: ignore [reportArgumentType]
ns.add_collection(ci) # pyright: ignore [reportArgumentType]
ns.add_collection(setup) # pyright: ignore [reportArgumentType]
ns.add_collection(test) # pyright: ignore [reportArgumentType]
ns.add_collection(ci) # pyright: ignore [reportArgumentType]
ns.add_task(create_installer_lab) # pyright: ignore [reportArgumentType]
ns.add_task(destroy_installer_lab) # pyright: ignore [reportArgumentType]
Loading