kontena-cli 0.13.4 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/kontena-cli.gemspec +2 -0
  4. data/lib/kontena/cli/app_command.rb +2 -0
  5. data/lib/kontena/cli/apps/common.rb +80 -74
  6. data/lib/kontena/cli/apps/config_command.rb +29 -0
  7. data/lib/kontena/cli/apps/deploy_command.rb +12 -81
  8. data/lib/kontena/cli/apps/docker_helper.rb +3 -3
  9. data/lib/kontena/cli/apps/init_command.rb +0 -3
  10. data/lib/kontena/cli/apps/list_command.rb +2 -3
  11. data/lib/kontena/cli/apps/logs_command.rb +2 -3
  12. data/lib/kontena/cli/apps/monitor_command.rb +3 -4
  13. data/lib/kontena/cli/apps/remove_command.rb +4 -4
  14. data/lib/kontena/cli/apps/restart_command.rb +2 -3
  15. data/lib/kontena/cli/apps/scale_command.rb +3 -5
  16. data/lib/kontena/cli/apps/service_generator.rb +123 -0
  17. data/lib/kontena/cli/apps/service_generator_v2.rb +26 -0
  18. data/lib/kontena/cli/apps/show_command.rb +1 -2
  19. data/lib/kontena/cli/apps/start_command.rb +2 -3
  20. data/lib/kontena/cli/apps/stop_command.rb +2 -3
  21. data/lib/kontena/cli/apps/yaml/reader.rb +150 -0
  22. data/lib/kontena/cli/apps/yaml/service_extender.rb +60 -0
  23. data/lib/kontena/cli/apps/yaml/validations.rb +79 -0
  24. data/lib/kontena/cli/apps/yaml/validator.rb +55 -0
  25. data/lib/kontena/cli/apps/yaml/validator_v2.rb +74 -0
  26. data/lib/kontena/cli/common.rb +23 -0
  27. data/lib/kontena/cli/etcd/remove_command.rb +2 -0
  28. data/lib/kontena/cli/grids/remove_command.rb +2 -0
  29. data/lib/kontena/cli/grids/users/remove_command.rb +3 -0
  30. data/lib/kontena/cli/master/azure/create_command.rb +0 -2
  31. data/lib/kontena/cli/master/packet/create_command.rb +42 -0
  32. data/lib/kontena/cli/master/packet_command.rb +14 -0
  33. data/lib/kontena/cli/master/upcloud/create_command.rb +39 -0
  34. data/lib/kontena/cli/master/upcloud_command.rb +13 -0
  35. data/lib/kontena/cli/master/users/remove_command.rb +3 -0
  36. data/lib/kontena/cli/master/users/roles/remove_command.rb +2 -0
  37. data/lib/kontena/cli/master_command.rb +4 -0
  38. data/lib/kontena/cli/node_command.rb +4 -0
  39. data/lib/kontena/cli/nodes/azure/create_command.rb +0 -2
  40. data/lib/kontena/cli/nodes/list_command.rb +4 -8
  41. data/lib/kontena/cli/nodes/packet/create_command.rb +35 -0
  42. data/lib/kontena/cli/nodes/packet/restart_command.rb +17 -0
  43. data/lib/kontena/cli/nodes/packet/terminate_command.rb +20 -0
  44. data/lib/kontena/cli/nodes/packet_command.rb +15 -0
  45. data/lib/kontena/cli/nodes/remove_command.rb +2 -0
  46. data/lib/kontena/cli/nodes/show_command.rb +3 -1
  47. data/lib/kontena/cli/nodes/upcloud/create_command.rb +33 -0
  48. data/lib/kontena/cli/nodes/upcloud/restart_command.rb +20 -0
  49. data/lib/kontena/cli/nodes/upcloud/terminate_command.rb +20 -0
  50. data/lib/kontena/cli/nodes/upcloud_command.rb +15 -0
  51. data/lib/kontena/cli/registry/remove_command.rb +3 -0
  52. data/lib/kontena/cli/services/remove_command.rb +2 -0
  53. data/lib/kontena/cli/services/services_helper.rb +1 -0
  54. data/lib/kontena/cli/vault/list_command.rb +2 -0
  55. data/lib/kontena/cli/vault/read_command.rb +2 -0
  56. data/lib/kontena/cli/vault/remove_command.rb +4 -0
  57. data/lib/kontena/cli/vault/update_command.rb +8 -1
  58. data/lib/kontena/cli/vault/write_command.rb +2 -0
  59. data/lib/kontena/cli/vpn/remove_command.rb +3 -0
  60. data/lib/kontena/machine/azure/master_provisioner.rb +2 -2
  61. data/lib/kontena/machine/azure/node_provisioner.rb +7 -4
  62. data/lib/kontena/machine/digital_ocean/node_provisioner.rb +1 -1
  63. data/lib/kontena/machine/packet.rb +17 -0
  64. data/lib/kontena/machine/packet/cloudinit.yml +66 -0
  65. data/lib/kontena/machine/packet/cloudinit_master.yml +118 -0
  66. data/lib/kontena/machine/packet/master_provisioner.rb +93 -0
  67. data/lib/kontena/machine/packet/node_destroyer.rb +42 -0
  68. data/lib/kontena/machine/packet/node_provisioner.rb +77 -0
  69. data/lib/kontena/machine/packet/node_restarter.rb +41 -0
  70. data/lib/kontena/machine/packet/packet_common.rb +89 -0
  71. data/lib/kontena/machine/upcloud.rb +9 -0
  72. data/lib/kontena/machine/upcloud/cloudinit.yml +64 -0
  73. data/lib/kontena/machine/upcloud/cloudinit_master.yml +118 -0
  74. data/lib/kontena/machine/upcloud/master_provisioner.rb +136 -0
  75. data/lib/kontena/machine/upcloud/node_destroyer.rb +82 -0
  76. data/lib/kontena/machine/upcloud/node_provisioner.rb +119 -0
  77. data/lib/kontena/machine/upcloud/node_restarter.rb +47 -0
  78. data/lib/kontena/machine/upcloud/upcloud_common.rb +70 -0
  79. data/lib/kontena/scripts/completer +8 -3
  80. data/spec/fixtures/docker-compose_v2.yml +10 -0
  81. data/spec/fixtures/kontena-invalid.yml +4 -0
  82. data/spec/fixtures/kontena-with-variables.yml +19 -0
  83. data/spec/fixtures/kontena.yml +2 -2
  84. data/spec/fixtures/kontena_v2.yml +35 -0
  85. data/spec/kontena/cli/app/common_spec.rb +39 -101
  86. data/spec/kontena/cli/app/deploy_command_spec.rb +37 -388
  87. data/spec/kontena/cli/app/docker_helper_spec.rb +4 -4
  88. data/spec/kontena/cli/app/service_generator_spec.rb +374 -0
  89. data/spec/kontena/cli/app/service_generator_v2_spec.rb +74 -0
  90. data/spec/kontena/cli/app/yaml/reader_spec.rb +249 -0
  91. data/spec/kontena/cli/app/yaml/service_extender_spec.rb +104 -0
  92. data/spec/kontena/cli/app/yaml/validator_spec.rb +263 -0
  93. data/spec/kontena/cli/app/yaml/validator_v2_spec.rb +309 -0
  94. data/spec/kontena/cli/common_spec.rb +39 -1
  95. data/spec/kontena/cli/master/users/remove_command_spec.rb +9 -0
  96. data/spec/kontena/cli/master/users/roles/remove_command_spec.rb +2 -0
  97. metadata +86 -2
