bim 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 58edf06fd00d02407176300f51c8a1b4106bb60b
4
+ data.tar.gz: 7d0e9084f6d50f8be333f53799cb34af28fbccc5
5
+ SHA512:
6
+ metadata.gz: 8ec3adf9c230316a7061561d7384f0f58728b3be03a49030418e825e52133218d95b25d8d6db5d35caccbe6fdcd8c0620c5e4757a19d9148033d9b79785ee980
7
+ data.tar.gz: d12d48c429d1b85b160e7a79d1d97ff51c0963ac630e4610261f746766bdf77b18246b93a6a3b92c190b1aed881cbd33536bef7f58573b1cc3456f3b440e0d05
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /bin/*
11
+ !/bin/bim
12
+ /vendor/
13
+
14
+ # rspec failure tracking
15
+ .rspec_status
data/.rubocop.yml ADDED
@@ -0,0 +1,20 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Metrics/AbcSize:
5
+ Max: 25
6
+
7
+ Metrics/LineLength:
8
+ Max: 120
9
+
10
+ Metrics/ClassLength:
11
+ Max: 120
12
+
13
+ Metrics/MethodLength:
14
+ Max: 15
15
+
16
+ Metrics/CyclomaticComplexity:
17
+ Max: 10
18
+
19
+ Style/FrozenStringLiteralComment:
20
+ Enabled: false
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in bim.gemspec
6
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 littlekbt
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # Bim
2
+
3
+ Bim is cli command to operate BIG-IP.
4
+
5
+ ※Support ssl certificate operation and sync operation now.
6
+
7
+ ## Requirement
8
+ - Ruby 2.3.0 +
9
+
10
+ ## Installtion
11
+
12
+ ```sh
13
+ $ gem install bim
14
+ ```
15
+
16
+ local install
17
+ ```sh
18
+ $ git clone https://github.com/littlekbt/bim.git
19
+ $ cd bim
20
+ $ bundle
21
+ $ gem build bim.gemspec
22
+ $ gem install --local bim-x.x.x.gem
23
+ ```
24
+
25
+ ## Setup
26
+ all commands needs three environment vriables.
27
+
28
+ - `BIGIP_HOST`: set bigip host
29
+ - `BIGIP_USER_ID`: set bigip admin userid
30
+ - `BIGIP_PASSWD`: set bigip admin password
31
+
32
+ if you want to use `--test` option, set TEST_VS vriable.
33
+ - `TEST_VS`: set test virtual server
34
+
35
+ ## Features
36
+ There are many features for deployment SSL Certificate from CLI to BIGIP.
37
+
38
+ #### Metadata
39
+ - get active host in the device group
40
+ - get group name that BIGIP_HOST belongs
41
+
42
+ #### Virtual Server
43
+ - get virutal server list and detail configuration
44
+
45
+ #### Sync
46
+ - execute sync action
47
+ - get sync state
48
+
49
+ #### SSL
50
+ - upload key and certificate
51
+ - create ssl client profile
52
+ - replace old ssl client profile to new ssl client profile
53
+
54
+ ## Usage
55
+
56
+ ```sh
57
+ $ bim [SUB COMMAND] [ARGS]
58
+ ```
59
+ ### Command-line Usage
60
+
61
+ #### Metadata
62
+
63
+ ```sh
64
+ # output active devices in the device group that BIGIP_HOST belongs.
65
+ $ bim meta actives
66
+
67
+ # output device group name.
68
+ $ bim meta device_groups
69
+ ```
70
+
71
+ #### Virtual Server
72
+
73
+ ```sh
74
+ # output virtual server list
75
+ $ bim vs list
76
+
77
+ # output one of the virtual server list
78
+ $ bim vs detail Virtual_Server_Name
79
+ ```
80
+
81
+ #### Sync
82
+
83
+ ```sh
84
+ # sync BIGIP_HOST configuration to GROUP.
85
+ $ bim sync GROUP
86
+
87
+ # output sync state.
88
+ $ bim sync state
89
+ ```
90
+
91
+ #### SSL
92
+
93
+ ```sh
94
+ # output bundles
95
+ $ bim ssl bundles
96
+
97
+ # output ssl profiles(property: certficate, private key, bundle)
98
+ $ bim ssl profiles
99
+
100
+ # output specified ssl profile
101
+ $ bim ssl detail SSL Profile Name
102
+
103
+ # upload and create_ssl_profile and replace.
104
+ $ bim ssl deploy OLD_SSL_PROFILE_NAME NEW_SSL_PROFILE_NAME PRIVATE_KEYFILE CERTIFICATE_FILE CHAIN
105
+
106
+ # set `--test` option, deploy to only virtual server specified by TEST_VS environment vriable.
107
+ $ TEST_VS=test_virtual_server bim deploy example.com.20160606 example.com.20170606 /path/to/example.com.key.20170606 /path/to/example.com.crt.20170606 chain --test
108
+
109
+ # upload private key and certificate.
110
+ $ bim ssl upload CERTIFICATE_PROFILE_NAME PRIVATE_KEYFILE(absolute path) CERTIFICATE_FILE(absolute path)
111
+
112
+ # upload private key.
113
+ $ bim ssl upload_key CERTIFICATE_PROFILE_NAME PRIVATE_KEYFILE(absolute path)
114
+
115
+ # upload certificate.
116
+ $ bim ssl upload_crt CERTIFICATE_PROFILE_NAME CERTIFICATE_FILE(absolute path)
117
+
118
+ # create ssl profile.
119
+ $ bim ssl create_profile SSL_PROFILE_NAME CHAIN
120
+
121
+ # replace virtual server's ssl profile using OLD_SSL_PROFILE_NAME to NEW_SSL_PROFILE_NAME.
122
+ $ bim ssl replace OLD_SSL_PROFILE_NAME NEW_SSL_PROFILE_NAME
123
+
124
+ # can use `--test` option the same as deploy.
125
+ $ TEST_VS=test_virtual_server bim replace OLD_SSL_PROFILE_NAME NEW_SSL_PROFILE_NAME --test
126
+ ```
127
+
128
+ ## License
129
+
130
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
131
+
132
+ ## Author
133
+ Littlekbt
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/bim.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ lib = File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require 'bim/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'bim'
7
+ spec.version = Bim::VERSION
8
+ spec.authors = ['littlekbt']
9
+ spec.email = ['kr.kubota.11@gmail.com']
10
+
11
+ spec.summary = 'bim is BigIP cli tool'
12
+ spec.homepage = 'https://github.com/littlekbt/bim'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.executables << 'bim'
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'thor', '~> 0.20.0'
22
+
23
+ spec.add_development_dependency 'bundler', '~> 1.15'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rspec', '~> 3.0'
26
+ end
data/bin/bim ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ require 'bundler/setup'
3
+ require 'bim'
4
+
5
+ begin
6
+ Bim::CLI.start
7
+ rescue ::Bim::UnsetHostEnvironmentError
8
+ puts({ 'error' => 'not exist BIGIP_HOST environment variable' }.to_json)
9
+ rescue ::Bim::UnsetUserIDEnvironmentError
10
+ puts({ 'error' => 'not exist BIGIP_USER_ID environment variable' }.to_json)
11
+ rescue ::Bim::UnsetPasswordEnvironmentError
12
+ puts({ 'error' => 'not exist BIGIP_PASSWD environment variable' }.to_json)
13
+ rescue ::Bim::UnauthorizedError
14
+ puts({ 'error' => 'unauthorized' }.to_json)
15
+ end
@@ -0,0 +1,15 @@
1
+ _bim() {
2
+ COMPREPLY=()
3
+ local cur prev
4
+ _get_comp_words_by_ref -n : cur prev
5
+
6
+ if [ "$COMP_CWORD" -eq 1 ]; then
7
+ COMPREPLY=( $(compgen -W "$(bim help | tail -n +2 | awk '{ print $2}')" -- "$cur") )
8
+ elif [ $COMP_CWORD -eq 2 ]; then
9
+ if [ $prev = "ssl" ] || [ $prev = "meta" ] || [ $prev = "sync" ]; then
10
+ COMPREPLY=( $(compgen -W "$(bim $prev help | tail -n +2 | awk '{ print $3}')" -- $cur) )
11
+ fi
12
+ fi
13
+ }
14
+
15
+ complete -F _bim bim
@@ -0,0 +1,37 @@
1
+ module Bim
2
+ module Action
3
+ # Meta class uses by Bim::Subcommands::Meta
4
+ class Meta
5
+ extend Bim::Util
6
+
7
+ DEVICE_PATH = '/mgmt/tm/cm/device'.freeze
8
+ DEVICE_GROUP_PATH = '/mgmt/tm/cm/deviceGroup'.freeze
9
+
10
+ class << self
11
+ def actives
12
+ uri = URI.join(Bim::BASE_URL, Bim::Action::Meta::DEVICE_PATH)
13
+ JSON
14
+ .parse(get_body(uri))['items']
15
+ .select { |item| item['failoverState'] == 'active' }
16
+ .inject([]) do |infos, item|
17
+ infos.push(hostname: item['hostname'], ip: item['managementIp'])
18
+ end.to_json
19
+ end
20
+
21
+ def device_groups
22
+ uri = URI.join(Bim::BASE_URL, Bim::Action::Meta::DEVICE_GROUP_PATH)
23
+ JSON
24
+ .parse(get_body(uri))['items']
25
+ .select { |item| item['type'] == 'sync-failover' }
26
+ .inject([]) do |infos, item|
27
+ m = if item&.dig('devicesReference')&.dig('link')
28
+ uri_r = URI.parse(item['devicesReference']['link'].sub('localhost', BIGIP_HOST))
29
+ JSON.parse(get_body(uri_r))['items'].map { |item_in| item_in['name'] }
30
+ end
31
+ infos.push(name: item['name'], members: m)
32
+ end.to_json
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,133 @@
1
+ module Bim
2
+ module Action
3
+ # SSL class used by Bim::Subcommands::SSL
4
+ class SSL
5
+ extend Bim::Util
6
+
7
+ UPLOAD_PATH = '/mgmt/shared/file-transfer/uploads/'.freeze
8
+ INSTALL_PATH = {
9
+ key: '/mgmt/tm/sys/crypto/key',
10
+ crt: '/mgmt/tm/sys/crypto/cert'
11
+ }.freeze
12
+ CREATE_SSL_PROFILE_PATH = '/mgmt/tm/ltm/profile/clientSsl'.freeze
13
+ VS_PATH = '/mgmt/tm/ltm/virtual'.freeze
14
+ CRT_FILES_PATH = '/mgmt/tm/sys/file/sslCert'.freeze
15
+ CRT_PROFILES_PATH = '/mgmt/tm/ltm/profile/client-ssl'.freeze
16
+
17
+ class << self
18
+ def bundles
19
+ uri = URI.join(Bim::BASE_URL, Bim::Action::SSL::CRT_FILES_PATH)
20
+ JSON
21
+ .parse(get_body(uri))['items']
22
+ .select { |item| item['isBundle'] == 'true' }
23
+ .map do |item|
24
+ { 'name' => item['name'].split('.')[0...-1].join('.') }
25
+ end.to_json
26
+ end
27
+
28
+ def profiles
29
+ uri = URI.join(Bim::BASE_URL, Bim::Action::SSL::CRT_PROFILES_PATH)
30
+ JSON.parse(get_body(uri))['items'].map do |item|
31
+ { 'name' => item['name'], 'fullPath' => item['fullPath'], 'key' => item['key'], 'chain' => item['chain'] }
32
+ end.to_json
33
+ end
34
+
35
+ def detail(profile_name)
36
+ uri = URI.join(Bim::BASE_URL, Bim::Action::SSL::CRT_PROFILES_PATH)
37
+ JSON
38
+ .parse(get_body(uri))['items']
39
+ .select { |item| item['name'] == profile_name || item['fullPath'] == profile_name }
40
+ .map do |item|
41
+ { 'name' => item['name'], 'fullPath' => item['fullPath'], 'key' => item['key'], 'chain' => item['chain'] }
42
+ end.to_json
43
+ end
44
+
45
+ def upload(filepath)
46
+ f = File.read(filepath)
47
+ uri = URI.join(Bim::BASE_URL, Bim::Action::SSL::UPLOAD_PATH, File.basename(filepath))
48
+ req = request(uri, Bim::AUTH, 'application/octet-stream', 'POST', f) do |req_in|
49
+ req_in['Content-Length'] = f.size
50
+ req_in['Content-Range'] = "0-#{f.size - 1}/#{f.size}"
51
+ req_in
52
+ end
53
+
54
+ http(uri).request(req).body
55
+ end
56
+
57
+ def install(type, crt_name, local_file_path)
58
+ uri = URI.join(Bim::BASE_URL, Bim::Action::SSL::INSTALL_PATH[type.to_sym])
59
+ req = request(
60
+ uri,
61
+ Bim::AUTH,
62
+ 'application/json',
63
+ 'POST',
64
+ { 'command' => 'install',
65
+ 'name' => crt_name,
66
+ 'from-local-file' => local_file_path }.to_json
67
+ )
68
+
69
+ http(uri).request(req).body
70
+ end
71
+
72
+ def create_ssl_profile(profilename, chain)
73
+ uri = URI.join(Bim::BASE_URL, Bim::Action::SSL::CREATE_SSL_PROFILE_PATH)
74
+ j = { 'name' => profilename,
75
+ 'ciphers' => 'DEFAULT:!SSLv3',
76
+ 'certKeyChain' => [
77
+ { 'name' => 'default',
78
+ 'key' => "#{profilename}.key",
79
+ 'cert' => "#{profilename}.crt",
80
+ 'chain' => "#{chain}.crt" }
81
+ ] }.to_json
82
+
83
+ req = request(uri, Bim::AUTH, 'application/json', 'POST', j)
84
+
85
+ http(uri).request(req).body
86
+ end
87
+
88
+ # rubocop:disable Metrics/AbcSize
89
+ def replace(old_profilename, new_profilename, test = nil)
90
+ result = { target_vs: [], change_vs: [], fail_vs: [] }
91
+ JSON.parse(vs_list)['items'].each do |vs|
92
+ next if test && vs['name'] != Bim::TEST_VS
93
+
94
+ names = JSON.parse(profiles(vs['profilesReference']['link']))['items'].map { |p| p['name'] }
95
+
96
+ next unless names.include?(old_profilename)
97
+ # can not update only diff.
98
+ old_names = names.map { |name| "/Common/#{name}" }
99
+ names.delete(old_profilename) && names.push(new_profilename)
100
+ names = names.map { |name| "/Common/#{name}" }
101
+
102
+ next unless yes_or_no?(output_msg(vs['name'], old_names, names))
103
+
104
+ result[:target_vs] << vs['name']
105
+ res = update_profiles(vs['selfLink'], names)
106
+ res.code == '200' ? result[:change_vs] << vs['name'] : result[:fail_vs] << vs['name']
107
+ end
108
+ result.to_json
109
+ end
110
+
111
+ private
112
+
113
+ def update_profiles(link, names)
114
+ uri = URI.parse(link.sub('localhost', BIGIP_HOST))
115
+ req = request(uri, Bim::AUTH, 'application/json', 'PATCH', { profiles: names }.to_json)
116
+
117
+ http(uri).request(req)
118
+ end
119
+
120
+ def output_msg(vs_name, old_names, new_names)
121
+ puts <<~MSG
122
+ virtual server: #{vs_name}
123
+ replace #{old_names} to #{new_names}
124
+ diff:
125
+ --: #{(old_names - new_names)}
126
+ ++: #{(new_names - old_names)}
127
+ MSG
128
+ print 'is it ok? [y|n]: '
129
+ end
130
+ end
131
+ end
132
+ end
133
+ end
@@ -0,0 +1,47 @@
1
+ module Bim
2
+ module Action
3
+ # Sync class used by Bim::Subcommands::Sync
4
+ class Sync
5
+ extend Bim::Util
6
+
7
+ SYNC_PATH = '/mgmt/tm/cm'.freeze
8
+ SYNC_STATE_PATH = '/mgmt/tm/cm/syncStatus'.freeze
9
+ FAILOVER_STATE_PATH = '/mgmt/tm/cm/failoverStatus'.freeze
10
+
11
+ class << self
12
+ def sync!(dest)
13
+ msg = "you want to sync #{BIGIP_HOST} configuration to #{dest}? [y|n]"
14
+ return { 'message' => "cancel sync #{BIGIP_HOST} to #{dest}" } unless yes_or_no?(msg)
15
+ uri = URI.join(Bim::BASE_URL, Bim::Action::Sync::SYNC_PATH)
16
+ j = { "command": 'run', "utilCmdArgs": "config-sync to-group #{dest}" }
17
+ req = request(uri, Bim::AUTH, 'application/json', 'POST', j.to_json)
18
+ http(uri).request(req).body
19
+ end
20
+
21
+ def state
22
+ uri = URI.join(Bim::BASE_URL, Bim::Action::Sync::SYNC_STATE_PATH)
23
+ req = request(uri, Bim::AUTH, 'application/json')
24
+ res = http(uri).request(req)
25
+ body = JSON.parse(res.body)
26
+ body['entries'].each_with_object({}) do |(_key, value), info|
27
+ entries = value['nestedStats']['entries']
28
+ info['color'] = entries['color']['description']
29
+ info['summary'] = entries['summary']['description']
30
+ end.to_json
31
+ end
32
+
33
+ def failover_state
34
+ uri = URI.join(Bim::BASE_URL, Bim::Action::Sync::FAILOVER_STATE_PATH)
35
+ req = request(uri, Bim::AUTH, 'application/json')
36
+ body = JSON.parse(http(uri).request(req).body)
37
+ body['entries'].each_with_object({}) do |(_key, value), info|
38
+ entries = value['nestedStats']['entries']
39
+ info['color'] = entries['color']['description']
40
+ info['summary'] = entries['summary']['description']
41
+ info['status'] = entries['status']['description']
42
+ end.to_json
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,31 @@
1
+ module Bim
2
+ module Action
3
+ # VS class used by Bim::Subcommands::VS
4
+ class VS
5
+ extend Bim::Util
6
+
7
+ VIRTUALS_PATH = '/mgmt/tm/ltm/virtual'.freeze
8
+
9
+ class << self
10
+ def list
11
+ JSON
12
+ .parse(vs_list)['items']
13
+ .map do |vs|
14
+ profiles = JSON.parse(profiles(vs['profilesReference']['link']))['items'].map { |p| p['fullPath'] }
15
+ { 'name' => vs['name'], 'profiles' => profiles }
16
+ end.to_json
17
+ end
18
+
19
+ def detail(name)
20
+ JSON
21
+ .parse(vs_list)['items']
22
+ .select { |vs| vs['name'] == name }
23
+ .map do |vs|
24
+ profiles = JSON.parse(profiles(vs['profilesReference']['link']))['items'].map { |p| p['fullPath'] }
25
+ { 'name' => vs['name'], 'profiles' => profiles }
26
+ end.first.to_json
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
data/lib/bim/action.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'bim/util'
2
+ require 'bim/action/meta'
3
+ require 'bim/action/sync'
4
+ require 'bim/action/ssl'
5
+ require 'bim/action/vs'
6
+
7
+ module Bim
8
+ # Action module is namespace
9
+ module Action
10
+ end
11
+ end
data/lib/bim/cli.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'thor'
2
+ require 'bim/subcommands'
3
+
4
+ module Bim
5
+ # CLI class is import subcommands
6
+ class CLI < Thor
7
+ desc 'meta [Subcommand]', "Subcommands: #{Bim::Subcommands::Meta.instance_methods(false).join(',')}"
8
+ subcommand 'meta', Bim::Subcommands::Meta
9
+
10
+ desc 'sync [Subcommand]', "Subcommands: #{Bim::Subcommands::Sync.instance_methods(false).join(',')}"
11
+ subcommand 'sync', Bim::Subcommands::Sync
12
+
13
+ desc 'ssl [Subcommand]', "Subcommands: #{Bim::Subcommands::SSL.instance_methods(false).join(',')}"
14
+ subcommand 'ssl', Bim::Subcommands::SSL
15
+
16
+ desc 'vs [Subcommand]', "Subcommands: #{Bim::Subcommands::VS.instance_methods(false).join(',')}"
17
+ subcommand 'vs', Bim::Subcommands::VS
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ module Bim
2
+ module Subcommands
3
+ # Meta class defines subcommands
4
+ class Meta < Thor
5
+ desc(
6
+ 'actives',
7
+ 'output active host'
8
+ )
9
+ def actives
10
+ puts Bim::Action::Meta.actives
11
+ end
12
+
13
+ desc(
14
+ 'device_groups',
15
+ 'outpu device group'
16
+ )
17
+ def device_groups
18
+ puts Bim::Action::Meta.device_groups
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,116 @@
1
+ module Bim
2
+ module Subcommands
3
+ # SSL class defines subcommands
4
+ class SSL < Thor
5
+ desc(
6
+ 'bundles',
7
+ 'output bundle certificat files info'
8
+ )
9
+ def bundles
10
+ puts Bim::Action::SSL.bundles
11
+ end
12
+
13
+ desc(
14
+ 'profiles',
15
+ 'output SSL Profiles info'
16
+ )
17
+ def profiles
18
+ puts Bim::Action::SSL.profiles
19
+ end
20
+
21
+ desc(
22
+ 'detail [PROFILE NAME]',
23
+ 'output specified SSL Profile info'
24
+ )
25
+ def detail(profile_name)
26
+ puts Bim::Action::SSL.detail(profile_name)
27
+ end
28
+
29
+ desc(
30
+ 'upload_key [CERTIFICATE_PROFILE_NAME] [PRIVATE_KEYFILE(absolute path)]',
31
+ 'upload private key file to bigip local & install to file management'
32
+ )
33
+ def upload_key(crt_name, key_file)
34
+ r = Bim::Action::SSL.upload(key_file)
35
+ puts Bim::Action::SSL.install(:key, crt_name, JSON.parse(r)['localFilePath'])
36
+ end
37
+
38
+ desc(
39
+ 'upload_crt [CERTIFICATE_PROFILE_NAME] [CERTIFICATE_FILE(absolute path)]',
40
+ 'upload certificate file to bigip local & install to file management'
41
+ )
42
+ def upload_crt(crt_name, crt_file)
43
+ r = Bim::Action::SSL.upload(crt_file)
44
+ puts Bim::Action::SSL.install(:crt, crt_name, JSON.parse(r)['localFilePath'])
45
+ end
46
+
47
+ desc(
48
+ 'upload [CERTIFICATE_PROFILE_NAME] [PRIVATE_KEYFILE(absolute path)] [CERTIFICATE_FILE(absolute path)]',
49
+ 'upload certificate file and private key file to bigip local & install to file management'
50
+ )
51
+ def upload(crt_name, key_file, crt_file)
52
+ result = []
53
+ r = Bim::Action::SSL.upload(key_file)
54
+ result.push Bim::Action::SSL.install(:key, crt_name, JSON.parse(r)['localFilePath'])
55
+
56
+ r = Bim::Action::SSL.upload(crt_file)
57
+ result.push Bim::Action::SSL.install(:crt, crt_name, JSON.parse(r)['localFilePath'])
58
+
59
+ puts result.map { |res| JSON.parse(res) }.to_json
60
+ end
61
+
62
+ desc(
63
+ 'create_ssl_profile [PROFILENAME] [CHAIN]',
64
+ 'create ssl profile using already install private key and certificate file'
65
+ )
66
+ def create_ssl_profile(profilename, chain)
67
+ puts Bim::Action::SSL.create_ssl_profile(profilename, chain)
68
+ end
69
+
70
+ desc(
71
+ 'replace [OLD_SSL_PROFILE_NAME] [NEW_SSL_PROFILE_NAME]',
72
+ 'replace ssl profile OLD_SSL_PROFILE_NAME to NEW_SSL_PROFILE_NAME'
73
+ )
74
+ method_option :test, type: :boolean
75
+ def replace(old_ssl_profilename, new_ssl_profilename)
76
+ if options[:test] && !ENV['TEST_VS']
77
+ puts 'You have to set TEST_VS environment variable.'
78
+ return
79
+ end
80
+
81
+ puts Bim::Action::SSL.replace(old_ssl_profilename, new_ssl_profilename, options[:test])
82
+ end
83
+
84
+ desc(
85
+ 'deploy [OLD_SSL_PROFILE_NAME] [NEW_SSL_PROFILE_NAME PRIVATE_KEYFILE] [CERTIFICATE_FILE] [CHAIN]',
86
+ 'deploy task do all need task, upload, create_ssl_profile, replace'
87
+ )
88
+ method_option :test, type: :boolean
89
+ def deploy(old_ssl_profilename, new_ssl_profilename, key_file, crt_file, chain)
90
+ if options[:test] && !ENV['TEST_VS']
91
+ puts 'You have to set TEST_VS environment variable.'
92
+ return
93
+ end
94
+
95
+ log('start deploy')
96
+ log('start upload private key and certificate')
97
+ upload(new_ssl_profilename, key_file, crt_file)
98
+ log('finish upload private key and certificate')
99
+ log('start create ssl profile')
100
+ create_ssl_profile(new_ssl_profilename, chain)
101
+ log('finish create ssl profile')
102
+ log('start replace ssl profile')
103
+ replace(old_ssl_profilename, new_ssl_profilename)
104
+ log('finish replace ssl profile')
105
+ log('finish deploy')
106
+ end
107
+
108
+ private
109
+
110
+ def log(msg, full_length = 50)
111
+ l = (full_length - msg.length) / 2
112
+ puts "#{'=' * l}#{msg}#{'=' * l}"
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,32 @@
1
+ module Bim
2
+ module Subcommands
3
+ # Sync class defines subcommands
4
+ class Sync < Thor
5
+ default_command :to_group
6
+
7
+ desc(
8
+ '[GROUP_NAME]',
9
+ 'sync device configuration to group.'
10
+ )
11
+ def to_group(group)
12
+ puts Bim::Action::Sync.sync!(group)
13
+ end
14
+
15
+ desc(
16
+ 'state',
17
+ 'get sync state'
18
+ )
19
+ def state
20
+ puts Bim::Action::Sync.state
21
+ end
22
+
23
+ desc(
24
+ 'failover_state',
25
+ 'get failover state'
26
+ )
27
+ def failover_state
28
+ puts Bim::Action::Sync.failover_state
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,22 @@
1
+ module Bim
2
+ module Subcommands
3
+ # VS class defines subcommands
4
+ class VS < Thor
5
+ desc(
6
+ 'list',
7
+ 'output virtual server info list'
8
+ )
9
+ def list
10
+ puts Bim::Action::VS.list
11
+ end
12
+
13
+ desc(
14
+ 'detail [NAME]',
15
+ 'output one of virtual server info'
16
+ )
17
+ def detail(name)
18
+ puts Bim::Action::VS.detail(name)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,11 @@
1
+ require 'bim/action'
2
+ require 'bim/subcommands/meta'
3
+ require 'bim/subcommands/sync'
4
+ require 'bim/subcommands/ssl'
5
+ require 'bim/subcommands/vs'
6
+
7
+ module Bim
8
+ # Subcommands module is namespace
9
+ module Subcommands
10
+ end
11
+ end
data/lib/bim/util.rb ADDED
@@ -0,0 +1,63 @@
1
+ require 'base64'
2
+ require 'net/http'
3
+ require 'openssl'
4
+
5
+ module Bim
6
+ # Util module defined common methods
7
+ module Util
8
+ VS_PATH = '/mgmt/tm/ltm/virtual'.freeze
9
+
10
+ private
11
+
12
+ def get_body(uri)
13
+ raise UnsetHostEnvironmentError if BIGIP_HOST.nil?
14
+ raise UnsetUserIDEnvironmentError if USER_ID.nil?
15
+ raise UnsetPasswordEnvironmentError if USER_PASSWD.nil?
16
+
17
+ res = http(uri).request(request(uri, Bim::AUTH, 'application/json'))
18
+
19
+ raise UnauthorizedError if res.code == '401'
20
+
21
+ res.body
22
+ end
23
+
24
+ def http(uri)
25
+ http = Net::HTTP.new(uri.hostname, uri.port)
26
+ http.use_ssl = true
27
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
28
+ http
29
+ end
30
+
31
+ def request(uri, auth, content_type, method = 'GET', body = nil)
32
+ req = case method
33
+ when 'GET'
34
+ Net::HTTP::Get.new(uri)
35
+ when 'POST'
36
+ Net::HTTP::Post.new(uri)
37
+ when 'PATCH'
38
+ Net::HTTP::Patch.new(uri)
39
+ end
40
+
41
+ req['Content-Type'] = content_type
42
+ req['Authorization'] = "Basic #{auth}"
43
+ req.body = body
44
+
45
+ block_given? ? yield(req) : req
46
+ end
47
+
48
+ def yes_or_no?(msg)
49
+ print msg
50
+ STDIN.gets.chomp.match?(/^[yY]/)
51
+ end
52
+
53
+ def vs_list
54
+ uri = URI.join(BASE_URL, VS_PATH)
55
+ get_body(uri)
56
+ end
57
+
58
+ def profiles(link)
59
+ uri = URI.parse(link.sub('localhost', BIGIP_HOST))
60
+ get_body(uri)
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ module Bim
2
+ VERSION = '0.1.0'.freeze
3
+ end
data/lib/bim.rb ADDED
@@ -0,0 +1,19 @@
1
+ require 'bim/version'
2
+ require 'bim/cli'
3
+ require 'json'
4
+ require 'base64'
5
+
6
+ module Bim
7
+ BIGIP_HOST = ENV['BIGIP_HOST']
8
+ BASE_URL = "https://#{BIGIP_HOST}/".freeze
9
+ TEST_VS = ENV['TEST_VS'].to_s
10
+ USER_ID = ENV['BIGIP_USER_ID']
11
+ USER_PASSWD = ENV['BIGIP_PASSWD']
12
+ AUTH = ::Base64.encode64("#{USER_ID}:#{USER_PASSWD}").chomp
13
+
14
+ class UnsetEnvironmentError < StandardError; end
15
+ class UnsetHostEnvironmentError < UnsetEnvironmentError; end
16
+ class UnsetUserIDEnvironmentError < UnsetEnvironmentError; end
17
+ class UnsetPasswordEnvironmentError < UnsetEnvironmentError; end
18
+ class UnauthorizedError < StandardError; end
19
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bim
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - littlekbt
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-09-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.20.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.20.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description:
70
+ email:
71
+ - kr.kubota.11@gmail.com
72
+ executables:
73
+ - bim
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - ".gitignore"
78
+ - ".rubocop.yml"
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bim.gemspec
84
+ - bin/bim
85
+ - completions/bim.bash
86
+ - lib/bim.rb
87
+ - lib/bim/action.rb
88
+ - lib/bim/action/meta.rb
89
+ - lib/bim/action/ssl.rb
90
+ - lib/bim/action/sync.rb
91
+ - lib/bim/action/vs.rb
92
+ - lib/bim/cli.rb
93
+ - lib/bim/subcommands.rb
94
+ - lib/bim/subcommands/meta.rb
95
+ - lib/bim/subcommands/ssl.rb
96
+ - lib/bim/subcommands/sync.rb
97
+ - lib/bim/subcommands/vs.rb
98
+ - lib/bim/util.rb
99
+ - lib/bim/version.rb
100
+ homepage: https://github.com/littlekbt/bim
101
+ licenses:
102
+ - MIT
103
+ metadata: {}
104
+ post_install_message:
105
+ rdoc_options: []
106
+ require_paths:
107
+ - lib
108
+ required_ruby_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 2.6.11
121
+ signing_key:
122
+ specification_version: 4
123
+ summary: bim is BigIP cli tool
124
+ test_files: []