Class: OpsworksWrapper::Deployer

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

Instance Method Summary collapse

Constructor Details

#initialize(app_id) ⇒ Deployer


8
9
10
# File 'lib/opsworks_wrapper.rb', line 8

def initialize(app_id)
  @app_id = app_id
end

Instance Method Details

#_wait_until_deployed(deployment_id, timeout) ⇒ Object

Waits on the provided deployment for specified timeout (seconds)


208
209
210
211
212
213
214
215
216
# File 'lib/opsworks_wrapper.rb', line 208

def _wait_until_deployed(deployment_id, timeout)
  opsworks_client.wait_until(:deployment_successful, deployment_ids: [deployment_id]) do |w|
    w.before_attempt do |attempt|
      puts "Attempt #{attempt} to check deployment status".light_black
    end
    w.interval = 10
    w.max_attempts = timeout / w.interval
  end
end

#app_idObject


28
29
30
# File 'lib/opsworks_wrapper.rb', line 28

def app_id
  @app_id
end

#create_deployment(command, instances, timeout) ⇒ Boolean

Creates an OpsWorks deployment with specified command If @instances is not nil, the deployment will only be performed on specified instances


175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/opsworks_wrapper.rb', line 175

def create_deployment(command, instances, timeout)
  instance_ids = nil
  instance_description = "all instances"

  if !instances.nil?
    instance_ids = instances.map(&:instance_id)
    instance_description = instances.map(&:hostname).join(',')
  end

  deployment_config = {
      stack_id: opsworks_app[:stack_id],
      app_id: app_id,
      instance_ids: instance_ids,
      command: command,
      comment: "Git Sha: #{current_sha}"
  }

  deployment = opsworks_client.create_deployment(deployment_config)
  print "Running command ".light_blue
  print "#{command[:name]}".light_blue.bold
  puts " on #{instance_description}".light_blue

  begin
    _wait_until_deployed(deployment[:deployment_id], timeout)
    puts "Deployment successful".green
    true
  rescue Aws::Waiters::Errors::WaiterFailed => e
    puts  "Failed to deploy: #{e.message}".red
    false
  end
end

#create_deployment_exclude(command, layer_to_exclude, timeout) ⇒ Boolean

Creates an OpsWorks deployment with specified command on all layers excluding layer_to_exclude


161
162
163
164
165
166
167
# File 'lib/opsworks_wrapper.rb', line 161

def create_deployment_exclude(command, layer_to_exclude, timeout)
  all_instances = get_instances
  excluded_instances = get_instances(layer_to_exclude)
  included_instances = all_instances - excluded_instances

  create_deployment(command, included_instances, timeout)
end

#current_shaObject


12
13
14
# File 'lib/opsworks_wrapper.rb', line 12

def current_sha
  @current_sha ||= `git rev-parse HEAD`.chomp
end

#deploy(layer_name = nil, timeout = 600) ⇒ Boolean

Run deploy command on specified layer or all layers if @layer_name is not specified (non rolling)


98
99
100
101
102
103
104
105
106
107
108
# File 'lib/opsworks_wrapper.rb', line 98

def deploy(layer_name = nil, timeout = 600)
  if layer_name
    puts "Deploying on #{layer_name} layer".light_white.bold
    instances = get_instances(layer_name)
  else
    puts "Deploying on all layers".light_white.bold
    instances = nil
  end

  create_deployment({name: 'deploy'}, instances, timeout)
end

#deploy_exclude(layer_name, timeout = 600) ⇒ Boolean

Deploy to all layers except specified layer (non-rolling)


151
152
153
154
# File 'lib/opsworks_wrapper.rb', line 151

def deploy_exclude(layer_name, timeout = 600)
  puts "Deploying to all layers except #{layer_name}".light_white.bold
  create_deployment_exclude({name: 'deploy'}, layer_name, timeout)
end

#deploy_instance_rolling(instance, elb, timeout = 600) ⇒ Boolean

Performs rolling deployment on an instance Will detach instance if elb is provided and re-attach after deployment succeeds


