Added create_job and describe_job to aws iot mock

This commit is contained in:
Stephan Huber 2018-05-09 09:22:12 +02:00
parent af7ac58d82
commit 4b4ce5acde
4 changed files with 337 additions and 13 deletions

View File

@ -58,6 +58,7 @@
- [ ] get_room
- [ ] get_room_skill_parameter
- [ ] get_skill_group
- [ ] list_device_events
- [ ] list_skills
- [ ] list_tags
- [ ] put_room_skill_parameter
@ -351,6 +352,7 @@
- [ ] delete_scaling_plan
- [ ] describe_scaling_plan_resources
- [ ] describe_scaling_plans
- [ ] update_scaling_plan
## batch - 93% implemented
- [ ] cancel_job
@ -434,6 +436,7 @@
- [ ] get_applied_schema_version
- [ ] get_directory
- [ ] get_facet
- [ ] get_object_attributes
- [ ] get_object_information
- [ ] get_schema_as_json
- [ ] get_typed_link_facet_information
@ -764,6 +767,8 @@
- [ ] create_pipeline
- [ ] delete_custom_action_type
- [ ] delete_pipeline
- [ ] delete_webhook
- [ ] deregister_webhook_with_third_party
- [ ] disable_stage_transition
- [ ] enable_stage_transition
- [ ] get_job_details
@ -774,6 +779,7 @@
- [ ] list_action_types
- [ ] list_pipeline_executions
- [ ] list_pipelines
- [ ] list_webhooks
- [ ] poll_for_jobs
- [ ] poll_for_third_party_jobs
- [ ] put_action_revision
@ -782,6 +788,8 @@
- [ ] put_job_success_result
- [ ] put_third_party_job_failure_result
- [ ] put_third_party_job_success_result
- [ ] put_webhook
- [ ] register_webhook_with_third_party
- [ ] retry_stage_execution
- [ ] start_pipeline_execution
- [ ] update_pipeline
@ -1057,6 +1065,7 @@
- [ ] create_project
- [ ] create_remote_access_session
- [ ] create_upload
- [ ] create_vpce_configuration
- [ ] delete_device_pool
- [ ] delete_instance_profile
- [ ] delete_network_profile
@ -1064,6 +1073,7 @@
- [ ] delete_remote_access_session
- [ ] delete_run
- [ ] delete_upload
- [ ] delete_vpce_configuration
- [ ] get_account_settings
- [ ] get_device
- [ ] get_device_instance
@ -1079,6 +1089,7 @@
- [ ] get_suite
- [ ] get_test
- [ ] get_upload
- [ ] get_vpce_configuration
- [ ] install_to_remote_access_session
- [ ] list_artifacts
- [ ] list_device_instances
@ -1098,6 +1109,7 @@
- [ ] list_tests
- [ ] list_unique_problems
- [ ] list_uploads
- [ ] list_vpce_configurations
- [ ] purchase_offering
- [ ] renew_offering
- [ ] schedule_run
@ -1108,6 +1120,7 @@
- [ ] update_instance_profile
- [ ] update_network_profile
- [ ] update_project
- [ ] update_vpce_configuration
## directconnect - 0% implemented
- [ ] allocate_connection_on_interconnect
@ -1264,7 +1277,7 @@
- [ ] update_radius
- [ ] verify_trust
## dynamodb - 22% implemented
## dynamodb - 21% implemented
- [ ] batch_get_item
- [ ] batch_write_item
- [ ] create_backup
@ -1276,6 +1289,7 @@
- [ ] describe_backup
- [ ] describe_continuous_backups
- [ ] describe_global_table
- [ ] describe_global_table_settings
- [ ] describe_limits
- [ ] describe_table
- [ ] describe_time_to_live
@ -1293,6 +1307,7 @@
- [ ] untag_resource
- [ ] update_continuous_backups
- [ ] update_global_table
- [ ] update_global_table_settings
- [ ] update_item
- [ ] update_table
- [ ] update_time_to_live
@ -1341,6 +1356,7 @@
- [ ] create_default_vpc
- [X] create_dhcp_options
- [ ] create_egress_only_internet_gateway
- [ ] create_fleet
- [ ] create_flow_logs
- [ ] create_fpga_image
- [X] create_image
@ -1375,6 +1391,7 @@
- [X] delete_customer_gateway
- [ ] delete_dhcp_options
- [ ] delete_egress_only_internet_gateway
- [ ] delete_fleets
- [ ] delete_flow_logs
- [ ] delete_fpga_image
- [X] delete_internet_gateway
@ -1416,6 +1433,9 @@
- [ ] describe_egress_only_internet_gateways
- [ ] describe_elastic_gpus
- [ ] describe_export_tasks
- [ ] describe_fleet_history
- [ ] describe_fleet_instances
- [ ] describe_fleets
- [ ] describe_flow_logs
- [ ] describe_fpga_image_attribute
- [ ] describe_fpga_images
@ -1512,6 +1532,7 @@
- [X] import_key_pair
- [ ] import_snapshot
- [ ] import_volume
- [ ] modify_fleet
- [ ] modify_fpga_image_attribute
- [ ] modify_hosts
- [ ] modify_id_format
@ -1884,8 +1905,11 @@
- [ ] delete_delivery_stream
- [ ] describe_delivery_stream
- [ ] list_delivery_streams
- [ ] list_tags_for_delivery_stream
- [ ] put_record
- [ ] put_record_batch
- [ ] tag_delivery_stream
- [ ] untag_delivery_stream
- [ ] update_destination
## fms - 0% implemented
@ -2375,7 +2399,7 @@
- [ ] unsubscribe_from_event
- [ ] update_assessment_target
## iot - 29% implemented
## iot - 30% implemented
- [ ] accept_certificate_transfer
- [X] add_thing_to_thing_group
- [ ] associate_targets_with_job
@ -2387,7 +2411,7 @@
- [ ] clear_default_authorizer
- [ ] create_authorizer
- [ ] create_certificate_from_csr
- [ ] create_job
- [X] create_job
- [X] create_keys_and_certificate
- [ ] create_ota_update
- [X] create_policy
@ -2420,7 +2444,7 @@
- [ ] describe_endpoint
- [ ] describe_event_configurations
- [ ] describe_index
- [ ] describe_job
- [X] describe_job
- [ ] describe_job_execution
- [ ] describe_role_alias
- [ ] describe_stream
@ -2512,6 +2536,38 @@
- [ ] start_next_pending_job_execution
- [ ] update_job_execution
## iotanalytics - 0% implemented
- [ ] batch_put_message
- [ ] cancel_pipeline_reprocessing
- [ ] create_channel
- [ ] create_dataset
- [ ] create_dataset_content
- [ ] create_datastore
- [ ] create_pipeline
- [ ] delete_channel
- [ ] delete_dataset
- [ ] delete_dataset_content
- [ ] delete_datastore
- [ ] delete_pipeline
- [ ] describe_channel
- [ ] describe_dataset
- [ ] describe_datastore
- [ ] describe_logging_options
- [ ] describe_pipeline
- [ ] get_dataset_content
- [ ] list_channels
- [ ] list_datasets
- [ ] list_datastores
- [ ] list_pipelines
- [ ] put_logging_options
- [ ] run_pipeline_activity
- [ ] sample_channel_data
- [ ] start_pipeline_reprocessing
- [ ] update_channel
- [ ] update_dataset
- [ ] update_datastore
- [ ] update_pipeline
## kinesis - 56% implemented
- [X] add_tags_to_stream
- [X] create_stream
@ -3513,6 +3569,9 @@
- [ ] update_tags_for_domain
- [ ] view_billing
## runtime.sagemaker - 0% implemented
- [ ] invoke_endpoint
## s3 - 15% implemented
- [ ] abort_multipart_upload
- [ ] complete_multipart_upload
@ -3938,6 +3997,7 @@
- [ ] delete_activation
- [ ] delete_association
- [ ] delete_document
- [ ] delete_inventory
- [ ] delete_maintenance_window
- [X] delete_parameter
- [X] delete_parameters
@ -3961,6 +4021,7 @@
- [ ] describe_instance_patch_states
- [ ] describe_instance_patch_states_for_patch_group
- [ ] describe_instance_patches
- [ ] describe_inventory_deletions
- [ ] describe_maintenance_window_execution_task_invocations
- [ ] describe_maintenance_window_execution_tasks
- [ ] describe_maintenance_window_executions
@ -4378,6 +4439,7 @@
- [ ] create_user
- [ ] delete_alias
- [ ] delete_group
- [ ] delete_mailbox_permissions
- [ ] delete_resource
- [ ] delete_user
- [ ] deregister_from_work_mail
@ -4390,35 +4452,48 @@
- [ ] list_aliases
- [ ] list_group_members
- [ ] list_groups
- [ ] list_mailbox_permissions
- [ ] list_organizations
- [ ] list_resource_delegates
- [ ] list_resources
- [ ] list_users
- [ ] put_mailbox_permissions
- [ ] register_to_work_mail
- [ ] reset_password
- [ ] update_primary_email_address
- [ ] update_resource
## workspaces - 0% implemented
- [ ] associate_ip_groups
- [ ] authorize_ip_rules
- [ ] create_ip_group
- [ ] create_tags
- [ ] create_workspaces
- [ ] delete_ip_group
- [ ] delete_tags
- [ ] describe_ip_groups
- [ ] describe_tags
- [ ] describe_workspace_bundles
- [ ] describe_workspace_directories
- [ ] describe_workspaces
- [ ] describe_workspaces_connection_status
- [ ] disassociate_ip_groups
- [ ] modify_workspace_properties
- [ ] modify_workspace_state
- [ ] reboot_workspaces
- [ ] rebuild_workspaces
- [ ] revoke_ip_rules
- [ ] start_workspaces
- [ ] stop_workspaces
- [ ] terminate_workspaces
- [ ] update_rules_of_ip_group
## xray - 0% implemented
- [ ] batch_get_traces
- [ ] get_encryption_config
- [ ] get_service_graph
- [ ] get_trace_graph
- [ ] get_trace_summaries
- [ ] put_encryption_config
- [ ] put_telemetry_records
- [ ] put_trace_segments

