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 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,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "provisioning"
4
+
5
+ Provisioning::CLI.start(ARGV, ENV)
@@ -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
@@ -0,0 +1,7 @@
1
+ require "provisioning/cli"
2
+ require "provisioning/console"
3
+ require "provisioning/digitalocean"
4
+ require "provisioning/dokku"
5
+
6
+ module Provisioning
7
+ end
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: []