@@ -8,6 +8,8 @@ module Kontena::Cli::Vault
8
8
 
9
9
  def execute
10
10
  require_api_url
11
+ require_current_grid
12
+
11
13
  token = require_token
12
14
  secret = value
13
15
  if secret.to_s == ''
@@ -2,9 +2,12 @@ module Kontena::Cli::Vpn
2
2
  class RemoveCommand < Clamp::Command
3
3
  include Kontena::Cli::Common
4
4
 
5
+ option "--force", :flag, "Force remove", default: false, attribute_name: :forced
6
+
5
7
  def execute
6
8
  require_api_url
7
9
  token = require_token
10
+ confirm unless forced?
8
11
 
9
12
  vpn = client(token).get("services/#{current_grid}/vpn") rescue nil
10
13
  abort("VPN service does not exist") if vpn.nil?
@@ -53,7 +53,7 @@ module Kontena
53
53
  vm_name: vm_name,
54
54
  vm_user: 'core',
55
55
  location: opts[:location],
56
- image: '2b171e93f07c4903bcad35bda10acf22__CoreOS-Stable-766.3.0',
56
+ image: '2b171e93f07c4903bcad35bda10acf22__CoreOS-Stable-1010.5.0',
57
57
  custom_data: Base64.encode64(user_data(userdata_vars)),
