diff --git a/src/deadline_test_fixtures/__init__.py b/src/deadline_test_fixtures/__init__.py index 2ea69c0..9b9db10 100644 --- a/src/deadline_test_fixtures/__init__.py +++ b/src/deadline_test_fixtures/__init__.py @@ -7,8 +7,10 @@ DeadlineWorkerConfiguration, DockerContainerWorker, EC2InstanceWorker, - WindowsInstanceWorker, - PosixInstanceWorker, + WindowsInstanceWorkerBase, + WindowsInstanceBuildWorker, + PosixInstanceWorkerBase, + PosixInstanceBuildWorker, Job, Farm, Fleet, @@ -53,8 +55,10 @@ "DeadlineWorkerConfiguration", "DockerContainerWorker", "EC2InstanceWorker", - "WindowsInstanceWorker", - "PosixInstanceWorker", + "WindowsInstanceWorkerBase", + "WindowsInstanceBuildWorker", + "PosixInstanceWorkerBase", + "PosixInstanceBuildWorker", "Farm", "Fleet", "Job", diff --git a/src/deadline_test_fixtures/deadline/__init__.py b/src/deadline_test_fixtures/deadline/__init__.py index c904e4d..b2a5dca 100644 --- a/src/deadline_test_fixtures/deadline/__init__.py +++ b/src/deadline_test_fixtures/deadline/__init__.py @@ -16,8 +16,10 @@ DeadlineWorkerConfiguration, DockerContainerWorker, EC2InstanceWorker, - PosixInstanceWorker, - WindowsInstanceWorker, + PosixInstanceWorkerBase, + PosixInstanceBuildWorker, + WindowsInstanceWorkerBase, + WindowsInstanceBuildWorker, PipInstall, ) @@ -29,8 +31,10 @@ "DeadlineWorkerConfiguration", "DockerContainerWorker", "EC2InstanceWorker", - "WindowsInstanceWorker", - "PosixInstanceWorker", + "WindowsInstanceWorkerBase", + "WindowsInstanceBuildWorker", + "PosixInstanceWorkerBase", + "PosixInstanceBuildWorker", "Farm", "Fleet", "Job", diff --git a/src/deadline_test_fixtures/deadline/worker.py b/src/deadline_test_fixtures/deadline/worker.py index e6117ef..b39c26a 100644 --- a/src/deadline_test_fixtures/deadline/worker.py +++ b/src/deadline_test_fixtures/deadline/worker.py @@ -409,13 +409,15 @@ def ami_id(self) -> str: @dataclass -class WindowsInstanceWorker(EC2InstanceWorker): +class WindowsInstanceWorkerBase(EC2InstanceWorker): + """Base class from which Windows ec2 test instances are derived. + + The methods in this base class are written with two cases of worker hosts in mind: + 1. A host that is based on a stock Windows server AMI, with no Deadline-anything installed, that + must install the worker agent and the like during boot-up. + 2. A host that already has the worker agent, job/agent users, and the like baked into + the host AMI in a location & manner that may differ from case (1). """ - This class represents a Windows EC2 Worker Host. - Any commands must be written in Powershell. - """ - - WIN2022_AMI_NAME: ClassVar[str] = "Windows_Server-2022-English-Full-Base" def ssm_document_name(self) -> str: return "AWS-RunPowerShellScript" @@ -434,7 +436,7 @@ def _start_worker_agent(self) -> None: [ "echo 'Running Get-Process to check if the agent is running'", 'for($i=1; $i -le 30 -and "" -ne $err ; $i++){sleep $i; Get-Process pythonservice -ErrorVariable err}', - "IF(Get-Process pythonservice){echo 'service is running'}ELSE{exit 1}", + "IF(Get-Process pythonservice){echo '+++SERVICE IS RUNNING+++'}ELSE{echo '+++SERVICE NOT RUNNING+++'; Get-Content -Encoding utf8 C:\ProgramData\Amazon\Deadline\Logs\worker-agent-bootstrap.log,C:\ProgramData\Amazon\Deadline\Logs\worker-agent.log; exit 1}", ] ), ) @@ -443,31 +445,17 @@ def _start_worker_agent(self) -> None: self.worker_id = self.get_worker_id() - def configure_worker_command(self, *, config: DeadlineWorkerConfiguration) -> str: - """Get the command to configure the Worker. This must be run as root.""" + def configure_worker_common(self, *, config: DeadlineWorkerConfiguration) -> str: + """Get the command to configure the Worker. This must be run as Administrator. + This cannot assume that the agent user exists. + """ - cmds = [ - config.worker_agent_install.install_command_for_windows, - *(config.pre_install_commands or []), - # fmt: off - ( - "install-deadline-worker " - + "-y " - + f"--farm-id {config.farm_id} " - + f"--fleet-id {config.fleet.id} " - + f"--region {config.region} " - + f"--user {config.agent_user} " - + f"{'--allow-shutdown ' if config.allow_shutdown else ''}" - + "--start" - ), - # fmt: on - ] + cmds = [] if config.service_model_path: cmds.append( f"aws configure add-model --service-model file://{config.service_model_path} --service-name deadline; " f"Copy-Item -Path ~\\.aws\\* -Destination C:\\Users\\Administrator\\.aws\\models -Recurse; " - f"Copy-Item -Path ~\\.aws\\* -Destination C:\\Users\\{config.agent_user}\\.aws\\models -Recurse; " f"Copy-Item -Path ~\\.aws\\* -Destination C:\\Users\\{config.job_user}\\.aws\\models -Recurse" ) @@ -475,8 +463,7 @@ def configure_worker_command(self, *, config: DeadlineWorkerConfiguration) -> st LOG.info( f"Using DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE: {os.environ.get('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE')}" ) - cmds.insert( - 0, + cmds.append( f"[System.Environment]::SetEnvironmentVariable('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE', '{os.environ.get('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE')}', [System.EnvironmentVariableTarget]::Machine); " "$env:DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE = [System.Environment]::GetEnvironmentVariable('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE','Machine')", ) @@ -492,44 +479,6 @@ def configure_worker_command(self, *, config: DeadlineWorkerConfiguration) -> st return "; ".join(cmds) - def userdata(self, s3_files) -> str: - copy_s3_command = "" - job_users_cmds = [] - - if s3_files: - copy_s3_command = " ; ".join([f"aws s3 cp {s3_uri} {dst}" for s3_uri, dst in s3_files]) - - if self.configuration.windows_job_users: - for job_user in self.configuration.windows_job_users: - job_users_cmds.append( - f"New-LocalUser -Name {job_user} -Password $password -FullName {job_user} -Description {job_user}" - ) - job_users_cmds.append( - f"$Cred = New-Object System.Management.Automation.PSCredential {job_user}, $password" - ) - job_users_cmds.append( - 'Start-Process cmd.exe -Credential $Cred -ArgumentList "/C" -LoadUserProfile -NoNewWindow' - ) - - configure_job_users = "\n".join(job_users_cmds) - - userdata = f""" - Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe" -OutFile "C:\python-3.11.9-amd64.exe" - $installerHash=(Get-FileHash "C:\python-3.11.9-amd64.exe" -Algorithm "MD5") - $expectedHash="e8dcd502e34932eebcaf1be056d5cbcd" - if ($installerHash.Hash -ne $expectedHash) {{ throw "Could not verify Python installer." }} - Start-Process -FilePath "C:\python-3.11.9-amd64.exe" -ArgumentList "/quiet InstallAllUsers=1 PrependPath=1 AppendPath=1" -Wait - Invoke-WebRequest -Uri "https://awscli.amazonaws.com/AWSCLIV2.msi" -Outfile "C:\AWSCLIV2.msi" - Start-Process msiexec.exe -ArgumentList "/i C:\AWSCLIV2.msi /quiet" -Wait - $env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") - $secret = aws secretsmanager get-secret-value --secret-id WindowsPasswordSecret --query SecretString --output text | ConvertFrom-Json - $password = ConvertTo-SecureString -String $($secret.password) -AsPlainText -Force - {copy_s3_command} - {configure_job_users} - """ - - return userdata - def start_worker_service(self): LOG.info("Sending command to start the Worker Agent service") @@ -543,14 +492,6 @@ def stop_worker_service(self): assert cmd_result.exit_code == 0, f"Failed to stop Worker Agent service: : {cmd_result}" - def ami_ssm_param_name(self) -> str: - # Grab the latest Windows Server 2022 AMI - # https://aws.amazon.com/blogs/mt/query-for-the-latest-windows-ami-using-systems-manager-parameter-store/ - ami_ssm_param: str = ( - f"/aws/service/ami-windows-latest/{WindowsInstanceWorker.WIN2022_AMI_NAME}" - ) - return ami_ssm_param - def get_worker_id(self) -> str: cmd_result = self.send_command( " ; ".join( @@ -571,13 +512,99 @@ def get_worker_id(self) -> str: @dataclass -class PosixInstanceWorker(EC2InstanceWorker): +class WindowsInstanceBuildWorker(WindowsInstanceWorkerBase): """ - This class represents a Linux EC2 Worker Host. - Any commands must be written in Bash. + This class represents a Windows EC2 Worker Host. + Any commands must be written in Powershell. """ - AL2023_AMI_NAME: ClassVar[str] = "al2023-ami-kernel-6.1-x86_64" + WIN2022_AMI_NAME: ClassVar[str] = "Windows_Server-2022-English-Full-Base" + + def configure_worker_command(self, *, config: DeadlineWorkerConfiguration) -> str: + """Get the command to configure the Worker. This must be run as Administrator.""" + cmds = [ + "Set-PSDebug -trace 1", + self.configure_worker_common(config=config), + config.worker_agent_install.install_command_for_windows, + *(config.pre_install_commands or []), + # fmt: off + ( + "install-deadline-worker " + + "-y " + + f"--farm-id {config.farm_id} " + + f"--fleet-id {config.fleet.id} " + + f"--region {config.region} " + + f"--user {config.agent_user} " + + f"{'--allow-shutdown ' if config.allow_shutdown else ''}" + + "--start" + ), + # fmt: on + ] + + if config.service_model_path: + cmds.append( + f"Copy-Item -Path ~\\.aws\\* -Destination C:\\Users\\{config.agent_user}\\.aws\\models -Recurse; " + ) + + return "; ".join(cmds) + + def userdata(self, s3_files) -> str: + copy_s3_command = "" + job_users_cmds = [] + + if s3_files: + copy_s3_command = " ; ".join([f"aws s3 cp {s3_uri} {dst}" for s3_uri, dst in s3_files]) + + if self.configuration.windows_job_users: + for job_user in self.configuration.windows_job_users: + job_users_cmds.append( + f"New-LocalUser -Name {job_user} -Password $password -FullName {job_user} -Description {job_user}" + ) + job_users_cmds.append( + f"$Cred = New-Object System.Management.Automation.PSCredential {job_user}, $password" + ) + job_users_cmds.append( + 'Start-Process cmd.exe -Credential $Cred -ArgumentList "/C" -LoadUserProfile -NoNewWindow' + ) + + configure_job_users = "\n".join(job_users_cmds) + + userdata = f""" +Invoke-WebRequest -Uri "https://www.python.org/ftp/python/3.11.9/python-3.11.9-amd64.exe" -OutFile "C:\python-3.11.9-amd64.exe" +$installerHash=(Get-FileHash "C:\python-3.11.9-amd64.exe" -Algorithm "MD5") +$expectedHash="e8dcd502e34932eebcaf1be056d5cbcd" +if ($installerHash.Hash -ne $expectedHash) {{ throw "Could not verify Python installer." }} +Start-Process -FilePath "C:\python-3.11.9-amd64.exe" -ArgumentList "/quiet InstallAllUsers=1 PrependPath=1 AppendPath=1" -Wait +Invoke-WebRequest -Uri "https://awscli.amazonaws.com/AWSCLIV2.msi" -Outfile "C:\AWSCLIV2.msi" +Start-Process msiexec.exe -ArgumentList "/i C:\AWSCLIV2.msi /quiet" -Wait +$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") +$secret = aws secretsmanager get-secret-value --secret-id WindowsPasswordSecret --query SecretString --output text | ConvertFrom-Json +$password = ConvertTo-SecureString -String $($secret.password) -AsPlainText -Force +{copy_s3_command} +{configure_job_users} +""" + + return userdata + + def ami_ssm_param_name(self) -> str: + # Grab the latest Windows Server 2022 AMI + # https://aws.amazon.com/blogs/mt/query-for-the-latest-windows-ami-using-systems-manager-parameter-store/ + ami_ssm_param: str = ( + f"/aws/service/ami-windows-latest/{WindowsInstanceBuildWorker.WIN2022_AMI_NAME}" + ) + return ami_ssm_param + + +@dataclass +class PosixInstanceWorkerBase(EC2InstanceWorker): + """Base class from which posix (i.e. Linux) ec2 test instances are derived. + + The methods in this base class are written with two cases of worker hosts in mind: + 1. A host that is based on a stock linux AMI, with no Deadline-anything installed, that + must install the worker agent and the like during boot-up. + 2. A host that already has the worker agent, job/agent users, and the like baked into + the host AMI in a location & manner that may differ from case (1). + """ def ssm_document_name(self) -> str: return "AWS-RunShellScript" @@ -587,6 +614,9 @@ def send_command(self, command: str) -> CommandResult: def _start_worker_agent(self) -> None: assert self.instance_id + LOG.info( + f"Starting worker for farm: {self.configuration.farm_id} and fleet: {self.configuration.fleet.id}" + ) LOG.info(f"Sending SSM command to configure Worker agent on instance {self.instance_id}") cmd_result = self.send_command(self.configure_worker_command(config=self.configuration)) @@ -595,28 +625,112 @@ def _start_worker_agent(self) -> None: LOG.info(f"Sending SSM command to start Worker agent on instance {self.instance_id}") cmd_result = self.send_command( - " && ".join( + "; ".join( [ - f"nohup runuser --login {self.configuration.agent_user} -c 'AWS_DEFAULT_REGION={self.configuration.region} deadline-worker-agent > /tmp/worker-agent-stdout.txt 2>&1 &'", - # Verify Worker is still running - "echo Waiting 5s for agent to get started", - "sleep 5", - "echo 'Running pgrep to see if deadline-worker-agent is running'", - f"pgrep --count --full -u {self.configuration.agent_user} deadline-worker-agent", + " && ".join( + [ + "set -x", + f"nohup runuser --login {self.configuration.agent_user} -c 'AWS_DEFAULT_REGION={self.configuration.region} deadline-worker-agent > /tmp/worker-agent-stdout.txt 2>&1 &'", + # Verify Worker is still running + "echo Waiting 5s for agent to get started", + "sleep 5", + "echo 'Running pgrep to see if deadline-worker-agent is running'", + # Note: pgrep has a non-zero exit code if no matching application can be found. + f"pgrep --count --full -u {self.configuration.agent_user} deadline-worker-agent", + ], + ), + # If the worker didn't start, then print out the agent logs that exist to aid in debugging. + "if test $? -ne 0; then echo '+++AGENT NOT RUNNING+++'; cat /var/log/amazon/deadline/worker-agent-bootstrap.log /var/log/amazon/deadline/worker-agent.log; exit 1; fi", ] - ), + ) ) assert cmd_result.exit_code == 0, f"Failed to start Worker agent: {cmd_result}" LOG.info("Successfully started Worker agent") self.worker_id = self.get_worker_id() + def configure_agent_user_environment( + self, config: DeadlineWorkerConfiguration + ) -> str: # pragma: no cover + """Get the command to configure the Worker. This must be run as root. + This can assume that the agent user exists. + """ + + cmds = [] + + if config.service_model_path: + cmds.append( + f"runuser -l {config.agent_user} -s /bin/bash -c 'aws configure add-model --service-model file://{config.service_model_path}'" + ) + + if os.environ.get("DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE"): + LOG.info( + f"Using DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE: {os.environ.get('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE')}" + ) + cmds.append( + f"runuser -l {config.agent_user} -s /bin/bash -c 'echo export DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE={os.environ.get('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE')} >> ~/.bashrc'", + ) + + if os.environ.get("AWS_ENDPOINT_URL_DEADLINE"): + LOG.info( + f"Using AWS_ENDPOINT_URL_DEADLINE: {os.environ.get('AWS_ENDPOINT_URL_DEADLINE')}" + ) + cmds.append( + f"runuser -l {config.agent_user} -s /bin/bash -c 'echo export AWS_ENDPOINT_URL_DEADLINE={os.environ.get('AWS_ENDPOINT_URL_DEADLINE')} >> ~/.bashrc'", + ) + + return " && ".join(cmds) + + def start_worker_service(self): + LOG.info("Sending command to start the Worker Agent service") + + cmd_result = self.send_command("systemctl start deadline-worker") + + assert cmd_result.exit_code == 0, f"Failed to start Worker Agent service: {cmd_result}" + + def stop_worker_service(self): + LOG.info("Sending command to stop the Worker Agent service") + cmd_result = self.send_command("systemctl stop deadline-worker") + + assert cmd_result.exit_code == 0, f"Failed to stop Worker Agent service: {cmd_result}" + + def get_worker_id(self) -> str: + # There can be a race condition, so we may need to wait a little bit for the status file to be written. + + worker_state_filename = "/var/lib/deadline/worker.json" + cmd_result = self.send_command( + " && ".join( + [ + f"t=0 && while [ $t -le 10 ] && ! (test -f {worker_state_filename}); do sleep $t; t=$[$t+1]; done", + f"cat {worker_state_filename} | jq -r '.worker_id'", + ] + ) + ) + assert cmd_result.exit_code == 0, f"Failed to get Worker ID: {cmd_result}" + + worker_id = cmd_result.stdout.rstrip("\n\r") + LOG.info(f"Worker ID: {worker_id}") + assert re.match( + r"^worker-[0-9a-f]{32}$", worker_id + ), f"Got nonvalid Worker ID from command stdout: {cmd_result}" + return worker_id + + +@dataclass +class PosixInstanceBuildWorker(PosixInstanceWorkerBase): + """ + This class represents a Linux EC2 Worker Host. + Any commands must be written in Bash. + """ + + AL2023_AMI_NAME: ClassVar[str] = "al2023-ami-kernel-6.1-x86_64" + def configure_worker_command( self, config: DeadlineWorkerConfiguration ) -> str: # pragma: no cover """Get the command to configure the Worker. This must be run as root.""" - cmds = [ + "set -x", "source /opt/deadline/worker/bin/activate", f"AWS_DEFAULT_REGION={self.configuration.region}", config.worker_agent_install.install_command_for_linux, @@ -651,27 +765,7 @@ def configure_worker_command( f'echo "{self.configuration.agent_user} ALL=({sudoer_rule_users}) NOPASSWD: ALL" > /etc/sudoers.d/{self.configuration.agent_user}' ) - if config.service_model_path: - cmds.append( - f"runuser -l {config.agent_user} -s /bin/bash -c 'aws configure add-model --service-model file://{config.service_model_path}'" - ) - - if os.environ.get("DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE"): - LOG.info( - f"Using DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE: {os.environ.get('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE')}" - ) - cmds.insert( - 0, - f"runuser -l {config.agent_user} -s /bin/bash -c 'echo export DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE={os.environ.get('DEADLINE_WORKER_ALLOW_INSTANCE_PROFILE')} >> ~/.bashrc'", - ) - - if os.environ.get("AWS_ENDPOINT_URL_DEADLINE"): - LOG.info( - f"Using AWS_ENDPOINT_URL_DEADLINE: {os.environ.get('AWS_ENDPOINT_URL_DEADLINE')}" - ) - cmds.append( - f"runuser -l {config.agent_user} -s /bin/bash -c 'echo export AWS_ENDPOINT_URL_DEADLINE={os.environ.get('AWS_ENDPOINT_URL_DEADLINE')} >> ~/.bashrc'", - ) + cmds.append(self.configure_agent_user_environment(config)) return " && ".join(cmds) @@ -692,56 +786,23 @@ def userdata(self, s3_files) -> str: configure_job_users = "\n".join(job_users_cmds) userdata = f"""#!/bin/bash - # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - set -x - groupadd --system {self.configuration.job_user_group} - {configure_job_users} - {copy_s3_command} - - mkdir /opt/deadline - python3 -m venv /opt/deadline/worker - """ - - return userdata - - def start_worker_service(self): - LOG.info("Sending command to start the Worker Agent service") - - cmd_result = self.send_command("systemctl start deadline-worker") - - assert cmd_result.exit_code == 0, f"Failed to start Worker Agent service: {cmd_result}" - - def stop_worker_service(self): - LOG.info("Sending command to stop the Worker Agent service") - cmd_result = self.send_command("systemctl stop deadline-worker") - - assert cmd_result.exit_code == 0, f"Failed to start Worker Agent service: {cmd_result}" +# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +set -x +groupadd --system {self.configuration.job_user_group} +{configure_job_users} +{copy_s3_command} - def get_worker_id(self) -> str: - # There can be a race condition, so we may need to wait a little bit for the status file to be written. +mkdir /opt/deadline +python3 -m venv /opt/deadline/worker +""" - worker_state_filename = "/var/lib/deadline/worker.json" - cmd_result = self.send_command( - " && ".join( - [ - f"t=0 && while [ $t -le 10 ] && ! (test -f {worker_state_filename}); do sleep $t; t=$[$t+1]; done", - f"cat {worker_state_filename} | jq -r '.worker_id'", - ] - ) - ) - assert cmd_result.exit_code == 0, f"Failed to get Worker ID: {cmd_result}" - - worker_id = cmd_result.stdout.rstrip("\n\r") - assert re.match( - r"^worker-[0-9a-f]{32}$", worker_id - ), f"Got nonvalid Worker ID from command stdout: {cmd_result}" - return worker_id + return userdata def ami_ssm_param_name(self) -> str: # Grab the latest AL2023 AMI # https://aws.amazon.com/blogs/compute/query-for-the-latest-amazon-linux-ami-ids-using-aws-systems-manager-parameter-store/ ami_ssm_param: str = ( - f"/aws/service/ami-amazon-linux-latest/{PosixInstanceWorker.AL2023_AMI_NAME}" + f"/aws/service/ami-amazon-linux-latest/{PosixInstanceBuildWorker.AL2023_AMI_NAME}" ) return ami_ssm_param diff --git a/src/deadline_test_fixtures/fixtures.py b/src/deadline_test_fixtures/fixtures.py index de3ce68..3931c5b 100644 --- a/src/deadline_test_fixtures/fixtures.py +++ b/src/deadline_test_fixtures/fixtures.py @@ -29,8 +29,8 @@ DeadlineWorkerConfiguration, DockerContainerWorker, PipInstall, - PosixInstanceWorker, - WindowsInstanceWorker, + PosixInstanceBuildWorker, + WindowsInstanceBuildWorker, EC2InstanceWorker, ) from .models import ( @@ -496,9 +496,9 @@ def ec2_worker_type(request: pytest.FixtureRequest) -> Generator[Type[DeadlineWo operating_system = request.getfixturevalue("operating_system") if operating_system.name == "AL2023": - yield PosixInstanceWorker + yield PosixInstanceBuildWorker elif operating_system.name == "WIN2022": - yield WindowsInstanceWorker + yield WindowsInstanceBuildWorker else: raise ValueError( 'Invalid value provided for "operating_system", valid options are \'OperatingSystem("AL2023")\' or \'OperatingSystem("WIN2022")\'.' diff --git a/test/unit/deadline/test_worker.py b/test/unit/deadline/test_worker.py index dd27a71..a0c1072 100644 --- a/test/unit/deadline/test_worker.py +++ b/test/unit/deadline/test_worker.py @@ -17,7 +17,7 @@ CommandResult, DeadlineWorkerConfiguration, DockerContainerWorker, - PosixInstanceWorker, + PosixInstanceBuildWorker, PipInstall, CodeArtifactRepositoryInfo, S3Object, @@ -86,7 +86,7 @@ def worker_config(region: str) -> DeadlineWorkerConfiguration: ) -class TestPosixInstanceWorker: +class TestPosixInstanceBuildWorker: @staticmethod def describe_instance(instance_id: str) -> Any: ec2_client = boto3.client("ec2") @@ -148,8 +148,8 @@ def worker( security_group_id: str, instance_profile_name: str, bootstrap_bucket_name: str, - ) -> PosixInstanceWorker: - return PosixInstanceWorker( + ) -> PosixInstanceBuildWorker: + return PosixInstanceBuildWorker( subnet_id=subnet_id, security_group_id=security_group_id, instance_profile_name=instance_profile_name, @@ -164,7 +164,7 @@ def worker( ) @patch.object(mod, "open", mock_open(read_data="mock data".encode())) - def test_start(self, worker: PosixInstanceWorker) -> None: + def test_start(self, worker: PosixInstanceBuildWorker) -> None: # GIVEN s3_files = [ ("s3://bucket/key", "/tmp/key"), @@ -193,7 +193,7 @@ def test_start(self, worker: PosixInstanceWorker) -> None: def test_stage_s3_bucket( self, - worker: PosixInstanceWorker, + worker: PosixInstanceBuildWorker, worker_config: DeadlineWorkerConfiguration, bootstrap_bucket_name: str, ) -> None: @@ -221,7 +221,7 @@ def test_stage_s3_bucket( def test_launch_instance( self, - worker: PosixInstanceWorker, + worker: PosixInstanceBuildWorker, vpc_id: str, subnet_id: str, security_group_id: str, @@ -233,7 +233,7 @@ def test_launch_instance( # THEN assert worker.instance_id is not None - instance = TestPosixInstanceWorker.describe_instance(worker.instance_id) + instance = TestPosixInstanceBuildWorker.describe_instance(worker.instance_id) assert instance["ImageId"] == worker.ami_id assert instance["State"]["Name"] == "running" assert instance["SubnetId"] == subnet_id @@ -248,7 +248,7 @@ def test_launch_instance( def test_start_worker_agent(self) -> None: pass - def test_stop(self, worker: PosixInstanceWorker) -> None: + def test_stop(self, worker: PosixInstanceBuildWorker) -> None: # GIVEN # WHEN with patch.object( @@ -258,18 +258,18 @@ def test_stop(self, worker: PosixInstanceWorker) -> None: instance_id = worker.instance_id assert instance_id is not None - instance = TestPosixInstanceWorker.describe_instance(instance_id) + instance = TestPosixInstanceBuildWorker.describe_instance(instance_id) assert instance["State"]["Name"] == "running" worker.stop() # THEN - instance = TestPosixInstanceWorker.describe_instance(instance_id) + instance = TestPosixInstanceBuildWorker.describe_instance(instance_id) assert instance["State"]["Name"] == "terminated" assert worker.instance_id is None class TestSendCommand: - def test_sends_command(self, worker: PosixInstanceWorker) -> None: + def test_sends_command(self, worker: PosixInstanceBuildWorker) -> None: # GIVEN cmd = 'echo "Hello world"' # WHEN @@ -291,7 +291,7 @@ def test_sends_command(self, worker: PosixInstanceWorker) -> None: Parameters={"commands": ["set -eou pipefail; " + cmd]}, ) - def test_retries_when_instance_not_ready(self, worker: PosixInstanceWorker) -> None: + def test_retries_when_instance_not_ready(self, worker: PosixInstanceBuildWorker) -> None: # GIVEN cmd = 'echo "Hello world"' # WHEN @@ -329,7 +329,7 @@ def side_effect(*args, **kwargs): * 2 ) - def test_raises_any_other_error(self, worker: PosixInstanceWorker) -> None: + def test_raises_any_other_error(self, worker: PosixInstanceBuildWorker) -> None: # GIVEN cmd = 'echo "Hello world"' # WHEN @@ -362,7 +362,7 @@ def test_raises_any_other_error(self, worker: PosixInstanceWorker) -> None: "worker-7c3377ec9eba444bb51cc7da18463081\r\n", ], ) - def test_get_worker_id(self, worker_id: str, worker: PosixInstanceWorker) -> None: + def test_get_worker_id(self, worker_id: str, worker: PosixInstanceBuildWorker) -> None: # GIVEN with patch.object( worker, "send_command", return_value=CommandResult(exit_code=0, stdout=worker_id) @@ -373,7 +373,7 @@ def test_get_worker_id(self, worker_id: str, worker: PosixInstanceWorker) -> Non # THEN assert result == worker_id.rstrip("\n\r") - def test_ami_id(self, worker: PosixInstanceWorker) -> None: + def test_ami_id(self, worker: PosixInstanceBuildWorker) -> None: # WHEN ami_id = worker.ami_id