sambot 0.1.99 → 0.1.100

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +10 -1
  4. data/bin/sambot +3 -0
  5. data/lib/sambot.rb +12 -2
  6. data/lib/sambot/chef/cookbook.rb +8 -13
  7. data/lib/sambot/chef/kitchen.rb +6 -5
  8. data/lib/sambot/chef/metadata.rb +2 -0
  9. data/lib/sambot/chef/server.rb +21 -23
  10. data/lib/sambot/cli.rb +4 -1
  11. data/lib/sambot/commands/base_command.rb +65 -1
  12. data/lib/sambot/commands/cookbook.rb +18 -60
  13. data/lib/sambot/commands/dns.rb +45 -0
  14. data/lib/sambot/commands/instance.rb +17 -0
  15. data/lib/sambot/commands/rdp.rb +18 -0
  16. data/lib/sambot/commands/report.rb +5 -6
  17. data/lib/sambot/commands/session.rb +16 -15
  18. data/lib/sambot/commands/team.rb +16 -0
  19. data/lib/sambot/commands/workstation.rb +8 -8
  20. data/lib/sambot/config.rb +2 -0
  21. data/lib/sambot/developer_workflow/brew.rb +31 -0
  22. data/lib/sambot/developer_workflow/dns.rb +22 -11
  23. data/lib/sambot/developer_workflow/networking.rb +30 -0
  24. data/lib/sambot/developer_workflow/session.rb +90 -11
  25. data/lib/sambot/developer_workflow/tunnel.rb +15 -0
  26. data/lib/sambot/developer_workflow/vault.rb +2 -0
  27. data/lib/sambot/developer_workflow/workstation.rb +33 -15
  28. data/lib/sambot/dns/records.rb +98 -0
  29. data/lib/sambot/dns/repository.rb +51 -0
  30. data/lib/sambot/docs/cookbook/build.txt +12 -0
  31. data/lib/sambot/docs/cookbook/clean.txt +2 -0
  32. data/lib/sambot/docs/cookbook/generate.txt +5 -0
  33. data/lib/sambot/{commands/rundeck.rb → docs/cookbook/version.txt} +0 -0
  34. data/lib/sambot/docs/dns/add.txt +0 -0
  35. data/lib/sambot/docs/dns/list.txt +0 -0
  36. data/lib/sambot/docs/dns/remove.txt +0 -0
  37. data/lib/sambot/docs/dns/show.txt +0 -0
  38. data/lib/sambot/docs/instance/generate.txt +0 -0
  39. data/lib/sambot/docs/report/consistency.txt +18 -0
  40. data/lib/sambot/docs/session/start.txt +0 -0
  41. data/lib/sambot/docs/session/stop.txt +0 -0
  42. data/lib/sambot/docs/team/list.txt +0 -0
  43. data/lib/sambot/docs/workstation/configure.txt +0 -0
  44. data/lib/sambot/file_management/file_checker.rb +30 -28
  45. data/lib/sambot/file_management/template_provider.rb +8 -6
  46. data/lib/sambot/rackspace/client.rb +9 -7
  47. data/lib/sambot/rackspace/flavors.rb +3 -3
  48. data/lib/sambot/rackspace/images.rb +7 -5
  49. data/lib/sambot/rackspace/instances.rb +20 -18
  50. data/lib/sambot/runtime.rb +2 -0
  51. data/lib/sambot/ssh/config_file.rb +53 -57
  52. data/lib/sambot/ssh/config_section.rb +60 -58
  53. data/lib/sambot/ssh/parser.rb +33 -32
  54. data/lib/sambot/templates/.kitchen.yml.erb +1 -1
  55. data/lib/sambot/ui.rb +2 -0
  56. data/lib/sambot/version.rb +3 -1
  57. data/sambot.gemspec +5 -1
  58. metadata +81 -13
  59. data/bin/cookbook +0 -4
  60. data/bin/report +0 -4
  61. data/bin/rundeck +0 -4
  62. data/bin/session +0 -4
  63. data/bin/workstation +0 -4
  64. data/lib/sambot/developer_workflow/bastion_host.rb +0 -58
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6e779e1412fd356ebd1c2d95a1e2bba17f95f271
4
- data.tar.gz: 34d07a2b89b11d01d7b38d8965df70a06fae25ef
3
+ metadata.gz: b5ec6ff097c32a95918f9ea05cdd036324ea8f54
4
+ data.tar.gz: 7d0a575a9b98dc0ae5db63e767e6256c793bf81a
5
5
  SHA512:
