vps 0.1.1 → 0.2.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d879c725aca451c863ec504e4fd4f7f9089bb5b0
4
- data.tar.gz: b0ebe2d831c630da62eb6e8c69452aebbcae4dcc
3
+ metadata.gz: 0715c15db0c61c43f427cde770c38cde3f65e677
4
+ data.tar.gz: 62fbbc6d56af47c025031dd5125ab7a4072d546d
5
5
  SHA512:
6
- metadata.gz: b750774204e6f237175c568f6528b9196a1bdf272193cc8ca1bfbfc7d77a539da72835f7160a2998532ae670c576312dcad2dc5eff6e8b3870e7801d68bb0992
7
- data.tar.gz: 84ed1b982a9d6e66d70a74845b2a33cbc4ed2c87f2830ae2b3a37b9cb6607ccd30bd870040f2b50a4aa882e0f5c0aeab1f1b194e2c045dce5b1113d393a8f025
6
+ metadata.gz: 0850d9d9a5888d1162e7cb491906f0afea445f82535a68ae03014b6304cb594c7c81f765f14325bf0b1d295a1a88a7e07ac009859f6d5c0ba727d3fee34988a8
7
+ data.tar.gz: 7c6dfffa4ce37dc82012bf13865cc03f9feb6367c1565305f5a7461f88fe73d951fccd502fbfc6544df7505f50fb1de15feabdef5ec29bffd682cfc0a768f1be
@@ -1,5 +1,30 @@
1
1
  ## VPS CHANGELOG
2
2
 
3
+ ### Version 0.2.3 (January 2, 2020)
4
+
5
+ * Support upstreams without domains
6
+
7
+ ### Version 0.2.2 (January 2, 2020)
8
+
9
+ * Automatically add container names for upstreams and services
10
+ * Add opportunity to add lines to the generated Dockerfile
11
+
12
+ ### Version 0.2.1 (January 2, 2020)
13
+
14
+ * Support NodeJS based applications
15
+ * Clean up default upstream specs
16
+ * Set container name when adding upstream
17
+
18
+ ### Version 0.2.0 (December 31, 2019)
19
+
20
+ * Provide ability to add both custom HTTP and HTTPS Nginx configs
21
+
22
+ ### Version 0.1.2 (September 29, 2019)
23
+
24
+ * Run postload tasks at the end of deployment
25
+ * Fix generating Rails and Rack Dockerfile (installing the correct Bundler version)
26
+ * Include configured :services in the generated docker-compose.yml file
27
+
3
28
  ### Version 0.1.1 (August 12, 2019)
4
29
 
5
30
  * Initial release
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.1.1
1
+ 0.2.3
data/lib/vps.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require "tmpdir"
1
2
  require "vps/version"
2
3
 
3
4
  module VPS
@@ -16,6 +16,7 @@ require "active_support/number_helper"
16
16
 
17
17
  require "vps"
18
18
  require "vps/core_ext/string"
19
+ require "vps/core_ext/ostruct"
19
20
  require "vps/cli/service"
20
21
  require "vps/cli/upstream"
21
22
  require "vps/cli/domain"
@@ -11,7 +11,7 @@ module VPS
11
11
 
12
12
  if (upstream = config[:upstreams].detect{|upstream| upstream[:name] == name})
13
13
  upstream[:email] = email if email
14
- upstream[:domains].push(domain).uniq!
14
+ (upstream[:domains] ||= []).push(domain).uniq!
15
15
  VPS.write_config(host, config)
16
16
  end
17
17
  end
@@ -57,7 +57,7 @@ module VPS
57
57
  (hash || {}).fetch(key)
58
58
  end.tap do |value|
59
59
  if to_domain && value
