Class: Guignol::Models::Instance

Inherits:
Base
  • Object
show all
Defined in:
lib/guignol/models/instance.rb

Defined Under Namespace

Classes: Error, HashERB

Instance Attribute Summary

Attributes inherited from Base

#connection, #name, #options, #subject

Instance Method Summary collapse

Methods inherited from Base

#exist?, #state, #uuid

Constructor Details

#initialize(name, options) ⇒ Instance

Returns a new instance of Instance.



20
21
22
23
24
25
26
27
28
# File 'lib/guignol/models/instance.rb', line 20

def initialize(name, options)
  if options[:user_data]
    options[:name] = name
    options[:user_data] = HashERB.new(options).parse(options[:user_data])
  end

  super
  subject.username = options[:username] if options[:username] && exists?
end

Instance Method Details

#createObject



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/guignol/models/instance.rb', line 35

def create
  log "server already exists" and return self if exist?

  create_options = Guignol::DefaultServerOptions.merge options.slice(:image_id, :flavor_id, :key_name, :security_group_ids, :user_data, :username, :availability_zone)

  zones = create_options[:volumes].map { |name,volume_options| Volume.new(name, volume_options).availability_zone }.compact.uniq
  availability_zone = create_options[:availability_zone]

  if options[:root_ebs_size]
    raise "root_ebs_size have to be a number" unless options[:root_ebs_size].is_a? Integer
    create_options[:block_device_mapping] = [{"DeviceName"=>"/dev/sda1", "Ebs.VolumeSize"=>options[:root_ebs_size], "Ebs.DeleteOnTermination"=>"true"}]
  end

  # check if provided availability_zone is valid
  if availability_zone
    unless availability_zone.match(connection.region)
      raise "availability zone #{availability_zone} is not in the defined region #{connection.region}"
    end
    if zones.first && zones.first != availability_zone
      raise "volume availability zone differs to configured server availability_zone"
    end
  end

  # check for pre-existing volume(s). if any exist, add their AZ to the server's options
  if zones.size > 1
    raise "pre-existing volumes volumes are in different availability zones"
  elsif zones.size == 1
    log "using AZ '#{zones.first}' since volumes already exist"
    create_options[:availability_zone] = zones.first
  end

  log "building server..."
  set_subject connection.servers.create(create_options)
  setup
  log "created as #{subject.dns_name}"

  return self
rescue Exception => e
  log "error while creating", :error => e
  destroy
  raise
end

#destroyObject



115
116
117
118
119
120
121
122
123
124
125
# File 'lib/guignol/models/instance.rb', line 115

def destroy
  log "server doesn't exist (ignoring)." and return self unless exist?

  log "tearing server down..."
  remove_dns
  subject.destroy
  wait_for_state 'stopped', 'terminated', 'nonexistent'
  # FIXME: remove tags here
  set_subject nil
  return self
end

#dns_nameObject



164
165
166
# File 'lib/guignol/models/instance.rb', line 164

def dns_name
  subject && subject.dns_name
end

#fqdnObject



30
31
32
# File 'lib/guignol/models/instance.rb', line 30

def fqdn
  name and domain and "#{name}.#{domain}"
end

#idObject



168
169
170
171
# File 'lib/guignol/models/instance.rb', line 168

def id
  return nil unless subject && subject.respond_to?(:id)
  subject.id
end

#startObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/guignol/models/instance.rb', line 79

def start
  log "server doesn't exist (ignoring)" and return unless exist?
  wait_for_state_transitions

  if subject.state != "stopped"
    log "server #{subject.state}."
  else
    log "starting server..."
    subject.start
    setup
    log "server started"
  end
  return self
rescue Exception => e
  log "error while starting", :error => e
  stop
  raise
end

#stopObject



98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/guignol/models/instance.rb', line 98

def stop
  wait_for_state_transitions
  reload
  if !exist?
    log "server doesn't exist (ignoring)."
  elsif subject.state != "running"
    log "server #{subject.state}."
  else
    log "stopping server..."
    remove_dns
    subject.stop
    wait_for_state 'stopped', 'terminated'
  end
  return self
end

#update_dnsObject



128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/guignol/models/instance.rb', line 128

def update_dns
  return unless options[:domain]
  unless subject && %w(pending running).include?(subject.state)
    log "server is #{subject ? subject.state : 'nil'}, not updating DNS"
    return
  end

  unless subject.dns_name
    log "server has no public DNS, not updating DNS"
    return
  end
  log "updating DNS"

  unless dns_zone
    log "DNS zone does not exist"
    return self
  end

  if record = dns_record
    if dns_record_matches?(record)
      log "DNS record already exists"
      return self
    else
      log "warning, while creating, DNS record exists but points to wrong server (fixing)"
      record.destroy
    end
  end

  # Route53's API is not concurrently accessible
  DNS_MUTEX.synchronize do
    dns_zone.records.create(:name => fqdn, :type => 'CNAME', :value => subject.dns_name, :ttl => 5)
  end
  log "#{fqdn} -> #{subject.dns_name}"
  return self
end