sambot 0.1.110 → 0.1.111
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 +4 -4
- data/lib/sambot.rb +2 -5
- data/lib/sambot/chef/cookbook.rb +7 -0
- data/lib/sambot/cli.rb +0 -3
- data/lib/sambot/commands/base_command.rb +9 -13
- data/lib/sambot/commands/cookbook.rb +5 -0
- data/lib/sambot/commands/session.rb +10 -12
- data/lib/sambot/commands/workstation.rb +2 -3
- data/lib/sambot/developer_workflow/brew.rb +21 -6
- data/lib/sambot/developer_workflow/dns.rb +16 -7
- data/lib/sambot/developer_workflow/networking.rb +12 -6
- data/lib/sambot/developer_workflow/proxy.rb +34 -0
- data/lib/sambot/developer_workflow/session.rb +20 -45
- data/lib/sambot/developer_workflow/tunnel.rb +3 -3
- data/lib/sambot/developer_workflow/tunnels.rb +40 -0
- data/lib/sambot/developer_workflow/vault.rb +5 -2
- data/lib/sambot/developer_workflow/workstation.rb +23 -16
- data/lib/sambot/runtime.rb +11 -3
- data/lib/sambot/templates/haproxy.conf.erb +21 -0
- data/lib/sambot/ui.rb +6 -3
- data/lib/sambot/version.rb +1 -1
- data/sambot.gemspec +2 -0
- metadata +33 -8
- data/Rakefile +0 -6
- data/lib/sambot/commands/dns.rb +0 -45
- data/lib/sambot/commands/instance.rb +0 -17
- data/lib/sambot/commands/rdp.rb +0 -18
- data/lib/sambot/commands/report.rb +0 -16
- data/lib/sambot/commands/team.rb +0 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 04cf2aa5575db3b8d682df8834ee8219bfbf7ebf
|
4
|
+
data.tar.gz: e664f1bfdb6988720af8966aa6bf9af92277502d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71f8344676808ea81f690b06891fb80820de093e37635b937613b8102e2f6b236d4f97b28d89d10ce5af5d6433340fd4a51d808d1c94e806cf97136f00244142
|
7
|
+
data.tar.gz: a4a9d08a9e08102507cddc15f060a2cb398752067481dbc823e53fc023703a39966235a1b50dab517984e900e5c49c36d5f6edd585a2a3296595f702e5df8082
|
data/lib/sambot.rb
CHANGED
@@ -27,7 +27,9 @@ require_relative 'sambot/ssh/config_section'
|
|
27
27
|
require_relative 'sambot/ssh/parser'
|
28
28
|
|
29
29
|
require_relative 'sambot/developer_workflow/tunnel'
|
30
|
+
require_relative 'sambot/developer_workflow/tunnels'
|
30
31
|
require_relative 'sambot/developer_workflow/brew'
|
32
|
+
require_relative 'sambot/developer_workflow/proxy'
|
31
33
|
require_relative 'sambot/developer_workflow/networking'
|
32
34
|
require_relative 'sambot/developer_workflow/dns'
|
33
35
|
require_relative 'sambot/developer_workflow/session'
|
@@ -36,13 +38,8 @@ require_relative 'sambot/developer_workflow/workstation'
|
|
36
38
|
|
37
39
|
require_relative 'sambot/commands/base_command'
|
38
40
|
require_relative 'sambot/commands/cookbook'
|
39
|
-
require_relative 'sambot/commands/rdp'
|
40
41
|
require_relative 'sambot/commands/session'
|
41
42
|
require_relative 'sambot/commands/workstation'
|
42
|
-
require_relative 'sambot/commands/instance'
|
43
|
-
require_relative 'sambot/commands/dns'
|
44
|
-
require_relative 'sambot/commands/team'
|
45
|
-
require_relative 'sambot/commands/report'
|
46
43
|
|
47
44
|
require_relative 'sambot/cli'
|
48
45
|
|
data/lib/sambot/chef/cookbook.rb
CHANGED
@@ -7,6 +7,12 @@ module Sambot
|
|
7
7
|
module Chef
|
8
8
|
class Cookbook
|
9
9
|
|
10
|
+
def self.register(config)
|
11
|
+
name = config['name']
|
12
|
+
identifier = config['identifier']
|
13
|
+
|
14
|
+
end
|
15
|
+
|
10
16
|
def self.build(config, essential_files, generated_files)
|
11
17
|
validate_cookbook_structure(config['platforms'], essential_files, generated_files)
|
12
18
|
setup_test_kitchen(config)
|
@@ -42,6 +48,7 @@ module Sambot
|
|
42
48
|
'name' => name,
|
43
49
|
'version' => '0.0.1',
|
44
50
|
'platforms' => platforms,
|
51
|
+
'identifier' => '',
|
45
52
|
'suites' => [{
|
46
53
|
'name' => 'default',
|
47
54
|
'run_list' => [
|
data/lib/sambot/cli.rb
CHANGED
@@ -60,11 +60,15 @@ module Sambot
|
|
60
60
|
|
61
61
|
no_commands do
|
62
62
|
|
63
|
-
def execute(
|
64
|
-
if
|
65
|
-
|
66
|
-
|
67
|
-
|
63
|
+
def execute(need_dev_credentials: false, need_sudo_password: false)
|
64
|
+
if need_dev_credentials && !ENV['SAMBOT_DEV_USERNAME']
|
65
|
+
raise ApplicationError, 'Your DEV/QE username needs to be set in the environment variable SAMBOT_DEV_USERNAME before this command can be run.'
|
66
|
+
end
|
67
|
+
if need_dev_credentials && !ENV['SAMBOT_DEV_PASSWORD']
|
68
|
+
raise ApplicationError, 'Your DEV/QE password needs to be set in the environment variable SAMBOT_DEV_PASSWORD before this command can be run.'
|
69
|
+
end
|
70
|
+
if need_sudo_password && !ENV['SAMBOT_SUDO_PASSWORD']
|
71
|
+
raise ApplicationError, 'Your local password needs to be set in the environment variable SAMBOT_SUDO_PASSWORD before this command can be run.'
|
68
72
|
end
|
69
73
|
Runtime.ensure_latest
|
70
74
|
yield
|
@@ -72,14 +76,6 @@ module Sambot
|
|
72
76
|
UI.error(e.message)
|
73
77
|
end
|
74
78
|
|
75
|
-
def ensure_not_running_as_sudo
|
76
|
-
#raise ApplicationError, "This command should not be run as sudo" unless ENV['USER'] != 'root'
|
77
|
-
end
|
78
|
-
|
79
|
-
def ensure_running_as_sudo
|
80
|
-
#raise ApplicationError, "This command needs to be run as sudo" unless ENV['USER'] == 'root'
|
81
|
-
end
|
82
|
-
|
83
79
|
def config
|
84
80
|
Config.new.read
|
85
81
|
end
|
@@ -37,6 +37,11 @@ module Sambot
|
|
37
37
|
execute { puts "##teamcity[buildNumber '#{config['version'].to_s}']" }
|
38
38
|
end
|
39
39
|
|
40
|
+
desc 'register', 'Registers the cookbook short name in Consul for use with Rundeck machine creation jobs'
|
41
|
+
def register
|
42
|
+
execute { Chef::Cookbook.register(config) }
|
43
|
+
end
|
44
|
+
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
@@ -6,23 +6,21 @@ module Sambot
|
|
6
6
|
|
7
7
|
namespace 'session'
|
8
8
|
|
9
|
-
desc 'start', 'Start a new
|
9
|
+
desc 'start', 'Start a new Sambot session'
|
10
10
|
def start
|
11
|
-
execute(:
|
12
|
-
|
13
|
-
password = ENV['SAMBOT_SESSION_PASSWORD']
|
14
|
-
unless username && password
|
15
|
-
username = ask(' What is your DEV/QE username i.e. jsmith? ')
|
16
|
-
password = ask(' What is your DEV/QE password? ', :echo => false)
|
17
|
-
say('')
|
18
|
-
end
|
19
|
-
DeveloperWorkflow::Session.new.start(username, password)
|
11
|
+
execute(need_dev_credentials: true, need_sudo_password: true) do
|
12
|
+
DeveloperWorkflow::Session.new.start(ENV['SAMBOT_DEV_USERNAME'], ENV['SAMBOT_DEV_PASSWORD'], ENV['SAMBOT_SUDO_PASSWORD'])
|
20
13
|
end
|
21
14
|
end
|
22
15
|
|
23
|
-
desc 'stop', 'Stop
|
16
|
+
desc 'stop', 'Stop any active Sambot session'
|
24
17
|
def stop
|
25
|
-
execute(:
|
18
|
+
execute(need_sudo_password: true) { DeveloperWorkflow::Session.new.stop }
|
19
|
+
end
|
20
|
+
|
21
|
+
desc 'status', 'Show the status of your Sambot session'
|
22
|
+
def status
|
23
|
+
execute(need_sudo_password: true) { DeveloperWorkflow::Session.new.show }
|
26
24
|
end
|
27
25
|
|
28
26
|
end
|
@@ -8,9 +8,8 @@ module Sambot
|
|
8
8
|
|
9
9
|
desc 'configure', 'Sets up an engineering workstation'
|
10
10
|
def configure
|
11
|
-
execute do
|
12
|
-
|
13
|
-
DeveloperWorkflow::Workstation.configure(username)
|
11
|
+
execute(need_dev_credentials: true, need_sudo_password: true) do
|
12
|
+
DeveloperWorkflow::Workstation.configure(ENV['SAMBOT_DEV_PASSWORD'])
|
14
13
|
end
|
15
14
|
end
|
16
15
|
|
@@ -5,25 +5,40 @@ module Sambot
|
|
5
5
|
class Brew
|
6
6
|
|
7
7
|
def configure
|
8
|
+
UI.debug("Updating Homebrew formulas and casks")
|
8
9
|
update
|
9
10
|
tap('caskroom/cask')
|
10
11
|
update
|
11
12
|
end
|
12
13
|
|
13
14
|
def update
|
14
|
-
|
15
|
+
Bundler.with_clean_env do
|
16
|
+
`brew update`
|
17
|
+
end
|
15
18
|
end
|
16
19
|
|
17
20
|
def tap(name)
|
18
|
-
|
21
|
+
Bundler.with_clean_env do
|
22
|
+
`brew tap #{name}`
|
23
|
+
end
|
19
24
|
end
|
20
25
|
|
21
|
-
def
|
22
|
-
`
|
26
|
+
def install_cask(cask, binary)
|
27
|
+
result = `which #{binary}`
|
28
|
+
if result
|
29
|
+
UI.info("Not installing the Homebrew cask #{cask} as the corresponding binary is already available")
|
30
|
+
else
|
31
|
+
`brew cask install #{cask}`
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
|
-
def
|
26
|
-
`
|
35
|
+
def install_formula(formula, binary)
|
36
|
+
result = `which #{binary}`
|
37
|
+
if result
|
38
|
+
UI.info("Not installing the Homebrew formula #{formula} as the corresponding binary is already available")
|
39
|
+
else
|
40
|
+
`brew install #{formula}`
|
41
|
+
end
|
27
42
|
end
|
28
43
|
|
29
44
|
end
|
@@ -6,27 +6,36 @@ module Sambot
|
|
6
6
|
module DeveloperWorkflow
|
7
7
|
class DNS
|
8
8
|
|
9
|
-
def self.update_hosts(forwards, src = '/etc/hosts')
|
10
|
-
|
9
|
+
def self.update_hosts(forwards, src = '/etc/hosts', dest = nil)
|
10
|
+
UI.info('Updating your hosts file to allow access to Advertising Studio services through local SSH tunnels')
|
11
|
+
modify_hosts(forwards, src, dest) do |entries, key, value|
|
12
|
+
UI.debug("Adding hosts entry #{key} #{value[:ip]}")
|
11
13
|
entries << Hosts::Entry.new(value[:ip], key)
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
15
|
-
def self.reset_hosts(forwards, src = '/etc/hosts')
|
16
|
-
|
17
|
+
def self.reset_hosts(forwards, src = '/etc/hosts', dest = nil)
|
18
|
+
UI.info('Removing extra entries in hosts file')
|
19
|
+
modify_hosts(forwards, src, dest)
|
17
20
|
end
|
18
21
|
|
19
22
|
private
|
20
23
|
|
21
|
-
def self.modify_hosts(forwards, src)
|
22
|
-
UI.debug('Updating your hosts file.')
|
24
|
+
def self.modify_hosts(forwards, src, dest)
|
23
25
|
hosts = Hosts::File.read(src)
|
24
26
|
entries = hosts.elements
|
25
27
|
forwards.each do |key, value|
|
26
28
|
entries.delete_if { |entry| entry.is_a?(Aef::Hosts::Entry) && entry.name == key.to_s}
|
27
29
|
yield(entries, key, value) if block_given?
|
28
30
|
end
|
29
|
-
|
31
|
+
if dest
|
32
|
+
hosts.write(:path => dest)
|
33
|
+
else
|
34
|
+
tempfile = Tempfile.new
|
35
|
+
hosts.write(:path => tempfile.path)
|
36
|
+
Runtime.sudo("cp #{tempfile.path} /etc/hosts")
|
37
|
+
end
|
38
|
+
|
30
39
|
end
|
31
40
|
|
32
41
|
end
|
@@ -7,7 +7,8 @@ module Sambot
|
|
7
7
|
|
8
8
|
attr_reader :local_addresses
|
9
9
|
|
10
|
-
def
|
10
|
+
def self.local_addresses
|
11
|
+
return @local_addresses if @local_addresses
|
11
12
|
addr_infos = Socket.getifaddrs
|
12
13
|
@local_addresses = []
|
13
14
|
addr_infos.each do |addr_info|
|
@@ -15,14 +16,19 @@ module Sambot
|
|
15
16
|
@local_addresses << addr_info.addr.ip_address
|
16
17
|
end
|
17
18
|
end
|
19
|
+
@local_addresses
|
18
20
|
end
|
19
21
|
|
20
|
-
def configure(
|
21
|
-
|
22
|
-
|
22
|
+
def self.configure(forwards)
|
23
|
+
network = Networking.new
|
24
|
+
forwards.each do |key, value|
|
25
|
+
ip = value[:ip]
|
26
|
+
if local_addresses.include?(ip)
|
27
|
+
Runtime.sudo("ifconfig lo0 -alias #{ip}")
|
28
|
+
end
|
29
|
+
UI.debug "Setting up the local IP #{ip} for accessing #{key}"
|
30
|
+
Runtime.sudo("ifconfig lo0 alias #{ip} up")
|
23
31
|
end
|
24
|
-
UI.debug "Setting up the local IP #{ip} for SSH tunneling purposes."
|
25
|
-
`sudo ifconfig lo0 alias #{ip} up`
|
26
32
|
end
|
27
33
|
|
28
34
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sambot
|
4
|
+
module DeveloperWorkflow
|
5
|
+
class Proxy
|
6
|
+
|
7
|
+
def self.start(forwards)
|
8
|
+
template_path = FileManagement::TemplateProvider.get_path('haproxy.conf.erb')
|
9
|
+
input = File.read(template_path)
|
10
|
+
eruby = Erubis::Eruby.new(input)
|
11
|
+
services = forwards.map do |key, value|
|
12
|
+
{
|
13
|
+
name: key.to_s.split('.')[0],
|
14
|
+
ip: value[:ip],
|
15
|
+
tunnel_port: value[:local_port],
|
16
|
+
local_port: value[:port]
|
17
|
+
}
|
18
|
+
end
|
19
|
+
services.each do |service|
|
20
|
+
UI.debug("Proxying #{service[:name]}.brighter.io:#{service[:local_port]} to #{service[:ip]}:#{service[:tunnel_port]}")
|
21
|
+
end
|
22
|
+
contents = eruby.evaluate({services: services})
|
23
|
+
temp_config = Tempfile.new
|
24
|
+
File.write(temp_config.path, contents)
|
25
|
+
Runtime.sudo("haproxy -f #{temp_config.path}")
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.stop
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -2,6 +2,7 @@
|
|
2
2
|
require 'titan'
|
3
3
|
require 'net/ssh'
|
4
4
|
require 'dante'
|
5
|
+
require 'haproxy-tools'
|
5
6
|
|
6
7
|
module Dante
|
7
8
|
class Runner
|
@@ -18,37 +19,34 @@ module Sambot
|
|
18
19
|
BASTION_HOST_IP = '146.177.10.174'
|
19
20
|
|
20
21
|
FORWARDS = {
|
21
|
-
'chef.brighter.io': { ip: '127.0.0.13', port: 443 },
|
22
|
-
'teamcity.brighter.io': { ip: '127.0.0.14', port: 443 },
|
23
|
-
'splunk.brighter.io': { ip: '127.0.0.15', port: 443 },
|
24
|
-
'jenkins.brighter.io': { ip: '127.0.0.16', port: 443 },
|
25
|
-
'vault.brighter.io': { ip: '127.0.0.17', port: 8200 }
|
22
|
+
'chef.brighter.io': { ip: '127.0.0.13', port: 443, local_port: 9013 },
|
23
|
+
'teamcity.brighter.io': { ip: '127.0.0.14', port: 443, local_port: 9014 },
|
24
|
+
'splunk.brighter.io': { ip: '127.0.0.15', port: 443, local_port: 9015 },
|
25
|
+
'jenkins.brighter.io': { ip: '127.0.0.16', port: 443, local_port: 9016 },
|
26
|
+
'vault.brighter.io': { ip: '127.0.0.17', port: 8200, local_port: 9017 }
|
26
27
|
}
|
27
28
|
|
28
|
-
def start(username, password)
|
29
|
-
|
29
|
+
def start(username, password, sudo_password)
|
30
|
+
Tunnels.stop
|
30
31
|
unless verify_credentials(username, password)
|
31
|
-
UI.error 'The session could not be started
|
32
|
+
UI.error 'The session could not be started'
|
32
33
|
exit
|
33
34
|
end
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
35
|
+
DNS.update_hosts(FORWARDS)
|
36
|
+
Proxy.start(FORWARDS)
|
37
|
+
Networking.configure(FORWARDS)
|
38
|
+
Tunnels.start(username, password, BASTION_HOST_IP, FORWARDS)
|
39
|
+
#setup_secrets_management(username, password)
|
40
|
+
UI.info("Your session has now started - run `sambot session stop` to close it")
|
38
41
|
end
|
39
42
|
|
40
43
|
def stop
|
41
|
-
|
44
|
+
Tunnels.stop
|
42
45
|
DNS.reset_hosts(FORWARDS)
|
43
46
|
end
|
44
47
|
|
45
48
|
private
|
46
49
|
|
47
|
-
def kill_active_sessions
|
48
|
-
Dante::Runner.new('sambot-session').execute(:kill => true)
|
49
|
-
UI.debug("All active Sambot sessions have been closed.")
|
50
|
-
end
|
51
|
-
|
52
50
|
def verify_credentials(username, password)
|
53
51
|
full_username = "DEV\\#{username}"
|
54
52
|
begin
|
@@ -61,44 +59,21 @@ module Sambot
|
|
61
59
|
rescue Errno::ECONNREFUSED
|
62
60
|
puts " Connection refused"
|
63
61
|
rescue Net::SSH::Disconnect
|
64
|
-
UI.error "Invalid username or password provided
|
62
|
+
UI.error "Invalid username or password provided"
|
65
63
|
end
|
66
64
|
return false
|
67
65
|
end
|
68
66
|
|
69
|
-
def start_daemon_for_tunneling(username, password)
|
70
|
-
Dante::Runner.new('sambot-session').execute(:daemonize => true, :log_path => 'sambot-session.log') do
|
71
|
-
setup_ssh_tunnels(username, password)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
67
|
def setup_secrets_management(username, password)
|
76
|
-
Vault.setup_environment('vault.brighter.io', FORWARDS['vault.brighter.io'.to_sym][:port], '/etc/profile.d/')
|
77
68
|
unless Vault.has_environment_variables?('/etc/profile.d/')
|
78
|
-
|
79
|
-
UI.info("Because this is the first time you have created a session, environment variables need to be set. Run `source sambot.env` to add them this session - future sessions won't need this step.")
|
69
|
+
UI.info("You have either not configured your workstation or you have not opened up a new shell to pick up the changes applied during configuration")
|
80
70
|
end
|
81
|
-
UI.debug "Authenticating with Hashicorp Vault in Rackspace DEV/QE
|
71
|
+
UI.debug "Authenticating with Hashicorp Vault in Rackspace DEV/QE"
|
82
72
|
token = Vault.authenticate(username, password)
|
83
|
-
UI.debug "Saving your Vault authentication token to ~/.vault-token
|
73
|
+
UI.debug "Saving your Vault authentication token to ~/.vault-token"
|
84
74
|
Vault.save_token(token)
|
85
75
|
end
|
86
76
|
|
87
|
-
def setup_ssh_tunnels(username, password)
|
88
|
-
full_username = "DEV\\#{username}"
|
89
|
-
UI.debug "Opening a connection to the Rackspace DEV/QE environment..."
|
90
|
-
Net::SSH.start(BASTION_HOST_IP, full_username, :password => password) do |session|
|
91
|
-
FORWARDS.each { |key, value| Tunnel.create(session, key, value[:ip], value[:port]) }
|
92
|
-
session.loop {true}
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
def setup_networking
|
97
|
-
DNS.update_hosts(FORWARDS)
|
98
|
-
network = Networking.new
|
99
|
-
FORWARDS.each { |key, value| network.configure(value[:ip]) }
|
100
|
-
end
|
101
|
-
|
102
77
|
end
|
103
78
|
end
|
104
79
|
end
|
@@ -5,9 +5,9 @@ module Sambot
|
|
5
5
|
module DeveloperWorkflow
|
6
6
|
class Tunnel
|
7
7
|
|
8
|
-
def self.create(session, host, ip, port)
|
9
|
-
UI.debug "Creating a tunnel from #{ip}:#{
|
10
|
-
session.forward.local(ip,
|
8
|
+
def self.create(session, host, ip, port, local_port)
|
9
|
+
UI.debug "Creating a tunnel from #{ip}:#{local_port} to #{host}:#{port}"
|
10
|
+
session.forward.local(ip, local_port, host, port)
|
11
11
|
end
|
12
12
|
|
13
13
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module Sambot
|
2
|
+
module DeveloperWorkflow
|
3
|
+
|
4
|
+
class Tunnels
|
5
|
+
|
6
|
+
PID_PATH = '/tmp/sambot-session.pid'
|
7
|
+
|
8
|
+
LOG_PATH = '/tmp/sambot-session.log'
|
9
|
+
|
10
|
+
SESSION_ID = 'sambot'
|
11
|
+
|
12
|
+
def self.start(username, password, bastion_host_ip, forwards)
|
13
|
+
UI.info("Starting daemon for tunneling - log is available at #{LOG_PATH}")
|
14
|
+
Dante::Runner.new(SESSION_ID).execute(:daemonize => true, :pid_path => PID_PATH, :log_path => LOG_PATH) do
|
15
|
+
setup_ssh_tunnels(username, password, bastion_host_ip, forwards)
|
16
|
+
end
|
17
|
+
sleep(2)
|
18
|
+
puts "----- Background Daemon Log -----"
|
19
|
+
puts File.read(LOG_PATH)
|
20
|
+
puts "---------------------------------"
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.stop
|
24
|
+
Dante::Runner.new(SESSION_ID).execute(:kill => true, :pid_path => PID_PATH)
|
25
|
+
UI.debug("All active sessions have been closed")
|
26
|
+
File.delete(LOG_PATH) if File.exist?(LOG_PATH)
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.setup_ssh_tunnels(username, password, bastion_host_ip, forwards)
|
30
|
+
full_username = "DEV\\#{username}"
|
31
|
+
UI.debug "Opening a connection to the Rackspace DEV/QE environment"
|
32
|
+
Net::SSH.start(bastion_host_ip, full_username, :password => password) do |session|
|
33
|
+
forwards.each { |key, value| Tunnel.create(session, key, value[:ip], value[:port], value[:local_port]) }
|
34
|
+
session.loop {true}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'vault'
|
4
|
+
require 'open4'
|
4
5
|
|
5
6
|
module Sambot
|
6
7
|
module DeveloperWorkflow
|
@@ -19,14 +20,16 @@ module Sambot
|
|
19
20
|
secret.auth.client_token
|
20
21
|
end
|
21
22
|
|
22
|
-
def self.setup_environment(
|
23
|
+
def self.setup_environment(root = '/etc/profile.d/')
|
23
24
|
save_environment_variable('VAULT_SKIP_VERIFY', true)
|
24
25
|
save_environment_variable('VAULT_ADDR', TARGET)
|
25
26
|
end
|
26
27
|
|
27
28
|
def self.save_environment_variable(key, value, path = '/etc/profile.d/')
|
28
29
|
path = File.join(path, "#{key}.sh")
|
29
|
-
|
30
|
+
file = Tempfile.new('foo')
|
31
|
+
file.write("export #{key}=#{value}")
|
32
|
+
Runtime.sudo("cp #{file.path} #{path}")
|
30
33
|
ENV[key] = value.to_s
|
31
34
|
end
|
32
35
|
|
@@ -4,45 +4,52 @@ module Sambot
|
|
4
4
|
module DeveloperWorkflow
|
5
5
|
class Workstation
|
6
6
|
|
7
|
-
FORMULAS =
|
8
|
-
|
9
|
-
|
7
|
+
FORMULAS = {
|
8
|
+
'git': 'git',
|
9
|
+
'vault': 'vault',
|
10
|
+
'haproxy': 'haproxy'
|
11
|
+
}
|
12
|
+
|
13
|
+
CASKS = {
|
14
|
+
'virtualbox': 'virtualbox',
|
15
|
+
'vagrant': 'vagrant',
|
16
|
+
'chefdk': 'chef'
|
17
|
+
}
|
10
18
|
|
11
19
|
XCODE_INSTALLATION_SCRIPT = 'xcode-select --install'
|
12
20
|
|
13
21
|
def self.configure(username)
|
14
|
-
UI.debug('Updating your environment variables.')
|
15
22
|
update_environment_variables
|
16
23
|
install_native_binaries
|
17
|
-
UI.info('Your workstation is now ready for use
|
24
|
+
UI.info('Your workstation is now ready for use - please close this shell and open up a new one to start making use of your new environment')
|
18
25
|
end
|
19
26
|
|
20
27
|
def self.install_native_binaries
|
21
|
-
|
28
|
+
if `xcode-select version`
|
29
|
+
UI.info("Not installing XCode Developer Tools as they are already")
|
30
|
+
else
|
31
|
+
system(XCODE_INSTALLATION_SCRIPT)
|
32
|
+
end
|
22
33
|
brew = Brew.new
|
23
34
|
brew.configure
|
24
35
|
install_formulas(brew)
|
25
36
|
install_casks(brew)
|
26
37
|
end
|
27
38
|
|
28
|
-
def self.
|
29
|
-
CASKS.each do |formula|
|
30
|
-
brew.install_cask(formula
|
39
|
+
def self.install_casks(brew)
|
40
|
+
CASKS.each do |formula, binary|
|
41
|
+
brew.install_cask(formula, binary)
|
31
42
|
end
|
32
43
|
end
|
33
44
|
|
34
45
|
def self.install_formulas(brew)
|
35
|
-
FORMULAS.each do |formula|
|
36
|
-
brew.install_formula(formula
|
46
|
+
FORMULAS.each do |formula, binary|
|
47
|
+
brew.install_formula(formula, binary)
|
37
48
|
end
|
38
49
|
end
|
39
50
|
|
40
|
-
def self.update_ssh_configuration(username)
|
41
|
-
config = Ssh::Parser.new.update('DEV\\' + username)
|
42
|
-
config.save
|
43
|
-
end
|
44
|
-
|
45
51
|
def self.update_environment_variables
|
52
|
+
UI.debug('Updating your Vault environment variables')
|
46
53
|
Vault.setup_environment
|
47
54
|
end
|
48
55
|
|
data/lib/sambot/runtime.rb
CHANGED
@@ -12,10 +12,18 @@ module Sambot
|
|
12
12
|
|
13
13
|
def self.ensure_latest
|
14
14
|
latest_version = Gems.new.versions('sambot')[0]["number"]
|
15
|
-
UI.debug("Current
|
16
|
-
UI.debug("Latest
|
15
|
+
UI.debug("Current version is #{Sambot::VERSION}")
|
16
|
+
UI.debug("Latest version is #{latest_version}")
|
17
17
|
if is_obsolete
|
18
|
-
UI.info('A newer version of
|
18
|
+
UI.info('A newer version of this gem exists - please update the gem before continuing')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.sudo(command)
|
23
|
+
Open4::popen4("sudo -S #{command}") do |pid, stdin, stdout, stderr|
|
24
|
+
stdin.puts ENV['SAMBOT_SUDO_PASSWORD']
|
25
|
+
stdin.close
|
26
|
+
stdout.read
|
19
27
|
end
|
20
28
|
end
|
21
29
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
global
|
2
|
+
chroot /var/lib/haproxy
|
3
|
+
stats socket /run/haproxy/admin.sock mode 660 level admin
|
4
|
+
stats timeout 30s
|
5
|
+
daemon
|
6
|
+
|
7
|
+
defaults
|
8
|
+
log global
|
9
|
+
mode tcp
|
10
|
+
option tcplog
|
11
|
+
timeout connect 5000
|
12
|
+
timeout client 50000
|
13
|
+
timeout server 50000
|
14
|
+
|
15
|
+
<% @services.each do |service| %>
|
16
|
+
backend <%= service[:name] %>-service
|
17
|
+
server <%= service[:name] %>-server <%= service[:ip] %>:<%= service[:tunnel_port] %>
|
18
|
+
frontend <%= service[:name] %>
|
19
|
+
bind <%= service[:ip] %>:<%= service[:local_port] %>
|
20
|
+
default_backend <%= service[:name] %>-service
|
21
|
+
<% end %>
|
data/lib/sambot/ui.rb
CHANGED
@@ -4,15 +4,18 @@ module Sambot
|
|
4
4
|
module UI
|
5
5
|
|
6
6
|
def self.debug(msg)
|
7
|
-
|
7
|
+
date_format = DateTime.now.strftime("%Y-%m-%d %H:%M:%S")
|
8
|
+
Thor.new.say("#{date_format} [D] #{msg}", :yellow)
|
8
9
|
end
|
9
10
|
|
10
11
|
def self.info(msg)
|
11
|
-
|
12
|
+
date_format = DateTime.now.strftime("%Y-%m-%d %H:%M:%S")
|
13
|
+
Thor.new.say("#{date_format} [I] #{msg}", :green)
|
12
14
|
end
|
13
15
|
|
14
16
|
def self.error(msg)
|
15
|
-
|
17
|
+
date_format = DateTime.now.strftime("%Y-%m-%d %H:%M:%S")
|
18
|
+
Thor.new.say("#{date_format} [E] #{msg}", :red)
|
16
19
|
end
|
17
20
|
|
18
21
|
end
|
data/lib/sambot/version.rb
CHANGED
data/sambot.gemspec
CHANGED
@@ -31,6 +31,8 @@ Gem::Specification.new do |spec|
|
|
31
31
|
spec.add_dependency 'dante'
|
32
32
|
spec.add_dependency 'net-ssh'
|
33
33
|
spec.add_dependency 'titan'
|
34
|
+
spec.add_dependency 'open4'
|
35
|
+
spec.add_dependency 'haproxy-tools'
|
34
36
|
spec.add_dependency 'chef', '~> 12.18'
|
35
37
|
spec.add_dependency 'thor', '~> 0.19'
|
36
38
|
spec.add_dependency 'erubis', '~> 2.7', '>= 2.7.0'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sambot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.111
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Olivier Kouame
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor-hollaback
|
@@ -178,6 +178,34 @@ dependencies:
|
|
178
178
|
- - ">="
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0'
|
181
|
+
- !ruby/object:Gem::Dependency
|
182
|
+
name: open4
|
183
|
+
requirement: !ruby/object:Gem::Requirement
|
184
|
+
requirements:
|
185
|
+
- - ">="
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: '0'
|
188
|
+
type: :runtime
|
189
|
+
prerelease: false
|
190
|
+
version_requirements: !ruby/object:Gem::Requirement
|
191
|
+
requirements:
|
192
|
+
- - ">="
|
193
|
+
- !ruby/object:Gem::Version
|
194
|
+
version: '0'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: haproxy-tools
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
181
209
|
- !ruby/object:Gem::Dependency
|
182
210
|
name: chef
|
183
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -410,7 +438,6 @@ files:
|
|
410
438
|
- ".ruby-version"
|
411
439
|
- Gemfile
|
412
440
|
- README.md
|
413
|
-
- Rakefile
|
414
441
|
- bin/sambot
|
415
442
|
- bin/setup
|
416
443
|
- lib/sambot.rb
|
@@ -422,19 +449,16 @@ files:
|
|
422
449
|
- lib/sambot/cli.rb
|
423
450
|
- lib/sambot/commands/base_command.rb
|
424
451
|
- lib/sambot/commands/cookbook.rb
|
425
|
-
- lib/sambot/commands/dns.rb
|
426
|
-
- lib/sambot/commands/instance.rb
|
427
|
-
- lib/sambot/commands/rdp.rb
|
428
|
-
- lib/sambot/commands/report.rb
|
429
452
|
- lib/sambot/commands/session.rb
|
430
|
-
- lib/sambot/commands/team.rb
|
431
453
|
- lib/sambot/commands/workstation.rb
|
432
454
|
- lib/sambot/config.rb
|
433
455
|
- lib/sambot/developer_workflow/brew.rb
|
434
456
|
- lib/sambot/developer_workflow/dns.rb
|
435
457
|
- lib/sambot/developer_workflow/networking.rb
|
458
|
+
- lib/sambot/developer_workflow/proxy.rb
|
436
459
|
- lib/sambot/developer_workflow/session.rb
|
437
460
|
- lib/sambot/developer_workflow/tunnel.rb
|
461
|
+
- lib/sambot/developer_workflow/tunnels.rb
|
438
462
|
- lib/sambot/developer_workflow/vault.rb
|
439
463
|
- lib/sambot/developer_workflow/workstation.rb
|
440
464
|
- lib/sambot/dns/records.rb
|
@@ -471,6 +495,7 @@ files:
|
|
471
495
|
- lib/sambot/templates/.rubocop.yml
|
472
496
|
- lib/sambot/templates/Berksfile
|
473
497
|
- lib/sambot/templates/chefignore
|
498
|
+
- lib/sambot/templates/haproxy.conf.erb
|
474
499
|
- lib/sambot/templates/metadata.rb.erb
|
475
500
|
- lib/sambot/templates/pre-push
|
476
501
|
- lib/sambot/templates/startup-script.ps1
|
data/Rakefile
DELETED
data/lib/sambot/commands/dns.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'git'
|
4
|
-
|
5
|
-
module Sambot
|
6
|
-
module Commands
|
7
|
-
class DNS < BaseCommand
|
8
|
-
|
9
|
-
namespace 'dns'
|
10
|
-
|
11
|
-
desc 'remove', 'Removes the given DNS entry'
|
12
|
-
option :hostname, :required => true, :desc => 'The DNS name for the A record'
|
13
|
-
def remove
|
14
|
-
execute(:sudo) do
|
15
|
-
Sambot::DNS::Repository.new.records.remove(options[:hostname])
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
desc 'list', 'Shows all DNS entries'
|
20
|
-
def list
|
21
|
-
execute do
|
22
|
-
records = Sambot::DNS::Repository.new.list_records
|
23
|
-
say
|
24
|
-
print_table(records)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
desc 'show', 'Shows a given DNS entry'
|
29
|
-
def show
|
30
|
-
rescue ApplicationError => e
|
31
|
-
UI.error(e.message)
|
32
|
-
end
|
33
|
-
|
34
|
-
desc 'add', 'Adds or modify a DNS entry'
|
35
|
-
option :address, :required => true, :desc => 'The internal IP address for the A record'
|
36
|
-
option :hostname, :required => true, :desc => 'The DNS name for the A record'
|
37
|
-
option :team, :desc => 'The team owning the instance pointed to. Leave blank if the hostname contains stable, patch or unstable i.e. stable-api'
|
38
|
-
long_desc docs('cookbook/clean')
|
39
|
-
def add
|
40
|
-
execute(:sudo) { Sambot::DNS::Repository.new.records.add(options[:hostname], options[:address], options[:team]) }
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sambot
|
4
|
-
module Commands
|
5
|
-
|
6
|
-
class Instance < BaseCommand
|
7
|
-
|
8
|
-
namespace 'instance'
|
9
|
-
|
10
|
-
desc 'generate', 'Generate a name for an instance based on the instance characteristics supplied'
|
11
|
-
def generate
|
12
|
-
execute {}
|
13
|
-
end
|
14
|
-
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/sambot/commands/rdp.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sambot
|
4
|
-
module Commands
|
5
|
-
class RDP < BaseCommand
|
6
|
-
|
7
|
-
namespace 'rdp'
|
8
|
-
|
9
|
-
desc 'config', 'Get a configuration file for Remote Desktop Manager Free'
|
10
|
-
def config
|
11
|
-
execute do
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
data/lib/sambot/commands/team.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Sambot
|
4
|
-
module Commands
|
5
|
-
class Team < BaseCommand
|
6
|
-
|
7
|
-
namespace 'team'
|
8
|
-
|
9
|
-
desc 'list', 'Display the names and symbols of all Advertising Studio engineering teams'
|
10
|
-
def list
|
11
|
-
execute {}
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|