58
58
  ssh_key: opts[:ssh_key]
59
59
  }
@@ -64,7 +64,7 @@ module Kontena
64
64
  virtual_network_name: opts[:virtual_network],
65
65
  subnet_name: opts[:subnet],
66
66
  tcp_endpoints: '80,443',
67
- private_key_file: opts[:ssh_key],
67
+ private_key_file: File.expand_path(opts[:ssh_key]),
68
68
  ssh_port: 22,
69
69
  vm_size: opts[:size],
70
70
  }
@@ -20,7 +20,7 @@ module Kontena
20
20
  abort('Invalid management certificate') unless File.exists?(File.expand_path(certificate))
21
21
 
22
22
  @client = ::Azure
23
- client.management_certificate = certificate
23
+ client.management_certificate = File.expand_path(certificate)
24
24
  client.subscription_id = subscription_id
25
25
  client.vm_management.initialize_external_logger(Logger.new) # We don't want all the output
26
26
  end
@@ -50,9 +50,9 @@ module Kontena
50
50
  vm_name: vm_name,
51
51
  vm_user: 'core',
52
52
  location: opts[:location],
53
- image: '2b171e93f07c4903bcad35bda10acf22__CoreOS-Stable-766.3.0',
53
+ image: '2b171e93f07c4903bcad35bda10acf22__CoreOS-Stable-1010.5.0',
54
54
  custom_data: Base64.encode64(user_data(userdata_vars)),
55
- ssh_key: opts[:ssh_key]
55
+ ssh_key: File.expand_path(opts[:ssh_key])
56
56
  }