6
- metadata.gz: 43e34ed4faad4c51a78006949492230236899c6461b8ac56813f099663bb41acc8fdfda5c37c4bd2c2d4783ac4849b6542a603dc26b4a7d8a2056d2dabf14b56
7
- data.tar.gz: 1cf8f3347ab0464e23040bda5757e367f2e50440cc9c75fde66cf79688d45aabe8e8d9f2d22c5a6baf313fad0d209a598cd8f7c754b4f00b8563eaa1e8909147
6
+ metadata.gz: d6e81a25dd723813f9124bd882ebffa040fe7599b68ebc7d25b1ad0e2892713b9b25ba0095faaec0688ea9350e971219f07a11e23b62fd315414a4b7313980a7
7
+ data.tar.gz: 050c201c54cb984af3472048f05962a75e5b14753cf307d9f88bc8c2f97d4ea40687fd959f96174d34790266e74b77cc7fe9b92b4931a220152571556244574d
data/.gitignore CHANGED
@@ -10,3 +10,4 @@
10
10
 
11
11
  # rspec failure tracking
12
12
  .rspec_status
13
+ sambot-session.log
data/.rubocop.yml CHANGED
@@ -7,5 +7,14 @@ Documentation:
7
7
  Metrics/AbcSize:
8
8
  Enabled: false
9
9
 
10
- Style/EmptyLinesAroundBody:
10
+ Style/EmptyLinesAroundClassBody:
11
+ Enabled: false
12
+
13
+ Style/EmptyLinesAroundBlockBody:
14
+ Enabled: false
15
+
16
+ Metrics/ModuleLength:
17
+ Enabled: false
18
+
19
+ Metrics/MethodLength:
11
20
  Enabled: false
data/bin/sambot CHANGED
@@ -1,3 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
+ require 'hashie'
3
+ $VERBOSE = nil
4
+ Hashie.logger = Logger.new(nil)
2
5
  require_relative '../lib/sambot'
3
6
  Sambot::CLI.start
data/lib/sambot.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require 'thor'
2
+
1
3
  require_relative 'sambot/application_error'
2
4
  require_relative 'sambot/config'
3
5
  require_relative 'sambot/ui'
@@ -17,11 +19,16 @@ require_relative 'sambot/rackspace/flavors'
17
19
  require_relative 'sambot/rackspace/images'
18
20
  require_relative 'sambot/rackspace/instances'
19
21
 
22
+ require_relative 'sambot/dns/records'
23
+ require_relative 'sambot/dns/repository'
24
+
20
25
  require_relative 'sambot/ssh/config_file'
21
26
  require_relative 'sambot/ssh/config_section'
22
27
  require_relative 'sambot/ssh/parser'
23
28
 
24
- require_relative 'sambot/developer_workflow/bastion_host'
29
+ require_relative 'sambot/developer_workflow/tunnel'
30
+ require_relative 'sambot/developer_workflow/brew'
31
+ require_relative 'sambot/developer_workflow/networking'
25
32
  require_relative 'sambot/developer_workflow/dns'
26
33
  require_relative 'sambot/developer_workflow/session'
27
34
  require_relative 'sambot/developer_workflow/vault'
@@ -29,9 +36,12 @@ require_relative 'sambot/developer_workflow/workstation'
29
36
 
30
37
  require_relative 'sambot/commands/base_command'
31
38
  require_relative 'sambot/commands/cookbook'
39
+ require_relative 'sambot/commands/rdp'
32
40
  require_relative 'sambot/commands/session'
33
41
  require_relative 'sambot/commands/workstation'
34
- require_relative 'sambot/commands/rundeck'
42
+ require_relative 'sambot/commands/instance'
43
+ require_relative 'sambot/commands/dns'
44
+ require_relative 'sambot/commands/team'
35
45
  require_relative 'sambot/commands/report'
36
46
 
37
47
  require_relative 'sambot/cli'
@@ -1,3 +1,5 @@
1
+ #frozen_string_literal: true
2
+
1
3
  require 'yaml'
2
4
  require 'git'
3
5
 
@@ -5,8 +7,7 @@ module Sambot
5
7
  module Chef
6
8
  class Cookbook
7
9
 
8
- def self.build(essential_files, generated_files)
9
- config = Config.new.read
10
+ def self.build(config, essential_files, generated_files)
10
11
  validate_cookbook_structure(config['platforms'], essential_files, generated_files)
11
12
  setup_test_kitchen(config)
12
13
  build_metadata(config)
@@ -16,26 +17,20 @@ module Sambot
16
17
 
17
18
  def self.clean(generated_files)
