kontena-plugin-aws 0.2.0.pre1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MjkzMTFkZDliMjJjNTI1NzhjYWFmMGZkYzllMzFmZDM2NjQxMzgwMQ==
4
+ OWYyM2NkMmM4YTdkZGU5ZDAzZWRiMzUyMjYwZDFjMDA0ZmI0ZTRkOA==
5
5
  data.tar.gz: !binary |-
6
- ODIyMjJlNDM3NTRhOWNiM2UwZTJkZDRmZmEyY2U2ZDM0NjM1YTcxNQ==
6
+ MWM3MmY3NTgzMzQzZWFkZjQyODA2OTg5Yzk0ZmFkOTZiNTI3OTA0Nw==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- MmUwNDkwZTdjNjRkMWQyNGYzYjM0M2ZmYjc0ODI3MDczYzA5YWQxZWFiODcx
10
- ZDBhMzI0OTEyMWY4N2M1MmRlYzI2ZjRmNjE5ZGExZjEwY2E1OWE1NWYxMzk4
11
- NTYxYjY1OTUxNWU4ZTg1MTgyMjUyNTJiZDgwODM0MjQ4ZDljY2Y=
9
+ YTBhODExYWY2NzZkZjc0YTgxNTJhNjM5MDFhOGI0NTY0YTMyOTkxMzhmMmJm
10
+ Y2E1N2Y4NDJkNjc5MGMwZDQzMzY1YWFhMTUzY2VjZDM1ZDM2YTM3N2U0NDAw
11
+ MGU3MjNiMDBhYzI3YjZmYWMzZGQ5YjA4ODVlNWY1ZTc2OWY5ZjA=
12
12
  data.tar.gz: !binary |-
13
- NjM4MGQ2YjMzZjUxMGE2ZTY3ODQ4ZTAzYmYzNDE5YmQ1Njc3OGQ3Nzg4YTcx
14
- MTk3NzA1OWI0OWE4MjI4NjQyZWQ5ZTMxODIwM2M2MjYwYzJkOWE4Nzc5NDNl
15
- ZjBlZDllOWVmNmY3MDY5MjI5YjM0MGMwZTVmM2MxOWJlNWM0NzY=
13
+ MWUyZDlhY2Y5NzQ5MjQ0NTU0Njc4NTJmMjYxMmE0ZTJlZThkZjhmNzlkZGEw
14
+ NDE0MDliYWRmYjJkMmRkZmRlOGM3ZDU4YjlkYTNhODhhM2QzOTAyODg2YjFl
15
+ NGQ5MTczMDY0MjJhY2ZiZTJlNzAyMGZkNDY3YjI0MjczYzkwZjY=
@@ -33,7 +33,16 @@ coreos:
33
33
  DOMAINS=kontena.local
34
34
  [DHCP]
35
35
  UseDNS=false
36
-
36
+ - name: etcd2.service
37
+ command: start
38
+ enable: true
39
+ content: |
40
+ Description=etcd 2.0
41
+ After=docker.service
42
+ [Service]
43
+ Restart=always
44
+ RestartSec=5
45
+ ExecStart=/usr/bin/docker logs --tail=10 -f kontena-etcd
37
46
  - name: 10-weave.network
38
47
  runtime: false
39
48
  content: |
@@ -89,11 +89,11 @@ coreos:
89
89
  --link kontena-server-mongo:mongodb \
90
90
  -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
91
91
  <% end -%>
92
- <% if server_name %>
93
- -e KONTENA_SERVER_NAME=<%= server_name %> \
92
+ <% if server_name -%>
93
+ -e SERVER_NAME=<%= server_name %> \
94
94
  <% end -%>
95
- <% if initial_admin_code %>
96
- -e KONTENA_INITIAL_ADMIN_CODE=<%= intial_admin_code %> \
95
+ <% if initial_admin_code -%>
96
+ -e INITIAL_ADMIN_CODE=<%= initial_admin_code %> \
97
97
  <% end -%>
98
98
  -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