57
57
  options = {
58
58
  cloud_service_name: cloud_service_name,
@@ -72,7 +72,10 @@ module Kontena
72
72
  sleep 2 until node = vm_exists_in_grid?(opts[:grid], vm_name)
73
73
  end
74
74
  if node
75
- labels = ["region=#{cloud_service(cloud_service_name).location}"]
75
+ labels = [
76
+ "region=#{cloud_service(cloud_service_name).location}",
77
+ "az=#{cloud_service(cloud_service_name).location}"
78
+ ]
76
79
  set_labels(node, labels)
77
80
  end
78
81
  end
@@ -47,7 +47,7 @@ module Kontena
47
47
  ShellSpinner "Waiting for node #{droplet.name.colorize(:cyan)} join to grid #{opts[:grid].colorize(:cyan)} " do
48
48
  sleep 2 until node = droplet_exists_in_grid?(opts[:grid], droplet)
49
49
  end
50
- set_labels(node, ["region=#{opts[:region]}"])
50
+ set_labels(node, ["region=#{opts[:region]}", "az=#{opts[:region]}"])
51
51
  end
52
52
 
53
53
  def user_data(vars)
@@ -0,0 +1,17 @@
1
+ begin
2
+ gem 'packethost', '>= 0.0.6'
3
+ require 'packethost'
4
+ rescue LoadError
5
+ puts "It seems that you don't have Packet API installed."
6
+ puts "Install it using: gem install packethost"
7
+ exit 1
8
+ end
9
+
10
+ require_relative 'random_name'
11
+ require_relative 'cert_helper'
12
+ require_relative 'packet/packet_common'
13
+ require_relative 'packet/node_provisioner'
14
+ require_relative 'packet/node_destroyer'
15
+ require_relative 'packet/node_restarter'
16
+ require_relative 'packet/master_provisioner'
17
+
@@ -0,0 +1,66 @@
1
+ #cloud-config
2
+ write_files:
3
+ - path: /etc/kontena-agent.env
4
+ permissions: 0600
5
+ owner: root
6
+ content: |
7
+ KONTENA_URI="<%= master_uri %>"
8
+ KONTENA_TOKEN="<%= grid_token %>"
9
+ KONTENA_PEER_INTERFACE=eth1
10
+ KONTENA_VERSION=<%= version %>
11
+ KONTENA_PRIVATE_IP=$private_ipv4
12
+ - path: /etc/systemd/system/docker.service.d/50-kontena.conf
13
+ content: |
14
+ [Service]
15
+ Environment='DOCKER_OPTS=--insecure-registry="10.81.0.0/19" --bip="172.17.43.1/16"'
16
+ - path: /etc/sysctl.d/99-inotify.conf
17
+ owner: root
18
+ permissions: 0644
19
+ content: |
20
+ fs.inotify.max_user_instances = 8192
21
+ - path: /etc/resolv.conf
22
+ permissions: 0644
23
+ owner: root
24
+ content: |
25
+ nameserver 172.17.43.1
26
+ nameserver 8.8.8.8
27
+ nameserver 8.8.4.4
28
+ coreos:
29
+ units:
30
+ - name: 10-weave.network
31
+ runtime: false
32
+ content: |
33
+ [Match]
34
+ Type=bridge
35
+ Name=weave*
36
+
37
+ [Network]
38
+ - name: kontena-agent.service
39
+ command: start
40
+ enable: true
41
+ content: |
42
+ [Unit]
43
+ Description=kontena-agent
44
+ After=network-online.target
45
+ After=docker.service
46
+ Description=Kontena Agent
47
+ Documentation=http://www.kontena.io/
48
+ Requires=network-online.target
49
+ Requires=docker.service
50
+
51
+ [Service]
52
+ Restart=always
53
+ RestartSec=5
54
+ EnvironmentFile=/etc/kontena-agent.env
55
+ ExecStartPre=-/usr/bin/docker stop kontena-agent
56
+ ExecStartPre=-/usr/bin/docker rm kontena-agent
57
+ ExecStartPre=/usr/bin/docker pull kontena/agent:${KONTENA_VERSION}
58
+ ExecStart=/usr/bin/docker run --name kontena-agent \
59
+ -e KONTENA_URI=${KONTENA_URI} \
60
+ -e KONTENA_TOKEN=${KONTENA_TOKEN} \
61
+ -e KONTENA_PEER_INTERFACE=${KONTENA_PEER_INTERFACE} \
62
+ -e KONTENA_PRIVATE_IP=${KONTENA_PRIVATE_IP} \
63
+ -v=/var/run/docker.sock:/var/run/docker.sock \
64
+ -v=/etc/kontena-agent.env:/etc/kontena.env \
65
+ --net=host \
66
+ kontena/agent:${KONTENA_VERSION}
@@ -0,0 +1,118 @@
1
+ #cloud-config
2
+ write_files:
3
+ - path: /etc/kontena-server.env
4
+ permissions: 0600
5
+ owner: root
6
+ content: |
7
+ KONTENA_VERSION=<%= version %>
8
+ KONTENA_VAULT_KEY=<%= vault_secret %>
9
+ KONTENA_VAULT_IV=<%= vault_iv %>
10
+ <% if ssl_cert %>SSL_CERT="/etc/kontena-server.pem"
11
+
12
+ - path: /etc/kontena-server.pem
13
+ permissions: 0600
14
+ owner: root
15
+ content: | <% ssl_cert.split(/\n/).each do |row| %>
16
+ <%= row %><% end %><% end %>
17
+ - path: /opt/bin/kontena-haproxy.sh
18
+ permissions: 0755
19
+ owner: root
20
+ content: |
21
+ #!/bin/sh
22
+ if [ -n "$SSL_CERT" ]; then
23
+ SSL_CERT=$(awk 1 ORS='\\n' $SSL_CERT)
24
+ else
25
+ SSL_CERT="**None**"
26
+ fi
27
+ /usr/bin/docker run --name=kontena-server-haproxy \
28
+ --link kontena-server-api:kontena-server-api \
29
+ -e SSL_CERT="$SSL_CERT" \
30
+ -p 80:80 -p 443:443 kontena/haproxy:latest
31
+ coreos:
32
+ units:
33
+ <% unless mongodb_uri -%>
34
+ - name: kontena-server-mongo.service
35
+ command: start
36
+ enable: true
37
+ content: |
38
+ [Unit]
39
+ Description=kontena-server-mongo
40
+ After=network-online.target
41
+ After=docker.service
42
+ Description=Kontena Server MongoDB
43
+ Documentation=http://www.mongodb.org/
44
+ Requires=network-online.target
45
+ Requires=docker.service
46
+
47
+ [Service]
48
+ Restart=always
49
+ RestartSec=5
50
+ ExecStartPre=/usr/bin/docker pull mongo:3.0
51
+ ExecStartPre=-/usr/bin/docker create --name=kontena-server-mongo-data mongo:3.0
52
+ ExecStartPre=-/usr/bin/docker stop kontena-server-mongo
53
+ ExecStartPre=-/usr/bin/docker rm kontena-server-mongo
54
+ ExecStart=/usr/bin/docker run --name=kontena-server-mongo \
55
+ --volumes-from=kontena-server-mongo-data \
56
+ mongo:3.0 mongod --smallfiles
57
+ <% end -%>
58
+ - name: kontena-server-api.service
59
+ command: start
60
+ enable: true
61
+ content: |
62
+ [Unit]
63
+ Description=kontena-server-api
64
+ After=network-online.target
65
+ After=docker.service
66
+ After=kontena-server-mongo.service
67
+ Description=Kontena Master
68
+ Documentation=http://www.kontena.io/
69
+ Before=kontena-server-haproxy.service
70
+ Wants=kontena-server-haproxy.service
71
+ Requires=network-online.target
72
+ Requires=docker.service
73
+ <% unless mongodb_uri -%>
74
+ Requires=kontena-server-mongo.service
75
+ <% end %>
76
+
77
+ [Service]
78
+ Restart=always
79
+ RestartSec=5
80
+ EnvironmentFile=/etc/kontena-server.env
81
+ ExecStartPre=-/usr/bin/docker stop kontena-server-api
82
+ ExecStartPre=-/usr/bin/docker rm kontena-server-api
83
+ ExecStartPre=/usr/bin/docker pull kontena/server:${KONTENA_VERSION}
84
+ ExecStart=/usr/bin/docker run --name kontena-server-api \
85
+ <% if mongodb_uri -%>
86
+ -e MONGODB_URI=<%= mongodb_uri %> \
87
+ <% else -%>
88
+ --link kontena-server-mongo:mongodb \
89
+ -e MONGODB_URI=mongodb://mongodb:27017/kontena_server \
90
+ <% end -%>
91
+ <% if auth_server %>
92
+ -e AUTH_API_URL=<%= auth_server %> \
93
+ <% end -%>
94
+ -e VAULT_KEY=${KONTENA_VAULT_KEY} -e VAULT_IV=${KONTENA_VAULT_IV} \
95
+ kontena/server:${KONTENA_VERSION}
96
+
97
+ - name: kontena-server-haproxy.service
98
+ command: start
99
+ enable: true
100
+ content: |
101
+ [Unit]
102
+ Description=kontena-server-haproxy
103
+ After=network-online.target
104
+ After=docker.service
105
+ Description=Kontena Server HAProxy
106
+ Documentation=http://www.kontena.io/
107
+ Requires=network-online.target
108
+ Requires=docker.service
109
+ Requires=kontena-server-api.service
110
+
111
+ [Service]
112
+ Restart=always
113
+ RestartSec=5
114
+ EnvironmentFile=/etc/kontena-server.env
115
+ ExecStartPre=-/usr/bin/docker stop kontena-server-haproxy
116
+ ExecStartPre=-/usr/bin/docker rm kontena-server-haproxy
117
+ ExecStartPre=/usr/bin/docker pull kontena/haproxy:latest
118
+ ExecStart=/opt/bin/kontena-haproxy.sh
@@ -0,0 +1,93 @@
1
+ require 'shell-spinner'
2
+
3
+ module Kontena
4
+ module Machine
5
+ module Packet
6
+ class MasterProvisioner
7
+ include RandomName
8
+ include Machine::CertHelper
9
+ include PacketCommon
10
+
11
+ attr_reader :client, :http_client
12
+
13
+ # @param [String] token Packet token
14
+ def initialize(token)
15
+ @client = login(token)
16
+ end
17
+
18
+ def run!(opts)
19
+ abort('Project does not exist in Packet') unless project = find_project(opts[:project])
20
+ abort('Facility does not exist in Packet') unless facility = find_facility(opts[:facility])
21
+ abort('Operating system coreos_stable does not exist in Packet') unless os = find_os('coreos_stable')
22
+ abort('Device type does not exist in Packet') unless plan = find_plan(opts[:plan])
23
+
24
+ check_or_create_ssh_key(File.expand_path(opts[:ssh_key])) if opts[:ssh_key]
25
+
26
+ if opts[:ssl_cert]
27
+ abort('Invalid ssl cert') unless File.exists?(File.expand_path(opts[:ssl_cert]))
28
+ ssl_cert = File.read(File.expand_path(opts[:ssl_cert]))
29
+ else
30
+ ShellSpinner "Generating self-signed SSL certificate" do
31
+ ssl_cert = generate_self_signed_cert
32
+ end
33
+ end
34
+
35
+ userdata_vars = {
36
+ ssl_cert: ssl_cert,
37
+ auth_server: opts[:auth_server],
38
+ version: opts[:version],
39
+ vault_secret: opts[:vault_secret],
40
+ vault_iv: opts[:vault_iv],
41
+ mongodb_uri: opts[:mongodb_uri]
42
+ }
43
+
44
+ device = project.new_device(
45
+ hostname: generate_name,
46
+ facility: facility.to_hash,
47
+ operating_system: os.to_hash,
48
+ plan: plan.to_hash,
49
+ billing_cycle: opts[:billing],
50
+ locked: true,
51
+ userdata: user_data(userdata_vars, 'cloudinit_master.yml')
52
+ )
53
+
54
+ ShellSpinner "Creating Packet device #{device.hostname.colorize(:cyan)} " do
55
+ api_retry "Packet API reported an error, please try again" do
56
+ response = client.create_device(device)
57
+ raise response.body unless response.success?
58
+ end
59
+
60
+ until device && [:active, :provisioning, :powering_on].include?(device.state)
61
+ device = find_device(project.id, device.hostname) rescue nil
62
+ sleep 5
63
+ end
64
+ end
65
+
66
+ public_ip = device_public_ip(device)
67
+ master_url = "https://#{public_ip['address']}"
68
+
69
+ Excon.defaults[:ssl_verify_peer] = false
70
+ @http_client = Excon.new("#{master_url}", :connect_timeout => 10)
71
+
72
+ ShellSpinner "Waiting for #{device.hostname.colorize(:cyan)} to start (estimate 4 minutes)" do
73
+ sleep 5 until master_running?
74
+ end
75
+
76
+ puts "Kontena Master is now running at #{master_url}"
77
+ puts "Use #{"kontena login --name=#{device.hostname.sub('kontena-master-', '')} #{master_url}".colorize(:light_black)} to complete Kontena Master setup"
78
+ end
79
+
80
+ def generate_name
81
+ "kontena-master-#{super}-#{rand(1..9)}"
82
+ end
83
+
84
+ def master_running?
85
+ http_client.get(path: '/').status == 200
86
+ rescue
87
+ false
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,42 @@
1
+ require 'shell-spinner'
2
+
3
+ module Kontena
4
+ module Machine
5
+ module Packet
6
+ class NodeDestroyer
7
+ include RandomName
8
+ include PacketCommon
9
+
10
+ attr_reader :client, :api_client
11
+
12
+ # @param [Kontena::Client] api_client Kontena api client
13
+ # @param [String] token Packet api token
14
+ def initialize(api_client, token)
15
+ @api_client = api_client
16
+ @client = login(token)
17
+ end
18
+
19
+ def run!(grid, project_id, name)
20
+ device = client.list_devices(project_id).find{|d| d.hostname == name}
21
+ abort("Device #{name.colorize(:cyan)} not found in Packet") unless device
22
+
23
+ ShellSpinner "Terminating Packet device #{name.colorize(:cyan)} " do
24
+ begin
25
+ response = client.delete_device(device.id)
26
+ raise unless response.success?
27
+ rescue
28
+ abort "Cannot delete device #{name.colorize(:cyan)} in Packet"
29
+ end
30
+ end
31
+
32
+ node = api_client.get("grids/#{grid['id']}/nodes")['nodes'].find{|n| n['name'] == name}
33
+ if node
34
+ ShellSpinner "Removing node #{name.colorize(:cyan)} from grid #{grid['name'].colorize(:cyan)} " do
35
+ api_client.delete("grids/#{grid['id']}/nodes/#{name}")
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,77 @@
1
+ require 'shell-spinner'
2
+
3
+ module Kontena
4
+ module Machine
5
+ module Packet
6
+ class NodeProvisioner
7
+ include RandomName
8
+ include PacketCommon
9
+
10
+ attr_reader :client, :api_client
11
+
12
+ # @param [Kontena::Client] api_client Kontena api client
13
+ # @param [String] token Digital Ocean token
14
+ def initialize(api_client, token)
15
+ @api_client = api_client
16
+ @client = login(token)
17
+ end
18
+
19
+ def run!(opts)
20
+ abort('Project does not exist in Packet') unless project = find_project(opts[:project])
21
+ abort('Facility does not exist in Packet') unless facility = find_facility(opts[:facility])
22
+ abort('Operating system coreos_stable does not exist in Packet') unless os = find_os('coreos_stable')
23
+ abort('Device type does not exist in Packet') unless plan = find_plan(opts[:plan])
24
+
25
+ check_or_create_ssh_key(opts[:ssh_key]) if opts[:ssh_key]
26
+
27
+ userdata_vars = {
28
+ version: opts[:version],
29
+ master_uri: opts[:master_uri],
30
+ grid_token: opts[:grid_token],
31
+ }
32
+
33
+ device = project.new_device(
34
+ hostname: generate_name,
35
+ facility: facility.to_hash,
36
+ operating_system: os.to_hash,
37
+ plan: plan.to_hash,
38
+ billing_cycle: opts[:billing],
39
+ locked: false,
40
+ userdata: user_data(userdata_vars, 'cloudinit.yml')
41
+ )
42
+
43
+ ShellSpinner "Creating Packet device #{device.hostname.colorize(:cyan)} " do
44
+ api_retry "Packet API reported an error, please try again" do
45
+ response = client.create_device(device)
46
+ raise response.body unless response.success?
47
+ end
48
+
49
+ until device && [:active, :provisioning, :powering_on].include?(device.state)
50
+ device = find_device(project.id, device.hostname) rescue nil
51
+ sleep 5
52
+ end
53
+ end
54
+
55
+ node = nil
56
+ ShellSpinner "Waiting for node #{device.hostname.colorize(:cyan)} join to grid #{opts[:grid].colorize(:cyan)} (estimate 4 minutes) " do
57
+ sleep 2 until node = device_exists_in_grid?(opts[:grid], device)
58
+ end
59
+ set_labels(node, ["region=#{opts[:facility]}", "provider=packet"])
60
+ end
61
+
62
+ def generate_name
63
+ "#{super}-#{rand(1..99)}"
64
+ end
65
+
66
+ def device_exists_in_grid?(grid, device)
67
+ api_client.get("grids/#{grid}/nodes")['nodes'].find{|n| n['name'] == device.hostname}
68
+ end
69
+
70
+ def set_labels(node, labels)
71
+ data = {labels: labels}
72
+ api_client.put("nodes/#{node['id']}", data, {}, {'Kontena-Grid-Token' => node['grid']['token']})
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end