module AWS.EC2.Instance
( describeInstances
, runInstances
, defaultRunInstancesRequest
, terminateInstances
, startInstances
, stopInstances
, rebootInstances
, getConsoleOutput
, getPasswordData
, describeInstanceStatus
, describeInstanceAttribute
, resetInstanceAttribute
, modifyInstanceAttribute
, monitorInstances
, unmonitorInstances
) where
import Data.Text (Text)
import Data.XML.Types (Event)
import Data.Conduit
import Control.Applicative
import Data.Maybe (fromMaybe, fromJust)
import qualified Data.Map as Map
import Control.Monad
import AWS.EC2.Internal
import AWS.EC2.Types
import AWS.EC2.Params
import AWS.EC2.Query
import AWS.Lib.Parser
import AWS.Util
describeInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> [Filter]
-> EC2 m (ResumableSource m Reservation)
describeInstances instances filters = do
ec2QuerySource "DescribeInstances" params $
itemConduit "reservationSet" reservationSink
where
params =
[ "InstanceId" |.#= instances
, filtersParam filters
]
reservationSink :: MonadThrow m
=> GLSink Event m Reservation
reservationSink =
Reservation
<$> getT "reservationId"
<*> getT "ownerId"
<*> groupSetSink
<*> instanceSetSink
<*> getT "requesterId"
instanceSetSink :: MonadThrow m
=> GLSink Event m [Instance]
instanceSetSink = itemsSet "instancesSet" $
Instance
<$> getT "instanceId"
<*> getT "imageId"
<*> instanceStateSink "instanceState"
<*> getT "privateDnsName"
<*> getT "dnsName"
<*> getT "reason"
<*> getT "keyName"
<*> getT "amiLaunchIndex"
<*> productCodeSink
<*> getT "instanceType"
<*> getT "launchTime"
<*> element "placement" (
Placement
<$> getT "availabilityZone"
<*> getT "groupName"
<*> getT "tenancy"
)
<*> getT "kernelId"
<*> getT "ramdiskId"
<*> getT "platform"
<*> element "monitoring" (getT "state")
<*> getT "subnetId"
<*> getT "vpcId"
<*> getT "privateIpAddress"
<*> getT "ipAddress"
<*> getT "sourceDestCheck"
<*> groupSetSink
<*> stateReasonSink
<*> getT "architecture"
<*> getT "rootDeviceType"
<*> getT "rootDeviceName"
<*> instanceBlockDeviceMappingsSink
<*> getT "instanceLifecycle"
<*> getT "spotInstanceRequestId"
<*> getT "virtualizationType"
<*> getT "clientToken"
<*> resourceTagSink
<*> getT "hypervisor"
<*> networkInterfaceSink
<*> elementM "iamInstanceProfile" (
IamInstanceProfile
<$> getT "arn"
<*> getT "id"
)
<*> getT "ebsOptimized"
instanceBlockDeviceMappingsSink :: MonadThrow m
=> GLSink Event m [InstanceBlockDeviceMapping]
instanceBlockDeviceMappingsSink = itemsSet "blockDeviceMapping" (
InstanceBlockDeviceMapping
<$> getT "deviceName"
<*> element "ebs" (
EbsInstanceBlockDevice
<$> getT "volumeId"
<*> getT "status"
<*> getT "attachTime"
<*> getT "deleteOnTermination"
)
)
instanceStateCodes :: [(Int, InstanceState)]
instanceStateCodes =
[ ( 0, InstanceStatePending)
, (16, InstanceStateRunning)
, (32, InstanceStateShuttingDown)
, (48, InstanceStateTerminated)
, (64, InstanceStateStopping)
, (80, InstanceStateStopped)
]
codeToState :: Int -> Text -> InstanceState
codeToState code _name = fromMaybe
(InstanceStateUnknown code)
(lookup code instanceStateCodes)
instanceStateSink :: MonadThrow m
=> Text -> GLSink Event m InstanceState
instanceStateSink label = element label $ codeToState
<$> getT "code"
<*> getT "name"
networkInterfaceSink :: MonadThrow m
=> GLSink Event m [InstanceNetworkInterface]
networkInterfaceSink = itemsSet "networkInterfaceSet" $
InstanceNetworkInterface
<$> getT "networkInterfaceId"
<*> getT "subnetId"
<*> getT "vpcId"
<*> getT "description"
<*> getT "ownerId"
<*> getT "status"
<*> getT "macAddress"
<*> getT "privateIpAddress"
<*> getT "privateDnsName"
<*> getT "sourceDestCheck"
<*> groupSetSink
<*> element "attachment" (
InstanceNetworkInterfaceAttachment
<$> getT "attachmentId"
<*> getT "deviceIndex"
<*> getT "status"
<*> getT "attachTime"
<*> getT "deleteOnTermination"
)
<*> instanceNetworkInterfaceAssociationSink
<*> itemsSet "privateIpAddressesSet" (
InstancePrivateIpAddress
<$> getT "privateIpAddress"
<*> getT "privateDnsName"
<*> getT "primary"
<*> instanceNetworkInterfaceAssociationSink
)
instanceNetworkInterfaceAssociationSink :: MonadThrow m
=> GLSink Event m (Maybe InstanceNetworkInterfaceAssociation)
instanceNetworkInterfaceAssociationSink = elementM "association" $
InstanceNetworkInterfaceAssociation
<$> getT "publicIp"
<*> getT "publicDnsName"
<*> getT "ipOwnerId"
describeInstanceStatus
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> Bool
-> [Filter]
-> Maybe Text
-> EC2 m (ResumableSource m InstanceStatus)
describeInstanceStatus instanceIds isAll filters token =
ec2QuerySource' "DescribeInstanceStatus" params token instanceStatusSet
where
params =
[ "InstanceId" |.#= instanceIds
, "IncludeAllInstances" |= boolToText isAll
, filtersParam filters
]
instanceStatusSet :: MonadThrow m
=> GLConduit Event m InstanceStatus
instanceStatusSet = do
itemConduit "instanceStatusSet" $
InstanceStatus
<$> getT "instanceId"
<*> getT "availabilityZone"
<*> itemsSet "eventsSet" (
InstanceStatusEvent
<$> getT "code"
<*> getT "description"
<*> getT "notBefore"
<*> getT "notAfter"
)
<*> instanceStateSink "instanceState"
<*> instanceStatusTypeSink "systemStatus"
<*> instanceStatusTypeSink "instanceStatus"
instanceStatusTypeSink :: MonadThrow m
=> Text -> GLSink Event m InstanceStatusType
instanceStatusTypeSink name = element name $
InstanceStatusType
<$> getT "status"
<*> itemsSet "details" (
InstanceStatusDetail
<$> getT "name"
<*> getT "status"
<*> getT "impairedSince"
)
startInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> EC2 m (ResumableSource m InstanceStateChange)
startInstances instanceIds =
ec2QuerySource "StartInstances" params instanceStateChangeSet
where
params = ["InstanceId" |.#= instanceIds]
instanceStateChangeSet
:: (MonadResource m, MonadBaseControl IO m)
=> Conduit Event m InstanceStateChange
instanceStateChangeSet = itemConduit "instancesSet" $ do
InstanceStateChange
<$> getT "instanceId"
<*> instanceStateSink "currentState"
<*> instanceStateSink "previousState"
stopInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> Bool
-> EC2 m (ResumableSource m InstanceStateChange)
stopInstances instanceIds force =
ec2QuerySource "StopInstances" params instanceStateChangeSet
where
params =
[ "InstanceId" |.#= instanceIds
, "Force" |= boolToText force]
rebootInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> EC2 m Bool
rebootInstances instanceIds =
ec2Query "RebootInstances" params $ getT "return"
where
params = ["InstanceId" |.#= instanceIds]
terminateInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> EC2 m (ResumableSource m InstanceStateChange)
terminateInstances instanceIds =
ec2QuerySource "TerminateInstances" params
instanceStateChangeSet
where
params = ["InstanceId" |.#= instanceIds]
runInstances
:: (MonadResource m, MonadBaseControl IO m)
=> RunInstancesRequest
-> EC2 m Reservation
runInstances param =
ec2Query "RunInstances" params reservationSink
where
params =
[ "ImageId" |= runInstancesRequestImageId param
, "MinCount" |= toText (runInstancesRequestMinCount param)
, "MaxCount" |= toText (runInstancesRequestMaxCount param)
, "KeyName" |=? runInstancesRequestKeyName param
, "SecurityGroupId" |.#= runInstancesRequestSecurityGroupIds param
, "SecurityGroup" |.#= runInstancesRequestSecurityGroups param
, "UserData" |=? bsToText <$> runInstancesRequestUserData param
, "InstanceType" |=? runInstancesRequestInstanceType param
, "Placement" |.
[ "AvailabilityZone" |=?
runInstancesRequestAvailabilityZone param
, "GroupName" |=?
runInstancesRequestPlacementGroup param
, "Tenancy" |=?
runInstancesRequestTenancy param
]
, "KernelId" |=? runInstancesRequestKernelId param
, "RamdiskId" |=? runInstancesRequestRamdiskId param
, blockDeviceMappingsParam $
runInstancesRequestBlockDeviceMappings param
, "Monitoring" |.+ "Enabled" |=?
boolToText <$> runInstancesRequestMonitoringEnabled param
, "SubnetId" |=? runInstancesRequestSubnetId param
, "DisableApiTermination" |=?
boolToText <$> runInstancesRequestDisableApiTermination param
, "InstanceInitiatedShutdownBehavior" |=?
sbToText <$> runInstancesRequestShutdownBehavior param
, "PrivateIpAddress" |=?
toText <$> runInstancesRequestPrivateIpAddress param
, "ClientToken" |=? runInstancesRequestClientToken param
, "NetworkInterface" |.#. map networkInterfaceParams
(runInstancesRequestNetworkInterfaces param)
, "IamInstanceProfile" |.? iamInstanceProfileParams <$>
runInstancesRequestIamInstanceProfile param
, "EbsOptimized" |=?
boolToText <$> runInstancesRequestEbsOptimized param
]
iamInstanceProfileParams iam =
[ "Arn" |= iamInstanceProfileArn iam
, "Name" |= iamInstanceProfileId iam
]
defaultRunInstancesRequest
:: Text
-> Int
-> Int
-> RunInstancesRequest
defaultRunInstancesRequest iid minCount maxCount
= RunInstancesRequest
iid
minCount
maxCount
Nothing
[]
[]
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
[]
Nothing
Nothing
Nothing
Nothing
Nothing
Nothing
[]
Nothing
Nothing
networkInterfaceParams :: NetworkInterfaceParam -> [QueryParam]
networkInterfaceParams (NetworkInterfaceParamCreate di si d pia pias sgi dot) =
[ "DeviceIndex" |= toText di
, "SubnetId" |= si
, "Description" |= d
, "PrivateIpAddress" |=? toText <$> pia
, "SecurityGroupId" |.#= sgi
, "DeleteOnTermination" |= boolToText dot
] ++ s pias
where
s SecondaryPrivateIpAddressParamNothing = []
s (SecondaryPrivateIpAddressParamCount c) =
["SecondaryPrivateIpAddressCount" |= toText c]
s (SecondaryPrivateIpAddressParamSpecified addrs pr) =
[ privateIpAddressesParam "PrivateIpAddresses" addrs
, maybeParam $ ipAddressPrimaryParam <$> pr
]
ipAddressPrimaryParam i =
"PrivateIpAddresses" |.+ toText i |.+ "Primary" |= "true"
networkInterfaceParams (NetworkInterfaceParamAttach nid idx dot) =
[ "NetworkInterfaceId" |= nid
, "DeviceIndex" |= toText idx
, "DeleteOnTermination" |= boolToText dot
]
sbToText :: ShutdownBehavior -> Text
sbToText ShutdownBehaviorStop = "stop"
sbToText ShutdownBehaviorTerminate = "terminate"
getConsoleOutput
:: (MonadResource m, MonadBaseControl IO m)
=> Text
-> EC2 m ConsoleOutput
getConsoleOutput iid =
ec2Query "GetConsoleOutput" ["InstanceId" |= iid] $
ConsoleOutput
<$> getT "instanceId"
<*> getT "timestamp"
<*> getT "output"
getPasswordData
:: (MonadResource m, MonadBaseControl IO m)
=> Text
-> EC2 m PasswordData
getPasswordData iid =
ec2Query "GetPasswordData" ["InstanceId" |= iid] $
PasswordData
<$> getT "instanceId"
<*> getT "timestamp"
<*> getT "passwordData"
describeInstanceAttribute
:: (MonadResource m, MonadBaseControl IO m)
=> Text
-> InstanceAttributeRequest
-> EC2 m InstanceAttribute
describeInstanceAttribute iid attr =
ec2Query "DescribeInstanceAttribute" params
$ getT_ "instanceId" *> f attr
where
str = iar attr
params =
[ "InstanceId" |= iid
, "Attribute" |= str
]
f InstanceAttributeRequestBlockDeviceMapping = instanceBlockDeviceMappingsSink
>>= return . InstanceAttributeBlockDeviceMapping
f InstanceAttributeRequestProductCodes =
productCodeSink >>= return . InstanceAttributeProductCodes
f InstanceAttributeRequestGroupSet =
(itemsSet str $ getT "groupId")
>>= return . InstanceAttributeGroupSet
f req = valueSink str (fromJust $ Map.lookup req h)
h = Map.fromList
[ (InstanceAttributeRequestInstanceType,
InstanceAttributeInstanceType . fromJust)
, (InstanceAttributeRequestKernelId, InstanceAttributeKernelId)
, (InstanceAttributeRequestRamdiskId, InstanceAttributeRamdiskId)
, (InstanceAttributeRequestUserData, InstanceAttributeUserData)
, (InstanceAttributeRequestDisableApiTermination,
InstanceAttributeDisableApiTermination . just)
, (InstanceAttributeRequestShutdownBehavior,
InstanceAttributeShutdownBehavior
. fromJust . fromTextMay . fromJust)
, (InstanceAttributeRequestRootDeviceName,
InstanceAttributeRootDeviceName)
, (InstanceAttributeRequestSourceDestCheck,
InstanceAttributeSourceDestCheck
. fromTextMay . fromJust)
, (InstanceAttributeRequestEbsOptimized,
InstanceAttributeEbsOptimized . just)
]
just = fromJust . join . (fromTextMay <$>)
valueSink name val =
(element name $ getT "value") >>= return . val
iar :: InstanceAttributeRequest -> Text
iar InstanceAttributeRequestInstanceType = "instanceType"
iar InstanceAttributeRequestKernelId = "kernel"
iar InstanceAttributeRequestRamdiskId = "ramdisk"
iar InstanceAttributeRequestUserData = "userData"
iar InstanceAttributeRequestDisableApiTermination = "disableApiTermination"
iar InstanceAttributeRequestShutdownBehavior = "instanceInitiatedShutdownBehavior"
iar InstanceAttributeRequestRootDeviceName = "rootDeviceName"
iar InstanceAttributeRequestBlockDeviceMapping = "blockDeviceMapping"
iar InstanceAttributeRequestSourceDestCheck = "sourceDestCheck"
iar InstanceAttributeRequestGroupSet = "groupSet"
iar InstanceAttributeRequestProductCodes = "productCodes"
iar InstanceAttributeRequestEbsOptimized = "ebsOptimized"
riap :: ResetInstanceAttributeRequest -> Text
riap ResetInstanceAttributeRequestKernel = "kernel"
riap ResetInstanceAttributeRequestRamdisk = "ramdisk"
riap ResetInstanceAttributeRequestSourceDestCheck = "sourceDestCheck"
resetInstanceAttribute
:: (MonadResource m, MonadBaseControl IO m)
=> Text
-> ResetInstanceAttributeRequest
-> EC2 m Bool
resetInstanceAttribute iid attr =
ec2Query "ResetInstanceAttribute" params $ getT "return"
where
params =
[ "InstanceId" |= iid
, "Attribute" |= riap attr
]
modifyInstanceAttribute
:: (MonadResource m, MonadBaseControl IO m)
=> Text
-> [ModifyInstanceAttributeRequest]
-> EC2 m Bool
modifyInstanceAttribute iid attrs =
ec2Query "ModifyInstanceAttribute" params $ getT "return"
where
params = ("InstanceId" |= iid) : map miap attrs
miap :: ModifyInstanceAttributeRequest -> QueryParam
miap (ModifyInstanceAttributeRequestInstanceType a) =
"InstanceType" |.+ "Value" |= a
miap (ModifyInstanceAttributeRequestKernelId a) =
"Kernel" |.+ "Value" |= a
miap (ModifyInstanceAttributeRequestRamdiskId a) =
"Ramdisk" |.+ "Value" |= a
miap (ModifyInstanceAttributeRequestUserData a) =
"UserData" |.+ "Value" |= a
miap (ModifyInstanceAttributeRequestDisableApiTermination a) =
"DisableApiTermination" |.+ "Value" |= toText a
miap (ModifyInstanceAttributeRequestShutdownBehavior a) =
"InstanceInitiatedShutdownBehavior" |.+ "Value" |= sbToText a
miap (ModifyInstanceAttributeRequestRootDeviceName a) =
"RootDeviceName" |= a
miap (ModifyInstanceAttributeRequestBlockDeviceMapping a) =
blockDeviceMappingsParam a
miap (ModifyInstanceAttributeRequestSourceDestCheck a) =
"SourceDestCheck" |.+ "Value" |= toText a
miap (ModifyInstanceAttributeRequestGroupSet a) =
"GroupId" |.#= a
miap (ModifyInstanceAttributeRequestEbsOptimized a) =
"EbsOptimized" |= toText a
monitorInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> EC2 m (ResumableSource m MonitorInstancesResponse)
monitorInstances iids =
ec2QuerySource "MonitorInstances" ["InstanceId" |.#= iids]
monitorInstancesResponseSink
monitorInstancesResponseSink
:: (MonadResource m, MonadBaseControl IO m)
=> Conduit Event m MonitorInstancesResponse
monitorInstancesResponseSink = itemConduit "instancesSet" $
MonitorInstancesResponse
<$> getT "instanceId"
<*> element "monitoring" (getT "state")
unmonitorInstances
:: (MonadResource m, MonadBaseControl IO m)
=> [Text]
-> EC2 m (ResumableSource m MonitorInstancesResponse)
unmonitorInstances iids =
ec2QuerySource "UnmonitorInstances" ["InstanceId" |.#= iids]
monitorInstancesResponseSink