99
99
  kontena/server:${KONTENA_VERSION}
@@ -2,6 +2,7 @@ require 'fileutils'
2
2
  require 'erb'
3
3
  require 'open3'
4
4
  require 'securerandom'
5
+ require 'json'
5
6
 
6
7
  require_relative 'common'
7
8
 
@@ -10,7 +11,7 @@ module Kontena::Machine::Aws
10
11
  include Kontena::Machine::RandomName
11
12
  include Kontena::Machine::CertHelper
12
13
  include Common
13
- include Kontena::Cli::ShellSpinner
14
+ include Kontena::Cli::Common
14
15
 
15
16
  attr_reader :ec2, :http_client, :region
16
17
 
@@ -30,7 +31,7 @@ module Kontena::Machine::Aws
30
31
  abort('Invalid ssl cert') unless File.exists?(File.expand_path(opts[:ssl_cert]))
31
32
  ssl_cert = File.read(File.expand_path(opts[:ssl_cert]))
32
33
  else
33
- spinner "Generating self-signed SSL certificate" do
34
+ spinner "Generating a self-signed SSL certificate" do
34
35
  ssl_cert = generate_self_signed_cert
35
36
  end
36
37
  end
@@ -89,10 +90,11 @@ module Kontena::Machine::Aws
89
90
  ]
90
91
  })
91
92
 
92
- spinner "Creating AWS instance #{name.colorize(:cyan)} " do
93
+ spinner "Creating an AWS instance #{name.colorize(:cyan)} " do
93
94
  sleep 1 until ec2_instance.reload.state.name == 'running'
94
95
  end
95
96
  public_ip = ec2_instance.reload.public_ip_address
97
+ master_version = nil
96
98
  if public_ip.nil?
97
99
  master_url = "https://#{ec2_instance.private_ip_address}"
98
100
  puts "Could not get public IP for the created master, private connect url is: #{master_url}"
@@ -101,16 +103,21 @@ module Kontena::Machine::Aws
101
103
  Excon.defaults[:ssl_verify_peer] = false
102
104
  http_client = Excon.new(master_url, :connect_timeout => 10)
103
105
  spinner "Waiting for #{name.colorize(:cyan)} to start " do
104
- sleep 1 until master_running?(http_client)
106
+ sleep 0.5 until master_running?(http_client)
105
107
  end
108
+
109
+ spinner "Retrieving Kontena Master version" do
110
+ master_version = JSON.parse(http_client.get(path: '/').body)["version"] rescue nil
111
+ end
112
+
113
+ spinner "Kontena Master #{master_version} is now running at #{master_url}"
106
114
  end
107
- puts
108
- puts "Kontena Master is now running at #{master_url}".colorize(:green)
109
- puts
110
115
  {
111
116
  name: name.sub('kontena-master-', ''),
112
117
  public_ip: public_ip,
113
- code: opts[:initial_admin_code]
118
+ code: opts[:initial_admin_code],
119
+ provider: 'aws',
120
+ version: master_version
114
121
  }
115
122
  end
116
123
 
@@ -33,69 +33,82 @@ module Kontena::Machine::Aws
33
33
  resolve_security_groups_to_ids(opts[:security_groups], opts[:vpc]) :
34
34
  ensure_security_group(opts[:grid], opts[:vpc])
35
35
 
36
- name = opts[:name ] || generate_name
37
-
38
36
  if opts[:subnet].nil?
39
37
  subnet = default_subnet(opts[:vpc], region+opts[:zone])
40
38
  else
41
39
  subnet = ec2.subnet(opts[:subnet])
42
40
  end
43
41
  dns_server = aws_dns_supported?(opts[:vpc]) ? '169.254.169.253' : '8.8.8.8'
