Class: Opsicle::ManageableInstance

Inherits:
Object
  • Object
show all
Defined in:
lib/opsicle/manageable_instance.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(instance, layer, stack, opsworks, ec2, cli) ⇒ ManageableInstance

Returns a new instance of ManageableInstance.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/opsicle/manageable_instance.rb', line 30

def initialize(instance, layer, stack, opsworks, ec2, cli)
  self.hostname = instance.hostname
  self.status = instance.status
  self.layer = layer
  self.stack = stack
  self.ami_id = instance.ami_id
  self.instance_type = instance.instance_type
  self.agent_version = instance.agent_version
  self.stack_id = instance.stack_id
  self.layer_ids = instance.layer_ids
  self.auto_scaling_type = instance.auto_scaling_type
  self.os = instance.os
  self.ssh_key_name = instance.ssh_key_name
  self.availability_zone = instance.availability_zone
  self.virtualization_type = instance.virtualization_type
  self.subnet_id = instance.subnet_id
  self.architecture = instance.architecture
  self.root_device_type = instance.root_device_type
  self.ebs_optimized = instance.ebs_optimized
  self.tenancy = instance.tenancy
  self.opsworks = opsworks
  self.ec2 = ec2
  self.cli = cli
  self.instance_id = instance.instance_id
  self.new_instance_id = nil
end

Instance Attribute Details

#agent_versionObject

Returns the value of attribute agent_version.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def agent_version
  @agent_version
end

#ami_idObject

Returns the value of attribute ami_id.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def ami_id
  @ami_id
end

#architectureObject

Returns the value of attribute architecture.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def architecture
  @architecture
end

#auto_scaling_typeObject

Returns the value of attribute auto_scaling_type.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def auto_scaling_type
  @auto_scaling_type
end

#availability_zoneObject

Returns the value of attribute availability_zone.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def availability_zone
  @availability_zone
end

#cliObject

Returns the value of attribute cli.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def cli
  @cli
end

#ebs_optimizedObject

Returns the value of attribute ebs_optimized.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def ebs_optimized
  @ebs_optimized
end

#ec2Object

Returns the value of attribute ec2.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def ec2
  @ec2
end

#hostnameObject

Returns the value of attribute hostname.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def hostname
  @hostname
end

#instance_idObject

Returns the value of attribute instance_id.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def instance_id
  @instance_id
end

#instance_typeObject

Returns the value of attribute instance_type.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def instance_type
  @instance_type
end

#layerObject

Returns the value of attribute layer.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def layer
  @layer
end

#layer_idsObject

Returns the value of attribute layer_ids.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def layer_ids
  @layer_ids
end

#new_instance_idObject

Returns the value of attribute new_instance_id.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def new_instance_id
  @new_instance_id
end

#opsworksObject

Returns the value of attribute opsworks.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def opsworks
  @opsworks
end

#osObject

Returns the value of attribute os.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def os
  @os
end

#root_device_typeObject

Returns the value of attribute root_device_type.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def root_device_type
  @root_device_type
end

#ssh_key_nameObject

Returns the value of attribute ssh_key_name.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def ssh_key_name
  @ssh_key_name
end

#stackObject

Returns the value of attribute stack.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def stack
  @stack
end

#stack_idObject

Returns the value of attribute stack_id.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def stack_id
  @stack_id
end

#statusObject

Returns the value of attribute status.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def status
  @status
end

#subnet_idObject

Returns the value of attribute subnet_id.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def subnet_id
  @subnet_id
end

#tenancyObject

Returns the value of attribute tenancy.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def tenancy
  @tenancy
end

#virtualization_typeObject

Returns the value of attribute virtualization_type.



3
4
5
# File 'lib/opsicle/manageable_instance.rb', line 3

def virtualization_type
  @virtualization_type
end

Instance Method Details

#add_tags(options = {}) ⇒ Object

Raises:

  • (ArgumentError)


258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/opsicle/manageable_instance.rb', line 258

def add_tags(options={})
  raise ArgumentError, 'The instance must be running to add tags' if options[:add_tags_mode] && @status != "online"

  if ask_to_add_tags
    tags = []

    tag_count.times do
      tags << define_tag
    end

    ec2_instance_id = @opsworks.describe_instances(instance_ids: [new_instance_id || instance_id]).instances.first.ec2_instance_id
    @ec2.create_tags(resources: [ ec2_instance_id ], tags: tags)
  end
end

#ask_for_new_option(description) ⇒ Object



213
214
215
# File 'lib/opsicle/manageable_instance.rb', line 213

def ask_for_new_option(description)
  @cli.ask("Please write in the new #{description} and press ENTER:")
end

#ask_for_overriding_permission(description, overriding_all) ⇒ Object