132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/opsworks_wrapper.rb', line 132

def deploy_instance_rolling(instance, elb, timeout = 600)
  if !elb.nil?
    elb.remove_instance(instance)
  end

  success = create_deployment({name: 'deploy'}, [instance], timeout)

  # only add instance back to elb if deployment succeeded
  if !elb.nil? && success
    success = elb.add_instance(instance)
  end

  success
end

#deploy_layer_rolling(layer_name, timeout = 600) ⇒ Boolean

Performs a rolling deploy on each instance in the layer If an elb is attached to the layer, de-registration and registration will be performed for the instance


115
116
117
118
119
120
121
122
123
124
# File 'lib/opsworks_wrapper.rb', line 115

def deploy_layer_rolling(layer_name, timeout = 600)
  instances = get_instances(layer_name)
  elb = get_elb(layer_name)
  success = true
  instances.each do |instance|
    success = deploy_instance_rolling(instance, elb, timeout)
    break if !success
  end
  success
end

#get_elb(layer_name) ⇒ Object?

Returns ELB instance for layer if one is attached


75
76
77
78
79
80
81
82
83
84
# File 'lib/opsworks_wrapper.rb', line 75

def get_elb(layer_name)
  layer_id = layers[layer_name].layer_id
  elbs = opsworks_client.describe_elastic_load_balancers(layer_ids:[layer_id])
  if elbs.elastic_load_balancers.size > 0
    name = elbs.elastic_load_balancers.first.elastic_load_balancer_name
    ELB.new(name)
  else
    nil
  end
end

#get_instances(layer_name = nil) ⇒ List[Object]

Returns a list of OpsWorks instances for a specific layer or all layers if @layer_name is not provided


61
62
63
64
65
66
67
68
69
70
# File 'lib/opsworks_wrapper.rb', line 61

def get_instances(layer_name = nil)
  if layer_name == nil
    data = opsworks_client.describe_instances(stack_id: opsworks_app[:stack_id])
  else
    layer_id = layers[layer_name].layer_id
    data = opsworks_client.describe_instances(layer_id: layer_id)
  end

  data.instances
end

#get_opsworks_appObject

Returns OpsWorks app details


49
50
51
52
53
54
55
# File 'lib/opsworks_wrapper.rb', line 49

def get_opsworks_app
  data = opsworks_client.describe_apps(app_ids: [app_id])
  if !(data[:apps] && data[:apps].count == 1)
    raise Error, "App #{app_id} not found.", error.backtrace
  end
  data[:apps].first
end

#get_opsworks_layersDictionary

Returns a dictionary for all OpsWorks layers keyed by layer name


38
39
40
41
42
43
44
45
# File 'lib/opsworks_wrapper.rb', line 38

def get_opsworks_layers
  data = opsworks_client.describe_layers(stack_id: opsworks_app[:stack_id])
  layers = {}
  data.layers.each do |layer|
    layers[layer.name] = layer
  end
  layers
end

#layersObject


32
33
34
# File 'lib/opsworks_wrapper.rb', line 32

def layers
  @layers ||= get_opsworks_layers
end

#load_balancer_clientObject


24
25
26
# File 'lib/opsworks_wrapper.rb', line 24

def load_balancer_client
  @client ||= Aws::ElasticLoadBalancing::Client.new
end

#opsworks_appObject


16
17
18
# File 'lib/opsworks_wrapper.rb', line 16

def opsworks_app
  @opsworks_app ||= get_opsworks_app
end

#opsworks_clientObject


20
21
22
# File 'lib/opsworks_wrapper.rb', line 20

def opsworks_client
  @opsworks_client ||= Aws::OpsWorks::Client.new
end

#update_cookbooks(timeout = 150) ⇒ Boolean

Run update cookbooks on all layers


89
90
91
92
# File 'lib/opsworks_wrapper.rb', line 89

def update_cookbooks(timeout = 150)
  puts 'Updating cookbooks'.light_white.bold
  create_deployment({name: 'update_custom_cookbooks'}, nil, timeout)
end