sambot 0.1.117 → 0.1.118
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/bin/slackbot +10 -0
- data/lib/sambot/commands/base_command.rb +10 -2
- data/lib/sambot/runtime.rb +10 -2
- data/lib/sambot/slack/api.rb +13 -0
- data/lib/sambot/slack/dispatcher.rb +16 -0
- data/lib/sambot/slack/formatter.rb +30 -0
- data/lib/sambot/slack/gus_bot.rb +14 -0
- data/lib/sambot/slack/product_tag.rb +19 -0
- data/lib/sambot/slack/work_item.rb +105 -0
- data/lib/sambot/templates/.gitignore.sample +2 -0
- data/lib/sambot/templates/haproxy.conf.erb +44 -7
- data/lib/sambot/ui.rb +6 -1
- data/lib/sambot/version.rb +1 -1
- data/lib/sambot/workflow/dns.rb +2 -2
- data/lib/sambot/workflow/proxy.rb +12 -12
- data/lib/sambot/workflow/session.rb +38 -11
- data/lib/sambot/workflow/tunnel.rb +3 -3
- data/lib/sambot/workflow/tunnels.rb +4 -4
- data/lib/sambot/workflow/vault.rb +4 -2
- data/lib/sambot.rb +7 -1
- data/sambot.gemspec +7 -0
- metadata +107 -3
- data/lib/sambot/workflow/networking.rb +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1805e2336fdd906d820e5745006354a299c3fb96
|
4
|
+
data.tar.gz: 2fabdabaa84f4c002b2bb7ef835d5d13c616ae68
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee012bbfc56033cd20dbdc69779722631978284e964508e35bd9799bb6fcc1965925b9802601ec5b870d677316d969870e1b6a146ed749fed9ec7bcda3c868f3
|
7
|
+
data.tar.gz: 34b7a0cfafc6be639fb5d499d9c1b7dd7843253abe889cb6fc4a01a1077b6f14d83af44b724fda0bd6abb68f7e93bbf46fec9cb02bbfca5cfcb6c120292930f7
|
data/bin/slackbot
ADDED
@@ -25,6 +25,14 @@ class Thor
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
class Thor
|
29
|
+
module Shell
|
30
|
+
class Color < Basic
|
31
|
+
GRAY = "\e[90m"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
28
36
|
|
29
37
|
class Thor
|
30
38
|
class << self
|
@@ -73,11 +81,11 @@ module Sambot
|
|
73
81
|
ENV['SAMBOT_DEV_USERNAME'] = UI.ask("Please provide your DEV/QE AD username: ")
|
74
82
|
end
|
75
83
|
if need_dev_credentials && !ENV['SAMBOT_DEV_PASSWORD']
|
76
|
-
ENV['
|
84
|
+
ENV['SAMBOT_DEV_PASSWORD'] = UI.ask_password("Please provide your DEV/QE AD password: ")
|
77
85
|
puts "\n"
|
78
86
|
end
|
79
87
|
if need_sudo_password && !ENV['SAMBOT_SUDO_PASSWORD']
|
80
|
-
ENV['
|
88
|
+
ENV['SAMBOT_SUDO_PASSWORD'] = UI.ask_password("Please provide your sudo password - this is required for operations such as setting up your local SSH tunnels: ")
|
81
89
|
puts "\n"
|
82
90
|
end
|
83
91
|
Runtime.ensure_latest
|
data/lib/sambot/runtime.rb
CHANGED
@@ -19,12 +19,20 @@ module Sambot
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
-
def self.sudo(command)
|
22
|
+
def self.sudo(command, flag_errors: true)
|
23
|
+
UI.warn("Running the command `sudo -S #{command}`")
|
24
|
+
output = ''
|
23
25
|
Open4::popen4("sudo -S #{command}") do |pid, stdin, stdout, stderr|
|
24
26
|
stdin.puts ENV['SAMBOT_SUDO_PASSWORD']
|
25
27
|
stdin.close
|
26
|
-
stdout.read
|
28
|
+
output = stdout.read
|
29
|
+
err = stderr.read
|
30
|
+
if flag_errors && err.strip.size > 0
|
31
|
+
UI.error(err)
|
32
|
+
exit -1
|
33
|
+
end
|
27
34
|
end
|
35
|
+
output
|
28
36
|
end
|
29
37
|
|
30
38
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Sambot
|
2
|
+
module Slack
|
3
|
+
class API
|
4
|
+
|
5
|
+
def self.connect
|
6
|
+
client_id = '3MVG99qusVZJwhsmVNpi.WqbGRUWtQC6srXMiq4QA.HjbH.jC.HsY24FyEzrtiGgfWTn7glS1Ni7P_xaUfyG3'
|
7
|
+
client_secret = '4690317352869892602'
|
8
|
+
Restforce.new(:client_id => client_id, :client_secret => client_secret, :username => 'olivier.kouame@gus.com', :password => 'Xamarin[2023]com99123')
|
9
|
+
end
|
10
|
+
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'slack-ruby-bot'
|
2
|
+
require 'restforce'
|
3
|
+
|
4
|
+
module Sambot
|
5
|
+
module Slack
|
6
|
+
class Dispatcher
|
7
|
+
|
8
|
+
def self.backlog
|
9
|
+
api = Sambot::Slack::API.connect
|
10
|
+
work_items = Sambot::Slack::WorkItem.find_by_product_tag(api, 'AS-PE').map { |x| Formatter.format(x) }
|
11
|
+
Formatter.index + work_items
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Sambot
|
2
|
+
module Slack
|
3
|
+
class Formatter
|
4
|
+
|
5
|
+
COLUMNS = {
|
6
|
+
'Blocked': {color: '#e85151', order: 1},
|
7
|
+
'In Progress': {color: '#49d14b', order: 2},
|
8
|
+
'Ready': {color: '#336334', order: 3},
|
9
|
+
'Pending Prioritization': {color: '#5b7aa3', order: 4},
|
10
|
+
'Icebox': {color: '#d1d1d1', order: 5}
|
11
|
+
}
|
12
|
+
|
13
|
+
def self.format(work_item)
|
14
|
+
{
|
15
|
+
fallback: "#{work_item.id_and_subject}",
|
16
|
+
title: "#{work_item.id_and_subject}",
|
17
|
+
text: "#{work_item.column} - #{work_item.assignee}",
|
18
|
+
color: "#{COLUMNS[work_item.column.to_sym] ? COLUMNS[work_item.column.to_sym][:color] : ''}"
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.index
|
23
|
+
COLUMNS.keys.map do |key|
|
24
|
+
{fallback: key, title: key, color: COLUMNS[key][:color]}
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'slack-ruby-bot'
|
2
|
+
require 'restforce'
|
3
|
+
|
4
|
+
module Sambot
|
5
|
+
module Slack
|
6
|
+
class GusBot < SlackRubyBot::Bot
|
7
|
+
|
8
|
+
command 'backlog' do |client, data, match|
|
9
|
+
client.web_client.chat_postMessage(channel: data.channel, attachments: Dispatcher.backlog)
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Sambot
|
2
|
+
module Slack
|
3
|
+
|
4
|
+
class ProductTag
|
5
|
+
attr_reader :id, :name
|
6
|
+
|
7
|
+
def initialize(id, name)
|
8
|
+
@id = id
|
9
|
+
@name = name
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.find(client, name)
|
13
|
+
query = "SELECT Id, Name FROM ADM_Product_Tag__c WHERE Active__c = true AND Name = '#{name}'"
|
14
|
+
client.query(query).map {|x| ProductTag.new(x[:Id], x[:Name]) }[0]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module Sambot
|
2
|
+
module Slack
|
3
|
+
class WorkItem
|
4
|
+
|
5
|
+
attr_reader :id, :name, :subject, :status, :product_tag
|
6
|
+
|
7
|
+
def initialize(s_object)
|
8
|
+
@s_object = s_object
|
9
|
+
end
|
10
|
+
|
11
|
+
def id; @s_object.Id; end
|
12
|
+
|
13
|
+
def name; @s_object.Name; end
|
14
|
+
|
15
|
+
def status; @s_object.Status__c; end
|
16
|
+
|
17
|
+
def product_tag; @s_object.Product_Tag__c; end
|
18
|
+
|
19
|
+
def subject; @s_object.Subject__c; end
|
20
|
+
|
21
|
+
def priority; @s_object.Priority__c; end
|
22
|
+
|
23
|
+
def product_owner; @s_object.Product_Owner__c; end
|
24
|
+
|
25
|
+
def qa_engineer; @s_object.QA_Engineer__c; end
|
26
|
+
|
27
|
+
def help_status; @s_object.Help_Status__c; end
|
28
|
+
|
29
|
+
def assignee; @s_object.Assignee__r.Name; end
|
30
|
+
|
31
|
+
def assigned_on; @s_object.Assigned_On__c; end
|
32
|
+
|
33
|
+
def last_activity_date; @s_object.LastActivityDate; end
|
34
|
+
|
35
|
+
def created_by_id; @s_object.CreatedById; end
|
36
|
+
|
37
|
+
def created_date; @s_object.CreatedDate; end
|
38
|
+
|
39
|
+
def record_type_id; @s_object.RecordTypeId; end
|
40
|
+
|
41
|
+
def owner_id; @s_object.OwnerId; end
|
42
|
+
|
43
|
+
def deleted?; @s_object.IsDeleted; end
|
44
|
+
|
45
|
+
def description; @s_object.Product_Owner__c; end
|
46
|
+
|
47
|
+
def story_points; @s_object.QA_Engineer__c; end
|
48
|
+
|
49
|
+
def closed_by; @s_object.Closed_By__c; end
|
50
|
+
|
51
|
+
def product_tag_name; @s_object.Product_Tag_Name__c; end
|
52
|
+
|
53
|
+
def epic; @s_object.Epic__c; end
|
54
|
+
|
55
|
+
def resolution; @s_object.Resolution__c; end
|
56
|
+
|
57
|
+
def column_rank; @s_object.Column_Rank__c || 0; end
|
58
|
+
|
59
|
+
def column; @s_object.Column__r ? @s_object.Column__r.Name : ''; end
|
60
|
+
|
61
|
+
def column_order
|
62
|
+
puts Formatter::COLUMNS[column.to_sym] ? Formatter::COLUMNS[column.to_sym][:order] : 100
|
63
|
+
column && Formatter::COLUMNS[column.to_sym] ? Formatter::COLUMNS[column.to_sym][:order] : 100
|
64
|
+
end
|
65
|
+
|
66
|
+
def id_and_subject; @s_object.WorkId_and_Subject__c; end
|
67
|
+
|
68
|
+
def self.find_by_product_tag(client, val)
|
69
|
+
product_tag = ProductTag.find(client, val)
|
70
|
+
query = "SELECT
|
71
|
+
Id,
|
72
|
+
Name,
|
73
|
+
Status__c,
|
74
|
+
Product_Tag__c,
|
75
|
+
Subject__c,
|
76
|
+
Priority__c,
|
77
|
+
Product_Owner__c,
|
78
|
+
QA_Engineer__c,
|
79
|
+
Help_Status__c,
|
80
|
+
Assignee__r.Name,
|
81
|
+
Assigned_On__c,
|
82
|
+
LastActivityDate,
|
83
|
+
CreatedById,
|
84
|
+
CreatedDate,
|
85
|
+
RecordTypeId,
|
86
|
+
OwnerId,
|
87
|
+
IsDeleted,
|
88
|
+
Description__c,
|
89
|
+
Story_Points__c,
|
90
|
+
Closed_By__c,
|
91
|
+
Product_Tag_Name__c,
|
92
|
+
Epic__c,
|
93
|
+
Resolution__c,
|
94
|
+
Column_Rank__c,
|
95
|
+
Column__r.Name,
|
96
|
+
WorkId_and_Subject__c
|
97
|
+
FROM ADM_Work__c \
|
98
|
+
WHERE Product_Tag__c = '#{product_tag.id}' AND (Status__c = 'New' OR Status__c = 'In Progress')"
|
99
|
+
results = client.query(query)
|
100
|
+
results.map {|x| WorkItem.new(x) }.sort_by {|x| [x.column_order, x.column_rank]}
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -7,15 +7,52 @@ global
|
|
7
7
|
defaults
|
8
8
|
log global
|
9
9
|
mode tcp
|
10
|
-
option tcplog
|
11
10
|
timeout connect 5000
|
12
11
|
timeout client 50000
|
13
12
|
timeout server 50000
|
14
13
|
|
15
|
-
<% @
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
14
|
+
<% @frontends.each do |x, services| %>
|
15
|
+
<% if x == 443 %>
|
16
|
+
<% services.each do |v| %>
|
17
|
+
backend <%= v[:name] %>-service
|
18
|
+
server <%= v[:name] %>-server 0.0.0.0:<%= v[:tunnel_port] %>
|
19
|
+
|
20
|
+
<% end %>
|
21
|
+
frontend ssl
|
22
|
+
bind 0.0.0.0:443
|
23
|
+
option socket-stats
|
24
|
+
tcp-request inspect-delay 5s
|
25
|
+
tcp-request content accept if { req_ssl_hello_type 1 }
|
26
|
+
<% services.each do |v| %>
|
27
|
+
use_backend <%= v[:name] %>-service if { req_ssl_sni -i <%= v[:name] %>.brighter.io }
|
28
|
+
<% end %>
|
29
|
+
<% elsif x == 8200%>
|
30
|
+
<% services.each do |v| %>
|
31
|
+
backend <%= v[:name] %>-service
|
32
|
+
server <%= v[:name] %>-server 0.0.0.0:<%= v[:tunnel_port] %>
|
33
|
+
<% end %>
|
34
|
+
|
35
|
+
frontend vault
|
36
|
+
bind 0.0.0.0:8200
|
37
|
+
option socket-stats
|
38
|
+
tcp-request inspect-delay 5s
|
39
|
+
tcp-request content accept if { req_ssl_hello_type 1 }
|
40
|
+
<% services.each do |v| %>
|
41
|
+
use_backend <%= v[:name] %>-service if { req_ssl_sni -i <%= v[:name] %>.brighter.io }
|
42
|
+
<% end %>
|
43
|
+
<% else %>
|
44
|
+
<% services.each do |v| %>
|
45
|
+
backend <%= v[:name] %>-service
|
46
|
+
server <%= v[:name] %>-server 0.0.0.0:<%= v[:tunnel_port] %>
|
47
|
+
|
48
|
+
<% end %>
|
49
|
+
|
50
|
+
frontend http
|
51
|
+
bind 0.0.0.0:80
|
52
|
+
<% services.each do |v| %>
|
53
|
+
acl host_<%= v[:name] %> hdr(host) -i <%= v[:name] %>.brighter.io
|
54
|
+
use_backend <%= v[:name] %>-service if host_<%= v[:name] %>
|
55
|
+
<% end %>
|
56
|
+
<% end %>
|
57
|
+
|
21
58
|
<% end %>
|
data/lib/sambot/ui.rb
CHANGED
@@ -11,9 +11,14 @@ module Sambot
|
|
11
11
|
Thor.new.ask(msg, :echo => false)
|
12
12
|
end
|
13
13
|
|
14
|
+
def self.warn(msg)
|
15
|
+
date_format = DateTime.now.strftime("%Y-%m-%d %H:%M:%S")
|
16
|
+
Thor.new.say("#{date_format} [W] #{msg}", :yellow)
|
17
|
+
end
|
18
|
+
|
14
19
|
def self.debug(msg)
|
15
20
|
date_format = DateTime.now.strftime("%Y-%m-%d %H:%M:%S")
|
16
|
-
Thor.new.say("#{date_format} [D] #{msg}", :
|
21
|
+
Thor.new.say("#{date_format} [D] #{msg}", :gray)
|
17
22
|
end
|
18
23
|
|
19
24
|
def self.info(msg)
|
data/lib/sambot/version.rb
CHANGED
data/lib/sambot/workflow/dns.rb
CHANGED
@@ -9,8 +9,8 @@ module Sambot
|
|
9
9
|
def self.update_hosts(forwards, src = '/etc/hosts', dest = nil)
|
10
10
|
UI.info('Updating your hosts file to allow access to Advertising Studio services through local SSH tunnels')
|
11
11
|
modify_hosts(forwards, src, dest) do |entries, key, value|
|
12
|
-
UI.debug("Adding hosts entry #{key}
|
13
|
-
entries << Hosts::Entry.new(
|
12
|
+
UI.debug("Adding hosts entry #{key} 127.0.0.1")
|
13
|
+
entries << Hosts::Entry.new("127.0.0.1", key)
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
@@ -7,27 +7,27 @@ module Sambot
|
|
7
7
|
CONFIG_PATH = '/tmp/haproxy.conf'
|
8
8
|
|
9
9
|
def self.start(forwards)
|
10
|
-
|
11
|
-
input = File.read(template_path)
|
12
|
-
eruby = Erubis::Eruby.new(input)
|
10
|
+
template = Sambot::Template.new('haproxy.conf.erb')
|
13
11
|
services = forwards.map do |key, value|
|
12
|
+
name = key.to_s.split('.')[0]
|
13
|
+
UI.debug("Proxying #{name}.brighter.io:#{value[:proxy_port]} to 0.0.0.0:#{value[:tunnel_port]}")
|
14
14
|
{
|
15
|
-
name:
|
16
|
-
|
17
|
-
|
18
|
-
local_port: value[:port]
|
15
|
+
name: name,
|
16
|
+
tunnel_port: value[:tunnel_port],
|
17
|
+
local_port: value[:proxy_port]
|
19
18
|
}
|
20
19
|
end
|
20
|
+
frontends = {}
|
21
|
+
services.map {|x| x[:local_port]}.uniq.each { |a| frontends[a] = [] }
|
21
22
|
services.each do |service|
|
22
|
-
|
23
|
+
frontends[service[:local_port]] << service
|
23
24
|
end
|
24
|
-
|
25
|
-
|
26
|
-
Runtime.sudo("haproxy -f #{CONFIG_PATH}")
|
25
|
+
template.write({frontends: frontends}, CONFIG_PATH)
|
26
|
+
Runtime.sudo("haproxy -f #{CONFIG_PATH}", flag_errors: true)
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.stop
|
30
|
-
Runtime.sudo("killall haproxy")
|
30
|
+
Runtime.sudo("killall haproxy", flag_errors: false)
|
31
31
|
end
|
32
32
|
|
33
33
|
end
|
@@ -19,24 +19,33 @@ module Sambot
|
|
19
19
|
BASTION_HOST_IP = '146.177.10.174'
|
20
20
|
|
21
21
|
FORWARDS = {
|
22
|
-
'chef.brighter.io': {
|
23
|
-
|
24
|
-
|
25
|
-
'
|
26
|
-
|
22
|
+
'chef.brighter.io': {
|
23
|
+
tunnel_port: 9000, dest_port: 443, proxy_port: 443
|
24
|
+
},
|
25
|
+
'teamcity.brighter.io': {
|
26
|
+
tunnel_port: 9001, dest_port: 8111, proxy_port: 443
|
27
|
+
},
|
28
|
+
'splunk.brighter.io': {
|
29
|
+
tunnel_port: 9002, dest_port: 8000, proxy_port: 443
|
30
|
+
},
|
31
|
+
'vault.brighter.io': {
|
32
|
+
tunnel_port: 9003, dest_port: 8200, proxy_port: 8200
|
33
|
+
}
|
27
34
|
}
|
28
35
|
|
29
|
-
def start(
|
30
|
-
|
31
|
-
unless verify_credentials(
|
36
|
+
def start(user, pass, sudo_password)
|
37
|
+
stop
|
38
|
+
unless verify_credentials(user, pass)
|
32
39
|
UI.error 'The session could not be started'
|
33
40
|
exit
|
34
41
|
end
|
35
42
|
DNS.update_hosts(FORWARDS)
|
36
43
|
Proxy.start(FORWARDS)
|
37
|
-
|
38
|
-
|
39
|
-
|
44
|
+
Runtime.sudo("ifconfig lo0 -alias 127.0.0.1")
|
45
|
+
Runtime.sudo("ifconfig lo0 alias 127.0.0.1 up")
|
46
|
+
Tunnels.start(user, pass, BASTION_HOST_IP, FORWARDS)
|
47
|
+
run_connectivity_checks()
|
48
|
+
setup_secrets_management(user, pass)
|
40
49
|
UI.info("Your session has now started - run `sambot session stop` to close it")
|
41
50
|
end
|
42
51
|
|
@@ -44,10 +53,24 @@ module Sambot
|
|
44
53
|
Tunnels.stop
|
45
54
|
DNS.reset_hosts(FORWARDS)
|
46
55
|
Proxy.stop
|
56
|
+
release_ports
|
47
57
|
end
|
48
58
|
|
49
59
|
private
|
50
60
|
|
61
|
+
def release_ports
|
62
|
+
FORWARDS.each do |k, v|
|
63
|
+
output = Runtime.sudo("lsof -wni tcp:#{v[:tunnel_port]}", flag_errors: true)
|
64
|
+
if output.strip.size > 0
|
65
|
+
line = output.strip.lines[1]
|
66
|
+
pid = line.split[1]
|
67
|
+
UI.debug(line)
|
68
|
+
Runtime.sudo("kill -9 #{pid}")
|
69
|
+
end
|
70
|
+
end
|
71
|
+
#TODO RELEASE PROXY PORTS
|
72
|
+
end
|
73
|
+
|
51
74
|
def verify_credentials(username, password)
|
52
75
|
full_username = "DEV\\#{username}"
|
53
76
|
begin
|
@@ -65,6 +88,10 @@ module Sambot
|
|
65
88
|
return false
|
66
89
|
end
|
67
90
|
|
91
|
+
def run_connectivity_checks
|
92
|
+
#TODO
|
93
|
+
end
|
94
|
+
|
68
95
|
def setup_secrets_management(username, password)
|
69
96
|
unless Vault.has_environment_variables?(FORWARDS)
|
70
97
|
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")
|
@@ -5,9 +5,9 @@ module Sambot
|
|
5
5
|
module Workflow
|
6
6
|
class Tunnel
|
7
7
|
|
8
|
-
def self.create(session, host,
|
9
|
-
UI.debug "Creating a tunnel from
|
10
|
-
session.forward.local(
|
8
|
+
def self.create(session, host, port, local_port)
|
9
|
+
UI.debug "Creating a tunnel from 0.0.0.0:#{local_port} to #{host}:#{port}"
|
10
|
+
session.forward.local("0.0.0.0", local_port, host, port)
|
11
11
|
end
|
12
12
|
|
13
13
|
end
|
@@ -11,7 +11,7 @@ module Sambot
|
|
11
11
|
|
12
12
|
def self.start(username, password, bastion_host_ip, forwards)
|
13
13
|
UI.info("Starting daemon for tunneling - log is available at #{LOG_PATH}")
|
14
|
-
Dante::Runner.new(SESSION_ID).execute(:
|
14
|
+
Dante::Runner.new(SESSION_ID).execute(daemonize: true, pid_path: PID_PATH, log_path: LOG_PATH) do
|
15
15
|
setup_ssh_tunnels(username, password, bastion_host_ip, forwards)
|
16
16
|
end
|
17
17
|
sleep(2)
|
@@ -21,7 +21,7 @@ module Sambot
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.stop
|
24
|
-
Dante::Runner.new(SESSION_ID).execute(:
|
24
|
+
Dante::Runner.new(SESSION_ID).execute(kill: true, pid_path: PID_PATH)
|
25
25
|
UI.debug("All active sessions have been closed")
|
26
26
|
File.delete(LOG_PATH) if File.exist?(LOG_PATH)
|
27
27
|
end
|
@@ -29,8 +29,8 @@ module Sambot
|
|
29
29
|
def self.setup_ssh_tunnels(username, password, bastion_host_ip, forwards)
|
30
30
|
full_username = "DEV\\#{username}"
|
31
31
|
UI.debug "Opening a connection to the Rackspace DEV/QE environment"
|
32
|
-
Net::SSH.start(bastion_host_ip, full_username, :
|
33
|
-
forwards.each { |key, value| Tunnel.create(session, key, value[:
|
32
|
+
Net::SSH.start(bastion_host_ip, full_username, password: password) do |session|
|
33
|
+
forwards.each { |key, value| Tunnel.create(session, key, value[:dest_port], value[:tunnel_port]) }
|
34
34
|
session.loop {true}
|
35
35
|
end
|
36
36
|
end
|
@@ -27,13 +27,15 @@ module Sambot
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.build_vault_address(forwards)
|
30
|
-
"https://vault.brighter.io:#{forwards[:'vault.brighter.io'][:
|
30
|
+
"https://vault.brighter.io:#{forwards[:'vault.brighter.io'][:proxy_port]}"
|
31
31
|
end
|
32
32
|
|
33
33
|
def self.save_environment_variable(key, value, target = File.expand_path('~/.bash_profile'))
|
34
34
|
contents = File.read(target)
|
35
35
|
contents = contents.gsub(/export #{key}=#{value}/, '') if has_environment_variable?(key, value, target)
|
36
|
-
|
36
|
+
new_line = "export #{key}=#{value.to_s}\n"
|
37
|
+
UI.debug("Adding `#{new_line}` to your ~/.bash_profile")
|
38
|
+
contents << new_line
|
37
39
|
File.write(target, contents)
|
38
40
|
ENV[key] = value.to_s
|
39
41
|
end
|
data/lib/sambot.rb
CHANGED
@@ -26,12 +26,18 @@ require_relative 'sambot/workflow/tunnel'
|
|
26
26
|
require_relative 'sambot/workflow/tunnels'
|
27
27
|
require_relative 'sambot/workflow/brew'
|
28
28
|
require_relative 'sambot/workflow/proxy'
|
29
|
-
require_relative 'sambot/workflow/networking'
|
30
29
|
require_relative 'sambot/workflow/dns'
|
31
30
|
require_relative 'sambot/workflow/session'
|
32
31
|
require_relative 'sambot/workflow/vault'
|
33
32
|
require_relative 'sambot/workflow/workstation'
|
34
33
|
|
34
|
+
require_relative 'sambot/slack/product_tag'
|
35
|
+
require_relative 'sambot/slack/work_item'
|
36
|
+
require_relative 'sambot/slack/api'
|
37
|
+
require_relative 'sambot/slack/formatter'
|
38
|
+
require_relative 'sambot/slack/gus_bot'
|
39
|
+
require_relative 'sambot/slack/dispatcher'
|
40
|
+
|
35
41
|
require_relative 'sambot/cli'
|
36
42
|
|
37
43
|
module Sambot
|
data/sambot.gemspec
CHANGED
@@ -21,15 +21,21 @@ Gem::Specification.new do |spec|
|
|
21
21
|
|
22
22
|
spec.add_dependency 'thor-hollaback'
|
23
23
|
spec.add_dependency 'git'
|
24
|
+
spec.add_dependency 'slack-ruby-bot'
|
25
|
+
spec.add_dependency 'celluloid-io'
|
24
26
|
spec.add_dependency 'process_exists'
|
25
27
|
spec.add_dependency 'climate_control'
|
26
28
|
spec.add_dependency 'vault'
|
27
29
|
spec.add_dependency 'hosts'
|
28
30
|
spec.add_dependency 'fog'
|
31
|
+
spec.add_dependency 'databasedotcom'
|
29
32
|
spec.add_dependency 'rhcl'
|
33
|
+
spec.add_dependency 'restforce'
|
30
34
|
spec.add_dependency 'ridley'
|
31
35
|
spec.add_dependency 'dante'
|
32
36
|
spec.add_dependency 'net-ssh'
|
37
|
+
spec.add_dependency 'eventmachine'
|
38
|
+
spec.add_dependency 'faye-websocket'
|
33
39
|
spec.add_dependency 'titan'
|
34
40
|
spec.add_dependency 'open4'
|
35
41
|
spec.add_dependency 'haproxy-tools'
|
@@ -39,6 +45,7 @@ Gem::Specification.new do |spec|
|
|
39
45
|
spec.add_dependency 'gems', '~> 1.0', '>= 1.0.0'
|
40
46
|
spec.add_development_dependency 'aruba'
|
41
47
|
spec.add_dependency 'awesome_print'
|
48
|
+
spec.add_development_dependency 'pry'
|
42
49
|
spec.add_development_dependency 'fuubar'
|
43
50
|
spec.add_development_dependency 'rubocop', '~> 0.49'
|
44
51
|
spec.add_development_dependency 'gem-release', '~> 1.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.118
|
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-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor-hollaback
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: slack-ruby-bot
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: celluloid-io
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
- !ruby/object:Gem::Dependency
|
42
70
|
name: process_exists
|
43
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +136,20 @@ dependencies:
|
|
108
136
|
- - ">="
|
109
137
|
- !ruby/object:Gem::Version
|
110
138
|
version: '0'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: databasedotcom
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0'
|
146
|
+
type: :runtime
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0'
|
111
153
|
- !ruby/object:Gem::Dependency
|
112
154
|
name: rhcl
|
113
155
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +164,20 @@ dependencies:
|
|
122
164
|
- - ">="
|
123
165
|
- !ruby/object:Gem::Version
|
124
166
|
version: '0'
|
167
|
+
- !ruby/object:Gem::Dependency
|
168
|
+
name: restforce
|
169
|
+
requirement: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
type: :runtime
|
175
|
+
prerelease: false
|
176
|
+
version_requirements: !ruby/object:Gem::Requirement
|
177
|
+
requirements:
|
178
|
+
- - ">="
|
179
|
+
- !ruby/object:Gem::Version
|
180
|
+
version: '0'
|
125
181
|
- !ruby/object:Gem::Dependency
|
126
182
|
name: ridley
|
127
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -164,6 +220,34 @@ dependencies:
|
|
164
220
|
- - ">="
|
165
221
|
- !ruby/object:Gem::Version
|
166
222
|
version: '0'
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: eventmachine
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :runtime
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
237
|
+
- !ruby/object:Gem::Dependency
|
238
|
+
name: faye-websocket
|
239
|
+
requirement: !ruby/object:Gem::Requirement
|
240
|
+
requirements:
|
241
|
+
- - ">="
|
242
|
+
- !ruby/object:Gem::Version
|
243
|
+
version: '0'
|
244
|
+
type: :runtime
|
245
|
+
prerelease: false
|
246
|
+
version_requirements: !ruby/object:Gem::Requirement
|
247
|
+
requirements:
|
248
|
+
- - ">="
|
249
|
+
- !ruby/object:Gem::Version
|
250
|
+
version: '0'
|
167
251
|
- !ruby/object:Gem::Dependency
|
168
252
|
name: titan
|
169
253
|
requirement: !ruby/object:Gem::Requirement
|
@@ -302,6 +386,20 @@ dependencies:
|
|
302
386
|
- - ">="
|
303
387
|
- !ruby/object:Gem::Version
|
304
388
|
version: '0'
|
389
|
+
- !ruby/object:Gem::Dependency
|
390
|
+
name: pry
|
391
|
+
requirement: !ruby/object:Gem::Requirement
|
392
|
+
requirements:
|
393
|
+
- - ">="
|
394
|
+
- !ruby/object:Gem::Version
|
395
|
+
version: '0'
|
396
|
+
type: :development
|
397
|
+
prerelease: false
|
398
|
+
version_requirements: !ruby/object:Gem::Requirement
|
399
|
+
requirements:
|
400
|
+
- - ">="
|
401
|
+
- !ruby/object:Gem::Version
|
402
|
+
version: '0'
|
305
403
|
- !ruby/object:Gem::Dependency
|
306
404
|
name: fuubar
|
307
405
|
requirement: !ruby/object:Gem::Requirement
|
@@ -440,6 +538,7 @@ files:
|
|
440
538
|
- README.md
|
441
539
|
- bin/sambot
|
442
540
|
- bin/setup
|
541
|
+
- bin/slackbot
|
443
542
|
- lib/sambot.rb
|
444
543
|
- lib/sambot/application_error.rb
|
445
544
|
- lib/sambot/chef/cookbook.rb
|
@@ -468,6 +567,12 @@ files:
|
|
468
567
|
- lib/sambot/rackspace/images.rb
|
469
568
|
- lib/sambot/rackspace/instances.rb
|
470
569
|
- lib/sambot/runtime.rb
|
570
|
+
- lib/sambot/slack/api.rb
|
571
|
+
- lib/sambot/slack/dispatcher.rb
|
572
|
+
- lib/sambot/slack/formatter.rb
|
573
|
+
- lib/sambot/slack/gus_bot.rb
|
574
|
+
- lib/sambot/slack/product_tag.rb
|
575
|
+
- lib/sambot/slack/work_item.rb
|
471
576
|
- lib/sambot/template.rb
|
472
577
|
- lib/sambot/templates/.config.yml.erb
|
473
578
|
- lib/sambot/templates/.gitignore.sample
|
@@ -490,7 +595,6 @@ files:
|
|
490
595
|
- lib/sambot/version.rb
|
491
596
|
- lib/sambot/workflow/brew.rb
|
492
597
|
- lib/sambot/workflow/dns.rb
|
493
|
-
- lib/sambot/workflow/networking.rb
|
494
598
|
- lib/sambot/workflow/proxy.rb
|
495
599
|
- lib/sambot/workflow/session.rb
|
496
600
|
- lib/sambot/workflow/tunnel.rb
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'socket'
|
3
|
-
|
4
|
-
module Sambot
|
5
|
-
module Workflow
|
6
|
-
class Networking
|
7
|
-
|
8
|
-
attr_reader :local_addresses
|
9
|
-
|
10
|
-
def self.local_addresses
|
11
|
-
return @local_addresses if @local_addresses
|
12
|
-
addr_infos = Socket.getifaddrs
|
13
|
-
@local_addresses = []
|
14
|
-
addr_infos.each do |addr_info|
|
15
|
-
if addr_info.addr && addr_info.name == 'lo0' && addr_info.addr.ipv4?
|
16
|
-
@local_addresses << addr_info.addr.ip_address
|
17
|
-
end
|
18
|
-
end
|
19
|
-
@local_addresses
|
20
|
-
end
|
21
|
-
|
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")
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|