sambot 0.1.110 → 0.1.111
Sign up to get free protection for your applications and to get access to all the features.
- 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
|