renuo-cli 4.24.0 → 4.25.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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 2db0ed70e43dfb8e6c5d05d3d08ed4313e7bb15a418cf05920561d55a4973c3e
|
|
4
|
+
data.tar.gz: a68fd2324f7d09dac3e1bed32f2d3b8ba3dccaf8ccc6e847b9d9585adc3d5c2a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 25f6a3ae51271d7c93227af3f147ea47ce7d041bb2d1194632eea875e58c161b4ed12794064192614d10ff8407d66179874be15571e90e9db9c0efac3d31bc00
|
|
7
|
+
data.tar.gz: db3b684155e2447af9a94fd48e2d9ef2e62e3ff9af11d3f47565cf87ec6a61d53ae841809d3a74e2b15408df9e096f7bc74670850170f4d6c333ce63228e3d61
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
# simplecov:disable
|
|
4
4
|
module Renuo::Cli::Commands::Ci
|
|
5
|
-
class CheckDeploioStatus
|
|
5
|
+
class CheckDeploioStatus # rubocop:disable Metrics/ClassLength
|
|
6
6
|
TIMEOUT_IN_SECONDS = 600
|
|
7
7
|
INTERVAL_IN_SECONDS = 5
|
|
8
8
|
LOG_DRAIN_SECONDS = 2
|
|
9
9
|
|
|
10
10
|
command "ci check-deploio-status" do |c|
|
|
11
11
|
c.syntax = "renuo ci check-deploio-status [options] <app-name>"
|
|
12
|
-
c.summary = "Checks the build status of the deployment."
|
|
12
|
+
c.summary = "Checks the build and release status of the deployment."
|
|
13
13
|
c.description = c.summary
|
|
14
14
|
c.option "-p", "--project <name>", String, "The name of the project"
|
|
15
15
|
c.option "-g", "--git-revision <hash>", String, "The Git revision"
|
|
@@ -17,9 +17,12 @@ module Renuo::Cli::Commands::Ci
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def run
|
|
20
|
-
puts "Checking build status for revision #{@revision}..."
|
|
20
|
+
puts "[RENUO-CLI] (1/2) Checking build status for revision #{@revision}..."
|
|
21
21
|
succeeded = with_streamed_build_logs { poll_build }
|
|
22
|
-
abort "build check timed out after #{TIMEOUT_IN_SECONDS} seconds" unless succeeded
|
|
22
|
+
abort "[RENUO-CLI] build check timed out after #{TIMEOUT_IN_SECONDS} seconds" unless succeeded
|
|
23
|
+
|
|
24
|
+
puts "[RENUO-CLI] (2/2) Checking release status for build #{build_name}..."
|
|
25
|
+
abort "[RENUO-CLI] release check timed out after #{TIMEOUT_IN_SECONDS} seconds" unless poll_release
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
private
|
|
@@ -29,20 +32,20 @@ module Renuo::Cli::Commands::Ci
|
|
|
29
32
|
@project = options.project
|
|
30
33
|
@revision = options.git_revision || ENV.fetch("SEMAPHORE_GIT_SHA", nil)
|
|
31
34
|
|
|
32
|
-
abort "missing app name" unless @app
|
|
33
|
-
abort "missing project name" unless @project
|
|
34
|
-
abort "this command must be run in Semaphore" unless @revision
|
|
35
|
+
abort "[RENUO-CLI] missing app name" unless @app
|
|
36
|
+
abort "[RENUO-CLI] missing project name" unless @project
|
|
37
|
+
abort "[RENUO-CLI] this command must be run in Semaphore" unless @revision
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def system!(cmd)
|
|
38
41
|
abort unless system cmd
|
|
39
42
|
end
|
|
40
43
|
|
|
41
|
-
def
|
|
42
|
-
command = "nctl get
|
|
44
|
+
def fetch(type)
|
|
45
|
+
command = "nctl get #{type} -a #{@app} -p #{@project} -o yaml"
|
|
43
46
|
stdout, stderr, status = Open3.capture3 command
|
|
44
47
|
|
|
45
|
-
abort "error fetching
|
|
48
|
+
abort "[RENUO-CLI] error fetching #{type} information: #{stderr}" unless status.success?
|
|
46
49
|
Psych.load_stream stdout
|
|
47
50
|
end
|
|
48
51
|
|
|
@@ -67,7 +70,7 @@ module Renuo::Cli::Commands::Ci
|
|
|
67
70
|
end
|
|
68
71
|
|
|
69
72
|
def build
|
|
70
|
-
@build ||=
|
|
73
|
+
@build ||= fetch("builds").find do |build|
|
|
71
74
|
build.dig("spec", "forProvider", "sourceConfig", "git", "revision") == @revision
|
|
72
75
|
end
|
|
73
76
|
end
|
|
@@ -80,34 +83,63 @@ module Renuo::Cli::Commands::Ci
|
|
|
80
83
|
build.dig("status", "atProvider", "buildStatus")
|
|
81
84
|
end
|
|
82
85
|
|
|
83
|
-
def
|
|
86
|
+
def release
|
|
87
|
+
@release ||= fetch("releases").find do |release|
|
|
88
|
+
release.dig("spec", "forProvider", "build", "name") == build_name
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def release_name
|
|
93
|
+
release.dig("metadata", "name")
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def release_status
|
|
97
|
+
release.dig("status", "atProvider", "releaseStatus")
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def succeeded?(type, name, status) # rubocop:disable Metrics/MethodLength
|
|
84
101
|
time = Time.current.iso8601.to_s
|
|
85
102
|
|
|
86
|
-
case
|
|
103
|
+
case status
|
|
87
104
|
when "available", "success"
|
|
88
|
-
puts "[RENUO-CLI] #{time}
|
|
105
|
+
puts "[RENUO-CLI] #{time} #{type} #{name} succeeded"
|
|
106
|
+
true
|
|
107
|
+
when "superseded"
|
|
108
|
+
puts "[RENUO-CLI] #{time} #{type} #{name} was superseded"
|
|
89
109
|
true
|
|
90
110
|
when "paused"
|
|
91
111
|
abort "[RENUO-CLI] #{time} app is paused"
|
|
92
112
|
when "error", "failed", "failure"
|
|
93
|
-
abort "[RENUO-CLI] #{time}
|
|
113
|
+
abort "[RENUO-CLI] #{time} #{type} #{name} failed"
|
|
94
114
|
else
|
|
95
|
-
puts "[RENUO-CLI] #{time}
|
|
115
|
+
puts "[RENUO-CLI] #{time} #{type} #{name} status is #{status}, waiting..."
|
|
96
116
|
false
|
|
97
117
|
end
|
|
98
118
|
end
|
|
99
119
|
|
|
100
|
-
def poll_build
|
|
120
|
+
def poll_build
|
|
121
|
+
poll do
|
|
122
|
+
next puts("[RENUO-CLI] no matching build found, waiting...") unless build
|
|
123
|
+
next true if succeeded?("build", build_name, build_status)
|
|
124
|
+
|
|
125
|
+
@build = nil
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def poll_release
|
|
130
|
+
poll do
|
|
131
|
+
next puts("[RENUO-CLI] no matching release found, waiting...") unless release
|
|
132
|
+
next true if succeeded?("release", release_name, release_status)
|
|
133
|
+
|
|
134
|
+
@release = nil
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def poll
|
|
101
139
|
elapsed = 0
|
|
102
140
|
|
|
103
141
|
while elapsed < TIMEOUT_IN_SECONDS
|
|
104
|
-
if
|
|
105
|
-
return true if build_succeeded?
|
|
106
|
-
|
|
107
|
-
@build = nil
|
|
108
|
-
else
|
|
109
|
-
puts "no matching build found, waiting..."
|
|
110
|
-
end
|
|
142
|
+
return true if yield
|
|
111
143
|
|
|
112
144
|
sleep INTERVAL_IN_SECONDS
|
|
113
145
|
elapsed += INTERVAL_IN_SECONDS
|
|
@@ -96,14 +96,7 @@ class Renuo::Cli::Commands::CreateNineCloudvm
|
|
|
96
96
|
|
|
97
97
|
def set_vault_name
|
|
98
98
|
@vault_name = ask("An SSH key to access the cloud VM will be stored on 1Password. " \
|
|
99
|
-
"Enter the 1Password vault name: ")
|
|
100
|
-
q.default = "Deploio"
|
|
101
|
-
end
|
|
102
|
-
end
|
|
103
|
-
|
|
104
|
-
def setup_ssh_key
|
|
105
|
-
say "\n# Generate the SSH key to access the cloud VM\n".bold
|
|
106
|
-
generate_ssh_key(SSH_KEY_FILE_NAME)
|
|
99
|
+
"Enter the 1Password vault name: ") { |q| q.default = "Deploio" }
|
|
107
100
|
end
|
|
108
101
|
|
|
109
102
|
def setup_environments
|
|
@@ -133,17 +126,25 @@ class Renuo::Cli::Commands::CreateNineCloudvm
|
|
|
133
126
|
--wait \\
|
|
134
127
|
--location="#{@location}" \\
|
|
135
128
|
--machine-type="#{@machine_type}" \\
|
|
136
|
-
--hostname="#{
|
|
129
|
+
--hostname="#{@project_name_with_org_prefix}-#{environment}" \\
|
|
137
130
|
--os="#{@os}" \\
|
|
138
131
|
--ssh-keys-from-files=#{SSH_KEY_FILE_NAME}.pub
|
|
132
|
+
|
|
133
|
+
# Add an A record for #{domain(environment)} pointing to the IP address of the #{environment} cloud VM
|
|
134
|
+
# (see: nctl get cloudvm #{environment} --project #{@project_name_with_org_prefix})
|
|
139
135
|
OUTPUT
|
|
140
136
|
end
|
|
141
137
|
|
|
142
|
-
def
|
|
143
|
-
"#{@
|
|
138
|
+
def domain(environment)
|
|
139
|
+
"#{@project_name}-#{environment}.renuoapp.ch"
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def ssh_url_fields
|
|
143
|
+
ENVIRONMENTS.map { |environment| "'#{environment}[url]=ssh://root@#{domain(environment)}'" }.join(" \\\n ")
|
|
144
144
|
end
|
|
145
145
|
|
|
146
|
-
def
|
|
146
|
+
def setup_ssh_key
|
|
147
|
+
say "\n# Generate the SSH key to access the cloud VM\n".bold
|
|
147
148
|
say <<~OUTPUT
|
|
148
149
|
# Create SSH key item in 1Password directly
|
|
149
150
|
op item create \\
|
|
@@ -152,15 +153,16 @@ class Renuo::Cli::Commands::CreateNineCloudvm
|
|
|
152
153
|
--ssh-generate-key #{SSH_ALGORITHM.downcase} \\
|
|
153
154
|
--title "#{@project_name_with_org_prefix}-cloudvm-key" \\
|
|
154
155
|
--vault #{@vault_name} \\
|
|
155
|
-
--tags #{@project_name_with_org_prefix}
|
|
156
|
+
--tags #{@project_name_with_org_prefix} \\
|
|
157
|
+
#{ssh_url_fields}
|
|
156
158
|
|
|
157
159
|
# Extract keys to temp files for cloud VM usage
|
|
158
160
|
op item get "#{@project_name_with_org_prefix}-cloudvm-key" --vault #{@vault_name} \\
|
|
159
161
|
--account renuo.1password.com \\
|
|
160
|
-
--reveal --fields "public key" > #{
|
|
162
|
+
--reveal --fields "public key" > #{SSH_KEY_FILE_NAME}.pub
|
|
161
163
|
op item get "#{@project_name_with_org_prefix}-cloudvm-key" --vault #{@vault_name} --reveal \\
|
|
162
164
|
--account renuo.1password.com \\
|
|
163
|
-
--fields "private key" --format json | jq -r '.ssh_formats.openssh.value' > #{
|
|
165
|
+
--fields "private key" --format json | jq -r '.ssh_formats.openssh.value' > #{SSH_KEY_FILE_NAME}
|
|
164
166
|
OUTPUT
|
|
165
167
|
end
|
|
166
168
|
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../debug"
|
|
4
|
+
|
|
5
|
+
class Renuo::Cli::Commands::Debug
|
|
6
|
+
# Lists all known apps grouped by service. Invoked via `renuo debug --all`.
|
|
7
|
+
# Prints every app and server found in the caches, grouped by category (Hetzner, Deploio, Heroku).
|
|
8
|
+
class All
|
|
9
|
+
CATEGORIES = [
|
|
10
|
+
{ title: "Hetzner", cache: "hetzner_vms", row: :hetzner_vm_row },
|
|
11
|
+
{ title: "Deploio", cache: "deploio_apps", row: :deploio_app_row },
|
|
12
|
+
{ title: "Deploio VMs", cache: "deploio_vms", row: :deploio_vm_row },
|
|
13
|
+
{ title: "Heroku", cache: "heroku_apps", row: :heroku_app_row }
|
|
14
|
+
].freeze
|
|
15
|
+
|
|
16
|
+
def run
|
|
17
|
+
CATEGORIES.each { |category| print_category(category) }
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def print_category(category)
|
|
23
|
+
rows = rows_for(category).sort_by(&:first)
|
|
24
|
+
|
|
25
|
+
say "\n#{header_for(category, rows.size)}"
|
|
26
|
+
return say " no entries, update the cache with `renuo debug <app-name or domain>`".light_black if rows.empty?
|
|
27
|
+
|
|
28
|
+
print_rows(rows)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def rows_for(category)
|
|
32
|
+
entries = Cache.restore(category[:cache]) || []
|
|
33
|
+
entries.map { |entry| send(category[:row], entry) }
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def header_for(category, count)
|
|
37
|
+
title = "#{category[:title]} (#{count})".bold
|
|
38
|
+
"#{title} #{"updated #{Cache.stored_at(category[:cache]) || "never"}".light_black}"
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def print_rows(rows)
|
|
42
|
+
widths = column_widths(rows)
|
|
43
|
+
rows.each do |row|
|
|
44
|
+
columns = row.each_with_index.map { |column, index| column.ljust(widths[index]) }
|
|
45
|
+
say " #{columns.join(" ").rstrip}"
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def column_widths(rows)
|
|
50
|
+
rows.first.each_index.map { |index| rows.map { |row| row[index].length }.max }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def hetzner_vm_row(server)
|
|
54
|
+
[server[:name].to_s, server[:public_ip].to_s, server[:fqdn].to_s]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def deploio_app_row(app)
|
|
58
|
+
[app[:name].to_s, [app[:organization], app[:namespace]].compact_blank.uniq.join("/"), app[:hosts].to_a.join(", ")]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def deploio_vm_row(server)
|
|
62
|
+
[server[:name].to_s, server[:namespace].to_s, [server[:ip], server[:fqdn]].compact_blank.join(" ")]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def heroku_app_row(app)
|
|
66
|
+
[app[:name].to_s, app[:domains].to_a.join(", ")]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -4,6 +4,7 @@ require_relative "../services/cache"
|
|
|
4
4
|
require_relative "../services/deploio"
|
|
5
5
|
require_relative "../services/heroku"
|
|
6
6
|
require_relative "../services/hetzner"
|
|
7
|
+
require_relative "debug/all"
|
|
7
8
|
require "shellwords"
|
|
8
9
|
|
|
9
10
|
class Renuo::Cli::Commands::Debug # rubocop:disable Metrics/ClassLength
|
|
@@ -23,6 +24,8 @@ class Renuo::Cli::Commands::Debug # rubocop:disable Metrics/ClassLength
|
|
|
23
24
|
c.option "-H", "--heroku", "Show only Heroku apps"
|
|
24
25
|
c.option "-d", "--deploio", "Show only Deploio apps"
|
|
25
26
|
c.option "-z", "--hetzner", "Show only Hetzner vms"
|
|
27
|
+
c.option "-a", "--all", "List all known apps grouped by category"
|
|
28
|
+
c.example "renuo debug --all", "Lists all cached apps and servers"
|
|
26
29
|
c.action do |args, options|
|
|
27
30
|
new.run(args, options)
|
|
28
31
|
rescue Interrupt
|
|
@@ -34,6 +37,8 @@ class Renuo::Cli::Commands::Debug # rubocop:disable Metrics/ClassLength
|
|
|
34
37
|
# rubocop:todo Metrics/MethodLength
|
|
35
38
|
# rubocop:todo Metrics/AbcSize
|
|
36
39
|
def run(args, options) # rubocop:todo Metrics/CyclomaticComplexity, Metrics/AbcSize, Metrics/MethodLength, Metrics/PerceivedComplexity
|
|
40
|
+
return All.new.run if options.all
|
|
41
|
+
|
|
37
42
|
query = args[0]
|
|
38
43
|
abort(">> Please provide an app name or domain.") if query.blank?
|
|
39
44
|
|
data/lib/renuo/cli/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: renuo-cli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.25.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Renuo AG
|
|
@@ -80,6 +80,7 @@ files:
|
|
|
80
80
|
- lib/renuo/cli/commands/create_pr.rb
|
|
81
81
|
- lib/renuo/cli/commands/create_slidev_presentation.rb
|
|
82
82
|
- lib/renuo/cli/commands/debug.rb
|
|
83
|
+
- lib/renuo/cli/commands/debug/all.rb
|
|
83
84
|
- lib/renuo/cli/commands/display_name.rb
|
|
84
85
|
- lib/renuo/cli/commands/fetch_emails.rb
|
|
85
86
|
- lib/renuo/cli/commands/fetch_secrets.rb
|
|
@@ -132,7 +133,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
132
133
|
- !ruby/object:Gem::Version
|
|
133
134
|
version: '0'
|
|
134
135
|
requirements: []
|
|
135
|
-
rubygems_version: 4.0.
|
|
136
|
+
rubygems_version: 4.0.21
|
|
136
137
|
specification_version: 4
|
|
137
138
|
summary: The Renuo CLI automates some common workflows.
|
|
138
139
|
test_files: []
|