18
19
  UI.info('Removing all generated files from this cookbook.')
19
- delete_file('metadata.rb')
20
- delete_file('winrm_config')
21
- delete_file('Berksfile.lock')
22
- delete_file('packer.json')
23
- generated_files.each { |file| delete_file(file) }
24
- Dir.glob('\.kitchen*\.yml').each do |file|
20
+ targets = ['metadata.rb', 'winrm_config', 'Berksfile.lock'] + generated_files + Dir.glob('\.kitchen*\.yml')
21
+ targets.each do |file|
25
22
  delete_file(file)
26
23
  end
27
24
  UI.info('The cookbook has been successfully cleaned.')
28
25
  end
29
26
 
30
- def self.generate(name, platforms, type, description, essential_files, generated_files)
27
+ def self.generate(config, name, platforms, type, description, essential_files, generated_files)
31
28
  Git.init(name)
32
29
  Dir.chdir(name) do
33
- FileUtils.mkdir('test')
34
- FileUtils.mkdir('spec')
35
- FileUtils.mkdir('recipes')
30
+ ['test', 'spec', 'recipes'].each {|target| FileUtils.mkdir(target) }
36
31
  FileUtils.touch('README.md')
37
32
  write_config(name, description, platforms, type)
38
- build(essential_files, generated_files)
33
+ build(config, essential_files, generated_files)
39
34
  end
40
35
  UI.info('The cookbook has been successfully generated.')
41
36
  end
@@ -1,11 +1,12 @@
1
+ #frozen_string_literal: true
2
+
1
3
  module Sambot
2
4
  module Chef
3
5
  class Kitchen
4
6
 
5
- KITCHEN_LOCAL_YML = ".kitchen.yml"
6
- KITCHEN_GCP_YML = ".kitchen.gcp.yml"
7
- KITCHEN_RACKSPACE_YML = ".kitchen.rackspace.yml"
8
-
7
+ KITCHEN_LOCAL_YML = '.kitchen.yml'
8
+ KITCHEN_GCP_YML = '.kitchen.gcp.yml'
9
+ KITCHEN_RACKSPACE_YML = '.kitchen.rackspace.yml'
9
10
 
10
11
  def self.generate_yml(cookbook_name, platforms, suites = nil)
11
12
  raise ApplicationError, 'Missing platforms when trying to generate Test-Kitchen YAML.' unless platforms
@@ -28,7 +29,7 @@ module Sambot
28
29
  filename = File.join(FileManagement::TemplateProvider.get_path("#{template}.erb"))
29
30
  contents = File.read(filename).gsub(/@@cookbook_name@@/, cookbook_name)
30
31
  eruby = Erubis::Eruby.new(contents)
31
- yaml = eruby.evaluate({platforms: platforms}).gsub(/\_@/, "<%=").gsub(/@\_/, "%>")
32
+ yaml = eruby.evaluate({platforms: platforms}).gsub(/\_@/, '<%=').gsub(/@\_/, '%>')
32
33
  YAML.load(yaml)
33
34
  end
34
35
 
@@ -1,3 +1,5 @@
1
+ #frozen_string_literal: true
2
+
1
3
  require 'erubis'
2
4
 
3
5
  module Sambot
@@ -1,3 +1,5 @@
1
+ #frozen_string_literal: true
2
+
1
3
  require 'ridley'
2
4
  require 'json'
3
5
 
@@ -6,23 +8,23 @@ module Sambot
6
8
  class Server
7
9
 
8
10
  SHORT_NAMES = {
9
- "wsus" => "WSUS",
10
- "nginx-proxy" => "PRXY",
11
- "jetstream" => "JTS",
12
- "task-scheduler" => "TASKS",
13
- "queue-service" => "QUE",
14
- "skylight" => "SKY",
15
- "prometheus" => "PRT",
16
- "octopus" => "OCTO",
17
- "vault" => "VAULT",
18
- "consul" => "CONSUL",
19
- "rabbitmq" => "RMQ",
20
- "etcd" => "ETCD",
21
- "teamcity-agent" => "TCA",
22
- "teamcity-server" => "TCS",
23
- "bastion" => "BST",
24
- "base" => "BASE",
25
- "grafana" => "MON"
11
+ 'wsus' => 'WSUS',
12
+ 'nginx-proxy' => 'PRXY',
13
+ 'jetstream' => 'JTS',
14
+ 'task-scheduler' => 'TASKS',
15
+ 'queue-service' => 'QUE',
16
+ 'skylight' => 'SKY',
17
+ 'prometheus' => 'PRT',
18
+ 'octopus' => 'OCTO',
19
+ 'vault' => 'VAULT',
20
+ 'consul' => 'CONSUL',
21
+ 'rabbitmq' => 'RMQ',
22
+ 'etcd' => 'ETCD',
23
+ 'teamcity-agent' => 'TCA',
24
+ 'teamcity-server' => 'TCS',
25
+ 'bastion' => 'BST',
26
+ 'base' => 'BASE',
27
+ 'grafana' => 'MON'
26
28
  }
