f11e3183bb
* Initial attempt to mock AWS Media Live create_channel endpoint. Test fails. * Completes basic implementation of Media Live create_channel endpoint * Completes basic implementation of Media Live list_channels endpoint * Adds skaffolds for describe_channel and delete_channel * Adds unit test for delete_channel * Adds unit test for describe_channel * Reduces repetitive code by introducing a Channel model * Implements MediaLive start_channel and stop_channel endpoints * Fixes lack of support for the dash character in resource ARNs * Implements MediaLive update_channel endpoint. * Implements MediaLive create_input endpoint (and Input model). * Implements MediaLive describe_input endpoint. * Implements MediaLive list_inputs endpoint. * Implements MediaLive update_input endpoint. * Addse server tests for MediaLive * Adds further url patterns for medialive * Fixes url patterns * Fixes url patterns
303 lines
10 KiB
Python
303 lines
10 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from collections import OrderedDict
|
|
from uuid import uuid4
|
|
|
|
from boto3 import Session
|
|
|
|
from moto.core import BaseBackend, BaseModel
|
|
|
|
|
|
class Input(BaseModel):
|
|
def __init__(self, *args, **kwargs):
|
|
self.arn = kwargs.get("arn")
|
|
self.attached_channels = kwargs.get("attached_channels", [])
|
|
self.destinations = kwargs.get("destinations", [])
|
|
self.input_id = kwargs.get("input_id")
|
|
self.input_class = kwargs.get("input_class", "STANDARD")
|
|
self.input_devices = kwargs.get("input_devices", [])
|
|
self.input_source_type = kwargs.get("input_source_type", "STATIC")
|
|
self.media_connect_flows = kwargs.get("media_connect_flows", [])
|
|
self.name = kwargs.get("name")
|
|
self.role_arn = kwargs.get("role_arn")
|
|
self.security_groups = kwargs.get("security_groups", [])
|
|
self.sources = kwargs.get("sources", [])
|
|
# Possible states: 'CREATING'|'DETACHED'|'ATTACHED'|'DELETING'|'DELETED'
|
|
self.state = kwargs.get("state")
|
|
self.tags = kwargs.get("tags")
|
|
self.input_type = kwargs.get("input_type")
|
|
|
|
def to_dict(self):
|
|
data = {
|
|
"arn": self.arn,
|
|
"attachedChannels": self.attached_channels,
|
|
"destinations": self.destinations,
|
|
"id": self.input_id,
|
|
"inputClass": self.input_class,
|
|
"inputDevices": self.input_devices,
|
|
"inputSourceType": self.input_source_type,
|
|
"mediaConnectFlows": self.media_connect_flows,
|
|
"name": self.name,
|
|
"roleArn": self.role_arn,
|
|
"securityGroups": self.security_groups,
|
|
"sources": self.sources,
|
|
"state": self.state,
|
|
"tags": self.tags,
|
|
"type": self.input_type,
|
|
}
|
|
return data
|
|
|
|
def _resolve_transient_states(self):
|
|
# Resolve transient states before second call
|
|
# (to simulate AWS taking its sweet time with these things)
|
|
if self.state in ["CREATING"]:
|
|
self.state = "DETACHED" # or ATTACHED
|
|
elif self.state == "DELETING":
|
|
self.state = "DELETED"
|
|
|
|
|
|
class Channel(BaseModel):
|
|
def __init__(self, *args, **kwargs):
|
|
self.arn = kwargs.get("arn")
|
|
self.cdi_input_specification = kwargs.get("cdi_input_specification")
|
|
self.channel_class = kwargs.get("channel_class", "STANDARD")
|
|
self.destinations = kwargs.get("destinations")
|
|
self.egress_endpoints = kwargs.get("egress_endpoints", [])
|
|
self.encoder_settings = kwargs.get("encoder_settings")
|
|
self.channel_id = kwargs.get("channel_id")
|
|
self.input_attachments = kwargs.get("input_attachments")
|
|
self.input_specification = kwargs.get("input_specification")
|
|
self.log_level = kwargs.get("log_level")
|
|
self.name = kwargs.get("name")
|
|
self.pipeline_details = kwargs.get("pipeline_details", [])
|
|
self.role_arn = kwargs.get("role_arn")
|
|
self.state = kwargs.get("state")
|
|
self.tags = kwargs.get("tags")
|
|
self._previous_state = None
|
|
|
|
def to_dict(self, exclude=None):
|
|
data = {
|
|
"arn": self.arn,
|
|
"cdiInputSpecification": self.cdi_input_specification,
|
|
"channelClass": self.channel_class,
|
|
"destinations": self.destinations,
|
|
"egressEndpoints": self.egress_endpoints,
|
|
"encoderSettings": self.encoder_settings,
|
|
"id": self.channel_id,
|
|
"inputAttachments": self.input_attachments,
|
|
"inputSpecification": self.input_specification,
|
|
"logLevel": self.log_level,
|
|
"name": self.name,
|
|
"pipelineDetails": self.pipeline_details,
|
|
"pipelinesRunningCount": 1
|
|
if self.channel_class == "SINGLE_PIPELINE"
|
|
else 2,
|
|
"roleArn": self.role_arn,
|
|
"state": self.state,
|
|
"tags": self.tags,
|
|
}
|
|
if exclude:
|
|
for key in exclude:
|
|
del data[key]
|
|
return data
|
|
|
|
def _resolve_transient_states(self):
|
|
# Resolve transient states before second call
|
|
# (to simulate AWS taking its sweet time with these things)
|
|
if self.state in ["CREATING", "STOPPING"]:
|
|
self.state = "IDLE"
|
|
elif self.state == "STARTING":
|
|
self.state = "RUNNING"
|
|
elif self.state == "DELETING":
|
|
self.state = "DELETED"
|
|
elif self.state == "UPDATING":
|
|
self.state = self._previous_state
|
|
self._previous_state = None
|
|
|
|
|
|
class MediaLiveBackend(BaseBackend):
|
|
def __init__(self, region_name=None):
|
|
super(MediaLiveBackend, self).__init__()
|
|
self.region_name = region_name
|
|
self._channels = OrderedDict()
|
|
self._inputs = OrderedDict()
|
|
|
|
def reset(self):
|
|
region_name = self.region_name
|
|
self.__dict__ = {}
|
|
self.__init__(region_name)
|
|
|
|
def create_channel(
|
|
self,
|
|
cdi_input_specification,
|
|
channel_class,
|
|
destinations,
|
|
encoder_settings,
|
|
input_attachments,
|
|
input_specification,
|
|
log_level,
|
|
name,
|
|
request_id,
|
|
reserved,
|
|
role_arn,
|
|
tags,
|
|
):
|
|
channel_id = uuid4().hex
|
|
arn = "arn:aws:medialive:channel:{}".format(channel_id)
|
|
channel = Channel(
|
|
arn=arn,
|
|
cdi_input_specification=cdi_input_specification,
|
|
channel_class=channel_class or "STANDARD",
|
|
destinations=destinations,
|
|
egress_endpoints=[],
|
|
encoder_settings=encoder_settings,
|
|
channel_id=channel_id,
|
|
input_attachments=input_attachments,
|
|
input_specification=input_specification,
|
|
log_level=log_level,
|
|
name=name,
|
|
pipeline_details=[],
|
|
role_arn=role_arn,
|
|
state="CREATING",
|
|
tags=tags,
|
|
)
|
|
self._channels[channel_id] = channel
|
|
return channel
|
|
|
|
def list_channels(self, max_results, next_token):
|
|
channels = list(self._channels.values())
|
|
if max_results is not None:
|
|
channels = channels[:max_results]
|
|
response_channels = [
|
|
c.to_dict(exclude=["encoderSettings", "pipelineDetails"]) for c in channels
|
|
]
|
|
return response_channels, next_token
|
|
|
|
def describe_channel(self, channel_id):
|
|
channel = self._channels[channel_id]
|
|
channel._resolve_transient_states()
|
|
return channel.to_dict()
|
|
|
|
def delete_channel(self, channel_id):
|
|
channel = self._channels[channel_id]
|
|
channel.state = "DELETING"
|
|
return channel.to_dict()
|
|
|
|
def start_channel(self, channel_id):
|
|
channel = self._channels[channel_id]
|
|
channel.state = "STARTING"
|
|
return channel.to_dict()
|
|
|
|
def stop_channel(self, channel_id):
|
|
channel = self._channels[channel_id]
|
|
channel.state = "STOPPING"
|
|
return channel.to_dict()
|
|
|
|
def update_channel(
|
|
self,
|
|
channel_id,
|
|
cdi_input_specification,
|
|
destinations,
|
|
encoder_settings,
|
|
input_attachments,
|
|
input_specification,
|
|
log_level,
|
|
name,
|
|
role_arn,
|
|
):
|
|
channel = self._channels[channel_id]
|
|
channel.cdi_input_specification = cdi_input_specification
|
|
channel.destinations = destinations
|
|
channel.encoder_settings = encoder_settings
|
|
channel.input_attachments = input_attachments
|
|
channel.input_specification = input_specification
|
|
channel.log_level = log_level
|
|
channel.name = name
|
|
channel.role_arn = role_arn
|
|
|
|
channel._resolve_transient_states()
|
|
channel._previous_state = channel.state
|
|
channel.state = "UPDATING"
|
|
|
|
return channel
|
|
|
|
def create_input(
|
|
self,
|
|
destinations,
|
|
input_devices,
|
|
input_security_groups,
|
|
media_connect_flows,
|
|
name,
|
|
request_id,
|
|
role_arn,
|
|
sources,
|
|
tags,
|
|
type,
|
|
vpc,
|
|
):
|
|
input_id = uuid4().hex
|
|
arn = "arn:aws:medialive:input:{}".format(input_id)
|
|
a_input = Input(
|
|
arn=arn,
|
|
input_id=input_id,
|
|
destinations=destinations,
|
|
input_devices=input_devices,
|
|
input_security_groups=input_security_groups,
|
|
media_connect_flows=media_connect_flows,
|
|
name=name,
|
|
role_arn=role_arn,
|
|
sources=sources,
|
|
tags=tags,
|
|
input_type=type,
|
|
state="CREATING",
|
|
)
|
|
self._inputs[input_id] = a_input
|
|
return a_input
|
|
|
|
def describe_input(self, input_id):
|
|
a_input = self._inputs[input_id]
|
|
a_input._resolve_transient_states()
|
|
return a_input.to_dict()
|
|
|
|
def list_inputs(self, max_results, next_token):
|
|
inputs = list(self._inputs.values())
|
|
if max_results is not None:
|
|
inputs = inputs[:max_results]
|
|
response_inputs = [i.to_dict() for i in inputs]
|
|
return response_inputs, next_token
|
|
|
|
def delete_input(self, input_id):
|
|
a_input = self._inputs[input_id]
|
|
a_input.state = "DELETING"
|
|
return a_input.to_dict()
|
|
|
|
def update_input(
|
|
self,
|
|
destinations,
|
|
input_devices,
|
|
input_id,
|
|
input_security_groups,
|
|
media_connect_flows,
|
|
name,
|
|
role_arn,
|
|
sources,
|
|
):
|
|
a_input = self._inputs[input_id]
|
|
a_input.destinations = destinations
|
|
a_input.input_devices = input_devices
|
|
a_input.security_groups = input_security_groups
|
|
a_input.media_connect_flows = media_connect_flows
|
|
a_input.name = name
|
|
a_input.role_arn = role_arn
|
|
a_input.sources = sources
|
|
return a_input
|
|
|
|
|
|
medialive_backends = {}
|
|
for region in Session().get_available_regions("medialive"):
|
|
medialive_backends[region] = MediaLiveBackend()
|
|
for region in Session().get_available_regions("medialive", partition_name="aws-us-gov"):
|
|
medialive_backends[region] = MediaLiveBackend()
|
|
for region in Session().get_available_regions("medialive", partition_name="aws-cn"):
|
|
medialive_backends[region] = MediaLiveBackend()
|