sct 0.1.17 → 0.1.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/sct +3 -4
- data/{.DS_Store → cluster/lib/.DS_Store} +0 -0
- data/cluster/lib/cluster.rb +6 -0
- data/cluster/lib/cluster/commands_generator.rb +109 -0
- data/cluster/lib/cluster/module.rb +7 -0
- data/{lib/sct → cluster/lib/cluster/resources}/.DS_Store +0 -0
- data/{resources → cluster/lib/cluster/resources}/corefile.yml +0 -0
- data/{lib/sct/commands/cluster.rb → cluster/lib/cluster/runner.rb} +160 -145
- data/{lib → sct/lib}/.DS_Store +0 -0
- data/sct/lib/sct.rb +17 -0
- data/sct/lib/sct/.DS_Store +0 -0
- data/sct/lib/sct/cli_tools_distributor.rb +50 -0
- data/{lib → sct/lib}/sct/command.rb +0 -0
- data/{lib → sct/lib}/sct/commands/hostfile.rb +7 -23
- data/sct/lib/sct/commands/init.rb +37 -0
- data/sct/lib/sct/commands/mysqlproxy.rb +20 -0
- data/sct/lib/sct/commands_generator.rb +56 -0
- data/sct/lib/sct/tools.rb +12 -0
- data/sct/lib/sct/version.rb +3 -0
- data/sct_core/lib/.DS_Store +0 -0
- data/sct_core/lib/sct_core.rb +14 -0
- data/sct_core/lib/sct_core/.DS_Store +0 -0
- data/sct_core/lib/sct_core/command_executor.rb +104 -0
- data/{lib/sct → sct_core/lib/sct_core}/config.rb +3 -3
- data/sct_core/lib/sct_core/core_ext/string.rb +9 -0
- data/{lib/sct/setup/helpers.rb → sct_core/lib/sct_core/helper.rb} +2 -2
- data/sct_core/lib/sct_core/module.rb +0 -0
- data/sct_core/lib/sct_core/sct_pty.rb +53 -0
- data/sct_core/lib/sct_core/ui/implementations/shell.rb +129 -0
- data/sct_core/lib/sct_core/ui/interface.rb +120 -0
- data/sct_core/lib/sct_core/ui/ui.rb +26 -0
- data/sct_core/lib/sct_core/update_checker/update_checker.rb +76 -0
- data/shell/README.md +0 -0
- data/shell/lib/shell.rb +3 -0
- data/{lib/sct → shell/lib/shell}/ClassLevelInheritableAttributes.rb +0 -0
- data/shell/lib/shell/commands_generator.rb +14 -0
- data/{lib/sct → shell/lib/shell}/docker/composer.rb +4 -3
- data/{lib/sct → shell/lib/shell}/docker/docker.rb +7 -10
- data/{lib/sct → shell/lib/shell}/docker/php.rb +3 -2
- data/{lib/sct → shell/lib/shell}/docker/yarn.rb +4 -3
- data/shell/lib/shell/module.rb +9 -0
- data/shell/lib/shell/runner.rb +34 -0
- data/shell/lib/shell/tools.rb +7 -0
- metadata +126 -53
- data/.gitignore +0 -12
- data/.gitlab/merge_request_templates/DefinitionOfDone.md +0 -14
- data/.rspec +0 -3
- data/.travis.yml +0 -7
- data/CODE_OF_CONDUCT.md +0 -74
- data/Gemfile +0 -4
- data/Gemfile.lock +0 -44
- data/LICENSE.txt +0 -21
- data/README.md +0 -134
- data/Rakefile +0 -6
- data/lib/sct.rb +0 -61
- data/lib/sct/command_interface.rb +0 -18
- data/lib/sct/command_option.rb +0 -14
- data/lib/sct/commands/composer.rb +0 -29
- data/lib/sct/commands/init.rb +0 -51
- data/lib/sct/commands/mysqlproxy.rb +0 -38
- data/lib/sct/commands/php.rb +0 -37
- data/lib/sct/commands/yarn.rb +0 -26
- data/lib/sct/version.rb +0 -3
- data/sct.gemspec +0 -40
data/{lib → sct/lib}/.DS_Store
RENAMED
File without changes
|
data/sct/lib/sct.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'sct_core'
|
2
|
+
|
3
|
+
require 'sct/version'
|
4
|
+
require 'sct/tools'
|
5
|
+
|
6
|
+
module Sct
|
7
|
+
|
8
|
+
Helper = SctCore::Helper
|
9
|
+
UI = SctCore::UI
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def load_actions
|
13
|
+
# we should load actions here. Something like:
|
14
|
+
# Sct::Actions.load_default_actions
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
Binary file
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Sct
|
2
|
+
class CLIToolsDistributor
|
3
|
+
class << self
|
4
|
+
def take_off
|
5
|
+
require 'sct'
|
6
|
+
|
7
|
+
tool_name = ARGV.first ? ARGV.first.downcase : nil
|
8
|
+
|
9
|
+
if tool_name && Sct::TOOLS.include?(tool_name.to_sym)
|
10
|
+
# Triggering a specific tool
|
11
|
+
|
12
|
+
require tool_name
|
13
|
+
begin
|
14
|
+
# First, remove the tool's name from the arguments
|
15
|
+
# Since it will be parsed by the `commander` at a later point
|
16
|
+
# and it must not contain the binary name
|
17
|
+
ARGV.shift
|
18
|
+
|
19
|
+
# Import the CommandsGenerator class, which is used to parse
|
20
|
+
# the user input
|
21
|
+
require File.join(tool_name, "commands_generator")
|
22
|
+
|
23
|
+
# Call the tool's CommandsGenerator class and let it do its thing
|
24
|
+
commands_generator = Object.const_get(tool_name.sct_module)::CommandsGenerator
|
25
|
+
rescue LoadError
|
26
|
+
# This will only happen if the tool we call here, doesn't provide
|
27
|
+
# a CommandsGenerator class yet
|
28
|
+
# When we launch this feature, this should never be the case
|
29
|
+
abort("#{tool_name} can't be called via `sct #{tool_name}`, run '#{tool_name}' directly instead".red)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Some of the tools might use other actions so need to load all
|
33
|
+
# actions before we start the tool generator here in the future
|
34
|
+
Sct.load_actions
|
35
|
+
|
36
|
+
# trigger start on tool
|
37
|
+
commands_generator.start
|
38
|
+
|
39
|
+
else
|
40
|
+
require "sct/commands_generator"
|
41
|
+
Sct::CommandsGenerator.start
|
42
|
+
end
|
43
|
+
ensure
|
44
|
+
SctCore::UpdateChecker.start_looking_for_update('sct')
|
45
|
+
SctCore::UpdateChecker.show_update_status('sct', Sct::VERSION)
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
File without changes
|
@@ -1,28 +1,14 @@
|
|
1
|
-
require 'sct/command_interface'
|
2
|
-
|
3
1
|
module Sct
|
4
2
|
class HostfileCommand
|
5
3
|
|
6
|
-
IS_PUBLIC_COMMAND = true
|
7
|
-
SYNTAX = 'sct hostfile'
|
8
|
-
SUMMARY = 'adds the ingress url to the users hostfile'
|
9
|
-
DESCRIPTION = ""
|
10
|
-
EXAMPLE = "sct hostfile"
|
11
|
-
EXAMPLE_DESCRIPTION = ""
|
12
|
-
|
13
|
-
OPTIONS = []
|
14
|
-
|
15
|
-
def self.options
|
16
|
-
end
|
17
|
-
|
18
4
|
def execute(args, options)
|
19
|
-
return
|
20
|
-
|
21
|
-
return puts "This command needs to be run with sudo.".red unless Sct::Helpers.isSudo
|
5
|
+
return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
|
22
6
|
|
23
|
-
return unless
|
7
|
+
return UI.error("This command needs to be run with sudo.") unless SctCore::Helper.isSudo
|
24
8
|
|
25
|
-
|
9
|
+
return unless SctCore::Helper.ingressAddress
|
10
|
+
|
11
|
+
ingressAddress = SctCore::Helper.ingressAddress
|
26
12
|
|
27
13
|
entries = [
|
28
14
|
{
|
@@ -52,7 +38,7 @@ module Sct
|
|
52
38
|
else
|
53
39
|
hosts_paths = ["/etc/hosts"]
|
54
40
|
|
55
|
-
if
|
41
|
+
if SctCore::Helper.operatingSystem == SctCore::Helper::WINDOWS
|
56
42
|
hosts_paths << "/mnt/c/Windows/System32/drivers/etc/hosts"
|
57
43
|
end
|
58
44
|
end
|
@@ -72,13 +58,11 @@ module Sct
|
|
72
58
|
|
73
59
|
File.write hosts_path, lines.join
|
74
60
|
|
75
|
-
|
61
|
+
UI.success("Patched #{hosts_path} with #{ingressAddress}")
|
76
62
|
end
|
77
63
|
|
78
64
|
end
|
79
65
|
|
80
|
-
implements CommandInterface
|
81
|
-
|
82
66
|
end
|
83
67
|
|
84
68
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'sct_core/ui/ui'
|
2
|
+
require 'sct_core/config'
|
3
|
+
|
4
|
+
module Sct
|
5
|
+
|
6
|
+
class InitCommand
|
7
|
+
|
8
|
+
def execute(args, options)
|
9
|
+
|
10
|
+
dir = SctCore::Config.dir
|
11
|
+
|
12
|
+
cli = HighLine.new
|
13
|
+
|
14
|
+
email = cli.ask("What is your email address?") { |q|
|
15
|
+
q.validate = URI::MailTo::EMAIL_REGEXP
|
16
|
+
}
|
17
|
+
|
18
|
+
cloud_proxy_path = cli.ask("What is the path of your cloud proxy json credentials?") { |q|
|
19
|
+
q.default = "~/.config/gcloud/application_default_credentials.json"
|
20
|
+
}
|
21
|
+
|
22
|
+
contents = ""
|
23
|
+
contents << "email=#{email}\n"
|
24
|
+
contents << "cloud-proxy-path=#{File.expand_path(cloud_proxy_path)}\n"
|
25
|
+
|
26
|
+
if !File.directory?(dir)
|
27
|
+
FileUtils.mkdir_p(dir)
|
28
|
+
end
|
29
|
+
|
30
|
+
File.write(SctCore::Config.path, contents)
|
31
|
+
|
32
|
+
puts "Generated config file at #{SctCore::Config.path}"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Sct
|
2
|
+
class MysqlproxyCommand
|
3
|
+
|
4
|
+
DEFAULT_SECRET_NAME = "gcloud-credentials"
|
5
|
+
|
6
|
+
def execute(args, options)
|
7
|
+
|
8
|
+
return UI.error("SCT has not been initialized. Run 'sct init' first.") unless SctCore::Config.exists
|
9
|
+
|
10
|
+
path = SctCore::Config.get('cloud-proxy-path')
|
11
|
+
|
12
|
+
system("kubectl delete secret gcloud-credentials")
|
13
|
+
system("kubectl create secret generic gcloud-credentials --from-file=#{path}")
|
14
|
+
|
15
|
+
UI.success("Authenticated with secret-name: '#{DEFAULT_SECRET_NAME}'")
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'commander'
|
2
|
+
require 'sct/command'
|
3
|
+
|
4
|
+
module Sct
|
5
|
+
class CommandsGenerator
|
6
|
+
include Commander::Methods
|
7
|
+
|
8
|
+
def self.start
|
9
|
+
self.new.run
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
program :name, 'sct'
|
14
|
+
program :version, Sct::VERSION
|
15
|
+
program :summary, 'CLI helper tool for local SCT development'
|
16
|
+
program :description, 'SCT is a CLI tool for developers using the Visma Continuous Deployment Model in conjunction with the Google Cloud Platform (GCP). It provides multiple command to set up and maintain a kubernetes cluster on a machine for local development'
|
17
|
+
|
18
|
+
global_option('--verbose') { $verbose = true }
|
19
|
+
|
20
|
+
command :init do |c|
|
21
|
+
c.syntax = 'sct init'
|
22
|
+
c.description = 'setup sct'
|
23
|
+
|
24
|
+
c.action do |args, options|
|
25
|
+
UI.important("setting up sct")
|
26
|
+
Sct::InitCommand.new.execute(args, options)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
command :hostfile do |c|
|
31
|
+
|
32
|
+
c.syntax = 'sct hostfile'
|
33
|
+
c.description = 'patch hostfile with kubernetes ip'
|
34
|
+
|
35
|
+
c.action do |args, options|
|
36
|
+
UI.important("Trying to patch hostfile")
|
37
|
+
Sct::HostfileCommand.new.execute(args, options)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
command :'mysql proxy' do |c|
|
42
|
+
|
43
|
+
c.syntax = 'sct mysql proxy'
|
44
|
+
c.description = 'setup google mysql proxy'
|
45
|
+
|
46
|
+
c.action do |args, options|
|
47
|
+
UI.important("Trying to setup mysql proxy")
|
48
|
+
Sct::MysqlproxyCommand.new.execute(args, options)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
run!
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
Binary file
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'sct_core/core_ext/string'
|
2
|
+
require_relative 'sct_core/config'
|
3
|
+
require_relative 'sct_core/helper'
|
4
|
+
require_relative 'sct_core/update_checker/update_checker'
|
5
|
+
require_relative 'sct_core/command_executor'
|
6
|
+
require_relative 'sct_core/ui/ui'
|
7
|
+
require_relative 'sct_core/sct_pty'
|
8
|
+
|
9
|
+
# third party code
|
10
|
+
require 'colored'
|
11
|
+
require 'commander'
|
12
|
+
|
13
|
+
# these need to be imported after commander
|
14
|
+
require_relative 'sct_core/module'
|
Binary file
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require_relative 'ui/ui'
|
2
|
+
require_relative 'sct_pty'
|
3
|
+
|
4
|
+
module SctCore
|
5
|
+
# Executes commands and takes care of error handling and more
|
6
|
+
class CommandExecutor
|
7
|
+
class << self
|
8
|
+
# Cross-platform way of finding an executable in the $PATH. Respects the $PATHEXT, which lists
|
9
|
+
# valid file extensions for executables on Windows.
|
10
|
+
#
|
11
|
+
# which('ruby') #=> /usr/bin/ruby
|
12
|
+
#
|
13
|
+
# Derived from https://stackoverflow.com/a/5471032/3005
|
14
|
+
def which(cmd)
|
15
|
+
# PATHEXT contains the list of file extensions that Windows considers executable, semicolon separated.
|
16
|
+
# e.g. ".COM;.EXE;.BAT;.CMD"
|
17
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : []
|
18
|
+
exts << '' # Always have an empty string (= no file extension)
|
19
|
+
|
20
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
21
|
+
exts.each do |ext|
|
22
|
+
cmd_path = File.join(path, "#{cmd}#{ext}")
|
23
|
+
return cmd_path if Helper.executable?(cmd_path)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
return nil
|
28
|
+
end
|
29
|
+
|
30
|
+
# @param command [String] The command to be executed
|
31
|
+
# @param print_all [Boolean] Do we want to print out the command output while running?
|
32
|
+
# @param print_command [Boolean] Should we print the command that's being executed
|
33
|
+
# @param error [Block] A block that's called if an error occurs
|
34
|
+
# @param prefix [Array] An array containing a prefix + block which might get applied to the output
|
35
|
+
# @param loading [String] A loading string that is shown before the first output
|
36
|
+
# @param suppress_output [Boolean] Should we print the command's output?
|
37
|
+
# @return [String] All the output as string
|
38
|
+
def execute(command: nil, print_all: false, print_command: true, error: nil, prefix: nil, loading: nil, suppress_output: false)
|
39
|
+
print_all = true if $verbose
|
40
|
+
prefix ||= {}
|
41
|
+
|
42
|
+
output = []
|
43
|
+
command = command.join(" ") if command.kind_of?(Array)
|
44
|
+
command = self.escape_characters_in_string(command)
|
45
|
+
UI.command(command) if print_command
|
46
|
+
|
47
|
+
if print_all && loading # this is only used to show the "Loading text"...
|
48
|
+
UI.command_output(loading)
|
49
|
+
end
|
50
|
+
|
51
|
+
begin
|
52
|
+
status = SctCore::SctPty.spawn(command) do |command_stdout, command_stdin, pid|
|
53
|
+
command_stdout.each do |l|
|
54
|
+
line = l.chomp
|
55
|
+
output << line
|
56
|
+
|
57
|
+
next unless print_all
|
58
|
+
|
59
|
+
# Prefix the current line with a string
|
60
|
+
prefix.each do |element|
|
61
|
+
line = element[:prefix] + line if element[:block] && element[:block].call(line)
|
62
|
+
end
|
63
|
+
|
64
|
+
UI.command_output(line) unless suppress_output
|
65
|
+
end
|
66
|
+
end
|
67
|
+
rescue => ex
|
68
|
+
# SctPty adds exit_status on to StandardError so every error will have a status code
|
69
|
+
status = ex.exit_status
|
70
|
+
|
71
|
+
# This could happen when the environment is wrong:
|
72
|
+
# > invalid byte sequence in US-ASCII (ArgumentError)
|
73
|
+
output << ex.to_s
|
74
|
+
o = output.join("\n")
|
75
|
+
puts(o)
|
76
|
+
if error
|
77
|
+
error.call(o, nil)
|
78
|
+
else
|
79
|
+
raise ex
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
# Exit status for build command, should be 0 if build succeeded
|
84
|
+
if status != 0
|
85
|
+
o = output.join("\n")
|
86
|
+
puts(o) unless suppress_output # the user has the right to see the raw output
|
87
|
+
UI.error("Exit status: #{status}")
|
88
|
+
if error
|
89
|
+
error.call(o, status)
|
90
|
+
else
|
91
|
+
UI.user_error!("Exit status: #{status}")
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
return output.join("\n")
|
96
|
+
end
|
97
|
+
|
98
|
+
def escape_characters_in_string(string)
|
99
|
+
pattern = /(\'|\"|\.|\*|\/|\-|\\|\)|\$|\+|\(|\^|\?|\!|\~|\`)/
|
100
|
+
string.gsub(pattern){|match|"\\" + match}
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
module
|
1
|
+
module SctCore
|
2
2
|
class Config
|
3
3
|
|
4
4
|
def self.dir
|
5
|
-
return "#{
|
5
|
+
return "#{SctCore::Helper.homePath}/.config/sct"
|
6
6
|
end
|
7
7
|
|
8
8
|
def self.path
|
@@ -30,7 +30,7 @@ module Sct
|
|
30
30
|
|
31
31
|
contents = File.read(self.path)
|
32
32
|
|
33
|
-
return
|
33
|
+
return SctCore::Helper.to_hash(contents)
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
File without changes
|
@@ -0,0 +1,53 @@
|
|
1
|
+
class StandardError
|
2
|
+
def exit_status
|
3
|
+
return -1
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
module SctCore
|
8
|
+
class SctPtyError < StandardError
|
9
|
+
attr_reader :exit_status
|
10
|
+
def initialize(e, exit_status)
|
11
|
+
super(e)
|
12
|
+
set_backtrace(e.backtrace) if e
|
13
|
+
@exit_status = exit_status
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class SctPty
|
18
|
+
def self.spawn(command)
|
19
|
+
require 'pty'
|
20
|
+
PTY.spawn(command) do |command_stdout, command_stdin, pid|
|
21
|
+
begin
|
22
|
+
yield(command_stdout, command_stdin, pid)
|
23
|
+
rescue Errno::EIO
|
24
|
+
# Exception ignored intentionally.
|
25
|
+
# https://stackoverflow.com/questions/10238298/ruby-on-linux-pty-goes-away-without-eof-raises-errnoeio
|
26
|
+
# This is expected on some linux systems, that indicates that the subcommand finished
|
27
|
+
# and we kept trying to read, ignore it
|
28
|
+
ensure
|
29
|
+
begin
|
30
|
+
Process.wait(pid)
|
31
|
+
rescue Errno::ECHILD, PTY::ChildExited
|
32
|
+
# The process might have exited.
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
$?.exitstatus
|
37
|
+
rescue LoadError
|
38
|
+
require 'open3'
|
39
|
+
Open3.popen2e(command) do |command_stdin, command_stdout, p| # note the inversion
|
40
|
+
yield(command_stdout, command_stdin, p.value.pid)
|
41
|
+
|
42
|
+
command_stdin.close
|
43
|
+
command_stdout.close
|
44
|
+
p.value.exitstatus
|
45
|
+
end
|
46
|
+
rescue StandardError => e
|
47
|
+
# Wrapping any error in SctPtyError to allow
|
48
|
+
# callers to see and use $?.exitstatus that
|
49
|
+
# would usually get returned
|
50
|
+
raise SctPtyError.new(e, $?.exitstatus)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|