-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a VM provisionner for GCP (#29214)
- Loading branch information
1 parent
61bc84e
commit f3313b8
Showing
6 changed files
with
312 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
package examples | ||
|
||
import ( | ||
gcphost "github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments/gcp/host/linux" | ||
"testing" | ||
|
||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e" | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments" | ||
) | ||
|
||
type gcpVMSuite struct { | ||
e2e.BaseSuite[environments.Host] | ||
} | ||
|
||
// TestGCPVMSuite runs tests for the VM interface to ensure its implementation is correct. | ||
func TestGCPVMSuite(t *testing.T) { | ||
suiteParams := []e2e.SuiteOption{e2e.WithProvisioner(gcphost.ProvisionerNoAgentNoFakeIntake())} | ||
e2e.Run(t, &gcpVMSuite{}, suiteParams...) | ||
} | ||
|
||
func (v *gcpVMSuite) TestExecute() { | ||
vm := v.Env().RemoteHost | ||
|
||
out, err := vm.Execute("whoami") | ||
v.Require().NoError(err) | ||
v.Require().NotEmpty(out) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
// Package gcphost contains the definition of the GCP Host environment. | ||
package gcphost | ||
|
||
import ( | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e" | ||
"github.com/DataDog/test-infra-definitions/resources/gcp" | ||
"github.com/DataDog/test-infra-definitions/scenarios/gcp/compute" | ||
"github.com/DataDog/test-infra-definitions/scenarios/gcp/fakeintake" | ||
|
||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments" | ||
|
||
"github.com/DataDog/test-infra-definitions/components/datadog/agent" | ||
"github.com/DataDog/test-infra-definitions/components/datadog/agentparams" | ||
"github.com/DataDog/test-infra-definitions/components/datadog/updater" | ||
"github.com/pulumi/pulumi/sdk/v3/go/pulumi" | ||
) | ||
|
||
const ( | ||
provisionerBaseID = "gcp-vm-" | ||
defaultVMName = "vm" | ||
) | ||
|
||
// Provisioner creates a VM environment with an VM, a FakeIntake and a Host Agent configured to talk to each other. | ||
// FakeIntake and Agent creation can be deactivated by using [WithoutFakeIntake] and [WithoutAgent] options. | ||
func Provisioner(opts ...ProvisionerOption) e2e.TypedProvisioner[environments.Host] { | ||
// We need to build params here to be able to use params.name in the provisioner name | ||
params := GetProvisionerParams(opts...) | ||
|
||
provisioner := e2e.NewTypedPulumiProvisioner(provisionerBaseID+params.name, func(ctx *pulumi.Context, env *environments.Host) error { | ||
// We ALWAYS need to make a deep copy of `params`, as the provisioner can be called multiple times. | ||
// and it's easy to forget about it, leading to hard-to-debug issues. | ||
params := GetProvisionerParams(opts...) | ||
return Run(ctx, env, RunParams{ProvisionerParams: params}) | ||
}, params.extraConfigParams) | ||
|
||
return provisioner | ||
} | ||
|
||
// Run deploys an environment given a pulumi.Context | ||
func Run(ctx *pulumi.Context, env *environments.Host, runParams RunParams) error { | ||
var gcpEnv gcp.Environment | ||
if runParams.Environment == nil { | ||
var err error | ||
gcpEnv, err = gcp.NewEnvironment(ctx) | ||
if err != nil { | ||
return err | ||
} | ||
} else { | ||
gcpEnv = *runParams.Environment | ||
} | ||
params := runParams.ProvisionerParams | ||
|
||
host, err := compute.NewVM(gcpEnv, params.name, params.instanceOptions...) | ||
if err != nil { | ||
return err | ||
} | ||
err = host.Export(ctx, &env.RemoteHost.HostOutput) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Create FakeIntake if required | ||
if params.fakeintakeOptions != nil { | ||
fakeIntake, err := fakeintake.NewVMInstance(gcpEnv, params.fakeintakeOptions...) | ||
if err != nil { | ||
return err | ||
} | ||
err = fakeIntake.Export(ctx, &env.FakeIntake.FakeintakeOutput) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
// Normally if FakeIntake is enabled, Agent is enabled, but just in case | ||
if params.agentOptions != nil { | ||
// Prepend in case it's overridden by the user | ||
newOpts := []agentparams.Option{agentparams.WithFakeintake(fakeIntake)} | ||
params.agentOptions = append(newOpts, params.agentOptions...) | ||
} | ||
} else { | ||
// Suite inits all fields by default, so we need to explicitly set it to nil | ||
env.FakeIntake = nil | ||
} | ||
if !params.installUpdater { | ||
// Suite inits all fields by default, so we need to explicitly set it to nil | ||
env.Updater = nil | ||
} | ||
|
||
// Create Agent if required | ||
if params.installUpdater && params.agentOptions != nil { | ||
updater, err := updater.NewHostUpdater(&gcpEnv, host, params.agentOptions...) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = updater.Export(ctx, &env.Updater.HostUpdaterOutput) | ||
if err != nil { | ||
return err | ||
} | ||
// todo: add agent once updater installs agent on bootstrap | ||
env.Agent = nil | ||
} else if params.agentOptions != nil { | ||
agent, err := agent.NewHostAgent(&gcpEnv, host, params.agentOptions...) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
err = agent.Export(ctx, &env.Agent.HostAgentOutput) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
env.Agent.ClientOptions = params.agentClientOptions | ||
} else { | ||
// Suite inits all fields by default, so we need to explicitly set it to nil | ||
env.Agent = nil | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
// Unless explicitly stated otherwise all files in this repository are licensed | ||
// under the Apache License Version 2.0. | ||
// This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
// Copyright 2016-present Datadog, Inc. | ||
|
||
package gcphost | ||
|
||
import ( | ||
"fmt" | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/e2e" | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/environments" | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/runner" | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/e2e/client/agentclientparams" | ||
"github.com/DataDog/datadog-agent/test/new-e2e/pkg/utils/optional" | ||
"github.com/DataDog/test-infra-definitions/components/datadog/agentparams" | ||
"github.com/DataDog/test-infra-definitions/resources/gcp" | ||
"github.com/DataDog/test-infra-definitions/scenarios/gcp/compute" | ||
"github.com/DataDog/test-infra-definitions/scenarios/gcp/fakeintake" | ||
) | ||
|
||
// ProvisionerParams is a set of parameters for the Provisioner. | ||
type ProvisionerParams struct { | ||
name string | ||
|
||
instanceOptions []compute.VMOption | ||
agentOptions []agentparams.Option | ||
agentClientOptions []agentclientparams.Option | ||
fakeintakeOptions []fakeintake.Option | ||
extraConfigParams runner.ConfigMap | ||
installUpdater bool | ||
} | ||
|
||
func newProvisionerParams() *ProvisionerParams { | ||
// We use nil arrays to decide if we should create or not | ||
return &ProvisionerParams{ | ||
name: defaultVMName, | ||
instanceOptions: []compute.VMOption{}, | ||
agentOptions: []agentparams.Option{}, | ||
agentClientOptions: []agentclientparams.Option{}, | ||
fakeintakeOptions: []fakeintake.Option{}, | ||
extraConfigParams: runner.ConfigMap{}, | ||
} | ||
} | ||
|
||
// GetProvisionerParams return ProvisionerParams from options opts setup | ||
func GetProvisionerParams(opts ...ProvisionerOption) *ProvisionerParams { | ||
params := newProvisionerParams() | ||
err := optional.ApplyOptions(params, opts) | ||
if err != nil { | ||
panic(fmt.Errorf("unable to apply ProvisionerOption, err: %w", err)) | ||
} | ||
return params | ||
} | ||
|
||
// ProvisionerOption is a provisioner option. | ||
type ProvisionerOption func(*ProvisionerParams) error | ||
|
||
// WithName sets the name of the provisioner. | ||
func WithName(name string) ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.name = name | ||
return nil | ||
} | ||
} | ||
|
||
// WithInstanceOptions adds options to the EC2 VM. | ||
func WithInstanceOptions(opts ...compute.VMOption) ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.instanceOptions = append(params.instanceOptions, opts...) | ||
return nil | ||
} | ||
} | ||
|
||
// WithAgentOptions adds options to the Agent. | ||
func WithAgentOptions(opts ...agentparams.Option) ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.agentOptions = append(params.agentOptions, opts...) | ||
return nil | ||
} | ||
} | ||
|
||
// WithAgentClientOptions adds options to the Agent client. | ||
func WithAgentClientOptions(opts ...agentclientparams.Option) ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.agentClientOptions = append(params.agentClientOptions, opts...) | ||
return nil | ||
} | ||
} | ||
|
||
// WithFakeIntakeOptions adds options to the FakeIntake. | ||
func WithFakeIntakeOptions(opts ...fakeintake.Option) ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.fakeintakeOptions = append(params.fakeintakeOptions, opts...) | ||
return nil | ||
} | ||
} | ||
|
||
// WithExtraConfigParams adds extra config parameters to the ConfigMap. | ||
func WithExtraConfigParams(configMap runner.ConfigMap) ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.extraConfigParams = configMap | ||
return nil | ||
} | ||
} | ||
|
||
// WithoutFakeIntake disables the creation of the FakeIntake. | ||
func WithoutFakeIntake() ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.fakeintakeOptions = nil | ||
return nil | ||
} | ||
} | ||
|
||
// WithoutAgent disables the creation of the Agent. | ||
func WithoutAgent() ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.agentOptions = nil | ||
return nil | ||
} | ||
} | ||
|
||
// WithUpdater installs the agent through the updater. | ||
func WithUpdater() ProvisionerOption { | ||
return func(params *ProvisionerParams) error { | ||
params.installUpdater = true | ||
return nil | ||
} | ||
} | ||
|
||
// ProvisionerNoAgentNoFakeIntake wraps Provisioner with hardcoded WithoutAgent and WithoutFakeIntake options. | ||
func ProvisionerNoAgentNoFakeIntake(opts ...ProvisionerOption) e2e.TypedProvisioner[environments.Host] { | ||
mergedOpts := make([]ProvisionerOption, 0, len(opts)+2) | ||
mergedOpts = append(mergedOpts, opts...) | ||
mergedOpts = append(mergedOpts, WithoutAgent(), WithoutFakeIntake()) | ||
|
||
return Provisioner(mergedOpts...) | ||
} | ||
|
||
// ProvisionerNoFakeIntake wraps Provisioner with hardcoded WithoutFakeIntake option. | ||
func ProvisionerNoFakeIntake(opts ...ProvisionerOption) e2e.TypedProvisioner[environments.Host] { | ||
mergedOpts := make([]ProvisionerOption, 0, len(opts)+1) | ||
mergedOpts = append(mergedOpts, opts...) | ||
mergedOpts = append(mergedOpts, WithoutFakeIntake()) | ||
|
||
return Provisioner(mergedOpts...) | ||
} | ||
|
||
// RunParams is a set of parameters for the Run function. | ||
type RunParams struct { | ||
Environment *gcp.Environment | ||
ProvisionerParams *ProvisionerParams | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters