-
Notifications
You must be signed in to change notification settings - Fork 1
MacOS support #1679
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
MacOS support #1679
Changes from 6 commits
d96d233
4458411
f0b16c9
2ef6f4d
14e1043
51c3125
5ad4dcf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,78 @@ | ||
| package agent | ||
|
|
||
| import ( | ||
| "fmt" | ||
| "strings" | ||
|
|
||
| "github.com/DataDog/test-infra-definitions/common/config" | ||
| "github.com/DataDog/test-infra-definitions/components/command" | ||
| "github.com/DataDog/test-infra-definitions/components/datadog/agentparams" | ||
| remoteComp "github.com/DataDog/test-infra-definitions/components/remote" | ||
|
|
||
| "github.com/pulumi/pulumi/sdk/v3/go/pulumi" | ||
| ) | ||
|
|
||
| type agentMacOSManager struct { | ||
| host *remoteComp.Host | ||
| } | ||
|
|
||
| func newMacOSManager(host *remoteComp.Host) agentOSManager { | ||
| return &agentMacOSManager{host: host} | ||
| } | ||
|
|
||
| // directInstallCommand expects a locally provided .dmg or .pkg uploaded to the host; it will install it with installer | ||
| func (am *agentMacOSManager) directInstallCommand(env config.Env, packagePath string, _ agentparams.PackageVersion, additionalInstallParameters []string, opts ...pulumi.ResourceOption) (command.Command, error) { | ||
| // Unsupported for now. | ||
| return nil, fmt.Errorf("installing directly from a dmg without the install script requires way too many step that would imply duplicating the install script code in there") | ||
| } | ||
|
|
||
| // getInstallCommand downloads appropriate pkg and installs it | ||
| func (am *agentMacOSManager) getInstallCommand(version agentparams.PackageVersion, apiKey pulumi.StringInput, _ []string) (pulumi.StringOutput, error) { | ||
| // For macOS, use the official install script which supports DD_API_KEY and version envs, | ||
| // mirroring Linux flow but using the macOS path. The script detects OS and uses pkg. | ||
| // If pipeline is specified, we cannot use public script; we assume local package will be provided in that case. | ||
|
|
||
| exports := []string{} | ||
| if version.Major != "" { | ||
| exports = append(exports, fmt.Sprintf("DD_AGENT_MAJOR_VERSION=%s", version.Major)) | ||
| } | ||
| if version.Minor != "" { | ||
| exports = append(exports, fmt.Sprintf("DD_AGENT_MINOR_VERSION=%s", version.Minor)) | ||
| } | ||
|
|
||
| if version.PipelineID != "" { | ||
| exports = append(exports, fmt.Sprintf("DD_REPO_URL=https://dd-agent-macostesting.s3.amazonaws.com/ci/datadog-agent/pipeline-%s-%s", version.PipelineID, am.host.OS.Descriptor().Architecture)) | ||
| } | ||
|
|
||
| env := strings.Join(exports, " ") | ||
| // Retry curl few times | ||
| cmd := fmt.Sprintf(`for i in 1 2 3 4 5; do curl -fsSL https://install.datadoghq.com/scripts/install_mac_os.sh -o install-script.sh && break || sleep $((2**$i)); done && for i in 1 2 3; do DD_API_KEY=%%s %%s %[1]s DD_INSTALL_ONLY=true bash install-script.sh && exit 0 || sleep $((2**$i)); done; exit 1`, env) | ||
| // Only the systemdaemon install is supported on macOS, because single user requires to interact with the pop-up. | ||
| pulumiCmdStr := pulumi.Sprintf(cmd, apiKey, pulumi.Sprintf("DD_SYSTEMDAEMON_INSTALL=true DD_SYSTEMDAEMON_USER_GROUP=%s:staff", am.host.Username)) | ||
| return pulumiCmdStr, nil | ||
| } | ||
|
|
||
| func (am *agentMacOSManager) getAgentConfigFolder() string { | ||
| // macOS Agent config default | ||
| return "/opt/datadog-agent/etc" | ||
| } | ||
|
|
||
| func (am *agentMacOSManager) restartAgentServices(transform command.Transformer, opts ...pulumi.ResourceOption) (command.Command, error) { | ||
| // On macOS, the launchd service is "com.datadoghq.agent" | ||
| cmdName := am.host.Name() + "-restart-agent" | ||
| var cmdArgs command.RunnerCommandArgs = &command.Args{ | ||
| Sudo: true, | ||
| Create: pulumi.String("launchctl kickstart -k system/com.datadoghq.agent"), | ||
| } | ||
| if transform != nil { | ||
| cmdName, cmdArgs = transform(cmdName, cmdArgs) | ||
| } | ||
| return am.host.OS.Runner().Command(cmdName, cmdArgs, opts...) | ||
| } | ||
|
|
||
| func (am *agentMacOSManager) ensureAgentUninstalled(version agentparams.PackageVersion, opts ...pulumi.ResourceOption) (command.Command, error) { | ||
| // No-op the install script should support installing again when the agent is already installed | ||
| return am.host.OS.Runner().Command("no-op-uninstall-agent", &command.Args{ | ||
| Create: pulumi.String("true"), | ||
| }, opts...) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,8 +44,8 @@ func GetPackagePath(localPath string, flavor tifos.Flavor, agentFlavor string, a | |
| wantedExt = ".deb" | ||
| case tifos.WindowsServer: | ||
| wantedExt = ".msi" | ||
| case tifos.MacosOS, tifos.Unknown: | ||
| fallthrough | ||
| case tifos.MacosOS: | ||
| wantedExt = ".dmg" | ||
|
KevinFairise2 marked this conversation as resolved.
Outdated
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: Could you add the fallthrough statement with tifos.Unknown? Like you did above |
||
| default: | ||
| return "", fmt.Errorf("unsupported flavor for local packages installation: %s", flavor) | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,9 +15,9 @@ const ( | |
| func ArchitectureFromString(archStr string) Architecture { | ||
| archStr = strings.ToLower(archStr) | ||
| switch archStr { | ||
| case "x86_64", "amd64", "": // Default architecture is AMD64 | ||
| case "x86_64", "amd64", "", "x86_64_mac": // Default architecture is AMD64 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Question: Why is the default architecture amd64? Since we have arm builds now maybe we want to change that?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since this function set the default for all the instances and not only Macos I think it makes sense to keep AMD64 as the default. Changing that would probably change the default architecture for all the existing tests which would be quite a big change |
||
| return AMD64Arch | ||
| case "arm64", "aarch64": | ||
| case "arm64", "aarch64", "arm64_mac": | ||
| return ARM64Arch | ||
| default: | ||
| panic(fmt.Sprintf("unknown architecture: %s", archStr)) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,5 +3,5 @@ package os | |
| // Implements commonly used descriptors for easier usage | ||
| var ( | ||
| MacOSDefault = MacOSSonoma | ||
| MacOSSonoma = NewDescriptorWithArch(MacosOS, "sonoma", ARM64Arch) | ||
| MacOSSonoma = NewDescriptor(MacosOS, "sonoma") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we define other versions such as ventura etc. ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or is it an aws limitation?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think other version are supported, at least sequoia exists. But we can probably add them later if they are needed |
||
| ) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| package ec2 | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/DataDog/test-infra-definitions/common/config" | ||
| "github.com/DataDog/test-infra-definitions/common/utils" | ||
| "github.com/DataDog/test-infra-definitions/resources/aws" | ||
|
|
||
| "github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2" | ||
| "github.com/pulumi/pulumi/sdk/v3/go/pulumi" | ||
| ) | ||
|
|
||
| type DedicatedHostArgs struct { | ||
| // Mandatory | ||
| InstanceType string // e.g., "mac1.metal", "mac2.metal" | ||
|
|
||
| // Optional | ||
| AvailabilityZone string // If not specified, will use first available zone | ||
| HostRecovery string // "on" or "off", defaults to "off" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: Should we use a boolean for that? |
||
| Tags pulumi.StringMap | ||
| } | ||
|
|
||
| // NewDedicatedHost creates an EC2 Dedicated Host for Mac instances | ||
| func NewDedicatedHost(e aws.Environment, name string, args DedicatedHostArgs, opts ...pulumi.ResourceOption) (*ec2.DedicatedHost, error) { | ||
| if args.InstanceType == "" { | ||
| return nil, fmt.Errorf("InstanceType is required for dedicated host") | ||
| } | ||
|
|
||
| // Default values | ||
| if args.HostRecovery == "" { | ||
| args.HostRecovery = "off" | ||
| } | ||
|
|
||
| var availabilityZone pulumi.StringInput | ||
| if args.AvailabilityZone == "" { | ||
| // Use the same AZ as the first subnet | ||
| availabilityZone = e.RandomSubnets().Index(pulumi.Int(0)).ApplyT(func(subnetId string) (string, error) { | ||
| // Get subnet info to determine AZ | ||
| subnet, err := ec2.LookupSubnet(e.Ctx(), &ec2.LookupSubnetArgs{ | ||
| Id: &subnetId, | ||
| }, e.WithProvider(config.ProviderAWS)) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| return subnet.AvailabilityZone, nil | ||
| }).(pulumi.StringOutput) | ||
| } else { | ||
| availabilityZone = pulumi.String(args.AvailabilityZone) | ||
| } | ||
|
|
||
| dedicatedHostArgs := &ec2.DedicatedHostArgs{ | ||
| InstanceType: pulumi.String(args.InstanceType), | ||
| AvailabilityZone: availabilityZone, | ||
| HostRecovery: pulumi.String(args.HostRecovery), | ||
| } | ||
|
|
||
| return ec2.NewDedicatedHost(e.Ctx(), | ||
| e.Namer.ResourceName(name), | ||
| dedicatedHostArgs, | ||
| utils.MergeOptions(opts, e.WithProviders(config.ProviderAWS), pulumi.RetainOnDelete(true))..., // Retain on delete because deleting a dedicated host is not possible unless it lived for at least 24 hours, the cleanup will be done by test-infra-cleaner | ||
| ) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.