44
- userdata_vars = {
45
- name: name,
46
- version: opts[:version],
47
- master_uri: opts[:master_uri],
48
- grid_token: opts[:grid_token],
49
- dns_server: dns_server
50
- }
51
-
52
- ec2_instance = ec2.create_instances({
53
- image_id: ami,
54
- min_count: 1,
55
- max_count: 1,
56
- instance_type: opts[:type],
57
- key_name: opts[:key_pair],
58
- user_data: Base64.encode64(user_data(userdata_vars)),
59
- block_device_mappings: [
60
- {
61
- device_name: '/dev/xvda',
62
- virtual_name: 'Root',
63
- ebs: {
64
- volume_size: opts[:storage],
65
- volume_type: 'gp2'
66
- }
67
- }
68
- ],
69
- network_interfaces: [
70
- {
71
- device_index: 0,
72
- subnet_id: subnet.subnet_id,
73
- groups: security_groups,
74
- associate_public_ip_address: opts[:associate_public_ip],
75
- delete_on_termination: true
76
- }
77
- ]
78
- }).first
79
- ec2_instance.create_tags({
80
- tags: [
81
- {key: 'Name', value: name},
82
- {key: 'kontena_grid', value: opts[:grid]}
83
- ]
84
- })
42
+ instances = []
43
+ opts[:count].to_i.times do |i|
44
+ if opts[:name] && opts[:count].to_i > 1
45
+ name = "#{opts[:name]}-#{i+1}"
46
+ elsif opts[:name]
47
+ name = opts[:name]
48
+ else
49
+ name = generate_name
50
+ end
85
51
 
86
- spinner "Creating AWS instance #{name.colorize(:cyan)} " do
87
- sleep 1 until ec2_instance.reload.state.name == 'running'
52
+ userdata_vars = {
53
+ name: name,
54
+ version: opts[:version],
55
+ master_uri: opts[:master_uri],
56
+ grid_token: opts[:grid_token],
57
+ dns_server: dns_server
58
+ }
59
+
60
+ ec2_instance = ec2.create_instances({
61
+ image_id: ami,
62
+ min_count: 1,
63
+ max_count: 1,
64
+ instance_type: opts[:type],
65
+ key_name: opts[:key_pair],
66
+ user_data: Base64.encode64(user_data(userdata_vars)),
67
+ block_device_mappings: [
68
+ {
69
+ device_name: '/dev/xvda',
70
+ virtual_name: 'Root',
71
+ ebs: {
72
+ volume_size: opts[:storage],
73
+ volume_type: 'gp2'
74
+ }
75
+ }
76
+ ],
77
+ network_interfaces: [
78
+ {
79
+ device_index: 0,
80
+ subnet_id: subnet.subnet_id,
81
+ groups: security_groups,
82
+ associate_public_ip_address: opts[:associate_public_ip],
83
+ delete_on_termination: true
84
+ }
85
+ ]
86
+ }).first
87
+ ec2_instance.create_tags({
88
+ tags: [
89
+ {key: 'Name', value: name},
90
+ {key: 'kontena_grid', value: opts[:grid]}
91
+ ]
92
+ })
93
+
94
+ spinner "Creating AWS instance #{name.colorize(:cyan)} " do
95
+ sleep 1 until ec2_instance.reload.state.name == 'running'
96
+ end
97
+ instances << name
88
98
  end
89
- node = nil
90
- spinner "Waiting for node #{name.colorize(:cyan)} join to grid #{opts[:grid].colorize(:cyan)} " do
91
- sleep 1 until node = instance_exists_in_grid?(opts[:grid], name)
99
+ instances.each do |instance_name|
100
+ node = nil
101
+ spinner "Waiting for node #{instance_name.colorize(:cyan)} join to grid #{opts[:grid].colorize(:cyan)} " do
102
+ sleep 1 until node = instance_exists_in_grid?(opts[:grid], instance_name)
103
+ end
104
+ labels = [
105
+ "region=#{region}",
106
+ "az=#{opts[:zone]}",
107
+ "provider=aws",
108
+ "type=#{opts[:type]}"
109
+ ]
110
+ set_labels(node, labels)
92
111
  end
93
- labels = [
94
- "region=#{region}",
95
- "az=#{opts[:zone]}",
96
- "provider=aws"
97
- ]
98
- set_labels(node, labels)
99
112
  end
