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.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/kontena-cli.gemspec +2 -0
- data/lib/kontena/cli/app_command.rb +2 -0
- data/lib/kontena/cli/apps/common.rb +80 -74
- data/lib/kontena/cli/apps/config_command.rb +29 -0
- data/lib/kontena/cli/apps/deploy_command.rb +12 -81
- data/lib/kontena/cli/apps/docker_helper.rb +3 -3
- data/lib/kontena/cli/apps/init_command.rb +0 -3
- data/lib/kontena/cli/apps/list_command.rb +2 -3
- data/lib/kontena/cli/apps/logs_command.rb +2 -3
- data/lib/kontena/cli/apps/monitor_command.rb +3 -4
- data/lib/kontena/cli/apps/remove_command.rb +4 -4
- data/lib/kontena/cli/apps/restart_command.rb +2 -3
- data/lib/kontena/cli/apps/scale_command.rb +3 -5
- data/lib/kontena/cli/apps/service_generator.rb +123 -0
- data/lib/kontena/cli/apps/service_generator_v2.rb +26 -0
- data/lib/kontena/cli/apps/show_command.rb +1 -2
- data/lib/kontena/cli/apps/start_command.rb +2 -3
- data/lib/kontena/cli/apps/stop_command.rb +2 -3
- data/lib/kontena/cli/apps/yaml/reader.rb +150 -0
- data/lib/kontena/cli/apps/yaml/service_extender.rb +60 -0
- data/lib/kontena/cli/apps/yaml/validations.rb +79 -0
- data/lib/kontena/cli/apps/yaml/validator.rb +55 -0
- data/lib/kontena/cli/apps/yaml/validator_v2.rb +74 -0
- data/lib/kontena/cli/common.rb +23 -0
- data/lib/kontena/cli/etcd/remove_command.rb +2 -0
- data/lib/kontena/cli/grids/remove_command.rb +2 -0
- data/lib/kontena/cli/grids/users/remove_command.rb +3 -0
- data/lib/kontena/cli/master/azure/create_command.rb +0 -2
- data/lib/kontena/cli/master/packet/create_command.rb +42 -0
- data/lib/kontena/cli/master/packet_command.rb +14 -0
- data/lib/kontena/cli/master/upcloud/create_command.rb +39 -0
- data/lib/kontena/cli/master/upcloud_command.rb +13 -0
- data/lib/kontena/cli/master/users/remove_command.rb +3 -0
- data/lib/kontena/cli/master/users/roles/remove_command.rb +2 -0
- data/lib/kontena/cli/master_command.rb +4 -0
- data/lib/kontena/cli/node_command.rb +4 -0
- data/lib/kontena/cli/nodes/azure/create_command.rb +0 -2
- data/lib/kontena/cli/nodes/list_command.rb +4 -8
- data/lib/kontena/cli/nodes/packet/create_command.rb +35 -0
- data/lib/kontena/cli/nodes/packet/restart_command.rb +17 -0
- data/lib/kontena/cli/nodes/packet/terminate_command.rb +20 -0
- data/lib/kontena/cli/nodes/packet_command.rb +15 -0
- data/lib/kontena/cli/nodes/remove_command.rb +2 -0
- data/lib/kontena/cli/nodes/show_command.rb +3 -1
- data/lib/kontena/cli/nodes/upcloud/create_command.rb +33 -0
- data/lib/kontena/cli/nodes/upcloud/restart_command.rb +20 -0
- data/lib/kontena/cli/nodes/upcloud/terminate_command.rb +20 -0
- data/lib/kontena/cli/nodes/upcloud_command.rb +15 -0
- data/lib/kontena/cli/registry/remove_command.rb +3 -0
- data/lib/kontena/cli/services/remove_command.rb +2 -0
- data/lib/kontena/cli/services/services_helper.rb +1 -0
- data/lib/kontena/cli/vault/list_command.rb +2 -0
- data/lib/kontena/cli/vault/read_command.rb +2 -0
- data/lib/kontena/cli/vault/remove_command.rb +4 -0
- data/lib/kontena/cli/vault/update_command.rb +8 -1
- data/lib/kontena/cli/vault/write_command.rb +2 -0
- data/lib/kontena/cli/vpn/remove_command.rb +3 -0
- data/lib/kontena/machine/azure/master_provisioner.rb +2 -2
- data/lib/kontena/machine/azure/node_provisioner.rb +7 -4
- data/lib/kontena/machine/digital_ocean/node_provisioner.rb +1 -1
- data/lib/kontena/machine/packet.rb +17 -0
- data/lib/kontena/machine/packet/cloudinit.yml +66 -0
- data/lib/kontena/machine/packet/cloudinit_master.yml +118 -0
- data/lib/kontena/machine/packet/master_provisioner.rb +93 -0
- data/lib/kontena/machine/packet/node_destroyer.rb +42 -0
- data/lib/kontena/machine/packet/node_provisioner.rb +77 -0
- data/lib/kontena/machine/packet/node_restarter.rb +41 -0
- data/lib/kontena/machine/packet/packet_common.rb +89 -0
- data/lib/kontena/machine/upcloud.rb +9 -0
- data/lib/kontena/machine/upcloud/cloudinit.yml +64 -0
- data/lib/kontena/machine/upcloud/cloudinit_master.yml +118 -0
- data/lib/kontena/machine/upcloud/master_provisioner.rb +136 -0
- data/lib/kontena/machine/upcloud/node_destroyer.rb +82 -0
- data/lib/kontena/machine/upcloud/node_provisioner.rb +119 -0
- data/lib/kontena/machine/upcloud/node_restarter.rb +47 -0
- data/lib/kontena/machine/upcloud/upcloud_common.rb +70 -0
- data/lib/kontena/scripts/completer +8 -3
- data/spec/fixtures/docker-compose_v2.yml +10 -0
- data/spec/fixtures/kontena-invalid.yml +4 -0
- data/spec/fixtures/kontena-with-variables.yml +19 -0
- data/spec/fixtures/kontena.yml +2 -2
- data/spec/fixtures/kontena_v2.yml +35 -0
- data/spec/kontena/cli/app/common_spec.rb +39 -101
- data/spec/kontena/cli/app/deploy_command_spec.rb +37 -388
- data/spec/kontena/cli/app/docker_helper_spec.rb +4 -4
- data/spec/kontena/cli/app/service_generator_spec.rb +374 -0
- data/spec/kontena/cli/app/service_generator_v2_spec.rb +74 -0
- data/spec/kontena/cli/app/yaml/reader_spec.rb +249 -0
- data/spec/kontena/cli/app/yaml/service_extender_spec.rb +104 -0
- data/spec/kontena/cli/app/yaml/validator_spec.rb +263 -0
- data/spec/kontena/cli/app/yaml/validator_v2_spec.rb +309 -0
- data/spec/kontena/cli/common_spec.rb +39 -1
- data/spec/kontena/cli/master/users/remove_command_spec.rb +9 -0
- data/spec/kontena/cli/master/users/roles/remove_command_spec.rb +2 -0
- metadata +86 -2
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'shell-spinner'
|
|
2
|
+
|
|
3
|
+
module Kontena
|
|
4
|
+
module Machine
|
|
5
|
+
module Packet
|
|
6
|
+
class NodeRestarter
|
|
7
|
+
include RandomName
|
|
8
|
+
include PacketCommon
|
|
9
|
+
|
|
10
|
+
attr_reader :client
|
|
11
|
+
|
|
12
|
+
# @param [String] token Packet api token
|
|
13
|
+
def initialize(token)
|
|
14
|
+
@client = login(token)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @param [String] project_id Packet project id
|
|
18
|
+
# @param [String] token Node hostname
|
|
19
|
+
def run!(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
|
+
abort("Your version of 'packethost' gem does not support rebooting servers") unless client.respond_to?(:reboot_device)
|
|
23
|
+
|
|
24
|
+
ShellSpinner "Restarting Packet device #{device.hostname.colorize(:cyan)} " do
|
|
25
|
+
begin
|
|
26
|
+
response = client.reboot_device(device)
|
|
27
|
+
raise unless response.success?
|
|
28
|
+
rescue
|
|
29
|
+
abort "Cannot delete device #{name.colorize(:cyan)} in Packet"
|
|
30
|
+
end
|
|
31
|
+
sleep 5
|
|
32
|
+
until device && device.state == :active
|
|
33
|
+
device = find_device(project.id, device.hostname) rescue nil
|
|
34
|
+
sleep 5
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
require 'erb'
|
|
2
|
+
|
|
3
|
+
module Kontena
|
|
4
|
+
module Machine
|
|
5
|
+
module Packet
|
|
6
|
+
module PacketCommon
|
|
7
|
+
# @param [String] token Packet token
|
|
8
|
+
def login(token)
|
|
9
|
+
::Packet::Client.new(token)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def create_ssh_key(ssh_key)
|
|
13
|
+
client.create_ssh_key(ssh_key_label(ssh_key))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def ssh_key_exist?(ssh_key)
|
|
17
|
+
client.list_ssh_keys.any?{|key| key.key == ssh_key}
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def ssh_key_label(ssh_key)
|
|
21
|
+
label = ssh_key[/^ssh.+?\s+\S+\s+(.*)$/, 1].to_s.strip
|
|
22
|
+
label.empty? ? "kontena-ssh-key-#{rand(1..9)}" : label
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @param [String] keyfile_path Path to ssh keyfile
|
|
26
|
+
def check_or_create_ssh_key(keyfile_path)
|
|
27
|
+
abort('Ssh key file not found') unless File.exist?(keyfile_path)
|
|
28
|
+
abort('Ssh key file not readable') unless File.readable?(keyfile_path)
|
|
29
|
+
ssh_key = File.read(keyfile_path).strip
|
|
30
|
+
create_ssh_key(ssh_key) unless ssh_key_exist?(ssh_key)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def find_project(project_id)
|
|
34
|
+
client.list_projects.find{|project| project.id == project_id}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def find_device(project_id, device_hostname)
|
|
38
|
+
client.list_devices(project_id).find{|device| device.hostname == device_hostname}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def find_facility(facility_code)
|
|
42
|
+
client.list_facilities.find{|f| f.code == facility_code}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def find_os(os_code)
|
|
46
|
+
client.list_operating_systems.find{|os| os.slug == os_code}
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def find_plan(plan_code)
|
|
50
|
+
client.list_plans.find{|plan| plan.slug == plan_code}
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def device_public_ip(device)
|
|
54
|
+
api_retry "Packet API did not find a public ip address for the device" do
|
|
55
|
+
device.ip_addresses.find{|ip| ip['public'] && ip['address_family'] == 4}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Retry API requests to recover from random tls errors
|
|
60
|
+
# @param [String] message Message to output when giving up
|
|
61
|
+
# @param [Fixnum] times Default: 5
|
|
62
|
+
def api_retry(message, times=5, &block)
|
|
63
|
+
attempt = 1
|
|
64
|
+
begin
|
|
65
|
+
yield
|
|
66
|
+
rescue => error
|
|
67
|
+
ENV['DEBUG'] && puts("Packet API error: #{error}: #{error.message} - attempt #{attempt}")
|
|
68
|
+
attempt += 1
|
|
69
|
+
if attempt < times
|
|
70
|
+
sleep 5 and retry
|
|
71
|
+
else
|
|
72
|
+
abort(message)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def user_data(vars, template_filename)
|
|
78
|
+
cloudinit_template = File.join(__dir__ , template_filename)
|
|
79
|
+
erb(File.read(cloudinit_template), vars)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def erb(template, vars)
|
|
83
|
+
ERB.new(template, nil, '%<>-').result(OpenStruct.new(vars).instance_eval { binding })
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require 'excon'
|
|
2
|
+
|
|
3
|
+
require_relative 'random_name'
|
|
4
|
+
require_relative 'cert_helper'
|
|
5
|
+
require_relative 'upcloud/upcloud_common'
|
|
6
|
+
require_relative 'upcloud/node_provisioner'
|
|
7
|
+
require_relative 'upcloud/node_destroyer'
|
|
8
|
+
require_relative 'upcloud/node_restarter'
|
|
9
|
+
require_relative 'upcloud/master_provisioner'
|
|
@@ -0,0 +1,64 @@
|
|
|
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
|
+
- path: /etc/systemd/system/docker.service.d/50-kontena.conf
|
|
12
|
+
content: |
|
|
13
|
+
[Service]
|
|
14
|
+
Environment='DOCKER_OPTS=--insecure-registry="10.81.0.0/19" --bip="172.17.43.1/16"'
|
|
15
|
+
- path: /etc/sysctl.d/99-inotify.conf
|
|
16
|
+
owner: root
|
|
17
|
+
permissions: 0644
|
|
18
|
+
content: |
|
|
19
|
+
fs.inotify.max_user_instances = 8192
|
|
20
|
+
- path: /etc/resolv.conf
|
|
21
|
+
permissions: 0644
|
|
22
|
+
owner: root
|
|
23
|
+
content: |
|
|
24
|
+
nameserver 172.17.43.1
|
|
25
|
+
nameserver 8.8.8.8
|
|
26
|
+
nameserver 8.8.4.4
|
|
27
|
+
coreos:
|
|
28
|
+
units:
|
|
29
|
+
- name: 10-weave.network
|
|
30
|
+
runtime: false
|
|
31
|
+
content: |
|
|
32
|
+
[Match]
|
|
33
|
+
Type=bridge
|
|
34
|
+
Name=weave*
|
|
35
|
+
|
|
36
|
+
[Network]
|
|
37
|
+
- name: kontena-agent.service
|
|
38
|
+
command: start
|
|
39
|
+
enable: true
|
|
40
|
+
content: |
|
|
41
|
+
[Unit]
|
|
42
|
+
Description=kontena-agent
|
|
43
|
+
After=network-online.target
|
|
44
|
+
After=docker.service
|
|
45
|
+
Description=Kontena Agent
|
|
46
|
+
Documentation=http://www.kontena.io/
|
|
47
|
+
Requires=network-online.target
|
|
48
|
+
Requires=docker.service
|
|
49
|
+
|
|
50
|
+
[Service]
|
|
51
|
+
Restart=always
|
|
52
|
+
RestartSec=5
|
|
53
|
+
EnvironmentFile=/etc/kontena-agent.env
|
|
54
|
+
ExecStartPre=-/usr/bin/docker stop kontena-agent
|
|
55
|
+
ExecStartPre=-/usr/bin/docker rm kontena-agent
|
|
56
|
+
ExecStartPre=/usr/bin/docker pull kontena/agent:${KONTENA_VERSION}
|
|
57
|
+
ExecStart=/usr/bin/docker run --name kontena-agent \
|
|
58
|
+
-e KONTENA_URI=${KONTENA_URI} \
|
|
59
|
+
-e KONTENA_TOKEN=${KONTENA_TOKEN} \
|
|
60
|
+
-e KONTENA_PEER_INTERFACE=${KONTENA_PEER_INTERFACE} \
|
|
61
|
+
-v=/var/run/docker.sock:/var/run/docker.sock \
|
|
62
|
+
-v=/etc/kontena-agent.env:/etc/kontena.env \
|
|
63
|
+
--net=host \
|
|
64
|
+
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,136 @@
|
|
|
1
|
+
require 'fileutils'
|
|
2
|
+
require 'erb'
|
|
3
|
+
require 'open3'
|
|
4
|
+
require 'shell-spinner'
|
|
5
|
+
|
|
6
|
+
module Kontena
|
|
7
|
+
module Machine
|
|
8
|
+
module Upcloud
|
|
9
|
+
class MasterProvisioner
|
|
10
|
+
include RandomName
|
|
11
|
+
include Machine::CertHelper
|
|
12
|
+
include UpcloudCommon
|
|
13
|
+
|
|
14
|
+
attr_reader :http_client, :username, :password
|
|
15
|
+
|
|
16
|
+
# @param [String] token Upcloud token
|
|
17
|
+
def initialize(upcloud_username, upcloud_password)
|
|
18
|
+
@username = upcloud_username
|
|
19
|
+
@password = upcloud_password
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run!(opts)
|
|
23
|
+
if File.readable?(File.expand_path(opts[:ssh_key]))
|
|
24
|
+
ssh_key = File.read(File.expand_path(opts[:ssh_key])).strip
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
abort('Invalid ssh key') unless ssh_key && ssh_key.start_with?('ssh-')
|
|
28
|
+
|
|
29
|
+
if opts[:ssl_cert]
|
|
30
|
+
abort('Invalid ssl cert') unless File.exists?(File.expand_path(opts[:ssl_cert]))
|
|
31
|
+
ssl_cert = File.read(File.expand_path(opts[:ssl_cert]))
|
|
32
|
+
else
|
|
33
|
+
ShellSpinner "Generating self-signed SSL certificate" do
|
|
34
|
+
ssl_cert = generate_self_signed_cert
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
abort('CoreOS template not found on Upcloud') unless coreos_template = find_template('CoreOS Stable')
|
|
39
|
+
abort('Server plan not found on Upcloud') unless plan = find_plan(opts[:plan])
|
|
40
|
+
abort('Zone not found on Upcloud') unless zone_exist?(opts[:zone])
|
|
41
|
+
|
|
42
|
+
hostname = generate_name
|
|
43
|
+
|
|
44
|
+
userdata_vars = {
|
|
45
|
+
ssl_cert: ssl_cert,
|
|
46
|
+
auth_server: opts[:auth_server],
|
|
47
|
+
version: opts[:version],
|
|
48
|
+
vault_secret: opts[:vault_secret],
|
|
49
|
+
vault_iv: opts[:vault_iv],
|
|
50
|
+
mongodb_uri: opts[:mongodb_uri]
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
device_data = {
|
|
54
|
+
server: {
|
|
55
|
+
zone: opts[:zone],
|
|
56
|
+
title: "Kontena Master #{hostname}",
|
|
57
|
+
hostname: hostname,
|
|
58
|
+
plan: plan[:name],
|
|
59
|
+
vnc: 'off',
|
|
60
|
+
timezone: 'UTC',
|
|
61
|
+
user_data: user_data(userdata_vars),
|
|
62
|
+
firewall: 'off',
|
|
63
|
+
storage_devices: {
|
|
64
|
+
storage_device: [
|
|
65
|
+
{
|
|
66
|
+
action: 'clone',
|
|
67
|
+
storage: coreos_template[:uuid],
|
|
68
|
+
title: "From template #{coreos_template[:title]}",
|
|
69
|
+
size: plan[:storage_size],
|
|
70
|
+
tier: 'maxiops'
|
|
71
|
+
}
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
login_user: {
|
|
75
|
+
create_password: 'no',
|
|
76
|
+
username: 'root',
|
|
77
|
+
ssh_keys: {
|
|
78
|
+
ssh_key: [ssh_key]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}.to_json
|
|
83
|
+
|
|
84
|
+
ShellSpinner "Creating Upcloud master #{hostname.colorize(:cyan)} " do
|
|
85
|
+
response = post('server', body: device_data)
|
|
86
|
+
if response.has_key?(:error)
|
|
87
|
+
abort("\nUpcloud server creation failed (#{response[:error].fetch(:error_message, '')})")
|
|
88
|
+
end
|
|
89
|
+
device_data = response[:server]
|
|
90
|
+
|
|
91
|
+
until device_data && device_data.fetch(:state, nil).to_s == 'maintenance'
|
|
92
|
+
device_data = get("server/#{device[:uuid]}").fetch(:server, {}) rescue nil
|
|
93
|
+
sleep 5
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
device_public_ip = device_data[:ip_addresses][:ip_address].find do |ip|
|
|
98
|
+
ip[:access].eql?('public') && ip[:family].eql?('IPv4')
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
abort('Server public ip not found, destroy manually.') unless device_public_ip
|
|
102
|
+
|
|
103
|
+
master_url = "https://#{device_public_ip[:address]}"
|
|
104
|
+
Excon.defaults[:ssl_verify_peer] = false
|
|
105
|
+
@http_client = Excon.new("#{master_url}", :connect_timeout => 10)
|
|
106
|
+
|
|
107
|
+
ShellSpinner "Waiting for #{hostname.colorize(:cyan)} to start" do
|
|
108
|
+
sleep 5 until master_running?
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
puts "Kontena Master is now running at #{master_url}"
|
|
112
|
+
puts "Use #{"kontena login --name=#{hostname.sub('kontena-master-', '')} #{master_url}".colorize(:light_black)} to complete Kontena Master setup"
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def user_data(vars)
|
|
116
|
+
cloudinit_template = File.join(__dir__ , '/cloudinit_master.yml')
|
|
117
|
+
erb(File.read(cloudinit_template), vars)
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def generate_name
|
|
121
|
+
"kontena-master-#{super}-#{rand(1..9)}"
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def master_running?
|
|
125
|
+
http_client.get(path: '/').status == 200
|
|
126
|
+
rescue
|
|
127
|
+
false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def erb(template, vars)
|
|
131
|
+
ERB.new(template, nil, '%<>-').result(OpenStruct.new(vars).instance_eval { binding })
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|