def test_tasks(env, scope_caps): scopes, expected_capabilities = scope_caps conf = PoolConfiguration( "test", { "artifacts": { "/some-file.txt": { "type": "file", "url": "project/fuzzing/private/file.txt", }, "/var/log/": { "type": "directory", "url": "project/fuzzing/private/var-log", }, }, "cloud": "gcp", "command": ["run-fuzzing.sh"], "container": "MozillaSecurity/fuzzer:latest", "cores_per_task": 1, "cpu": "x64", "cycle_time": "1h", "disk_size": "10g", "imageset": "anything", "macros": {}, "max_run_time": "30s", "metal": False, "minimum_memory_per_core": "1g", "name": "Amazing fuzzing pool", "parents": [], "platform": "linux", "preprocess": None, "schedule_start": None, "scopes": scopes, "tasks": 2, }, ) task_ids, tasks = zip(*conf.build_tasks("someTaskId", env=env)) # Check we have 2 valid generated task ids assert len(task_ids) == 2 assert all(map(slugid.decode, task_ids)) # Check we have 2 valid task definitions assert len(tasks) == 2 def _check_date(task, *keys): # Dates can not be checked directly as they are generated assert keys, "must specify at least one key" value = task for key in keys: obj = value assert isinstance(obj, dict) value = obj[key] assert isinstance(value, str) date = datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ") del obj[key] return date for i, task in enumerate(tasks): created = _check_date(task, "created") deadline = _check_date(task, "deadline") expires = _check_date(task, "expires") assert expires >= deadline > created expected_env = { "TASKCLUSTER_FUZZING_POOL": "test", "TASKCLUSTER_SECRET": "project/fuzzing/decision", } if env is not None: expected_env.update(env) log_expires = _check_date(task, "payload", "artifacts", "project/fuzzing/private/logs", "expires") assert log_expires == expires log_expires = _check_date(task, "payload", "artifacts", "project/fuzzing/private/file.txt", "expires") assert log_expires == expires log_expires = _check_date(task, "payload", "artifacts", "project/fuzzing/private/var-log", "expires") assert log_expires == expires assert set( task["scopes"]) == set(["secrets:get:project/fuzzing/decision"] + scopes) # scopes are already asserted above # - read the value for comparison instead of deleting the key, so the object is # printed in full on failure scopes = task["scopes"] assert task == { "dependencies": ["someTaskId"], "extra": {}, "metadata": { "description": ("*DO NOT EDIT* - This resource is configured automatically.\n\n" "Fuzzing resources generated by https://github.com/MozillaSecurity" "/orion/tree/master/services/fuzzing-decision"), "name": f"Fuzzing task linux-test - {i+1}/2", "owner": "*****@*****.**", "source": "https://github.com/MozillaSecurity/orion", }, "payload": { "artifacts": { "project/fuzzing/private/logs": { "path": "/logs/", "type": "directory", }, "project/fuzzing/private/file.txt": { "path": "/some-file.txt", "type": "file", }, "project/fuzzing/private/var-log": { "path": "/var/log/", "type": "directory", }, }, "cache": {}, "capabilities": expected_capabilities, "env": expected_env, "features": { "taskclusterProxy": True }, "image": "MozillaSecurity/fuzzer:latest", "maxRunTime": 30, }, "priority": "high", "provisionerId": "proj-fuzzing", "retries": 5, "routes": [], "schedulerId": "-", "scopes": scopes, "tags": {}, "taskGroupId": "someTaskId", "workerType": "linux-test", }
def test_gcp_resources(env, mock_clouds, mock_machines): conf = PoolConfiguration( "test", { "cloud": "gcp", "command": ["run-fuzzing.sh"], "container": "MozillaSecurity/fuzzer:latest", "cores_per_task": 2, "cpu": "x64", "cycle_time": "12h", "disk_size": "120g", "imageset": "docker-worker", "macros": {}, "max_run_time": "12h", "metal": False, "minimum_memory_per_core": "1g", "name": "Amazing fuzzing pool", "parents": [], "platform": "linux", "preprocess": None, "schedule_start": "1970-01-01T00:00:00Z", "scopes": [], "tasks": 3, }, ) resources = conf.build_resources(mock_clouds, mock_machines, env=env) assert len(resources) == 3 pool, hook, role = resources assert pool.to_json() == { "config": { "launchConfigs": [ { "capacityPerInstance": 1, "disks": [{ "autoDelete": True, "boot": True, "initializeParams": { "diskSizeGb": 120, "sourceImage": "path/to/image", }, "type": "PERSISTENT", }], "machineType": "zones/us-west1-a/machineTypes/2-cpus", "networkInterfaces": [{ "accessConfigs": [{ "type": "ONE_TO_ONE_NAT" }] }], "region": "us-west1", "scheduling": { "onHostMaintenance": "terminate" }, "workerConfig": { "dockerConfig": { "allowDisableSeccomp": True, "allowPrivileged": True, }, "genericWorker": { "config": { "deploymentId": "ff173b0660475975", "wstAudience": "communitytc", "wstServerURL": WST_URL, }, }, "shutdown": { "afterIdleSeconds": 15, "enabled": True }, }, "zone": "us-west1-a", }, { "capacityPerInstance": 1, "disks": [{ "autoDelete": True, "boot": True, "initializeParams": { "diskSizeGb": 120, "sourceImage": "path/to/image", }, "type": "PERSISTENT", }], "machineType": "zones/us-west1-b/machineTypes/2-cpus", "networkInterfaces": [{ "accessConfigs": [{ "type": "ONE_TO_ONE_NAT" }] }], "region": "us-west1", "scheduling": { "onHostMaintenance": "terminate" }, "workerConfig": { "dockerConfig": { "allowDisableSeccomp": True, "allowPrivileged": True, }, "genericWorker": { "config": { "deploymentId": "ff173b0660475975", "wstAudience": "communitytc", "wstServerURL": WST_URL, }, }, "shutdown": { "afterIdleSeconds": 15, "enabled": True }, }, "zone": "us-west1-b", }, { "capacityPerInstance": 1, "disks": [{ "autoDelete": True, "boot": True, "initializeParams": { "diskSizeGb": 120, "sourceImage": "path/to/image", }, "type": "PERSISTENT", }], "machineType": "zones/us-west1-a/machineTypes/more-ram", "networkInterfaces": [{ "accessConfigs": [{ "type": "ONE_TO_ONE_NAT" }] }], "region": "us-west1", "scheduling": { "onHostMaintenance": "terminate" }, "workerConfig": { "dockerConfig": { "allowDisableSeccomp": True, "allowPrivileged": True, }, "genericWorker": { "config": { "deploymentId": "ff173b0660475975", "wstAudience": "communitytc", "wstServerURL": WST_URL, }, }, "shutdown": { "afterIdleSeconds": 15, "enabled": True }, }, "zone": "us-west1-a", }, ], "lifecycle": { "registrationTimeout": 900, "reregistrationTimeout": 345600 }, "maxCapacity": 7, "minCapacity": 0, }, "description": ("*DO NOT EDIT* - This resource is configured automatically.\n\nFuzzing " "resources generated by https://github.com/MozillaSecurity/orion/tree" "/master/services/fuzzing-decision"), "emailOnError": True, "kind": "WorkerPool", "owner": "*****@*****.**", "providerId": "community-tc-workers-google", "workerPoolId": "proj-fuzzing/linux-test", } # Update env in valid hook valid_hook = copy.deepcopy(VALID_HOOK) if env is not None: valid_hook["task"]["payload"]["env"].update(env) assert hook.to_json() == valid_hook assert role.to_json() == VALID_ROLE
def test_tasks( env: Optional[Dict[str, str]], scope_caps, platform: str, run_as_admin: bool, mocker: MockerFixture, ) -> None: mocker.patch.dict( "fuzzing_decision.decision.pool.MountArtifactResolver.CACHE", {"orion.fuzzer.main": "task-mount-abc"}, ) scopes, expected_capabilities = scope_caps if run_as_admin: scopes.extend(( "generic-worker:os-group:proj-fuzzing/windows-test/Administrators", "generic-worker:run-as-administrator:proj-fuzzing/windows-test", )) conf = PoolConfiguration( "test", { "artifacts": { "/some-file.txt": { "type": "file", "url": "project/fuzzing/private/file.txt", }, "/var/log/": { "type": "directory", "url": "project/fuzzing/private/var-log", }, }, "cloud": "gcp", "command": ["run-fuzzing.sh"], "container": "MozillaSecurity/fuzzer:latest" if platform != "windows" else { "namespace": "orion.fuzzer.main", "type": "indexed-image", "path": "public/msys2.tar.bz2", }, "cores_per_task": 1, "cpu": "x64", "cycle_time": "1h", "disk_size": "10g", "imageset": "anything", "macros": {}, "max_run_time": "30s", "metal": False, "minimum_memory_per_core": "1g", "name": "Amazing fuzzing pool", "parents": [], "platform": platform, "preprocess": None, "schedule_start": None, "scopes": scopes, "tasks": 2, "run_as_admin": run_as_admin, }, ) task_ids, tasks = zip(*conf.build_tasks("someTaskId", env=env)) # Check we have 2 valid generated task ids assert len(task_ids) == 2 assert all(map(slugid.decode, task_ids)) # Check we have 2 valid task definitions assert len(tasks) == 2 def _get_date(value: str) -> datetime.datetime: assert isinstance(value, str) return datetime.datetime.strptime(value, "%Y-%m-%dT%H:%M:%S.%fZ") for i, task in enumerate(tasks): created = _get_date(task.pop("created")) deadline = _get_date(task.pop("deadline")) expires = _get_date(task.pop("expires")) assert expires >= deadline > created expected_env = { "TASKCLUSTER_FUZZING_POOL": "test", "TASKCLUSTER_SECRET": "project/fuzzing/decision", } if env is not None: expected_env.update(env) if platform == "windows": # translate to docker-worker style dict task["payload"]["artifacts"] = { artifact.pop("name"): artifact for artifact in task["payload"]["artifacts"] } assert expires == _get_date( task["payload"]["artifacts"]["project/fuzzing/private/logs"].pop( "expires")) assert expires == _get_date( task["payload"]["artifacts"] ["project/fuzzing/private/file.txt"].pop("expires")) assert expires == _get_date( task["payload"]["artifacts"] ["project/fuzzing/private/var-log"].pop("expires")) assert set( task["scopes"]) == set(["secrets:get:project/fuzzing/decision"] + scopes) # scopes are already asserted above # - read the value for comparison instead of deleting the key, so the object is # printed in full on failure scopes = task["scopes"] expected = { "dependencies": ["someTaskId"], "extra": {}, "metadata": { "description": ("*DO NOT EDIT* - This resource is configured automatically.\n\n" "Fuzzing resources generated by https://github.com/MozillaSecurity" "/orion/tree/master/services/fuzzing-decision"), "name": f"Fuzzing task {platform}-test - {i+1}/2", "owner": "*****@*****.**", "source": "https://github.com/MozillaSecurity/orion", }, "payload": { "artifacts": { "project/fuzzing/private/logs": { "path": "logs" if platform == "windows" else "/logs/", "type": "directory", }, "project/fuzzing/private/file.txt": { "path": "/some-file.txt", "type": "file", }, "project/fuzzing/private/var-log": { "path": "/var/log/", "type": "directory", }, }, "env": expected_env, "features": { "taskclusterProxy": True }, "maxRunTime": 30, }, "priority": "high", "provisionerId": "proj-fuzzing", "retries": 5, "routes": [], "schedulerId": "-", "scopes": scopes, "tags": {}, "taskGroupId": "someTaskId", "workerType": f"{platform}-test", } if platform == "windows": expected["dependencies"].append("task-mount-abc") expected["payload"]["mounts"] = [ { "content": { "artifact": "public/msys2.tar.bz2", "taskId": "task-mount-abc", }, "directory": ".", "format": "tar.bz2", }, ] if run_as_admin: expected["payload"]["osGroups"] = ["Administrators"] expected["payload"]["features"]["runAsAdministrator"] = True expected["payload"]["env"]["MSYSTEM"] = "MINGW64" # command is unique to windows, since we have no Docker entrypoint assert task["payload"]["command"] for cmd in task["payload"]["command"][:-1]: assert cmd.startswith("set ") assert task["payload"]["command"][-1] == "fuzzing-pool-launch" expected["payload"]["command"] = task["payload"]["command"] else: expected["payload"]["image"] = "MozillaSecurity/fuzzer:latest" if expected_capabilities: expected["payload"]["capabilities"] = expected_capabilities assert task == expected
def test_aws_resources(env, mock_clouds, mock_machines): conf = PoolConfiguration( "test", { "cloud": "aws", "command": ["run-fuzzing.sh"], "container": "MozillaSecurity/fuzzer:latest", "cores_per_task": 2, "cpu": "arm64", "cycle_time": "12h", "disk_size": "120g", "imageset": "generic-worker-A", "macros": {}, "max_run_time": "12h", "metal": False, "minimum_memory_per_core": "1g", "name": "Amazing fuzzing pool", "parents": [], "platform": "linux", "preprocess": None, "schedule_start": "1970-01-01T00:00:00Z", "scopes": [], "tasks": 3, }, ) resources = conf.build_resources(mock_clouds, mock_machines, env=env) assert len(resources) == 3 pool, hook, role = resources assert pool.to_json() == { "config": { "launchConfigs": [{ "capacityPerInstance": 1, "launchConfig": { "ImageId": "ami-1234", "InstanceMarketOptions": { "MarketType": "spot" }, "InstanceType": "a2", "Placement": { "AvailabilityZone": "us-west-1a" }, "SecurityGroupIds": ["sg-A"], "SubnetId": "subnet-XXX", }, "region": "us-west-1", "workerConfig": { "dockerConfig": { "allowDisableSeccomp": True, "allowPrivileged": True, }, "genericWorker": { "config": { "anyKey": "anyValue", "deploymentId": "d9465de45bdee4be", "os": "linux", "wstAudience": "communitytc", "wstServerURL": WST_URL, }, }, "shutdown": { "afterIdleSeconds": 15, "enabled": True }, }, }], "lifecycle": { "registrationTimeout": 900, "reregistrationTimeout": 345600 }, "maxCapacity": 7, "minCapacity": 0, }, "description": ("*DO NOT EDIT* - This resource is configured automatically.\n\nFuzzing " "resources generated by https://github.com/MozillaSecurity/orion/tree" "/master/services/fuzzing-decision"), "emailOnError": True, "kind": "WorkerPool", "owner": "*****@*****.**", "providerId": "community-tc-workers-aws", "workerPoolId": "proj-fuzzing/linux-test", } # Update env in valid hook valid_hook = copy.deepcopy(VALID_HOOK) if env is not None: valid_hook["task"]["payload"]["env"].update(env) assert hook.to_json() == valid_hook assert role.to_json() == VALID_ROLE
def test_aws_resources( env: Optional[Dict[str, str]], mock_clouds: Dict[str, Provider], mock_machines: MachineTypes, platform: str, ) -> None: conf = PoolConfiguration( "test", { "cloud": "aws", "command": ["run-fuzzing.sh"], "container": "MozillaSecurity/fuzzer:latest", "cores_per_task": 2, "cpu": "arm64", "cycle_time": "12h", "disk_size": "120g", "imageset": "generic-worker-A", "macros": {}, "max_run_time": "12h", "metal": False, "minimum_memory_per_core": "1g", "name": "Amazing fuzzing pool", "parents": [], "platform": platform, "preprocess": None, "schedule_start": "1970-01-01T00:00:00Z", "scopes": [], "tasks": 3, "run_as_admin": False, }, ) resources = list(conf.build_resources(mock_clouds, mock_machines, env=env)) assert len(resources) == 3 pool, hook, role = resources empty_str_dict: Dict[str, str] = {} expected: Dict[str, Any] = { "config": { "launchConfigs": [{ "capacityPerInstance": 1, "launchConfig": { "ImageId": "ami-1234", "InstanceMarketOptions": { "MarketType": "spot" }, "InstanceType": "a2", "Placement": { "AvailabilityZone": "us-west-1a" }, "SecurityGroupIds": ["sg-A"], "SubnetId": "subnet-XXX", }, "region": "us-west-1", "workerConfig": empty_str_dict, }], "maxCapacity": 6, "minCapacity": 0, }, "description": ("*DO NOT EDIT* - This resource is configured automatically.\n\nFuzzing " "resources generated by https://github.com/MozillaSecurity/orion/tree" "/master/services/fuzzing-decision"), "emailOnError": True, "kind": "WorkerPool", "owner": "*****@*****.**", "providerId": "community-tc-workers-aws", "workerPoolId": f"proj-fuzzing/{platform}-test", } if platform == "linux": expected["config"]["lifecycle"] = { "registrationTimeout": 900, "reregistrationTimeout": 345600, } expected["config"]["launchConfigs"][0]["workerConfig"].update({ "dockerConfig": { "allowDisableSeccomp": True, "allowPrivileged": True, }, "shutdown": { "afterIdleSeconds": 180, "enabled": True }, }) else: expected["config"]["launchConfigs"][0]["workerConfig"].update( { "genericWorker": { "config": { "anyKey": "anyValue", "deploymentId": "d82eac5c561913ee", "wstAudience": "communitytc", "wstServerURL": ("https://community-websocktunnel.services.mozilla.com" ), }, }, }, ) assert pool.to_json() == expected # Update env in valid hook valid_hook = _get_expected_hook(platform) if env is not None: valid_hook["task"]["payload"]["env"].update(env) assert hook.to_json() == valid_hook assert role.to_json() == _get_expected_role(platform)