100
113
 
101
114
  ##
@@ -1,7 +1,7 @@
1
1
  module Kontena
2
2
  module Plugin
3
3
  module Aws
4
- VERSION = "0.2.0.pre1"
4
+ VERSION = "0.2.0"
5
5
  end
6
6
  end
7
7
  end
@@ -1,20 +1,22 @@
1
1
  require 'securerandom'
2
+ require_relative '../prompts'
2
3
 
3
4
  module Kontena::Plugin::Aws::Master
4
5
  class CreateCommand < Kontena::Command
5
6
  include Kontena::Cli::Common
7
+ include Kontena::Plugin::Aws::Prompts
6
8
 
7
9
  option "--name", "[NAME]", "Set Master name"
8
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
9
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
10
- option "--key-pair", "KEY_PAIR", "EC2 key pair name", required: true
10
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
11
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
12
+ option "--key-pair", "KEY_PAIR", "EC2 key pair name"
11
13
  option "--ssl-cert", "SSL CERT", "SSL certificate file (default: generate self-signed cert)"
12
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
13
- option "--zone", "ZONE", "EC2 Availability Zone", default: 'a'
14
- option "--vpc-id", "VPC ID", "Virtual Private Cloud (VPC) ID (default: default vpc)"
15
- option "--subnet-id", "SUBNET ID", "VPC option to specify subnet to launch instance into (default: first subnet from vpc/az)"
16
- option "--type", "SIZE", "Instance type", default: 't2.small'
17
- option "--storage", "STORAGE", "Storage size (GiB)", default: '30'
14
+ option "--region", "REGION", "EC2 Region", environment_variable: "AWS_REGION"
15
+ option "--zone", "ZONE", "EC2 Availability Zone (a,b,c,d,e)"
16
+ option "--vpc-id", "VPC ID", "Virtual Private Cloud (VPC) ID"
17
+ option "--subnet-id", "SUBNET ID", "VPC option to specify subnet to launch instance into (default: first subnet in vpc/az)"
18
+ option "--type", "SIZE", "Instance type"
19
+ option "--storage", "STORAGE", "Storage size (GiB)"
18
20
  option "--vault-secret", "VAULT_SECRET", "Secret key for Vault (default: generate random secret)"
19
21
  option "--vault-iv", "VAULT_IV", "Initialization vector for Vault (default: generate random iv)"
20
22
  option "--mongodb-uri", "URI", "External MongoDB uri (optional)"
@@ -24,18 +26,28 @@ module Kontena::Plugin::Aws::Master
24
26
 
25
27
  def execute
26
28
  require 'kontena/machine/aws'
29
+ aws_access_key = ask_aws_access_key
30
+ aws_secret_key = ask_aws_secret_key
31
+ aws_region = ask_aws_region(aws_access_key, aws_secret_key)
32
+ aws_zone = ask_aws_az(aws_access_key, aws_secret_key, aws_region)
33
+ aws_vpc_id = ask_aws_vpc(aws_access_key, aws_secret_key, aws_region)
27
34
 