View File

@ -5,6 +5,9 @@ import string
import random
import hashlib
import uuid
import re
from datetime import datetime
from dateutil.tz import tzlocal
from moto.core import BaseBackend, BaseModel
from collections import OrderedDict
from .exceptions import (
@ -159,11 +162,76 @@ class FakePolicy(BaseModel):
}
class FakeJob(BaseModel):
JOB_ID_REGEX_PATTERN = "[a-zA-Z0-9_-]"
JOB_ID_REGEX = re.compile(JOB_ID_REGEX_PATTERN)
def __init__(self, job_id, targets, document_source, document, description, presigned_url_config, target_selection,
job_executions_rollout_config, document_parameters, region_name):
if not self._job_id_matcher(self.JOB_ID_REGEX, job_id):
raise InvalidRequestException()
self.region_name = region_name
self.job_id = job_id
self.job_arn = 'arn:aws:iot:%s:1:job/%s' % (self.region_name, job_id)
self.targets = targets
self.document_source = document_source
self.document = document
self.description = description
self.presigned_url_config = presigned_url_config
self.target_selection = target_selection
self.job_executions_rollout_config = job_executions_rollout_config
self.status = None # IN_PROGRESS | CANCELED | COMPLETED
self.comment = None
self.created_at = time.mktime(datetime(2015, 1, 1).timetuple())
self.last_updated_at = time.mktime(datetime(2015, 1, 1).timetuple())
self.completed_at = None
self.job_process_details = {
'processingTargets': targets,
'numberOfQueuedThings': 1,
'numberOfCanceledThings': 0,
'numberOfSucceededThings': 0,
'numberOfFailedThings': 0,
'numberOfRejectedThings': 0,
'numberOfInProgressThings': 0,
'numberOfRemovedThings': 0
}
self.document_parameters = document_parameters
def to_dict(self):
obj = {
'jobArn': self.job_arn,
'jobId': self.job_id,
'targets': self.targets,
'description': self.description,
'presignedUrlConfig': self.presigned_url_config,
'targetSelection': self.target_selection,
'jobExecutionsRolloutConfig': self.job_executions_rollout_config,
'status': self.status,
'comment': self.comment,
'createdAt': self.created_at,
'lastUpdatedAt': self.last_updated_at,
'completedAt': self.completedAt,
'jobProcessDetails': self.job_process_details,
'documentParameters': self.document_parameters,
'document': self.document,
'documentSource': self.document_source
}
return obj
def _job_id_matcher(self, regex, argument):
regex_match = regex.match(argument)
length_match = len(argument) <= 64
return regex_match and length_match
class IoTBackend(BaseBackend):
def __init__(self, region_name=None):
super(IoTBackend, self).__init__()
self.region_name = region_name
self.things = OrderedDict()
self.jobs = OrderedDict()
self.thing_types = OrderedDict()
self.thing_groups = OrderedDict()
self.certificates = OrderedDict()
@ -507,6 +575,16 @@ class IoTBackend(BaseBackend):
thing.thing_name, None
)
def create_job(self, job_id, targets, document_source, document, description, presigned_url_config,
target_selection, job_executions_rollout_config, document_parameters):
job = FakeJob(job_id, targets, document_source, document, description, presigned_url_config, target_selection,
job_executions_rollout_config, document_parameters, self.region_name)
self.jobs[job_id] = job
return job.job_arn, job_id, description
def describe_job(self, job_id):
return self.jobs[job_id]
available_regions = boto3.session.Session().get_available_regions("iot")
iot_backends = {region: IoTBackend(region) for region in available_regions}

