cumulus-aws 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.gitignore +3 -0
- data/.travis.yml +12 -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/cumulus-aws.gemspec +20 -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/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
|