28
- provisioner = provisioner(access_key, secret_key, region)
35
+ exit_with_error("Could not find any Virtual Private Cloud (VPC). Please create one in the AWS console first.") unless aws_vpc_id
36
+ aws_subnet_id = ask_aws_subnet(aws_access_key, aws_secret_key, aws_region, aws_zone, aws_vpc_id)
37
+ aws_key_pair = ask_aws_key_pair(aws_access_key, aws_secret_key, aws_region)
38
+ aws_type = ask_aws_instance_type
39
+ aws_storage = ask_aws_storage
40
+ provisioner = provisioner(aws_access_key, aws_secret_key, aws_region)
29
41
  provisioner.run!(
30
42
  name: name,
31
- type: type,
32
- vpc: vpc_id,
33
- zone: zone,
34
- subnet: subnet_id,
43
+ type: aws_type,
44
+ vpc: aws_vpc_id,
45
+ zone: aws_zone,
46
+ subnet: aws_subnet_id,
35
47
  ssl_cert: ssl_cert,
36
- storage: storage,
48
+ storage: aws_storage,
37
49
  version: version,
38
- key_pair: key_pair,
50
+ key_pair: aws_key_pair,
39
51
  vault_secret: vault_secret || SecureRandom.hex(24),
40
52
  vault_iv: vault_iv || SecureRandom.hex(24),
41
53
  mongodb_uri: mongodb_uri,
@@ -2,17 +2,19 @@ module Kontena::Plugin::Aws::Nodes
2
2
  class CreateCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
+ include Kontena::Plugin::Aws::Prompts
5
6
 
6
7
  parameter "[NAME]", "Node name"
7
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
8
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
9
- option "--key-pair", "KEY_PAIR", "EC2 Key Pair", required: true
10
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
11
- option "--zone", "ZONE", "EC2 Availability Zone", default: 'a'
8
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
9
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
10
+ option "--key-pair", "KEY_PAIR", "EC2 Key Pair"
11
+ option "--region", "REGION", "EC2 Region", environment_variable: "AWS_REGION"
12
+ option "--zone", "ZONE", "EC2 Availability Zone (a,b,c,d,e)"
12
13
  option "--vpc-id", "VPC ID", "Virtual Private Cloud (VPC) ID (default: default vpc)"
13
14
  option "--subnet-id", "SUBNET ID", "VPC option to specify subnet to launch instance into (default: first subnet in vpc/az)"
14
- option "--type", "SIZE", "Instance type", default: 't2.small'
15
- option "--storage", "STORAGE", "Storage size (GiB)", default: '30'
15
+ option "--type", "SIZE", "Instance type"
16
+ option "--storage", "STORAGE", "Storage size (GiB)"
17
+ option "--count", "COUNT", "How many instances to create"
16
18
  option "--version", "VERSION", "Define installed Kontena version", default: 'latest'
17
19
  option "--associate-public-ip-address", :flag, "Whether to associated public IP in case the VPC defaults to not doing it", default: true, attribute_name: :associate_public_ip
18
20
  option "--security-groups", "SECURITY GROUPS", "Comma separated list of security groups (names) where the new instance will be attached (default: create grid specific group if not already existing)"
@@ -23,19 +25,31 @@ module Kontena::Plugin::Aws::Nodes
23
25
 
24
26
  require 'kontena/machine/aws'
25
27
  grid = fetch_grid(current_grid)
26
- provisioner = provisioner(client(require_token), access_key, secret_key, region)
28
+ aws_access_key = ask_aws_access_key
29
+ aws_secret_key = ask_aws_secret_key
30
+ aws_region = ask_aws_region(aws_access_key, aws_secret_key)
31
+ aws_zone = ask_aws_az(aws_access_key, aws_secret_key, aws_region)
32
+ aws_vpc_id = ask_aws_vpc(aws_access_key, aws_secret_key, aws_region)
33
+ exit_with_error("Could not find any Virtual Private Cloud (VPC). Please create one in the AWS console first.") unless aws_vpc_id
34
+ aws_subnet_id = ask_aws_subnet(aws_access_key, aws_secret_key, aws_region, aws_zone, aws_vpc_id)
35
+ aws_key_pair = ask_aws_key_pair(aws_access_key, aws_secret_key, aws_region)
36
+ aws_type = ask_aws_instance_type
37
+ aws_storage = ask_aws_storage
38
+ aws_count = ask_instance_count
39
+ provisioner = provisioner(client(require_token), aws_access_key, aws_secret_key, aws_region)
27
40
  provisioner.run!(
28
41
  master_uri: api_url,
29
42
  grid_token: grid['token'],
30
43
  grid: current_grid,
31
44
  name: name,
32
- type: type,
33
- vpc: vpc_id,
34
- zone: zone,
35
- subnet: subnet_id,
36
- storage: storage,
45
+ type: aws_type,
46
+ vpc: aws_vpc_id,
47
+ zone: aws_zone,
48
+ subnet: aws_subnet_id,
49
+ storage: aws_storage,
37
50
  version: version,
38
- key_pair: key_pair,
51
+ key_pair: aws_key_pair,
52
+ count: aws_count,
39
53
  associate_public_ip: associate_public_ip?,
40
54
  security_groups: security_groups
41
55
  )
@@ -55,5 +69,13 @@ module Kontena::Plugin::Aws::Nodes
55
69
  def provisioner(client, access_key, secret_key, region)
56
70
  Kontena::Machine::Aws::NodeProvisioner.new(client, access_key, secret_key, region)
57
71
  end
72
+
73
+ def ask_instance_count
74
+ if self.count.nil?
75
+ prompt.ask('How many instances?: ', default: 1)
76
+ else
77
+ self.count
78
+ end
79
+ end
58
80
  end
59
81
  end
@@ -1,25 +1,40 @@
1
1
  module Kontena::Plugin::Aws::Nodes
2
- class RestartCommand < Clamp::Command
2
+ class RestartCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
+ include Kontena::Plugin::Aws::Prompts
5
6
 
6
- parameter "NAME", "Node name"
7
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
8
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
9
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
7
+ parameter "[NAME]", "Node name"
8
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
9
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
10
+ option "--region", "REGION", "EC2 Region", environment_variable: "AWS_REGION"
10
11
 
11
12
  def execute
12
13
  require_api_url
13
14
  require_current_grid
15
+ token = require_token
16
+ node_name = self.name || ask_node(token)
17
+ node = client(token).get("grids/#{current_grid}/nodes/#{node_name}")
14
18
 
19
+ aws_access_key = ask_aws_access_key
20
+ aws_secret_key = ask_aws_secret_key
21
+ aws_region = self.region || resolve_or_ask_region(node, aws_access_key, aws_secret_key)
15
22
  require_relative '../../../machine/aws'
16
23
 
17
- restarter = restarter(access_key, secret_key, region)
18
- restarter.run!(name)
24
+ restarter = restarter(aws_access_key, aws_secret_key, aws_region)
25
+ restarter.run!(node_name)
19
26
  end
20
27
 
21
28
  def restarter(access_key, secret_key, region)
22
29
  Kontena::Machine::Aws::NodeRestarter.new(access_key, secret_key, region)
23
30
  end
31
+
32
+ def resolve_or_ask_region(node, access_key, secret_key)
33
+ if node['labels'] && region_label = node['labels'].find{ |l| l.split('=').first == 'region' }
34
+ region = region_label.split('=').last
35
+ end
36
+ region = ask_aws_region(access_key, secret_key) unless region
37
+ region
38
+ end
24
39
  end
25
40
  end
@@ -1,25 +1,43 @@
1
1
  module Kontena::Plugin::Aws::Nodes
2
- class TerminateCommand < Clamp::Command
2
+ class TerminateCommand < Kontena::Command
3
3
  include Kontena::Cli::Common
4
4
  include Kontena::Cli::GridOptions
5
+ include Kontena::Plugin::Aws::Prompts
5
6
 
6
- parameter "NAME", "Node name"
7
- option "--access-key", "ACCESS_KEY", "AWS access key ID", required: true
8
- option "--secret-key", "SECRET_KEY", "AWS secret key", required: true
9
- option "--region", "REGION", "EC2 Region", default: 'eu-west-1'
7
+ parameter "[NAME]", "Node name"
8
+ option "--access-key", "ACCESS_KEY", "AWS access key ID", environment_variable: "AWS_ACCESS_KEY_ID"
9
+ option "--secret-key", "SECRET_KEY", "AWS secret access key", environment_variable: "AWS_SECRET_ACCESS_KEY"
10
+ option "--region", "REGION", "EC2 Region (default: node's region)", environment_variable: "AWS_REGION"
11
+ option "--force", :flag, "Force remove", default: false, attribute_name: :forced
10
12
 
11
13
  def execute
12
14
  require_api_url
13
15
  require_current_grid
14
16
 
17
+ token = require_token
18
+ node_name = self.name || ask_node(token)
19
+ node = client(token).get("grids/#{current_grid}/nodes/#{node_name}")
20
+ aws_access_key = ask_aws_access_key
21
+ aws_secret_key = ask_aws_secret_key
22
+ aws_region = self.region || resolve_or_ask_region(node, aws_access_key, aws_secret_key)
23
+
24
+ confirm_command(node_name) unless forced?
15
25
  require 'kontena/machine/aws'
16
26
  grid = client(require_token).get("grids/#{current_grid}")
17
- destroyer = destroyer(client(require_token), access_key, secret_key, region)
18
- destroyer.run!(grid, name)
27
+ destroyer = destroyer(client(require_token), aws_access_key, aws_secret_key, aws_region)
28
+ destroyer.run!(grid, node_name)
19
29
  end
20
30
 
21
31
  def destroyer(client, access_key, secret_key, region)
22
32
  Kontena::Machine::Aws::NodeDestroyer.new(client, access_key, secret_key, region)
23
33
  end
34
+
35
+ def resolve_or_ask_region(node, access_key, secret_key)
36
+ if node['labels'] && region_label = node['labels'].find{ |l| l.split('=').first == 'region' }
37
+ region = region_label.split('=').last
38
+ end
39
+ region = ask_aws_region(access_key, secret_key) unless region
40
+ region
41
+ end
24
42
  end
25
43
  end
@@ -0,0 +1,148 @@
1
+ require 'aws-sdk'
2
+ module Kontena::Plugin::Aws::Prompts
3
+
4
+ def ask_aws_access_key
5
+ if self.access_key.nil?
6
+ prompt.ask('AWS access key: ', echo: false)
7
+ else
8
+ self.access_key
9
+ end
10
+ end
11
+
12
+ def ask_aws_secret_key
13
+ if self.secret_key.nil?
14
+ prompt.ask('AWS secret key: ', echo: false)
15
+ else
16
+ self.secret_key
17
+ end
18
+ end
19
+
20
+ def ask_aws_key_pair(access_key, secret_key, region)
21
+ if self.key_pair.nil?
22
+ prompt.select("Choose EC2 key pair: ") do |menu|
23
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
24
+ aws_client.describe_key_pairs.key_pairs.each{ |key_pair|
25
+ menu.choice key_pair.key_name, key_pair.key_name
26
+ }
27
+ end
28
+ else
29
+ self.key_pair
30
+ end
31
+ end
32
+
33
+ def ask_aws_region(access_key, secret_key, default = 'eu-west-1')
34
+ if self.region.nil?
35
+ prompt.select("Choose EC2 region: ") do |menu|
36
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: 'eu-west-1')
37
+ i = 1
38
+ aws_client.describe_regions.regions.sort_by{|r| r.region_name }.each{ |region|
39
+ menu.choice region.region_name, region.region_name
40
+ if region.region_name == default
41
+ menu.default i
42
+ end
43
+ i += 1
44
+ }
45
+ end
46
+ else
47
+ self.region
48
+ end
49
+ end
50
+
51
+ def ask_aws_az(access_key, secret_key, region)
52
+ if self.zone.nil?
53
+ prompt.select("Choose EC2 Availability Zone: ") do |menu|
54
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
55
+ aws_client.describe_availability_zones.availability_zones.sort_by{|r| r.zone_name }.each{ |zone|
56
+ if zone.state == 'available'
57
+ menu.choice zone.zone_name, zone.zone_name.sub(zone.region_name, '')
58
+ end
59
+ }
60
+ end
61
+ else
62
+ self.zone
63
+ end
64
+ end
65
+
66
+ def ask_aws_vpc(access_key, secret_key, region)
67
+ if self.vpc_id.nil?
68
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
69
+ vpcs = aws_client.describe_vpcs.vpcs
70
+ return nil if vpcs.size == 0
71
+ if vpcs.size == 1 && vpcs.first.state == "available"
72
+ vpcs.first.vpc_id
73
+ else
74
+ prompt.select("Choose Virtual Private Cloud (VPC) ID: ") do |menu|
75
+ vpcs.each{ |vpc|
76
+ if vpc.state == 'available'
77
+ name = vpc.vpc_id
78
+ name += ' (default)' if vpc.is_default
79
+ menu.choice name, vpc.vpc_id
80
+ end
81
+ }
82
+ end
83
+ end
84
+ else
85
+ self.vpc_id
86
+ end
87
+ end
88
+
89
+ def ask_aws_subnet(access_key, secret_key, region, zone, vpc)
90
+ if self.subnet_id.nil?
91
+ aws_client = ::Aws::EC2::Client.new(access_key_id: access_key, secret_access_key: secret_key, region: region)
92
+ subnets_result = aws_client.describe_subnets(filters: [
93
+ { name: "vpc-id", values: [vpc] },
94
+ { name: "availability-zone", values: [zone]}
95
+ ])
96
+ subnets = subnets_result.subnets.sort_by{|s| s.cidr_block}
97
+ return nil if subnets.size == 0
98
+ if subnets.size == 1 && subnets.first.state == "available"
99
+ puts "Using Subnet (#{subnets.first.subnet_id})"
100
+ subnets.first.subnet_id
101
+ else
102
+ prompt.select("Specify subnet to launch instance into: ") do |menu|
103
+ subnets.each{ |subnet|
104
+ if subnet.state == 'available'
105
+ menu.choice "#{subnet.subnet_id} (#{subnet.cidr_block})", subnet.subnet_id
106
+ end
107
+ }
108
+ end
109
+ end
110
+ else
111
+ self.subnet_id
112
+ end
113
+ end
114
+
115
+ def ask_aws_instance_type(default = 't2.small')
116
+ if self.type.nil?
117
+ prompt.ask('Instance type: ', default: default)
118
+ else
119
+ self.type
120
+ end
121
+ end
122
+
123
+ def ask_aws_storage(default = '30')
124
+ if self.storage.nil?
125
+ prompt.ask('Storage size (GiB): ', default: default)
126
+ else
127
+ self.storage
128
+ end
129
+ end
130
+
131
+ def ask_node(token)
132
+ if self.name.nil?
133
+ nodes = client(token).get("grids/#{current_grid}/nodes")
134
+ nodes = nodes['nodes'].select{ |n|
135
+ n['labels'] && n['labels'].include?('provider=aws'.freeze)
136
+ }
137
+ raise "Did not find any nodes with label provider=aws" if nodes.size == 0
138
+ prompt.select("Select node: ") do |menu|
139
+ nodes.sort_by{|n| n['node_number'] }.reverse.each do |node|
140
+ initial = node['initial_member'] ? '(initial) ' : ''
141
+ menu.choice "#{node['name']} #{initial}", node['name']
142
+ end
143
+ end
144
+ else
145
+ self.name
146
+ end
147
+ end
148
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kontena-plugin-aws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0.pre1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kontena, Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-30 00:00:00.000000000 Z
11
+ date: 2016-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kontena-cli
@@ -102,6 +102,7 @@ files:
102
102
  - lib/kontena/plugin/aws/nodes/create_command.rb
103
103
  - lib/kontena/plugin/aws/nodes/restart_command.rb
104
104
  - lib/kontena/plugin/aws/nodes/terminate_command.rb
105
+ - lib/kontena/plugin/aws/prompts.rb
105
106
  - lib/kontena/plugin/aws_command.rb
106
107
  - lib/kontena_cli_plugin.rb
107
108
  homepage: https://github.com/kontena/kontena-plugin-aws
@@ -119,9 +120,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
119
120
  version: '0'
120
121
  required_rubygems_version: !ruby/object:Gem::Requirement
121
122
  requirements:
122
- - - ! '>'
123
+ - - ! '>='
123
124
  - !ruby/object:Gem::Version
124
- version: 1.3.1
125
+ version: '0'
125
126
  requirements: []
126
127
  rubyforge_project:
127
128
  rubygems_version: 2.4.5