View File

@ -102,6 +102,42 @@ class IoTResponse(BaseResponse):
)
return json.dumps(dict())
def create_job(self):
job_arn, job_id, description = self.iot_backend.create_job(
job_id=self._get_param("jobId"),
targets=self._get_param("targets"),
description=self._get_param("description"),
document_source=self._get_param("documentSource"),
document=self._get_param("document"),
presigned_url_config=self._get_param("presignedUrlConfig"),
target_selection=self._get_param("targetSelection"),
job_executions_rollout_config=self._get_param("jobExecutionsRolloutConfig"),
document_parameters=self._get_param("documentParameters")
)
return json.dumps(dict(jobArn=job_arn, jobId=job_id, description=description))
def describe_job(self):
job = self.iot_backend.describe_job(job_id=self._get_param("jobId"))
return json.dumps(dict(
documentSource=job.document_source,
job=dict(
comment=job.comment,
completedAt=job.completed_at,
createdAt=job.created_at,
description=job.description,
documentParameters=job.document_parameters,
jobArn=job.job_arn,
jobExecutionsRolloutConfig=job.job_executions_rollout_config,
jobId=job.job_id,
jobProcessDetails=job.job_process_details,
lastUpdatedAt=job.last_updated_at,
presignedUrlConfig=job.presigned_url_config,
status=job.status,
targets=job.targets,
targetSelection=job.target_selection
)))
def create_keys_and_certificate(self):
set_as_active = self._get_bool_param("setAsActive")
cert, key_pair = self.iot_backend.create_keys_and_certificate(

View File

@ -2,6 +2,7 @@ from __future__ import unicode_literals
import boto3
import sure # noqa
import json
from moto import mock_iot
@ -96,6 +97,7 @@ def test_certs():
res = client.list_certificates()
res.should.have.key('certificates').which.should.have.length_of(0)
@mock_iot
def test_certs_create_inactive():
client = boto3.client('iot', region_name='ap-northeast-1')
@ -113,6 +115,7 @@ def test_certs_create_inactive():
cert_desc = cert['certificateDescription']
cert_desc.should.have.key('status').which.should.equal('ACTIVE')
@mock_iot
def test_policy():
client = boto3.client('iot', region_name='ap-northeast-1')
@ -239,9 +242,9 @@ def test_thing_groups():
thing_group.should.have.key('thingGroupArn')
thing_group = client.describe_thing_group(thingGroupName=group_name)
thing_group.should.have.key('thingGroupProperties')\
.which.should.have.key('attributePayload')\
.which.should.have.key('attributes')
thing_group.should.have.key('thingGroupProperties') \
.which.should.have.key('attributePayload') \
.which.should.have.key('attributes')
res_props = thing_group['thingGroupProperties']['attributePayload']['attributes']
res_props.should.have.key('key1').which.should.equal('val01')
res_props.should.have.key('Key02').which.should.equal('VAL2')
@ -260,9 +263,9 @@ def test_thing_groups():
thingGroupProperties=new_props
)
thing_group = client.describe_thing_group(thingGroupName=group_name)
thing_group.should.have.key('thingGroupProperties')\
.which.should.have.key('attributePayload')\
.which.should.have.key('attributes')
thing_group.should.have.key('thingGroupProperties') \
.which.should.have.key('attributePayload') \
.which.should.have.key('attributes')
res_props = thing_group['thingGroupProperties']['attributePayload']['attributes']
res_props.should.have.key('key1').which.should.equal('val01')
res_props.should.have.key('Key02').which.should.equal('VAL2')
@ -282,9 +285,9 @@ def test_thing_groups():
thingGroupProperties=new_props
)
thing_group = client.describe_thing_group(thingGroupName=group_name)
thing_group.should.have.key('thingGroupProperties')\
.which.should.have.key('attributePayload')\
.which.should.have.key('attributes')
thing_group.should.have.key('thingGroupProperties') \
.which.should.have.key('attributePayload') \
.which.should.have.key('attributes')
res_props = thing_group['thingGroupProperties']['attributePayload']['attributes']
res_props.should.have.key('k4').which.should.equal('v4')
res_props.should_not.have.key('key1')
@ -383,3 +386,135 @@ def test_thing_group_relations():
)
things.should.have.key('things')
things['things'].should.have.length_of(0)
@mock_iot
def test_create_job():
client = boto3.client('iot', region_name='eu-west-1')
name = "my-thing"
job_id = "TestJob"
# thing
thing = client.create_thing(thingName=name)
thing.should.have.key('thingName').which.should.equal(name)
thing.should.have.key('thingArn')
# job document
job_document = {
"field": "value"
}
job = client.create_job(
jobId=job_id,
targets=[thing["thingArn"]],
document=json.dumps(job_document),
description="Description",
presignedUrlConfig={
'roleArn': 'arn:aws:iam::1:role/service-role/iot_job_role',
'expiresInSec': 123
},
targetSelection="CONTINUOUS",
jobExecutionsRolloutConfig={
'maximumPerMinute': 10
}
)
job.should.have.key('jobId').which.should.equal(job_id)
job.should.have.key('jobArn')
job.should.have.key('description')
@mock_iot
def test_describe_job():
client = boto3.client('iot', region_name='eu-west-1')
name = "my-thing"
job_id = "TestJob"
# thing
thing = client.create_thing(thingName=name)
thing.should.have.key('thingName').which.should.equal(name)
thing.should.have.key('thingArn')
job = client.create_job(
jobId=job_id,
targets=[thing["thingArn"]],
documentSource="https://s3-eu-west-1.amazonaws.com/bucket-name/job_document.json",
presignedUrlConfig={
'roleArn': 'arn:aws:iam::1:role/service-role/iot_job_role',
'expiresInSec': 123
},
targetSelection="CONTINUOUS",
jobExecutionsRolloutConfig={
'maximumPerMinute': 10
}
)
job.should.have.key('jobId').which.should.equal(job_id)
job.should.have.key('jobArn')
job = client.describe_job(jobId=job_id)
job.should.have.key('documentSource')
job.should.have.key('job')
job.should.have.key('job').which.should.have.key("jobArn")
job.should.have.key('job').which.should.have.key("jobId").which.should.equal(job_id)
job.should.have.key('job').which.should.have.key("targets")
job.should.have.key('job').which.should.have.key("jobProcessDetails")
job.should.have.key('job').which.should.have.key("lastUpdatedAt")
job.should.have.key('job').which.should.have.key("createdAt")
job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig")
job.should.have.key('job').which.should.have.key("targetSelection").which.should.equal("CONTINUOUS")
job.should.have.key('job').which.should.have.key("presignedUrlConfig")
job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key(
"roleArn").which.should.equal('arn:aws:iam::1:role/service-role/iot_job_role')
job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key(
"expiresInSec").which.should.equal(123)
job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig").which.should.have.key(
"maximumPerMinute").which.should.equal(10)
@mock_iot
def test_describe_job_1():
client = boto3.client('iot', region_name='eu-west-1')
name = "my-thing"
job_id = "TestJob"
# thing
thing = client.create_thing(thingName=name)
thing.should.have.key('thingName').which.should.equal(name)
thing.should.have.key('thingArn')
# job document
job_document = {
"field": "value"
}
job = client.create_job(
jobId=job_id,
targets=[thing["thingArn"]],
document=json.dumps(job_document),
presignedUrlConfig={
'roleArn': 'arn:aws:iam::1:role/service-role/iot_job_role',
'expiresInSec': 123
},
targetSelection="CONTINUOUS",
jobExecutionsRolloutConfig={
'maximumPerMinute': 10
}
)
job.should.have.key('jobId').which.should.equal(job_id)
job.should.have.key('jobArn')
job = client.describe_job(jobId=job_id)
job.should.have.key('job')
job.should.have.key('job').which.should.have.key("jobArn")
job.should.have.key('job').which.should.have.key("jobId").which.should.equal(job_id)
job.should.have.key('job').which.should.have.key("targets")
job.should.have.key('job').which.should.have.key("jobProcessDetails")
job.should.have.key('job').which.should.have.key("lastUpdatedAt")
job.should.have.key('job').which.should.have.key("createdAt")
job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig")
job.should.have.key('job').which.should.have.key("targetSelection").which.should.equal("CONTINUOUS")
job.should.have.key('job').which.should.have.key("presignedUrlConfig")
job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key(
"roleArn").which.should.equal('arn:aws:iam::1:role/service-role/iot_job_role')
job.should.have.key('job').which.should.have.key("presignedUrlConfig").which.should.have.key(
"expiresInSec").which.should.equal(123)
job.should.have.key('job').which.should.have.key("jobExecutionsRolloutConfig").which.should.have.key(
"maximumPerMinute").which.should.equal(10)