60
- if (domain = value[:domains].first)
60
+ if (domain = (value[:domains] || ["-"]).first)
61
61
  return domain.gsub(/https?:\/\//, "")
62
62
  end
63
63
  end
@@ -9,18 +9,11 @@ module VPS
9
9
  path = File.expand_path(path)
10
10
 
11
11
  unless config[:upstreams].any?{|upstream| upstream[:name] == name}
12
- type, tool_version, port = derive_upstream(path)
13
- config[:upstreams].push({
12
+ spec = derive_upstream(path)
13
+ config[:upstreams].push(spec.merge({
14
14
  :name => name || File.basename(path),
15
- :path => path,
16
- :type => type,
17
- :tool_version => tool_version,
18
- :port => port,
19
- :domains => [],
20
- :email => nil,
21
- :compose => nil,
22
- :nginx => nil
23
- })
15
+ :path => path
16
+ }))
24
17
  VPS.write_config(host, config)
25
18
  end
26
19
  end
@@ -65,19 +58,42 @@ module VPS
65
58
  |> IO.puts()
66
59
  ELIXIR
67
60
  type = `cd #{path} && mix run -e "#{elixir.strip.gsub(/\n\s+/, " ")}" | tail -n 1`.strip
68
- [
69
- type,
70
- `cd #{path} && mix run -e "System.version() |> IO.puts()" | tail -n 1`.strip,
71
- (type == "phoenix") ? 4000 : `cd #{path} && mix run -e ":ranch.info |> hd() |> elem(0) |> :ranch.get_port() |> IO.puts()" | tail -n 1`.strip.to_i
72
- ]
61
+ {
62
+ type: type,
63
+ elixir_version: `cd #{path} && mix run -e "System.version() |> IO.puts()" | tail -n 1`.strip,
64
+ port: (type == "phoenix") ? 4000 : `cd #{path} && mix run -e ":ranch.info |> hd() |> elem(0) |> :ranch.get_port() |> IO.puts()" | tail -n 1`.strip.to_i
65
+ }
73
66
  elsif Dir["#{path}/Gemfile"].any?
74
67
  lines = `cd #{path} && BUNDLE_GEMFILE=#{path}/Gemfile bundle list`.split("\n")
75
68
  type = %w(rails rack).detect{|gem| lines.any?{|line| line.include?("* #{gem} (")}}
76
- [
77
- type,
78
- `$SHELL -l -c 'cd #{path} && ruby -e "puts RUBY_VERSION"'`.strip,
79
- (type == "rails" ? 3000 : 9292) # :'(
80
- ]
69
+ {
70
+ type: type,
71
+ ruby_version: `$SHELL -l -c 'cd #{path} && ruby -e "puts RUBY_VERSION"'`.strip,
72
+ bundler_version: `$SHELL -l -c 'cd #{path} && bundle -v'`.split.last,
73
+ port: (type == "rails" ? 3000 : 9292) # :'(
74
+ }.tap do |spec|
75
+ if type == "rails"
76
+ spec[:nginx] = {
77
+ root: "/opt/app/public",
78
+ try_files: true,
79
+ proxy_redirect: "off"
80
+ }
81
+ end
82
+ end
83
+ elsif Dir["#{path}/package.json"].any?
84
+ tmpfile = "#{Dir.tmpdir}/vps-debug.log"
85
+ pid = spawn("cd #{path} && npm start", :out => tmpfile, :err => "/dev/null")
86
+ Process.detach(pid)
87
+ sleep 5
88
+ `ps aux | grep -e "no[d]e #{path}"`.strip.split("\n").collect do |line|
89
+ `kill -9 #{line.split(" ")[1]}`
90
+ end
91
+ port = File.read(tmpfile).match(/on port (\d+)/).captures.first.to_i
92
+ {
93
+ type: "node",
94
+ node_version: `$SHELL -l -c 'cd #{path} && node -v'`.match(/[\d\.?]+/).to_s,
95
+ port: port
96
+ }
81
97
  end
82
98
  end
83
99
 
@@ -0,0 +1,17 @@
1
+ class OpenStruct
2
+ def self.to_hash(object, hash = {})
3
+ case object
4
+ when OpenStruct then
5
+ object.each_pair do |key, value|
6
+ hash[key.to_s] = to_hash(value)
7
+ end
8
+ hash
9
+ when Array then
10
+ object.collect do |value|
11
+ to_hash(value)
12
+ end
13
+ else
14
+ object
15
+ end
16
+ end
17
+ end
@@ -1,7 +1,7 @@
1
1
  module VPS
2
2
  MAJOR = 0
3
- MINOR = 1
4
- TINY = 1
3
+ MINOR = 2
4
+ TINY = 3
5
5
 
6
6
  VERSION = [MAJOR, MINOR, TINY].join(".")
7
7
  end
@@ -86,11 +86,11 @@ tasks:
86
86
  command:
87
87
  - chmod +x {{ release_path }}/init-letsencrypt/{{ upstream.name }}.sh
88
88
  - cd {{ release_path }} && if [ ! -d "data/certbot/conf/live/{{ domain:upstream }}" ]; then yes Y | sudo ./init-letsencrypt/{{ upstream.name }}.sh; fi
89
- - task: run_tasks
90
- tasks: << postload >>
91
89
  - description: Starting containers
92
90
  task: remote_execute
93
91
  command: cd {{ release_path }} && docker-compose up {{ up }} -d
94
92
  - description: Checking running docker images
95
93
  task: remote_execute
96
94
  command: docker ps
95
+ - task: run_tasks
96
+ tasks: << postload >>
@@ -3,19 +3,26 @@
3
3
  upstream <%= upstream[:name] %> {
4
4
  server <%= upstream[:name] %>:<%= upstream[:port] %>;
5
5
  }
6
- <%- upstream[:domains].partition{|domain| domain.include?("http://")}.reject(&:empty?).each do |domains| %>
6
+ <%- (upstream[:domains] || []).partition{|domain| domain.include?("http://")}.reject(&:empty?).each do |domains| %>
7
7
  <%-
8
8
  https = domains.first.include?("https://")
9
9
  domains = domains.collect{|domain| domain.gsub(/https?:\/\//, "")}.join(" ")
10
10
  domain = domains.split(" ")[0]
11
+ nginx = upstream[:nginx] || {}
11
12
  proxy_pass = "http://#{ upstream[:name] }"
12
13
  %>
13
14
 
14
15
  server {
16
+ <%- unless domains.empty? %>
15
17
  listen 80;
16
18
  server_name <%= domains %>;
17
19
  server_tokens off;
18
20
 
21
+ <%- end %>
22
+ <%- if nginx[:http] %>
23
+ <%= nginx[:http].gsub("PROXY_PASS", proxy_pass).indent(2) %>
24
+
25
+ <%- end %>
19
26
  <%- if https %>
20
27
  location /.well-known/acme-challenge/ {
21
28
  root /var/www/certbot;
@@ -37,15 +44,25 @@ server {
37
44
  ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
38
45
 
39
46
  <%- end %>
40
- <%- if upstream[:nginx] %>
41
- <%= upstream[:nginx].gsub("PROXY_PASS", proxy_pass).indent(2) %>
47
+ <%- if nginx[:root] %>
48
+ root <%= nginx[:root] %>;
49
+ <%- end %>
50
+ <%- if nginx[:try_files] %>
51
+ try_files $uri @app;
42
52
 
43
53
  <%- end %>
44
- location / {
54
+ <%- if nginx[:https] %>
55
+ <%= nginx[:https].gsub("PROXY_PASS", proxy_pass).indent(2) %>
56
+
57
+ <%- end %>
58
+ location <%= nginx[:try_files] ? "@app" : "/" %> {
45
59
  proxy_pass <%= proxy_pass %>;
46
60
  proxy_set_header Host $http_host;
47
61
  proxy_set_header X-Real-IP $remote_addr;
48
62
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
63
+ <%- if nginx[:proxy_redirect] %>
64
+ proxy_redirect <%= nginx[:proxy_redirect] %>;
65
+ <%- end %>
49
66
  }
50
67
  }
51
68
  <%- end %>
@@ -1,10 +1,5 @@
1
1
  version: "3"
2
- <%
3
- https = upstreams.any?{|upstream| upstream[:domains].any?{|domain| domain.include?("https://")}}
4
- to_yaml = proc do |struct|
5
- struct.to_h.inject({}){|h, (k, v)| h[k.to_s] = v; h}.to_yaml
6
- end
7
- %>
2
+ <% https = upstreams.any?{|upstream| upstream[:domains].any?{|domain| domain.include?("https://")}} %>
8
3
  services:
9
4
 
10
5
  nginx:
@@ -28,7 +23,7 @@ services:
28
23
  command: "/bin/sh -c 'while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"'"
29
24
 
30
25
  certbot:
31
- image: certbot/certbot
26
+ image: certbot/certbot:v0.27.1
32
27
  container_name: certbot
33
28
  restart: unless-stopped
34
29
  volumes:
@@ -36,21 +31,29 @@ services:
36
31
  - ./data/certbot/www:/var/www/certbot
37
32
  entrypoint: "/bin/sh -c 'trap exit TERM; while :; do certbot renew; sleep 12h & wait $${!}; done;'"
38
33
  <%- end %>
34
+ <%- services.to_h.each do |name, spec| %>
35
+
36
+ <%= name %>:
37
+ <%= OpenStruct.to_hash(spec).to_yaml.sub(/^.*?\n/, "").sub("\n", "\ncontainer_name: #{name}\n").indent(4) %>
38
+ <%- end %>
39
39
  <%- upstreams.each do |upstream| %>
40
40
 
41
41
  <%= upstream.name %>:
42
42
  image: <%= upstream.name %>
43
+ container_name: <%= upstream.name %>
43
44
  restart: always
44
45
  <%- unless upstream[:compose].inspect.match(/\bports\b/) %>
45
46
  ports:
46
47
  - <%= upstream.port %>
47
48
  <%- end %>
48
49
  <%- if upstream[:compose] %>
49
- <%= to_yaml.(upstream[:compose]).sub(/^.*?\n/, "").indent(4) %>
50
+ <%= OpenStruct.to_hash(upstream[:compose]).to_yaml.sub(/^.*?\n/, "").indent(4) %>
50
51
  <%- end %>
51
52
  <%- end %>
52
- <%- services.each do |service, config| %>
53
+ <%- unless (volumes || []).empty? %>
53
54
 
54
- <%= service %>:
55
- <%= to_yaml.(config).sub(/^.*?\n/, "").indent(4) %>
56
- <%- end %>
55
+ volumes:
56
+ <%- volumes.each do |volume| %>
57
+ <%= volume %>:
58
+ <%- end %>
59
+ <%- end %>
@@ -0,0 +1,15 @@
1
+ FROM node:<%= upstream.node_version %>-alpine
2
+
3
+ RUN apk update \
4
+ && apk --no-cache --update add \
5
+ build-base nodejs tzdata
6
+
7
+ WORKDIR /opt/app
8
+ COPY . .
9
+
10
+ ENV NODE_ENV=production
11
+ <%- if upstream.dockerfile %>
12
+ <%= upstream.dockerfile.strip %>
13
+ <%- end %>
14
+ RUN npm install
15
+ CMD ["npm", "start"]
@@ -1,4 +1,4 @@
1
- FROM elixir:<%= upstream.tool_version %>-alpine
1
+ FROM elixir:<%= upstream.elixir_version %>-alpine
2
2
 
3
3
  RUN apk update \
4
4
  && apk --no-cache --update add alpine-sdk \
@@ -9,5 +9,8 @@ WORKDIR /opt/app
9
9
  COPY . .
10
10
 
11
11
  ENV MIX_ENV=prod
12
+ <%- if upstream.dockerfile %>
13
+ <%= upstream.dockerfile.strip %>
14
+ <%- end %>
12
15
  RUN mix do deps.get --only prod, deps.compile
13
16
  CMD ["sh", "-c", "mix phx.server"]
@@ -1,4 +1,4 @@
1
- FROM elixir:<%= upstream.tool_version %>-alpine
1
+ FROM elixir:<%= upstream.elixir_version %>-alpine
2
2
 
3
3
  RUN apk update \
4
4
  && apk --no-cache --update add alpine-sdk \
@@ -9,5 +9,8 @@ WORKDIR /opt/app
9
9
  COPY . .
10
10
 
11
11
  ENV MIX_ENV=prod
12
+ <%- if upstream.dockerfile %>
13
+ <%= upstream.dockerfile.strip %>
14
+ <%- end %>
12
15
  RUN mix do deps.get --only prod, deps.compile
13
16
  CMD ["sh", "-c", "mix run --no-halt"]
@@ -1,4 +1,4 @@
1
- FROM ruby:<%= upstream.tool_version %>-alpine
1
+ FROM ruby:<%= upstream.ruby_version %>-alpine
2
2
 
3
3
  RUN apk update \
4
4
  && apk --no-cache --update add \
@@ -11,5 +11,9 @@ WORKDIR /opt/app
11
11
  COPY . .
12
12
 
13
13
  ENV RACK_ENV=production
14
+ <%- if upstream.dockerfile %>
15
+ <%= upstream.dockerfile.strip %>
16
+ <%- end %>
17
+ RUN gem install bundler -v <%= upstream.bundler_version %>
14
18
  RUN bundle install --without development test
15
- CMD ["rackup", "config.ru", "-o", "0.0.0.0"]
19
+ CMD ["bundle", "exec", "rackup", "config.ru", "-o", "0.0.0.0"]
@@ -1,4 +1,4 @@
1
- FROM ruby:<%= upstream.tool_version %>-alpine
1
+ FROM ruby:<%= upstream.ruby_version %>-alpine
2
2
 
3
3
  RUN apk update \
4
4
  && apk --no-cache --update add \
@@ -10,6 +10,13 @@ RUN apk update \
10
10
  WORKDIR /opt/app
11
11
  COPY . .
12
12
 
13
+ EXPOSE <%= upstream.port %>
14
+
13
15
  ENV RAILS_ENV=production
16
+ <%- if upstream.dockerfile %>
17
+ <%= upstream.dockerfile.strip %>
18
+ <%- end %>
19
+ RUN gem install bundler -v <%= upstream.bundler_version %>
14
20
  RUN bundle install --without development test
21
+ CMD ["rm", "-f", "tmp/pids/server.pid"]
15
22
  CMD ["rails", "server", "-b", "0.0.0.0"]
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
 
3
- <%- if (domains = upstream[:domains].collect{|domain| domain.dup.gsub!("https://", "")}.compact).any? %>
3
+ <%- if (domains = (upstream[:domains] || []).collect{|domain| domain.dup.gsub!("https://", "")}.compact).any? %>
4
4
  domains=(<%= domains.join(" ") %>)
5
5
  email="<%= upstream[:email] || "noreply@#{domains.first}" %>" # Adding a valid address is strongly recommended
6
6
  data_path="./data/certbot"
@@ -17,8 +17,8 @@ fi
17
17
  if [ ! -e "$data_path/conf/options-ssl-nginx.conf" ] || [ ! -e "$data_path/conf/ssl-dhparams.pem" ]; then
18
18
  echo "### Downloading recommended TLS parameters ..."
19
19
  mkdir -p "$data_path/conf"
20
- curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
21
- curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
20
+ curl -s https://raw.githubusercontent.com/certbot/certbot/v0.40.1/certbot-nginx/certbot_nginx/tls_configs/options-ssl-nginx.conf > "$data_path/conf/options-ssl-nginx.conf"
21
+ curl -s https://raw.githubusercontent.com/certbot/certbot/v0.40.1/certbot/ssl-dhparams.pem > "$data_path/conf/ssl-dhparams.pem"
22
22
  echo
23
23
  fi
24
24
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vps
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Engel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-08-12 00:00:00.000000000 Z
11
+ date: 2020-01-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -162,6 +162,7 @@ files:
162
162
  - lib/vps/cli/playbook/tasks.rb
163
163
  - lib/vps/cli/service.rb
164
164
  - lib/vps/cli/upstream.rb
165
+ - lib/vps/core_ext/ostruct.rb
165
166
  - lib/vps/core_ext/string.rb
166
167
  - lib/vps/version.rb
167
168
  - playbooks/deploy.yml
@@ -173,6 +174,7 @@ files:
173
174
  - script/console
174
175
  - templates/docker/data/nginx/app.conf.erb
175
176
  - templates/docker/docker-compose.yml.erb
177
+ - templates/docker/upstream/Dockerfile.node.erb
176
178
  - templates/docker/upstream/Dockerfile.phoenix.erb
177
179
  - templates/docker/upstream/Dockerfile.plug.erb
178
180
  - templates/docker/upstream/Dockerfile.rack.erb