Class: HiveQueen

Inherits:
Object
  • Object
show all
Defined in:
lib/capistrano/hivequeen.rb,
lib/capistrano/hivequeen/multiio.rb,
lib/capistrano/hivequeen/version.rb,
lib/capistrano/hivequeen/ec2_instance_connect.rb

Overview

Keeps an in-memory history of printed lines (to persist to HQ), and puts to stderr (capistrano’s default)

Defined Under Namespace

Classes: DeploymentError, InsecureCredentials, MultiIO, Version

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.endpointObject

Returns the value of attribute endpoint.



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

def endpoint
  @endpoint
end

.loggerObject

Returns the value of attribute logger.



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

def logger
  @logger
end

.passwordObject

Returns the value of attribute password.



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

def password
  @password
end

.projectObject

Returns the value of attribute project.



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

def project
  @project
end

.usernameObject

Returns the value of attribute username.



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

def username
  @username
end

Class Method Details

.commit_status(commit_sha) ⇒ Object



52
53
54
# File 'lib/capistrano/hivequeen.rb', line 52

def commit_status(commit_sha)
  get("/projects/#{project}/commit_statuses/#{commit_sha}.json")
end

.credentials_from_pathObject



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/capistrano/hivequeen.rb', line 80

def credentials_from_path
  # Check that credentials are not accessible to world or group
  mode = File.stat(credentials_path).mode
  raise InsecureCredentials unless (mode % 64 == 0)

  File.read(credentials_path)

rescue InsecureCredentials
  puts "#{credentials_path} is insecure. Please change you password and run"
  puts "chmod 600 #{credentials_path}"
  exit 1
rescue Errno::ENOENT, RuntimeError
  puts "Could not read HiveQueen credentials from #{credentials_path}."
  puts "#{credentials_path} should contain your username and password seperated by a colon"
  puts "Run this command with your credentials:"
  puts " $ echo username:password > #{credentials_path}; chmod 600 #{credentials_path}"
  exit 1
end

.default_rolesObject



30
31
32
# File 'lib/capistrano/hivequeen.rb', line 30

def default_roles
  @project_data['default_roles']
end

.ec2_clientObject



2
3
4
# File 'lib/capistrano/hivequeen/ec2_instance_connect.rb', line 2

def self.ec2_client
  @ec2_client ||= Aws::EC2::Client.new
end

.ec2_instance_connect(*private_dns) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/capistrano/hivequeen/ec2_instance_connect.rb', line 13

def self.ec2_instance_connect(*private_dns)
  # Get SSH public key contents
  ssh_public_key = File.read(File.expand_path('~/.ssh/ksr_ed25519.pub'))

  # Get SSH bastion instance(s) from Name tag
  ssh_params = { filters: [{ name: 'tag:Name', values: %w[ssh-bastion] }, {name: 'instance-state-name', values: %w[running]}] }
  logger.trace("ec2:DescribeInstances #{ssh_params.to_json}")
  bastions = ec2_client.describe_instances(**ssh_params).reservations.map(&:instances).flatten

  # Get EC2 instances from private DNS name
  ec2_params = { filters: [{ name: 'network-interface.private-dns-name', values: private_dns }, {name: 'instance-state-name', values: %w[running]}] }
  logger.trace("ec2:DescribeInstances #{ec2_params.to_json}")
  instances = ec2_client.describe_instances(**ec2_params).reservations.map(&:instances).flatten

  # Collect EC2 Instance Connect request threads
  threads = (bastions + instances).map do |instance|
    Thread.new do
      ec2ic_params = {
        availability_zone: instance.placement.availability_zone,
        instance_id:       instance.instance_id,
        instance_os_user:  'ksr',
        ssh_public_key:    ssh_public_key,
      }
      logger.trace("ec2-instance-connect:SendSSHPublicKey #{ec2ic_params.to_json}")
      ec2_instance_connect_client.send_ssh_public_key(**ec2ic_params)
    end
  end

  # Execute EC2 Instance Connect request threads
  threads.each(&:join)
end

.ec2_instance_connect_clientObject



6
7
8
9
10
11
# File 'lib/capistrano/hivequeen/ec2_instance_connect.rb', line 6

def self.ec2_instance_connect_client
  @ec2_instance_connect_client ||= Aws::EC2InstanceConnect::Client.new(
    retry_limit:   5,
    retry_backoff: -> (c) { sleep(5) },
  )
end

.environment_namesObject



38
39
40
# File 'lib/capistrano/hivequeen.rb', line 38

def environment_names
  environments.map{|e| e['name'].to_sym }
end

.environmentsObject



34
35
36
# File 'lib/capistrano/hivequeen.rb', line 34

def environments
  project_data['environments']
end

.finish_deployment(environment_id, deployment_id) ⇒ Object



64
65
66
67
68
69
70
71
# File 'lib/capistrano/hivequeen.rb', line 64

def finish_deployment(environment_id, deployment_id)
  state = $! ? 'failed' : 'succeeded'
  puts "Finishing deployment in Hivequeen. State: #{state}"
  params = {:deployment => {:state => state}}
  deploy_log = logger.device.history
  params[:deployment][:deploy_log] = deploy_log if deploy_log
  put_or_post('PUT', "/environments/#{environment_id}/deployments/#{deployment_id}.json", params)
end

.get_credentials!Object

Load credentials from ~/.hivequeen



74
75
76
77
78
# File 'lib/capistrano/hivequeen.rb', line 74

def get_credentials!
  creds = ENV['HIVEQUEEN_CREDENTIALS'] || credentials_from_path
  @username, @password = creds.chomp.split(':')
  raise unless username && password
end

.project_dataObject



26
27
28
# File 'lib/capistrano/hivequeen.rb', line 26

def project_data
  @project_data ||= get("/#{project}.json")
end

.repositoryObject



42
43
44
# File 'lib/capistrano/hivequeen.rb', line 42

def repository
  project_data['repo']
end

.roles(env_id) ⇒ Object



46
47
48
49
50
# File 'lib/capistrano/hivequeen.rb', line 46

def roles(env_id)
  env_id = env_id.to_sym
  @roles ||= {}
  @roles[env_id] ||= get("/#{env_id}.json")
end

.start_deployment(environment_id, params) ⇒ Object



56
57
58
59
60
61
62
# File 'lib/capistrano/hivequeen.rb', line 56

def start_deployment(environment_id, params)
  required_params = [:task, :commit]
  required_params.each do |key|
    raise ArgumentError.new("#{key} is a required param") unless params.key?(key)
  end
  put_or_post('POST', "/environments/#{environment_id}/deployments.json", :deployment => params)
end