27
29
 
28
30
  def initialize(ridley = nil)
@@ -43,18 +45,14 @@ module Sambot
43
45
  end
44
46
 
45
47
  def find_role_name(cookbook)
46
- naive_name = cookbook.gsub(/as-role-/, "").gsub(/as-app-role-/, "")
48
+ naive_name = cookbook.gsub(/as-role-/, '').gsub(/as-app-role-/, '')
47
49
  if SHORT_NAMES.key?(naive_name)
48
50
  SHORT_NAMES[naive_name]
49
51
  else
50
- raise "Could not generate an instance name"
52
+ raise 'Could not generate an instance name'
51
53
  end
52
54
  end
53
55
 
54
56
  end
55
57
  end
56
58
  end
57
-
58
-
59
- #Find out what's happening on the security front
60
- #Summarize conversation with Daven & take
data/lib/sambot/cli.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'thor'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Sambot
4
4
  class CLI < Thor
@@ -12,5 +12,8 @@ module Sambot
12
12
  desc 'workstation', 'Manage engineer workstations'
13
13
  subcommand 'workstation', Sambot::Commands::Workstation
14
14
 
15
+ desc 'dns', 'Manage DEV/QE DNS'
16
+ subcommand 'dns', Sambot::Commands::DNS
17
+
15
18
  end
16
19
  end
@@ -1,5 +1,56 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thor/hollaback'
2
4
 