217
218
219
220
221
222
223
224
# File 'lib/opsicle/manageable_instance.rb', line 217

def ask_for_overriding_permission(description, overriding_all)
  if overriding_all
    ans = @cli.ask("Do you wish to override this #{description}? By overriding, you are choosing to override the current #{description} for all of the following instances you're cloning.\n1) Yes\n2) No", Integer)
  else
    ans = @cli.ask("Do you wish to override this #{description}?\n1) Yes\n2) No", Integer)
  end
  ans == 1
end

#ask_for_possible_options(arr, description) ⇒ Object



207
208
209
210
211
# File 'lib/opsicle/manageable_instance.rb', line 207

def ask_for_possible_options(arr, description)
  arr.each_with_index { |id, index| puts "#{index.to_i + 1}) #{id}"}
  id_index = @cli.ask("Which #{description}?\n", Integer) { |q| q.in = 1..arr.length.to_i } - 1
  arr[id_index]
end

#ask_to_add_tagsObject



283
284
285
286
# File 'lib/opsicle/manageable_instance.rb', line 283

def ask_to_add_tags
  ans = @cli.ask("\nDo you wish to add EC2 tags to this instance?\n1) Yes\n2) No", Integer)
  ans == 1
end

#ask_to_start_instanceObject



288
289
290
291
# File 'lib/opsicle/manageable_instance.rb', line 288

def ask_to_start_instance
  ans = @cli.ask("Do you wish to start this new instance?\n1) Yes\n2) No", Integer)
  ans == 1
end

#auto_generated_hostnameObject



86
87
88
89
90
91
92
# File 'lib/opsicle/manageable_instance.rb', line 86

def auto_generated_hostname
  if hostname =~ /\d\d\z/
    increment_hostname
  else
    hostname << "-clone"
  end
end

#clone(options) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/opsicle/manageable_instance.rb', line 57

def clone(options)
  puts "\nCloning an instance..."

  new_instance_hostname = make_new_hostname
  ami_id = verify_ami_id
  agent_version = verify_agent_version
  subnet_id = verify_subnet_id
  instance_type = verify_instance_type

  create_new_instance(new_instance_hostname, instance_type, ami_id, agent_version, subnet_id)
  start_new_instance
end

#clone_with_defaults(options) ⇒ Object



71
72
73
74
75
76
77
# File 'lib/opsicle/manageable_instance.rb', line 71

def clone_with_defaults(options)
  puts "\nCloning an instance..."
  new_hostname = auto_generated_hostname
  create_new_instance(new_hostname, instance_type, ami_id, agent_version, subnet_id)
  opsworks.start_instance(instance_id: new_instance_id)
  puts "\nNew instance is starting…"
end

#create_new_instance(new_instance_hostname, instance_type, ami_id, agent_version, subnet_id) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# File 'lib/opsicle/manageable_instance.rb', line 226

def create_new_instance(new_instance_hostname, instance_type, ami_id, agent_version, subnet_id)
  new_instance = @opsworks.create_instance({
    stack_id: self.stack_id, # required
    layer_ids: self.layer_ids, # required
    instance_type: instance_type, # required
    auto_scaling_type: self.auto_scaling_type, # accepts load, timer
    hostname: new_instance_hostname,
    os: self.os,
    ami_id: ami_id,
    ssh_key_name: self.ssh_key_name,
    # availability_zone: self.availability_zone,
    subnet_id: subnet_id,
    virtualization_type: self.virtualization_type,
    architecture: self.architecture, # accepts x86_64, i386
    root_device_type: self.root_device_type, # accepts ebs, instance-store
    #ebs_optimized: self.ebs_optimized,
    agent_version: agent_version,
    tenancy: self.tenancy,
  })
  self.new_instance_id = new_instance.instance_id
  self.layer.add_new_instance(new_instance_id)
  puts "\nNew instance #{new_instance_hostname} has been created: #{new_instance_id}"
end

#define_tagObject



273
274
275
276
277
# File 'lib/opsicle/manageable_instance.rb', line 273

def define_tag
  tag_key = ask_for_new_option('tag name')
  tag_value = ask_for_new_option('tag value')
  { key: tag_key, value: tag_value }
end

#find_subnet_name(subnet) ⇒ Object



114
115
116
117
118
119
# File 'lib/opsicle/manageable_instance.rb', line 114

def find_subnet_name(subnet)
  tags = subnet.tags
  tag = nil
  tags.each { |t| tag = t if t.key == 'Name' }
  tag.value if tag
end

#hostname_unique?(name) ⇒ Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/opsicle/manageable_instance.rb', line 110

def hostname_unique?(name)
  !sibling_hostnames.include?(name)
end

#increment_hostnameObject



