provisioning 0.0.1.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/provision +5 -0
- data/lib/provisioning/cli.rb +105 -0
- data/lib/provisioning/console.rb +22 -0
- data/lib/provisioning/digitalocean.rb +100 -0
- data/lib/provisioning/dokku.rb +58 -0
- data/lib/provisioning.rb +7 -0
- metadata +130 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 24a8c455a3b419d172d520a0bf765ee3ad408b0b
|
4
|
+
data.tar.gz: 0f976f7ae8452797c1502bbcfbf4448f9878aaa4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7f94d389eb42dbe86eb9cc9a47f6850a2821fdaf6817e399e32b25082289b2fdd8f74f5a032c4aad2ca8841594fd6625b74a65b5ad0164ff897f000303d502f5
|
7
|
+
data.tar.gz: 1894e90832225ab2f513a747c9c1b45972602ea30e7eb9a6f76f1037dce1566fa5fd43fdfc54147255c57b310ab4e7675d2157f4c03bc056f9d97e8b0144caa1
|
data/bin/provision
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require "git"
|
2
|
+
require "json"
|
3
|
+
require "net/ssh"
|
4
|
+
require "rainbow"
|
5
|
+
|
6
|
+
require "provisioning"
|
7
|
+
|
8
|
+
module Provisioning
|
9
|
+
module CLI
|
10
|
+
def self.get_ssh_key(fingerprint)
|
11
|
+
Console.info("Getting SSH key from authentication agent")
|
12
|
+
agent = Net::SSH::Authentication::Agent.connect
|
13
|
+
agent.identities.find do |identity|
|
14
|
+
identity.fingerprint == fingerprint
|
15
|
+
end || Console.error("could not get key from the authentication agent, run `ssh-add`")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.start(args, env)
|
19
|
+
config_file = args.shift || "provisioning.json"
|
20
|
+
|
21
|
+
begin
|
22
|
+
config = JSON.parse(File.open(config_file).read)
|
23
|
+
rescue Errno::ENOENT, JSON::ParserError
|
24
|
+
Console.error("could not read json provisioning file '#{config_file}'")
|
25
|
+
end
|
26
|
+
|
27
|
+
ssh_key_fingerprint = config["ssh"]["key"]["fingerprint"]
|
28
|
+
|
29
|
+
ssh_key = get_ssh_key(ssh_key_fingerprint)
|
30
|
+
puts
|
31
|
+
|
32
|
+
app_name = config["app"]["name"]
|
33
|
+
domain = config["domain"]
|
34
|
+
platform = config["providers"]["platform"]
|
35
|
+
server_hostname = [platform, domain].join(".")
|
36
|
+
server_address = nil
|
37
|
+
|
38
|
+
if config["providers"]["hosting"] == "digitalocean"
|
39
|
+
digitalocean = DigitalOcean.new(config["digitalocean"])
|
40
|
+
|
41
|
+
digitalocean.upload_ssh_key(ssh_key)
|
42
|
+
puts
|
43
|
+
|
44
|
+
droplet = digitalocean.create_droplet(
|
45
|
+
name: server_hostname,
|
46
|
+
ssh_key_fingerprint: ssh_key_fingerprint
|
47
|
+
)
|
48
|
+
server_address = droplet.networks.v4.first.ip_address
|
49
|
+
puts
|
50
|
+
end
|
51
|
+
|
52
|
+
if config["providers"]["dns"] == "digitalocean"
|
53
|
+
digitalocean = DigitalOcean.new(config["digitalocean"])
|
54
|
+
|
55
|
+
digitalocean.create_domain(domain, server_address)
|
56
|
+
Console.success("Configue '#{domain}' with the following DNS servers:")
|
57
|
+
digitalocean.get_domain_name_servers(domain).each do |server|
|
58
|
+
Console.success(" - #{server}")
|
59
|
+
end
|
60
|
+
puts
|
61
|
+
|
62
|
+
digitalocean.create_domain_record(
|
63
|
+
domain: domain,
|
64
|
+
type: "A",
|
65
|
+
name: platform,
|
66
|
+
data: server_address
|
67
|
+
)
|
68
|
+
digitalocean.create_domain_record(
|
69
|
+
domain: domain,
|
70
|
+
type: "CNAME",
|
71
|
+
name: app_name,
|
72
|
+
data: "#{server_hostname}."
|
73
|
+
)
|
74
|
+
config["app"]["domains"].each do |app_domain|
|
75
|
+
Console.success("Configue '#{app_domain}' to point to '#{server_hostname}'")
|
76
|
+
end
|
77
|
+
puts
|
78
|
+
end
|
79
|
+
|
80
|
+
if config["providers"]["platform"] == "dokku"
|
81
|
+
dokku = Dokku.new(config["dokku"])
|
82
|
+
dokku.setup(address: server_address, domain: domain)
|
83
|
+
Console.success("Run `gem install dokku-cli` to get dokku client on your machine")
|
84
|
+
puts
|
85
|
+
|
86
|
+
dokku.create_app(config["app"])
|
87
|
+
puts
|
88
|
+
|
89
|
+
Console.info("Adding dokku to git remotes")
|
90
|
+
begin
|
91
|
+
git = Git.open(".")
|
92
|
+
rescue ArgumentError
|
93
|
+
Console.warning("not a git repository, skipping")
|
94
|
+
else
|
95
|
+
if git.remotes.map(&:name).include?("dokku")
|
96
|
+
Console.warning("remote already exists, skipping")
|
97
|
+
else
|
98
|
+
git.add_remote("dokku", "dokku@#{server_hostname}:#{app_name}")
|
99
|
+
end
|
100
|
+
Console.success("Run `git push dokku master` to deploy your code")
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "rainbow"
|
2
|
+
|
3
|
+
module Provisioning
|
4
|
+
module Console
|
5
|
+
def self.info(text)
|
6
|
+
puts text
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.success(text)
|
10
|
+
puts Rainbow("#{text}").green
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.warning(text)
|
14
|
+
puts Rainbow("Warning: #{text}").yellow
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.error(text)
|
18
|
+
puts Rainbow("Error: #{text}").red
|
19
|
+
exit 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require "droplet_kit"
|
2
|
+
|
3
|
+
require "provisioning"
|
4
|
+
|
5
|
+
module Provisioning
|
6
|
+
class DigitalOcean
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@client = DropletKit::Client.new(access_token: @config["token"])
|
10
|
+
end
|
11
|
+
|
12
|
+
def upload_ssh_key(ssh_key)
|
13
|
+
Console.info("Uploading SSH key to DigitalOcean")
|
14
|
+
|
15
|
+
disable_verbose
|
16
|
+
if @client.ssh_keys.all.map(&:fingerprint).include?(ssh_key.fingerprint)
|
17
|
+
Console.warning("SSH key already uploaded to DigitalOcean, skipping")
|
18
|
+
else
|
19
|
+
key = DropletKit::SSHKey.new(
|
20
|
+
name: "provisioning key",
|
21
|
+
public_key: ssh_key.to_s
|
22
|
+
)
|
23
|
+
@client.ssh_keys.create(key)
|
24
|
+
end
|
25
|
+
restore_verbose
|
26
|
+
end
|
27
|
+
|
28
|
+
def create_droplet(name:, ssh_key_fingerprint:)
|
29
|
+
Console.info("Creating droplet '#{name}'")
|
30
|
+
|
31
|
+
disable_verbose
|
32
|
+
@client.droplets.all.each do |droplet|
|
33
|
+
if droplet.name == name
|
34
|
+
Console.warning("droplet already exists, skipping")
|
35
|
+
return droplet
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
droplet = DropletKit::Droplet.new(
|
40
|
+
name: name,
|
41
|
+
region: @config["droplet"]["region"],
|
42
|
+
image: @config["droplet"]["image"],
|
43
|
+
size: @config["droplet"]["size"],
|
44
|
+
ssh_keys: [ssh_key_fingerprint]
|
45
|
+
)
|
46
|
+
@client.droplets.create(droplet)
|
47
|
+
droplet
|
48
|
+
ensure
|
49
|
+
restore_verbose
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_domain(name, address)
|
53
|
+
Console.info("Creating domain '#{name}'")
|
54
|
+
|
55
|
+
disable_verbose
|
56
|
+
if @client.domains.all.map(&:name).include?(name)
|
57
|
+
Console.warning("domain already exists, skipping")
|
58
|
+
else
|
59
|
+
domain = DropletKit::Domain.new(name: name, ip_address: address)
|
60
|
+
@client.domains.create(domain)
|
61
|
+
end
|
62
|
+
ensure
|
63
|
+
restore_verbose
|
64
|
+
end
|
65
|
+
|
66
|
+
def create_domain_record(domain:, type:, name:, data:)
|
67
|
+
Console.info("Creating domain record #{type} '#{name}.#{domain}' to '#{data}'")
|
68
|
+
|
69
|
+
disable_verbose
|
70
|
+
if @client.domain_records.all(for_domain: domain).map(&:name).include?(name)
|
71
|
+
Console.warning("record already exists, skipping")
|
72
|
+
else
|
73
|
+
record = DropletKit::DomainRecord.new(type: type, name: name, data: data)
|
74
|
+
@client.domain_records.create(record, for_domain: domain)
|
75
|
+
end
|
76
|
+
ensure
|
77
|
+
restore_verbose
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_domain_name_servers(domain)
|
81
|
+
disable_verbose
|
82
|
+
@client.domain_records.all(for_domain: domain).
|
83
|
+
select { |r| r.type == "NS" }.
|
84
|
+
map(&:data)
|
85
|
+
ensure
|
86
|
+
restore_verbose
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def disable_verbose
|
92
|
+
$OLD_VERBOSE = $VERBOSE
|
93
|
+
$VERBOSE = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def restore_verbose
|
97
|
+
$VERBOSE = $OLD_VERBOSE
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require "net/ssh"
|
2
|
+
|
3
|
+
require "provisioning"
|
4
|
+
|
5
|
+
module Provisioning
|
6
|
+
class Dokku
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@servers = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def setup(address:, domain:)
|
13
|
+
@servers << address
|
14
|
+
version = @config["version"]
|
15
|
+
Console.info("Installing dokku #{version} on '#{address}'")
|
16
|
+
Net::SSH.start(address, "root") do |ssh|
|
17
|
+
if ssh.exec!("which dokku").present?
|
18
|
+
Console.warning("dokku already installed, skipping")
|
19
|
+
else
|
20
|
+
puts ssh.exec!("wget https://raw.githubusercontent.com/dokku/dokku/#{version}/bootstrap.sh")
|
21
|
+
puts ssh.exec!("DOKKU_TAG=#{version} bash bootstrap.sh")
|
22
|
+
puts ssh.exec!("service dokku-installer stop")
|
23
|
+
puts ssh.exec!("systemctl disable dokku-installer")
|
24
|
+
puts ssh.exec!("cat .ssh/authorized_keys | sshcommand acl-add dokku admin")
|
25
|
+
puts ssh.exec!("echo -n #{domain} > /home/dokku/VHOST")
|
26
|
+
puts ssh.exec!("echo -n #{domain} > /home/dokku/HOSTNAME")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def create_app(config)
|
32
|
+
name = config["name"]
|
33
|
+
@servers.each do |address|
|
34
|
+
Console.info("Creating dokku app '#{name}' on '#{address}'")
|
35
|
+
Net::SSH.start(address, "root") do |ssh|
|
36
|
+
existing_apps = ssh.exec!("dokku apps").to_s.lines.map(&:chomp)
|
37
|
+
if existing_apps.include?(name)
|
38
|
+
Console.warning("app already exists, skipping")
|
39
|
+
else
|
40
|
+
puts ssh.exec!("dokku apps:create #{name}")
|
41
|
+
|
42
|
+
config["services"].each do |service|
|
43
|
+
case service
|
44
|
+
when "mongo", "postgres", "redis"
|
45
|
+
puts ssh.exec!("dokku plugin:install https://github.com/dokku/dokku-#{service}.git #{service}")
|
46
|
+
puts ssh.exec!("dokku #{service}:create #{name}-#{service}")
|
47
|
+
puts ssh.exec!("dokku #{service}:link #{name}-#{service} #{name}")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
domains = config["domains"].join(" ")
|
52
|
+
puts ssh.exec!("dokku domains:add #{name} #{domains}")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/provisioning.rb
ADDED
metadata
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: provisioning
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1.alpha.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Vincent Ollivier
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-09-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: git
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.3.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.3.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rainbow
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '2.2'
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: 2.2.0
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - "~>"
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '2.2'
|
50
|
+
- - ">="
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: 2.2.0
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: droplet_kit
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - "~>"
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '2.1'
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: 2.1.0
|
63
|
+
type: :runtime
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - "~>"
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '2.1'
|
70
|
+
- - ">="
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: 2.1.0
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: net-ssh
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - "~>"
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '4.1'
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 4.1.0
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '4.1'
|
90
|
+
- - ">="
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: 4.1.0
|
93
|
+
description: PaaS Provisioning
|
94
|
+
email: v@vinc.cc
|
95
|
+
executables:
|
96
|
+
- provision
|
97
|
+
extensions: []
|
98
|
+
extra_rdoc_files: []
|
99
|
+
files:
|
100
|
+
- bin/provision
|
101
|
+
- lib/provisioning.rb
|
102
|
+
- lib/provisioning/cli.rb
|
103
|
+
- lib/provisioning/console.rb
|
104
|
+
- lib/provisioning/digitalocean.rb
|
105
|
+
- lib/provisioning/dokku.rb
|
106
|
+
homepage: https://github.com/vinc/provisioning.rb
|
107
|
+
licenses:
|
108
|
+
- MIT
|
109
|
+
metadata: {}
|
110
|
+
post_install_message:
|
111
|
+
rdoc_options: []
|
112
|
+
require_paths:
|
113
|
+
- lib
|
114
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">"
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: 1.3.1
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 2.6.8
|
127
|
+
signing_key:
|
128
|
+
specification_version: 4
|
129
|
+
summary: PaaS Provisioning
|
130
|
+
test_files: []
|