lucid-cumulus 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +29 -0
- data/LICENSE +202 -0
- data/README.md +41 -0
- data/autocomplete +137 -0
- data/bin/cumulus +658 -0
- data/cumulus +2 -0
- data/lib/autoscaling/AutoScaling.rb +40 -0
- data/lib/autoscaling/loader/Loader.rb +56 -0
- data/lib/autoscaling/manager/Manager.rb +360 -0
- data/lib/autoscaling/models/AlarmConfig.rb +165 -0
- data/lib/autoscaling/models/AlarmDiff.rb +172 -0
- data/lib/autoscaling/models/AutoScalingDiff.rb +178 -0
- data/lib/autoscaling/models/GroupConfig.rb +330 -0
- data/lib/autoscaling/models/PolicyConfig.rb +135 -0
- data/lib/autoscaling/models/PolicyDiff.rb +73 -0
- data/lib/autoscaling/models/ScheduledActionDiff.rb +53 -0
- data/lib/autoscaling/models/ScheduledConfig.rb +96 -0
- data/lib/aws_extensions/ec2/DhcpOptions.rb +41 -0
- data/lib/aws_extensions/ec2/Instance.rb +29 -0
- data/lib/aws_extensions/ec2/NetworkAcl.rb +25 -0
- data/lib/aws_extensions/ec2/NetworkInterface.rb +14 -0
- data/lib/aws_extensions/ec2/RouteTable.rb +26 -0
- data/lib/aws_extensions/ec2/SecurityGroup.rb +16 -0
- data/lib/aws_extensions/ec2/Subnet.rb +28 -0
- data/lib/aws_extensions/ec2/Volume.rb +24 -0
- data/lib/aws_extensions/ec2/Vpc.rb +14 -0
- data/lib/aws_extensions/ec2/VpcEndpoint.rb +11 -0
- data/lib/aws_extensions/elb/BackendServerDescription.rb +12 -0
- data/lib/aws_extensions/elb/PolicyDescription.rb +14 -0
- data/lib/aws_extensions/kinesis/StreamDescription.rb +12 -0
- data/lib/aws_extensions/route53/AliasTarget.rb +21 -0
- data/lib/aws_extensions/s3/Bucket.rb +33 -0
- data/lib/aws_extensions/s3/BucketAcl.rb +28 -0
- data/lib/aws_extensions/s3/BucketCors.rb +17 -0
- data/lib/aws_extensions/s3/BucketLifecycle.rb +21 -0
- data/lib/aws_extensions/s3/BucketLogging.rb +18 -0
- data/lib/aws_extensions/s3/BucketNotification.rb +23 -0
- data/lib/aws_extensions/s3/BucketPolicy.rb +18 -0
- data/lib/aws_extensions/s3/BucketTagging.rb +15 -0
- data/lib/aws_extensions/s3/BucketVersioning.rb +14 -0
- data/lib/aws_extensions/s3/BucketWebsite.rb +49 -0
- data/lib/aws_extensions/s3/CORSRule.rb +27 -0
- data/lib/aws_extensions/s3/ReplicationConfiguration.rb +22 -0
- data/lib/cloudfront/CloudFront.rb +83 -0
- data/lib/cloudfront/loader/Loader.rb +31 -0
- data/lib/cloudfront/manager/Manager.rb +183 -0
- data/lib/cloudfront/models/CacheBehaviorConfig.rb +237 -0
- data/lib/cloudfront/models/CacheBehaviorDiff.rb +211 -0
- data/lib/cloudfront/models/CustomOriginConfig.rb +51 -0
- data/lib/cloudfront/models/CustomOriginDiff.rb +74 -0
- data/lib/cloudfront/models/DistributionConfig.rb +183 -0
- data/lib/cloudfront/models/DistributionDiff.rb +131 -0
- data/lib/cloudfront/models/InvalidationConfig.rb +37 -0
- data/lib/cloudfront/models/OriginConfig.rb +144 -0
- data/lib/cloudfront/models/OriginDiff.rb +86 -0
- data/lib/cloudfront/models/OriginSslProtocols.rb +28 -0
- data/lib/cloudfront/models/OriginSslProtocolsDiff.rb +39 -0
- data/lib/common/BaseLoader.rb +80 -0
- data/lib/common/manager/Manager.rb +148 -0
- data/lib/common/models/Diff.rb +114 -0
- data/lib/common/models/ListChange.rb +21 -0
- data/lib/common/models/TagsDiff.rb +55 -0
- data/lib/common/models/UTCTimeSource.rb +17 -0
- data/lib/conf/Configuration.rb +365 -0
- data/lib/ec2/EC2.rb +503 -0
- data/lib/ec2/IPProtocolMapping.rb +165 -0
- data/lib/ec2/loaders/EbsLoader.rb +19 -0
- data/lib/ec2/loaders/InstanceLoader.rb +32 -0
- data/lib/ec2/managers/EbsManager.rb +176 -0
- data/lib/ec2/managers/InstanceManager.rb +509 -0
- data/lib/ec2/models/EbsGroupConfig.rb +133 -0
- data/lib/ec2/models/EbsGroupDiff.rb +48 -0
- data/lib/ec2/models/InstanceConfig.rb +202 -0
- data/lib/ec2/models/InstanceDiff.rb +95 -0
- data/lib/elb/ELB.rb +148 -0
- data/lib/elb/loader/Loader.rb +65 -0
- data/lib/elb/manager/Manager.rb +581 -0
- data/lib/elb/models/AccessLogConfig.rb +82 -0
- data/lib/elb/models/AccessLogDiff.rb +47 -0
- data/lib/elb/models/HealthCheckConfig.rb +91 -0
- data/lib/elb/models/HealthCheckDiff.rb +50 -0
- data/lib/elb/models/ListenerConfig.rb +99 -0
- data/lib/elb/models/ListenerDiff.rb +91 -0
- data/lib/elb/models/LoadBalancerConfig.rb +239 -0
- data/lib/elb/models/LoadBalancerDiff.rb +265 -0
- data/lib/iam/IAM.rb +36 -0
- data/lib/iam/loader/Loader.rb +117 -0
- data/lib/iam/manager/IamGroups.rb +98 -0
- data/lib/iam/manager/IamResource.rb +288 -0
- data/lib/iam/manager/IamRoles.rb +112 -0
- data/lib/iam/manager/IamUsers.rb +54 -0
- data/lib/iam/manager/Manager.rb +29 -0
- data/lib/iam/migration/AssumeRoleUnifier.rb +34 -0
- data/lib/iam/migration/PolicyUnifier.rb +90 -0
- data/lib/iam/models/GroupConfig.rb +40 -0
- data/lib/iam/models/IamDiff.rb +132 -0
- data/lib/iam/models/PolicyConfig.rb +67 -0
- data/lib/iam/models/ResourceWithPolicy.rb +208 -0
- data/lib/iam/models/RoleConfig.rb +53 -0
- data/lib/iam/models/StatementConfig.rb +35 -0
- data/lib/iam/models/UserConfig.rb +21 -0
- data/lib/kinesis/Kinesis.rb +94 -0
- data/lib/kinesis/loader/Loader.rb +19 -0
- data/lib/kinesis/manager/Manager.rb +206 -0
- data/lib/kinesis/models/StreamConfig.rb +75 -0
- data/lib/kinesis/models/StreamDiff.rb +58 -0
- data/lib/lambda/Lambda.rb +41 -0
- data/lib/route53/loader/Loader.rb +32 -0
- data/lib/route53/manager/Manager.rb +241 -0
- data/lib/route53/models/AliasTarget.rb +86 -0
- data/lib/route53/models/RecordConfig.rb +178 -0
- data/lib/route53/models/RecordDiff.rb +140 -0
- data/lib/route53/models/Vpc.rb +24 -0
- data/lib/route53/models/ZoneConfig.rb +156 -0
- data/lib/route53/models/ZoneDiff.rb +118 -0
- data/lib/s3/S3.rb +89 -0
- data/lib/s3/loader/Loader.rb +66 -0
- data/lib/s3/manager/Manager.rb +296 -0
- data/lib/s3/models/BucketConfig.rb +321 -0
- data/lib/s3/models/BucketDiff.rb +167 -0
- data/lib/s3/models/GrantConfig.rb +189 -0
- data/lib/s3/models/GrantDiff.rb +50 -0
- data/lib/s3/models/LifecycleConfig.rb +142 -0
- data/lib/s3/models/LifecycleDiff.rb +46 -0
- data/lib/s3/models/LoggingConfig.rb +81 -0
- data/lib/s3/models/NotificationConfig.rb +157 -0
- data/lib/s3/models/NotificationDiff.rb +62 -0
- data/lib/s3/models/ReplicationConfig.rb +133 -0
- data/lib/s3/models/ReplicationDiff.rb +60 -0
- data/lib/s3/models/WebsiteConfig.rb +107 -0
- data/lib/security/SecurityGroups.rb +39 -0
- data/lib/security/loader/Loader.rb +94 -0
- data/lib/security/manager/Manager.rb +246 -0
- data/lib/security/models/RuleConfig.rb +161 -0
- data/lib/security/models/RuleDiff.rb +72 -0
- data/lib/security/models/RuleMigration.rb +127 -0
- data/lib/security/models/SecurityGroupConfig.rb +172 -0
- data/lib/security/models/SecurityGroupDiff.rb +112 -0
- data/lib/sns/SNS.rb +40 -0
- data/lib/sqs/SQS.rb +62 -0
- data/lib/sqs/loader/Loader.rb +34 -0
- data/lib/sqs/manager/Manager.rb +128 -0
- data/lib/sqs/models/DeadLetterConfig.rb +70 -0
- data/lib/sqs/models/DeadLetterDiff.rb +35 -0
- data/lib/sqs/models/QueueConfig.rb +115 -0
- data/lib/sqs/models/QueueDiff.rb +89 -0
- data/lib/util/Colors.rb +111 -0
- data/lib/util/StatusCodes.rb +51 -0
- data/lib/vpc/loader/Loader.rb +73 -0
- data/lib/vpc/manager/Manager.rb +954 -0
- data/lib/vpc/models/AclEntryConfig.rb +150 -0
- data/lib/vpc/models/AclEntryDiff.rb +54 -0
- data/lib/vpc/models/DhcpConfig.rb +100 -0
- data/lib/vpc/models/DhcpDiff.rb +90 -0
- data/lib/vpc/models/EndpointConfig.rb +76 -0
- data/lib/vpc/models/EndpointDiff.rb +69 -0
- data/lib/vpc/models/NetworkAclConfig.rb +87 -0
- data/lib/vpc/models/NetworkAclDiff.rb +116 -0
- data/lib/vpc/models/RouteConfig.rb +82 -0
- data/lib/vpc/models/RouteDiff.rb +50 -0
- data/lib/vpc/models/RouteTableConfig.rb +92 -0
- data/lib/vpc/models/RouteTableDiff.rb +101 -0
- data/lib/vpc/models/SubnetConfig.rb +113 -0
- data/lib/vpc/models/SubnetDiff.rb +78 -0
- data/lib/vpc/models/VpcConfig.rb +173 -0
- data/lib/vpc/models/VpcDiff.rb +315 -0
- data/lucid-cumulus.gemspec +20 -0
- data/rakefile.rb +8 -0
- metadata +245 -0
@@ -0,0 +1,165 @@
|
|
1
|
+
module Cumulus
|
2
|
+
module EC2
|
3
|
+
class IPProtocolMapping
|
4
|
+
@@protocol_keyword = Hash[{
|
5
|
+
"-1" => "all",
|
6
|
+
"0" => "HOPOPT",
|
7
|
+
"1" => "ICMP",
|
8
|
+
"2" => "IGMP",
|
9
|
+
"3" => "GGP",
|
10
|
+
"4" => "IP-in-IP",
|
11
|
+
"5" => "ST",
|
12
|
+
"6" => "TCP",
|
13
|
+
"7" => "CBT",
|
14
|
+
"8" => "EGP",
|
15
|
+
"9" => "IGP",
|
16
|
+
"10" => "BBN-RCC-MON",
|
17
|
+
"11" => "NVP-II",
|
18
|
+
"12" => "PUP",
|
19
|
+
"13" => "ARGUS",
|
20
|
+
"14" => "EMCON",
|
21
|
+
"15" => "XNET",
|
22
|
+
"16" => "CHAOS",
|
23
|
+
"17" => "UDP",
|
24
|
+
"18" => "MUX",
|
25
|
+
"19" => "DCN-MEAS",
|
26
|
+
"20" => "HMP",
|
27
|
+
"21" => "PRM",
|
28
|
+
"22" => "XNS-IDP",
|
29
|
+
"23" => "TRUNK-1",
|
30
|
+
"24" => "TRUNK-2",
|
31
|
+
"25" => "LEAF-1",
|
32
|
+
"26" => "LEAF-2",
|
33
|
+
"27" => "RDP",
|
34
|
+
"28" => "IRTP",
|
35
|
+
"29" => "ISO-TP4",
|
36
|
+
"30" => "NETBLT",
|
37
|
+
"31" => "MFE-NSP",
|
38
|
+
"32" => "MERIT-INP",
|
39
|
+
"33" => "DCCP",
|
40
|
+
"34" => "3PC",
|
41
|
+
"35" => "IDPR",
|
42
|
+
"36" => "XTP",
|
43
|
+
"37" => "DDP",
|
44
|
+
"38" => "IDPR-CMTP",
|
45
|
+
"39" => "TP++",
|
46
|
+
"40" => "IL",
|
47
|
+
"41" => "IPv6",
|
48
|
+
"42" => "SDRP",
|
49
|
+
"43" => "IPv6-Route",
|
50
|
+
"44" => "IPv6-Frag",
|
51
|
+
"45" => "IDRP",
|
52
|
+
"46" => "RSVP",
|
53
|
+
"47" => "GRE",
|
54
|
+
"48" => "MHRP",
|
55
|
+
"49" => "BNA",
|
56
|
+
"50" => "ESP",
|
57
|
+
"51" => "AH",
|
58
|
+
"52" => "I-NLSP",
|
59
|
+
"53" => "SWIPE",
|
60
|
+
"54" => "NARP",
|
61
|
+
"55" => "MOBILE",
|
62
|
+
"56" => "TLSP",
|
63
|
+
"57" => "SKIP",
|
64
|
+
"58" => "IPv6-ICMP",
|
65
|
+
"59" => "IPv6-NoNxt",
|
66
|
+
"60" => "IPv6-Opts",
|
67
|
+
"61" => "61",
|
68
|
+
"62" => "CFTP",
|
69
|
+
"63" => "63",
|
70
|
+
"64" => "SAT-EXPAK",
|
71
|
+
"65" => "KRYPTOLAN",
|
72
|
+
"66" => "RVD",
|
73
|
+
"67" => "IPPC",
|
74
|
+
"68" => "68",
|
75
|
+
"69" => "SAT-MON",
|
76
|
+
"70" => "VISA",
|
77
|
+
"71" => "IPCU",
|
78
|
+
"72" => "CPNX",
|
79
|
+
"73" => "CPHB",
|
80
|
+
"74" => "WSN",
|
81
|
+
"75" => "PVP",
|
82
|
+
"76" => "BR-SAT-MON",
|
83
|
+
"77" => "SUN-ND",
|
84
|
+
"78" => "WB-MON",
|
85
|
+
"79" => "WB-EXPAK",
|
86
|
+
"80" => "ISO-IP",
|
87
|
+
"81" => "VMTP",
|
88
|
+
"82" => "SECURE-VMTP",
|
89
|
+
"83" => "VINES",
|
90
|
+
"85" => "NSFNET-IGP",
|
91
|
+
"86" => "DGP",
|
92
|
+
"87" => "TCF",
|
93
|
+
"88" => "EIGRP",
|
94
|
+
"89" => "OSPF",
|
95
|
+
"90" => "Sprite-RPC",
|
96
|
+
"91" => "LARP",
|
97
|
+
"92" => "MTP",
|
98
|
+
"93" => "AX.25",
|
99
|
+
"94" => "IPIP",
|
100
|
+
"95" => "MICP",
|
101
|
+
"96" => "SCC-SP",
|
102
|
+
"97" => "ETHERIP",
|
103
|
+
"98" => "ENCAP",
|
104
|
+
"99" => "99",
|
105
|
+
"100" => "GMTP",
|
106
|
+
"101" => "IFMP",
|
107
|
+
"102" => "PNNI",
|
108
|
+
"103" => "PIM",
|
109
|
+
"104" => "ARIS",
|
110
|
+
"105" => "SCPS",
|
111
|
+
"106" => "QNX",
|
112
|
+
"107" => "A/N",
|
113
|
+
"108" => "IPComp",
|
114
|
+
"109" => "SNP",
|
115
|
+
"110" => "Compaq-Peer",
|
116
|
+
"111" => "IPX-in-IP",
|
117
|
+
"112" => "VRRP",
|
118
|
+
"113" => "PGM",
|
119
|
+
"114" => "114",
|
120
|
+
"115" => "L2TP",
|
121
|
+
"116" => "DDX",
|
122
|
+
"117" => "IATP",
|
123
|
+
"118" => "STP",
|
124
|
+
"119" => "SRP",
|
125
|
+
"120" => "UTI",
|
126
|
+
"121" => "SMP",
|
127
|
+
"122" => "SM",
|
128
|
+
"123" => "PTP",
|
129
|
+
"124" => "IS-IS over IPv4",
|
130
|
+
"125" => "FIRE",
|
131
|
+
"126" => "CRTP",
|
132
|
+
"127" => "CRUDP",
|
133
|
+
"128" => "SSCOPMCE",
|
134
|
+
"129" => "IPLT",
|
135
|
+
"130" => "SPS",
|
136
|
+
"131" => "PIPE",
|
137
|
+
"132" => "SCTP",
|
138
|
+
"133" => "FC",
|
139
|
+
"134" => "RSVP-E2E-IGNORE",
|
140
|
+
"135" => "Mobility Header",
|
141
|
+
"136" => "UDPLite",
|
142
|
+
"137" => "MPLS-in-IP",
|
143
|
+
"138" => "manet",
|
144
|
+
"139" => "HIP",
|
145
|
+
"140" => "Shim6",
|
146
|
+
"141" => "WESP",
|
147
|
+
"142" => "ROHC"
|
148
|
+
}.map { |protocol, keyword| [protocol, keyword.downcase] }]
|
149
|
+
|
150
|
+
@@keyword_protocol = @@protocol_keyword.invert
|
151
|
+
|
152
|
+
@@special_cases = {
|
153
|
+
"84" => ["ttp", "iptm"]
|
154
|
+
}
|
155
|
+
|
156
|
+
def self.keyword(protocol)
|
157
|
+
@@protocol_keyword[protocol] || @@special_cases[protocol].first
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.protocol(keyword)
|
161
|
+
@@keyword_protocol[keyword.downcase] || @@special_cases.select { |k, v| v.include? keyword.downcase }.map { |k, _| k }.first
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "common/BaseLoader"
|
2
|
+
require "conf/Configuration"
|
3
|
+
require "ec2/models/EbsGroupConfig"
|
4
|
+
|
5
|
+
module Cumulus
|
6
|
+
module EC2
|
7
|
+
module EbsLoader
|
8
|
+
|
9
|
+
include Common::BaseLoader
|
10
|
+
|
11
|
+
@@groups_dir = Configuration.instance.ec2.ebs_directory
|
12
|
+
|
13
|
+
def self.groups
|
14
|
+
Common::BaseLoader::resources(@@groups_dir, &EbsGroupConfig.method(:new))
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "common/BaseLoader"
|
2
|
+
require "conf/Configuration"
|
3
|
+
|
4
|
+
require "base64"
|
5
|
+
|
6
|
+
module Cumulus
|
7
|
+
module EC2
|
8
|
+
module InstanceLoader
|
9
|
+
|
10
|
+
include Common::BaseLoader
|
11
|
+
|
12
|
+
@@instances_dir = Configuration.instance.ec2.instances_directory
|
13
|
+
@@user_data_dir = Configuration.instance.ec2.user_data_directory
|
14
|
+
|
15
|
+
def self.instances
|
16
|
+
Common::BaseLoader::resources(@@instances_dir, &InstanceConfig.method(:new))
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.user_data(file)
|
20
|
+
Common::BaseLoader::load_file(file, @@user_data_dir)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Public: Returns a Hash of user data file name to base64 of its contents.
|
24
|
+
def self.user_data_base64
|
25
|
+
@user_data_base64 ||= Hash[Common::BaseLoader::resources(@@user_data_dir, false, &Proc.new do |name, contents|
|
26
|
+
[name, Base64.encode64(contents)]
|
27
|
+
end)]
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
require "common/manager/Manager"
|
2
|
+
require "conf/Configuration"
|
3
|
+
require "ec2/EC2"
|
4
|
+
require "ec2/loaders/EbsLoader"
|
5
|
+
require "ec2/models/EbsGroupConfig"
|
6
|
+
require "ec2/models/EbsGroupDiff"
|
7
|
+
require "util/StatusCodes"
|
8
|
+
|
9
|
+
require "aws-sdk"
|
10
|
+
|
11
|
+
module Cumulus
|
12
|
+
module EC2
|
13
|
+
class EbsManager < Common::Manager
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
super()
|
17
|
+
@create_asset = true
|
18
|
+
@client = Aws::EC2::Client.new(Configuration.instance.client)
|
19
|
+
end
|
20
|
+
|
21
|
+
def resource_name
|
22
|
+
"EBS Volume Group"
|
23
|
+
end
|
24
|
+
|
25
|
+
def local_resources
|
26
|
+
@local_resources ||= Hash[EbsLoader.groups.map { |local| [local.name, local] }]
|
27
|
+
end
|
28
|
+
|
29
|
+
def aws_resources
|
30
|
+
@aws_resources ||= EC2::group_ebs_volumes
|
31
|
+
end
|
32
|
+
|
33
|
+
def unmanaged_diff(aws)
|
34
|
+
EbsGroupDiff.unmanaged(aws)
|
35
|
+
end
|
36
|
+
|
37
|
+
def added_diff(local)
|
38
|
+
EbsGroupDiff.added(local)
|
39
|
+
end
|
40
|
+
|
41
|
+
def diff_resource(local, aws)
|
42
|
+
local.diff(aws)
|
43
|
+
end
|
44
|
+
|
45
|
+
EbsMigrationData = Struct.new(:cumulus_group, :set_group_vols)
|
46
|
+
def migrate
|
47
|
+
puts Colors.blue("Migrating EBS Volume Groups...")
|
48
|
+
|
49
|
+
# Create the directories
|
50
|
+
ec2_dir = "#{@migration_root}/ec2"
|
51
|
+
ebs_dir = "#{ec2_dir}/ebs"
|
52
|
+
|
53
|
+
if !Dir.exists?(@migration_root)
|
54
|
+
Dir.mkdir(@migration_root)
|
55
|
+
end
|
56
|
+
if !Dir.exists?(ec2_dir)
|
57
|
+
Dir.mkdir(ec2_dir)
|
58
|
+
end
|
59
|
+
if !Dir.exists?(ebs_dir)
|
60
|
+
Dir.mkdir(ebs_dir)
|
61
|
+
end
|
62
|
+
|
63
|
+
puts "Would you like Cumulus to automatically update your volumes to have a Group tag that matches the name of the instance they are attached to? (y/n)"
|
64
|
+
update_tags = (STDIN.getc.downcase[0] == "y")
|
65
|
+
|
66
|
+
# Migrate any volumes that have already been grouped
|
67
|
+
vol_groups = Hash[EC2.group_ebs_volumes.map { |group_name, cumulus_group| [group_name, EbsMigrationData.new(cumulus_group, nil)] }]
|
68
|
+
|
69
|
+
# Use the instance name to group volumes if they do not have a group. Anything
|
70
|
+
# not attached should not get migrated
|
71
|
+
migratable_vols = EC2.ebs_volumes.select { |vol| vol.group.nil? and !vol.attachments.empty? and vol.attached? }
|
72
|
+
instance_grouped = migratable_vols.group_by do |vol|
|
73
|
+
attachments = vol.attachments.select { |att| att.state == "attached" || att.state == "attaching" }
|
74
|
+
attachments.first.instance_id
|
75
|
+
end
|
76
|
+
|
77
|
+
instance_grouped.each do |instance_id, vols|
|
78
|
+
instance_name = EC2.id_instances[instance_id].name || instance_id
|
79
|
+
vol_groups[instance_name] = EbsMigrationData.new(EbsGroupConfig.new(instance_name).populate!(vols), vols)
|
80
|
+
end
|
81
|
+
|
82
|
+
vol_groups.each do |group_name, data|
|
83
|
+
puts "Migrating group #{group_name}"
|
84
|
+
|
85
|
+
if update_tags and data.set_group_vols
|
86
|
+
data.set_group_vols.each do |vol|
|
87
|
+
if vol.group.nil?
|
88
|
+
set_group_name(vol.volume_id, group_name)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
json = JSON.pretty_generate(data.cumulus_group.to_hash)
|
94
|
+
File.open("#{ebs_dir}/#{group_name}.json", "w") { |f| f.write(json) }
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def create(local)
|
100
|
+
local.volume_groups.each do |vg|
|
101
|
+
vg.count.times do
|
102
|
+
create_volume(vg, local.availability_zone, local.name)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def update(local, diffs)
|
108
|
+
|
109
|
+
# If they tried to update AZ, use the old value
|
110
|
+
availability_zone = (diffs.select { |d| d.type == EbsGroupChange::AZ }.first.aws rescue local.availability_zone)
|
111
|
+
|
112
|
+
diffs.each do |diff|
|
113
|
+
case diff.type
|
114
|
+
when EbsGroupChange::AZ
|
115
|
+
puts Colors.blue("Availability zone cannot be updated")
|
116
|
+
when EbsGroupChange::VG_REMOVED
|
117
|
+
puts Colors.blue("Cumulus does not delete or detach volumes. Manually update #{diff.local.description}")
|
118
|
+
when EbsGroupChange::VG_ADDED
|
119
|
+
added_vg = diff.local
|
120
|
+
puts Colors.blue("Creating #{added_vg.count} x #{added_vg.description}...")
|
121
|
+
added_vg.count.times do
|
122
|
+
create_volume(added_vg, availability_zone, local.name)
|
123
|
+
end
|
124
|
+
when EbsGroupChange::VG_COUNT
|
125
|
+
if diff.local.count < diff.aws.count
|
126
|
+
puts Colors.blue("Cumulus will not delete or detach volumes. Manually update #{diff.local.description}")
|
127
|
+
else
|
128
|
+
num_added = diff.local.count - diff.aws.count
|
129
|
+
puts Colors.blue("Adding #{num_added} x #{diff.local.description}...")
|
130
|
+
num_added.times do
|
131
|
+
create_volume(diff.local, availability_zone, local.name)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
# Internal: Sets the Group tag for an ebs volume
|
141
|
+
def set_group_name(volume_id, group_name)
|
142
|
+
@client.create_tags({
|
143
|
+
resources: [volume_id],
|
144
|
+
tags: [
|
145
|
+
{
|
146
|
+
key: "Group",
|
147
|
+
value: group_name
|
148
|
+
}
|
149
|
+
]
|
150
|
+
})
|
151
|
+
end
|
152
|
+
|
153
|
+
# Internal: Creates a volume then sets the group name
|
154
|
+
#
|
155
|
+
# vg - the VolumeGroup config to use for volume attributes
|
156
|
+
# az - the availability zone to create the volume in
|
157
|
+
# group_name - the name of the group the volume belongs to
|
158
|
+
def create_volume(vg, az, group_name)
|
159
|
+
resp = @client.create_volume({
|
160
|
+
size: vg.size,
|
161
|
+
availability_zone: az,
|
162
|
+
volume_type: vg.type,
|
163
|
+
iops: vg.iops,
|
164
|
+
encrypted: vg.encrypted,
|
165
|
+
kms_key_id: vg.kms_key
|
166
|
+
})
|
167
|
+
|
168
|
+
set_group_name(resp.volume_id, group_name)
|
169
|
+
rescue => e
|
170
|
+
puts "Failed to create a volume of #{vg.description}: #{e}"
|
171
|
+
exit StatusCodes::EXCEPTION
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,509 @@
|
|
1
|
+
require "autoscaling/AutoScaling"
|
2
|
+
require "common/manager/Manager"
|
3
|
+
require "conf/Configuration"
|
4
|
+
require "ec2/EC2"
|
5
|
+
require "ec2/loaders/InstanceLoader"
|
6
|
+
require "ec2/models/InstanceConfig"
|
7
|
+
require "ec2/models/InstanceDiff"
|
8
|
+
require "iam/IAM"
|
9
|
+
require "util/StatusCodes"
|
10
|
+
|
11
|
+
require "aws-sdk"
|
12
|
+
require "base64"
|
13
|
+
|
14
|
+
module Cumulus
|
15
|
+
module EC2
|
16
|
+
class InstanceManager < Common::Manager
|
17
|
+
|
18
|
+
def initialize
|
19
|
+
super()
|
20
|
+
@create_asset = true
|
21
|
+
@client = Aws::EC2::Client.new(Configuration.instance.client)
|
22
|
+
@device_name_base = Configuration.instance.ec2.volume_mount_base
|
23
|
+
@device_name_start = Configuration.instance.ec2.volume_mount_start
|
24
|
+
@device_name_end = Configuration.instance.ec2.volume_mount_end
|
25
|
+
end
|
26
|
+
|
27
|
+
def resource_name
|
28
|
+
"EC2 Instance"
|
29
|
+
end
|
30
|
+
|
31
|
+
def local_resources
|
32
|
+
@local_resources ||= Hash[InstanceLoader.instances.map { |local| [local.name, local] }]
|
33
|
+
end
|
34
|
+
|
35
|
+
def aws_resources
|
36
|
+
@aws_resources ||=
|
37
|
+
EC2::named_instances
|
38
|
+
.reject { |name, i| AutoScaling::instance_ids.include?(i.instance_id) }
|
39
|
+
.select { |name, i| !Configuration.instance.ec2.ignore_unmanaged_instances || local_resources.has_key?(name) }
|
40
|
+
end
|
41
|
+
|
42
|
+
def unmanaged_diff(aws)
|
43
|
+
InstanceDiff.unmanaged(aws)
|
44
|
+
end
|
45
|
+
|
46
|
+
def added_diff(local)
|
47
|
+
InstanceDiff.added(local)
|
48
|
+
end
|
49
|
+
|
50
|
+
def diff_resource(local, aws)
|
51
|
+
puts Colors.blue("Processing #{local.name}...")
|
52
|
+
instance_attributes = EC2::id_instance_attributes(aws.instance_id)
|
53
|
+
user_data_file = InstanceLoader.user_data_base64.key(instance_attributes.user_data)
|
54
|
+
cumulus_version = InstanceConfig.new(local.name).populate!(aws, user_data_file, instance_attributes.tags)
|
55
|
+
|
56
|
+
local.diff(cumulus_version)
|
57
|
+
end
|
58
|
+
|
59
|
+
def migrate
|
60
|
+
puts Colors.blue("Migrating Instances...")
|
61
|
+
|
62
|
+
# Create the directories
|
63
|
+
ec2_dir = "#{@migration_root}/ec2"
|
64
|
+
instances_dir = "#{ec2_dir}/instances"
|
65
|
+
user_data_dir = "#{ec2_dir}/user-data-scripts"
|
66
|
+
|
67
|
+
if !Dir.exists?(@migration_root)
|
68
|
+
Dir.mkdir(@migration_root)
|
69
|
+
end
|
70
|
+
if !Dir.exists?(ec2_dir)
|
71
|
+
Dir.mkdir(ec2_dir)
|
72
|
+
end
|
73
|
+
if !Dir.exists?(instances_dir)
|
74
|
+
Dir.mkdir(instances_dir)
|
75
|
+
end
|
76
|
+
if !Dir.exists?(user_data_dir)
|
77
|
+
Dir.mkdir(user_data_dir)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Only migrate instances not in an autoscaling group
|
81
|
+
migratable_instances = EC2::named_instances.reject { |name, i| AutoScaling::instance_ids.include?(i.instance_id) }
|
82
|
+
puts "Will migrate #{migratable_instances.length} instances"
|
83
|
+
|
84
|
+
migratable_instances.each do |name, instance|
|
85
|
+
puts "Migrating #{name}..."
|
86
|
+
|
87
|
+
instance_attributes = EC2::id_instance_attributes(instance.instance_id)
|
88
|
+
|
89
|
+
# If there was user data set, migrate that too
|
90
|
+
if instance_attributes.user_data
|
91
|
+
user_data_file = "#{name}.sh"
|
92
|
+
file_location = "#{user_data_dir}/#{user_data_file}"
|
93
|
+
puts "Migrating user data script to #{file_location}"
|
94
|
+
file_contents = Base64.decode64(instance_attributes.user_data)
|
95
|
+
File.open(file_location, "w") { |f| f.write(file_contents) }
|
96
|
+
end
|
97
|
+
|
98
|
+
cumulus_instance = InstanceConfig.new(name).populate!(instance, user_data_file, instance_attributes.tags)
|
99
|
+
|
100
|
+
json = JSON.pretty_generate(cumulus_instance.to_hash)
|
101
|
+
File.open("#{instances_dir}/#{name}.json", "w") { |f| f.write(json) }
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
def create(local)
|
107
|
+
#######################################
|
108
|
+
# Make sure required attributes are set
|
109
|
+
#######################################
|
110
|
+
|
111
|
+
# Check for image
|
112
|
+
errors = []
|
113
|
+
image_id = local.image || Configuration.instance.ec2.default_image_id
|
114
|
+
if image_id.nil?
|
115
|
+
errors << "image is required"
|
116
|
+
end
|
117
|
+
|
118
|
+
# Check for IAM profile
|
119
|
+
profile_arn = if local.profile.nil?
|
120
|
+
errors << "profile is required"
|
121
|
+
nil
|
122
|
+
else
|
123
|
+
arn = IAM::get_instance_profile_arn(local.profile)
|
124
|
+
if arn.nil?
|
125
|
+
errors << "no profile named #{local.profile} exists"
|
126
|
+
end
|
127
|
+
arn
|
128
|
+
end
|
129
|
+
|
130
|
+
# Check for security groups
|
131
|
+
if local.security_groups.empty?
|
132
|
+
errors << "security-groups is required"
|
133
|
+
end
|
134
|
+
|
135
|
+
# Check for subnet
|
136
|
+
if local.subnet.nil?
|
137
|
+
errors << "subnet is required"
|
138
|
+
end
|
139
|
+
|
140
|
+
aws_subnet = EC2::named_subnets[local.subnet]
|
141
|
+
if aws_subnet.nil?
|
142
|
+
errors << "subnet #{local.subnet} does not exist"
|
143
|
+
end
|
144
|
+
|
145
|
+
# Get the vpc id from the subnet
|
146
|
+
vpc_id = aws_subnet.vpc_id
|
147
|
+
|
148
|
+
security_group_ids = local.security_groups.map do |sg|
|
149
|
+
sg_id = SecurityGroups.vpc_security_group_id_names[vpc_id].key(sg)
|
150
|
+
if sg_id.nil?
|
151
|
+
errors << "security group #{sg} does not exist"
|
152
|
+
end
|
153
|
+
sg_id
|
154
|
+
end
|
155
|
+
|
156
|
+
# Check for type
|
157
|
+
if local.type.nil?
|
158
|
+
errors << "type is required"
|
159
|
+
end
|
160
|
+
|
161
|
+
# Make sure the placement group exists
|
162
|
+
if !local.placement_group.nil? and EC2::named_placement_groups[local.placement_group].nil?
|
163
|
+
errors << "placement group #{local.placement_group} does not exist"
|
164
|
+
end
|
165
|
+
|
166
|
+
availability_zone = if aws_subnet then aws_subnet.availability_zone end
|
167
|
+
|
168
|
+
# Check for volume groups
|
169
|
+
volumes = if !local.volume_groups.empty?
|
170
|
+
# Try to get the volumes for each volume group, make sure they are in the right AZ
|
171
|
+
local.volume_groups.map do |vg|
|
172
|
+
vols = EC2::group_ebs_volumes_aws[vg]
|
173
|
+
if vols.nil?
|
174
|
+
errors << "volume group #{vg} does not exist"
|
175
|
+
elsif vols.empty?
|
176
|
+
errors << "could not find volumes for group #{vg}"
|
177
|
+
else
|
178
|
+
if availability_zone and vols.any? { |vol| vol.availability_zone != availability_zone }
|
179
|
+
errors << "not all volumes in #{vg} are in the correct availability zone: #{availability_zone}"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
vols
|
183
|
+
end.flatten
|
184
|
+
else
|
185
|
+
puts "Warning: Only the root volume will be attached to the instance"
|
186
|
+
[]
|
187
|
+
end
|
188
|
+
|
189
|
+
# Make sure there are not more volumes than device names for volumes
|
190
|
+
if (@device_name_end.ord - @device_name_start.ord + 1) < volumes.length
|
191
|
+
errors << "cannot attach more volumes than there are names for between #{@device_name_base}#{@device_name_start} and #{@device_name_base}#{@device_name_end}"
|
192
|
+
end
|
193
|
+
|
194
|
+
if !errors.empty?
|
195
|
+
puts "Could not create #{local.name}:"
|
196
|
+
errors.each { |e| puts "\t#{e}"}
|
197
|
+
exit StatusCodes::EXCEPTION
|
198
|
+
end
|
199
|
+
|
200
|
+
created_instance = @client.run_instances({
|
201
|
+
image_id: image_id,
|
202
|
+
min_count: 1,
|
203
|
+
max_count: 1,
|
204
|
+
key_name: local.key_name,
|
205
|
+
security_group_ids: if local.network_interfaces == 0 then security_group_ids end,
|
206
|
+
user_data: if local.user_data then Base64.encode64(InstanceLoader.user_data(local.user_data)) end,
|
207
|
+
instance_type: local.type,
|
208
|
+
subnet_id: if local.network_interfaces == 0 then aws_subnet.subnet_id end,
|
209
|
+
placement: {
|
210
|
+
availability_zone: availability_zone,
|
211
|
+
group_name: local.placement_group,
|
212
|
+
tenancy: local.tenancy,
|
213
|
+
},
|
214
|
+
monitoring: {
|
215
|
+
enabled: local.monitoring
|
216
|
+
},
|
217
|
+
private_ip_address: if local.network_interfaces == 0 then local.private_ip_address end,
|
218
|
+
network_interfaces: Array.new(local.network_interfaces) do |index|
|
219
|
+
{
|
220
|
+
subnet_id: aws_subnet.subnet_id,
|
221
|
+
groups: security_group_ids,
|
222
|
+
delete_on_termination: true,
|
223
|
+
device_index: index,
|
224
|
+
private_ip_addresses: if local.network_interfaces == 1 and local.private_ip_address
|
225
|
+
[
|
226
|
+
{
|
227
|
+
private_ip_address: local.private_ip_address,
|
228
|
+
primary: true
|
229
|
+
}
|
230
|
+
]
|
231
|
+
end
|
232
|
+
}
|
233
|
+
end,
|
234
|
+
iam_instance_profile: {
|
235
|
+
arn: profile_arn
|
236
|
+
},
|
237
|
+
ebs_optimized: local.ebs_optimized
|
238
|
+
}).instances.first
|
239
|
+
|
240
|
+
# Wait until the instance is running then attach volumes
|
241
|
+
print "Waiting for instance to run"
|
242
|
+
@client.wait_until(:instance_running, {
|
243
|
+
instance_ids: [created_instance.instance_id]
|
244
|
+
}) do |waiter|
|
245
|
+
waiter.before_wait { print "." }
|
246
|
+
end
|
247
|
+
puts ""
|
248
|
+
|
249
|
+
if !local.tags.empty?
|
250
|
+
set_tags(created_instance.instance_id, local.tags)
|
251
|
+
end
|
252
|
+
set_name(created_instance.instance_id, local.name)
|
253
|
+
|
254
|
+
if created_instance.source_dest_check != local.source_dest_check
|
255
|
+
set_instance_source_dest_check(created_instance.instance_id, local.source_dest_check)
|
256
|
+
end
|
257
|
+
|
258
|
+
# If there are multiple network interfaces, source dest check must be set on each one
|
259
|
+
if created_instance.network_interfaces.length > 1
|
260
|
+
created_instance.network_interfaces.each do |interface|
|
261
|
+
set_interface_source_dest_check(interface.network_interface_id, local.source_dest_check)
|
262
|
+
end
|
263
|
+
else
|
264
|
+
set_instance_source_dest_check(created_instance.instance_id, local.source_dest_check)
|
265
|
+
end
|
266
|
+
|
267
|
+
# Attach volume groups
|
268
|
+
attach_volumes(created_instance.instance_id, volumes, @device_name_start)
|
269
|
+
|
270
|
+
end
|
271
|
+
|
272
|
+
def update(local, diffs)
|
273
|
+
aws_instance = EC2::named_instances[local.name]
|
274
|
+
|
275
|
+
diffs.each do |diff|
|
276
|
+
case diff.type
|
277
|
+
when InstanceChange::PROFILE,
|
278
|
+
InstanceChange::SUBNET,
|
279
|
+
InstanceChange::TYPE,
|
280
|
+
InstanceChange::TENANCY
|
281
|
+
|
282
|
+
puts Colors.red("Cannot change #{diff.asset_type}")
|
283
|
+
when InstanceChange::EBS
|
284
|
+
if !aws_instance.stopped?
|
285
|
+
puts Colors.red("Cannot update EBS Optimized unless the instance is stopped")
|
286
|
+
else
|
287
|
+
puts "Setting EBS Optimized to #{local.ebs_optimized}..."
|
288
|
+
set_ebs_optimized(aws_instance.instance_id, local.ebs_optimized)
|
289
|
+
end
|
290
|
+
when InstanceChange::MONITORING
|
291
|
+
if local.monitoring
|
292
|
+
puts "Enabling monitoring..."
|
293
|
+
set_monitoring(aws_instance.instance_id, true)
|
294
|
+
else
|
295
|
+
puts "Disabling monitoring..."
|
296
|
+
set_monitoring(aws_instance.instance_id, false)
|
297
|
+
end
|
298
|
+
when InstanceChange::SECURITY_GROUPS
|
299
|
+
puts "Updating Security Groups..."
|
300
|
+
|
301
|
+
# If there are multiple network interfaces, security groups must be set on each one
|
302
|
+
if aws_instance.network_interfaces.length > 1
|
303
|
+
aws_instance.network_interfaces.each do |interface|
|
304
|
+
set_interface_security_groups(aws_instance.vpc_id, interface.network_interface_id, local.security_groups)
|
305
|
+
end
|
306
|
+
else
|
307
|
+
set_instance_security_groups(aws_instance.vpc_id, aws_instance.instance_id, local.security_groups)
|
308
|
+
end
|
309
|
+
|
310
|
+
when InstanceChange::SDCHECK
|
311
|
+
puts "Setting Source Dest Check to #{local.source_dest_check}..."
|
312
|
+
|
313
|
+
# If there are multiple network interfaces, source dest check must be set on each one
|
314
|
+
if aws_instance.network_interfaces.length > 1
|
315
|
+
aws_instance.network_interfaces.each do |interface|
|
316
|
+
set_interface_source_dest_check(interface.network_interface_id, local.source_dest_check)
|
317
|
+
end
|
318
|
+
else
|
319
|
+
set_instance_source_dest_check(aws_instance.instance_id, local.source_dest_check)
|
320
|
+
end
|
321
|
+
when InstanceChange::INTERFACES
|
322
|
+
if diff.aws > diff.local
|
323
|
+
puts Colors.red("Cumulus will not detach or delete network interfaces. You must do so manually and update the config")
|
324
|
+
else
|
325
|
+
# Figure out highest device index for current interfaces
|
326
|
+
highest_device_index = (aws_instance.network_interfaces.map(&:attachment).map(&:device_index).max || 0) + 1
|
327
|
+
|
328
|
+
(diff.local - diff.aws).times do |i|
|
329
|
+
puts "Creating network interface..."
|
330
|
+
interface_id = create_network_interface(aws_instance.vpc_id, aws_instance.subnet_id, local.security_groups)
|
331
|
+
set_interface_source_dest_check(interface_id, local.source_dest_check)
|
332
|
+
|
333
|
+
puts "Attaching network interface..."
|
334
|
+
attachment_id = attach_network_interface(aws_instance.instance_id, interface_id, highest_device_index + i)
|
335
|
+
set_delete_on_terminate(interface_id, attachment_id)
|
336
|
+
end
|
337
|
+
end
|
338
|
+
when InstanceChange::VOLUME_GROUPS
|
339
|
+
# Figure out the highest device name for already attached volumes
|
340
|
+
last_device_name = aws_instance.nonroot_devices.map(&:device_name).sort.last
|
341
|
+
start_attaching_at = if last_device_name then (last_device_name[-1].ord + 1).chr else @start_device_letter end
|
342
|
+
|
343
|
+
# Figure out which volumes in the group are not attached
|
344
|
+
volumes_to_attach = diff.local.map { |group_name, group_config| EC2::group_ebs_volumes_aws[group_name] }.flatten.select(&:detached?)
|
345
|
+
|
346
|
+
# Make sure there are not more volumes than device names for volumes
|
347
|
+
if start_attaching_at.ord > @device_name_end.ord
|
348
|
+
puts Colors.red("Cannot attach volumes past #{@device_name_base}#{@device_name_end}")
|
349
|
+
elsif (@device_name_end.ord - start_attaching_at.ord + 1) < volumes_to_attach.length
|
350
|
+
puts Colors.red("Cannot attach more volumes than there are names for between #{@device_name_base}#{start_attaching_at} and #{@device_name_base}#{@device_name_end}")
|
351
|
+
else
|
352
|
+
attach_volumes(aws_instance.instance_id, volumes_to_attach, start_attaching_at)
|
353
|
+
end
|
354
|
+
when InstanceChange::TAGS
|
355
|
+
puts "Updating tags..."
|
356
|
+
|
357
|
+
if !diff.tags_to_remove.empty?
|
358
|
+
delete_tags(aws_instance.instance_id, diff.tags_to_remove)
|
359
|
+
end
|
360
|
+
|
361
|
+
if !diff.tags_to_add.empty?
|
362
|
+
set_tags(aws_instance.instance_id, diff.tags_to_add)
|
363
|
+
end
|
364
|
+
|
365
|
+
end
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
private
|
370
|
+
|
371
|
+
def set_name(instance_id, name)
|
372
|
+
@client.create_tags({
|
373
|
+
resources: [instance_id],
|
374
|
+
tags: [
|
375
|
+
{
|
376
|
+
key: "Name",
|
377
|
+
value: name
|
378
|
+
}
|
379
|
+
]
|
380
|
+
})
|
381
|
+
end
|
382
|
+
|
383
|
+
def set_tags(instance_id, tags)
|
384
|
+
@client.create_tags({
|
385
|
+
resources: [instance_id],
|
386
|
+
tags: tags.map do |key, val|
|
387
|
+
{
|
388
|
+
key: key,
|
389
|
+
value: val
|
390
|
+
}
|
391
|
+
end
|
392
|
+
})
|
393
|
+
end
|
394
|
+
|
395
|
+
def delete_tags(instance_id, tags)
|
396
|
+
@client.delete_tags({
|
397
|
+
resources: [instance_id],
|
398
|
+
tags: tags.map do |key, val|
|
399
|
+
{
|
400
|
+
key: key,
|
401
|
+
value: val
|
402
|
+
}
|
403
|
+
end
|
404
|
+
})
|
405
|
+
end
|
406
|
+
|
407
|
+
def set_instance_source_dest_check(instance_id, source_dest_check)
|
408
|
+
@client.modify_instance_attribute({
|
409
|
+
instance_id: instance_id,
|
410
|
+
source_dest_check: {
|
411
|
+
value: source_dest_check
|
412
|
+
}
|
413
|
+
})
|
414
|
+
end
|
415
|
+
|
416
|
+
def set_interface_source_dest_check(interface_id, source_dest_check)
|
417
|
+
@client.modify_network_interface_attribute({
|
418
|
+
network_interface_id: interface_id,
|
419
|
+
source_dest_check: {
|
420
|
+
value: source_dest_check
|
421
|
+
}
|
422
|
+
})
|
423
|
+
end
|
424
|
+
|
425
|
+
def set_ebs_optimized(instance_id, optimized)
|
426
|
+
@client.modify_instance_attribute({
|
427
|
+
instance_id: instance_id,
|
428
|
+
ebs_optimized: {
|
429
|
+
value: optimized
|
430
|
+
}
|
431
|
+
})
|
432
|
+
end
|
433
|
+
|
434
|
+
def set_instance_security_groups(vpc_id, instance_id, sg_names)
|
435
|
+
@client.modify_instance_attribute({
|
436
|
+
instance_id: instance_id,
|
437
|
+
groups: sg_names.map { |sg| SecurityGroups.vpc_security_group_id_names[vpc_id].key(sg) }
|
438
|
+
})
|
439
|
+
end
|
440
|
+
|
441
|
+
def set_interface_security_groups(vpc_id, interface_id, sg_names)
|
442
|
+
@client.modify_network_interface_attribute({
|
443
|
+
network_interface_id: interface_id,
|
444
|
+
groups: sg_names.map { |sg| SecurityGroups.vpc_security_group_id_names[vpc_id].key(sg) }
|
445
|
+
})
|
446
|
+
end
|
447
|
+
|
448
|
+
def set_monitoring(instance_id, monitoring)
|
449
|
+
if monitoring
|
450
|
+
@client.monitor_instances({
|
451
|
+
instance_ids: [instance_id]
|
452
|
+
})
|
453
|
+
else
|
454
|
+
@client.unmonitor_instances({
|
455
|
+
instance_ids: [instance_id]
|
456
|
+
})
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
def create_network_interface(vpc_id, subnet_id, sg_names)
|
461
|
+
@client.create_network_interface({
|
462
|
+
subnet_id: subnet_id,
|
463
|
+
groups: sg_names.map { |sg| SecurityGroups.vpc_security_group_id_names[vpc_id].key(sg) }
|
464
|
+
}).network_interface.network_interface_id
|
465
|
+
end
|
466
|
+
|
467
|
+
def attach_network_interface(instance_id, interface_id, device_index)
|
468
|
+
@client.attach_network_interface({
|
469
|
+
network_interface_id: interface_id,
|
470
|
+
instance_id: instance_id,
|
471
|
+
device_index: device_index
|
472
|
+
}).attachment_id
|
473
|
+
end
|
474
|
+
|
475
|
+
def set_delete_on_terminate(interface_id, attachment_id)
|
476
|
+
@client.modify_network_interface_attribute({
|
477
|
+
network_interface_id: interface_id,
|
478
|
+
attachment: {
|
479
|
+
attachment_id: attachment_id,
|
480
|
+
delete_on_termination: true
|
481
|
+
}
|
482
|
+
})
|
483
|
+
end
|
484
|
+
|
485
|
+
def attach_volumes(instance_id, volumes, start_device_letter)
|
486
|
+
|
487
|
+
device_letter = start_device_letter
|
488
|
+
|
489
|
+
# sort volumes by size then map to id
|
490
|
+
volume_ids = volumes.sort_by(&:size).map(&:volume_id)
|
491
|
+
|
492
|
+
volume_ids.each do |vol_id|
|
493
|
+
device_name = "#{@device_name_base}#{device_letter}"
|
494
|
+
puts "Attaching volume to #{device_name}..."
|
495
|
+
|
496
|
+
@client.attach_volume({
|
497
|
+
instance_id: instance_id,
|
498
|
+
volume_id: vol_id,
|
499
|
+
device: device_name
|
500
|
+
})
|
501
|
+
|
502
|
+
device_letter = (device_letter.ord + 1).chr
|
503
|
+
end
|
504
|
+
|
505
|
+
end
|
506
|
+
|
507
|
+
end
|
508
|
+
end
|
509
|
+
end
|