98
99
100
101
102
103
104
# File 'lib/opsicle/manageable_instance.rb', line 98

def increment_hostname
  name = hostname
  until hostname_unique?(name) do
    name = name.gsub(/(\d\d\z)/) { "#{($1.to_i + 1).to_s.rjust(2, '0')}" }
  end
  name
end

#make_new_hostnameObject



79
80
81
82
83
84
# File 'lib/opsicle/manageable_instance.rb', line 79

def make_new_hostname
  new_instance_hostname = auto_generated_hostname
  puts "\nAutomatically generated hostname: #{new_instance_hostname}\n"
  new_instance_hostname = ask_for_new_option("instance's hostname") if ask_for_overriding_permission("hostname", false)
  new_instance_hostname
end

#sibling_hostnamesObject



94
95
96
# File 'lib/opsicle/manageable_instance.rb', line 94

def sibling_hostnames
  self.layer.instances.collect { |instance| instance.hostname }
end

#start_new_instanceObject



250
251
252
253
254
255
256
# File 'lib/opsicle/manageable_instance.rb', line 250

def start_new_instance
  if ask_to_start_instance
    @opsworks.start_instance(instance_id: self.new_instance_id)
    puts "\nNew instance is starting…"
    add_tags
  end
end

#tag_countObject



279
280
281
# File 'lib/opsicle/manageable_instance.rb', line 279

def tag_count
  @cli.ask("How many tags do you wish to add? Please write in the number as an integer and press ENTER:").to_i
end

#verify_agent_versionObject



146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/opsicle/manageable_instance.rb', line 146

def verify_agent_version
  if self.layer.agent_version
    agent_version = self.layer.agent_version
  else
    puts "\nCurrent agent version is #{self.agent_version}"

    if ask_for_overriding_permission("agent version", true)
      agents = @opsworks.describe_agent_versions(stack_id: self.stack_id).agent_versions
      version_ids = agents.collect { |i| i.version }.uniq
      agent_version = ask_for_possible_options(version_ids, "agent version")

      self.layer.agent_version = agent_version   # only set agent version for whole layer if they override
    else
      agent_version = self.agent_version
    end
  end

  agent_version
end

#verify_ami_idObject



121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/opsicle/manageable_instance.rb', line 121

def verify_ami_id
  if self.layer.ami_id
    ami_id = self.layer.ami_id
  else
    puts "\nCurrent AMI id is #{self.ami_id}"

    if ask_for_overriding_permission("AMI ID", true)
      instances = @opsworks.describe_instances(stack_id: self.stack_id).instances
      ami_ids = instances.collect { |i| i.ami_id }.uniq
      ami_ids << "Provide a different AMI ID."
      ami_id = ask_for_possible_options(ami_ids, "AMI ID")

      if ami_id == "Provide a different AMI ID."
        ami_id = ask_for_new_option('AMI ID')
      end

      self.layer.ami_id = ami_id   # only set AMI ID for whole layer if they override it
    else
      ami_id = self.ami_id
    end
  end

  ami_id
end

#verify_instance_typeObject



200
201
202
203
204
205
# File 'lib/opsicle/manageable_instance.rb', line 200

def verify_instance_type
  puts "\nCurrent instance type is #{self.instance_type}"
  rewriting = ask_for_overriding_permission("instance type", false)
  instance_type = rewriting ? ask_for_new_option('instance type') : self.instance_type
  instance_type
end

#verify_subnet_idObject



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/opsicle/manageable_instance.rb', line 166

def verify_subnet_id
  if self.layer.subnet_id
    subnet_id = self.layer.subnet_id
  else
    current_subnet = Aws::EC2::Subnet.new(id: self.subnet_id, client: @ec2)
    subnet_name = find_subnet_name(current_subnet)
    puts "\nCurrent subnet ID is \"#{subnet_name}\" #{current_subnet.availability_zone} (#{self.subnet_id})"

    if ask_for_overriding_permission("subnet ID", true)
      ec2_subnets = ec2.describe_subnets.subnets
      subnets = []

      ec2_subnets.each do |subnet|
        if subnet.vpc_id == stack.vpc_id
          subnet_name = find_subnet_name(subnet)
          zone_name = subnet.availability_zone
          subnet_id = subnet.subnet_id
          subnets << "\"#{subnet_name}\" #{zone_name} (#{subnet_id})"
        end
      end

      subnets = subnets.sort
      subnet_id = ask_for_possible_options(subnets, "subnet ID")
      subnet_id = subnet_id.scan(/(subnet-[a-z0-9]*)/).first.first if subnet_id

      self.layer.subnet_id = subnet_id   # only set the subnet ID for whole layer if they override it
    else
      subnet_id = self.subnet_id
    end
  end

  subnet_id
end