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