5
+ class Thor
6
+ module Shell
7
+ class Basic
8
+ def print_wrapped(message, options = {})
9
+ indent = options[:indent] || 0
10
+ width = 100 - indent
11
+ paras = message.split("\n\n")
12
+
13
+ paras.map! do |unwrapped|
14
+ unwrapped.strip.tr("\n", " ").squeeze(" ").gsub(/.{1,#{width}}(?:\s|\Z)/) { ($& + 5.chr).gsub(/\n\005/, "\n").gsub(/\005/, "\n") }
15
+ end
16
+
17
+ paras.each do |para|
18
+ para.split("\n").each do |line|
19
+ stdout.puts line.insert(0, " " * indent)
20
+ end
21
+ stdout.puts unless para == paras.last
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+
29
+ class Thor
30
+ class << self
31
+ def command_help(shell, command_name)
32
+ meth = normalize_command_name(command_name)
33
+ command = all_commands[meth]
34
+ handle_no_command_error(meth) unless command
35
+ shell.say
36
+ shell.say("Usage:", :green)
37
+ shell.say
38
+ shell.say " sambot #{namespace} #{command_name} "
39
+ shell.say
40
+ shell.say
41
+ class_options_help(shell, nil => command.options.values)
42
+ if command.long_description
43
+ shell.say "Description:", :green
44
+ shell.say
45
+ shell.print_wrapped(docs("#{namespace}/#{command_name}"), :indent => 2)
46
+ else
47
+ shell.say command.description
48
+ end
49
+ shell.say
50
+ end
51
+ end
52
+ end
53
+
3
54
  module Sambot
4
55
  module Commands
5
56
 
@@ -8,9 +59,22 @@ module Sambot
8
59
  before :check_version
9
60
 
10
61
  no_commands do
11
- def check_version
62
+
63
+ def execute
12
64
  Runtime.ensure_latest
65
+ yield
66
+ rescue ApplicationError => e
67
+ UI.error(e.message)
13
68
  end
69
+
70
+ def config
71
+ Config.new.read
72
+ end
73
+
74
+ def self.docs(path)
75
+ File.read(File.join(File.dirname(__FILE__), '../docs', path + '.txt'))
76
+ end
77
+
14
78
  end
15
79
 
16
80
  end
@@ -1,4 +1,4 @@
1
- require 'thor'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Sambot
4
4
  module Commands
@@ -8,75 +8,33 @@ module Sambot
8
8
 
9
9
  class Cookbook < BaseCommand
10
10
 
11
- GUIDE =
12
- {
13
- clean: {
14
- SHORT_DESC: 'Remove all generated build files from a cookbook',
15
- LONG_DESC: <<-LONGDESC
16
- `sambot cookbook clean` will remove all files generated by `sambot cookbook build`.
17
- This is required to ensure the generated files are not stored in source control.
18
- LONGDESC
19
- },
20
- build: {
21
- SHORT_DESC: 'Builds a cookbook from its configuration file',
22
- LONG_DESC: <<-LONGDESC
23
- `sambot cookbook build` will generate all the files required for the functioning
24
- of a Chef cookbook from a configuration file. The motivation behind this setup is to
25
- standardize and simplify the Chef cookbook creation workflow. The configuration file should be
26
- called .config.yml and stored in the root of the Chef cookbook.
27
- LONGDESC
28
- },
29
- generate: {
30
- SHORT_DESC: 'Creates a new cookbook',
31
- LONG_DESC: <<-LONGDESC
32
- `sambot cookbook generate` will create a new cookbook. This can be either a
33
- wrapper cookbook or an instance role cookbook.
34
- LONGDESC
35
- },
36
- version: {
37
- SHORT_DESC: 'Gives the cookbook version as a TeamCity service message',
38
- LONG_DESC: ''
39
- }
40
- }
41
-
42
11
  namespace 'cookbook'
43
12
 
44
- desc 'clean', GUIDE[:clean][:SHORT_DESC]
45
- long_desc GUIDE[:clean][:LONG_DESC]
13
+ desc 'clean', 'Remove all generated build files from a cookbook'
46
14
  def clean
47
- Chef::Cookbook.clean(GENERATED_FILES - ['.gitignore'])
48
- rescue ApplicationError => e
49
- error(e.message)
15
+ execute { Chef::Cookbook.clean(GENERATED_FILES - ['.gitignore']) }
50
16
  end
51
17
 
52
- desc 'build', GUIDE[:clean][:SHORT_DESC]
53
- long_desc GUIDE[:clean][:LONG_DESC]
18
+ desc 'build', 'Builds a cookbook from its configuration file'
54
19
  def build
55
- Chef::Cookbook.build(ESSENTIAL_FILES, GENERATED_FILES)
56
- rescue ApplicationError => e
57
- error(e.message)
20
+ execute { Chef::Cookbook.build(config, ESSENTIAL_FILES, GENERATED_FILES) }
58
21
  end
59
22
 
60
- desc 'generate', GUIDE[:generate][:SHORT_DESC]
61
- long_desc GUIDE[:generate][:LONG_DESC]
62
- def generate()
63
- name = ask(' What is the name of this cookbook?')
64
- description = ask(' What does this cookbook do?')
65
- platforms = ask(' What operating system will this cookbook run on?', :limited_to => ['windows', 'centos', 'both'])
66
- type = ask(' What type of cookbook will this be?', :limited_to => ['wrapper', 'role'])
67
- platforms = platforms == 'both' ? ['centos', 'windows'] : [platforms]
68
- Chef::Cookbook.generate(name, platforms, type, description, ESSENTIAL_FILES, GENERATED_FILES)
69
- rescue ApplicationError => e
70
- error(e.message)
23
+ desc 'generate', 'Creates a new cookbook'
24
+ def generate
25
+ execute do
26
+ name = ask(' What is the name of this cookbook?')
27
+ description = ask(' What does this cookbook do?')
28
+ platforms = ask(' What operating system will this cookbook run on?', :limited_to => ['windows', 'centos', 'both'])
29
+ type = ask(' What type of cookbook will this be?', :limited_to => ['wrapper', 'role'])
30
+ platforms = platforms == 'both' ? ['centos', 'windows'] : [platforms]
31
+ Chef::Cookbook.generate(config, name, platforms, type, description, ESSENTIAL_FILES, GENERATED_FILES)
32
+ end
71
33
  end
72
34
 
73
- desc 'version', GUIDE[:version][:SHORT_DESC]
74
- long_desc GUIDE[:version][:LONG_DESC]
75
- def version()
76
- result = Config.new.read
77
- puts "##teamcity[buildNumber '#{result['version'].to_s}']"
78
- rescue ApplicationError => e
79
- error(e.message)
35
+ desc 'version', 'Gives the cookbook version as a TeamCity service message'
36
+ def version
37
+ execute { puts "##teamcity[buildNumber '#{config['version'].to_s}']" }
80
38
  end
81
39
 
82
40
  end
@@ -0,0 +1,45 @@
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 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 { Sambot::DNS::Repository.new.records.add(options[:hostname], options[:address], options[:team]) }
41
+ end
42
+
43
+ end
44
+ end
45
+ end