bim 0.1.0
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 +7 -0
- data/.gitignore +15 -0
- data/.rubocop.yml +20 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +133 -0
- data/Rakefile +6 -0
- data/bim.gemspec +26 -0
- data/bin/bim +15 -0
- data/completions/bim.bash +15 -0
- data/lib/bim/action/meta.rb +37 -0
- data/lib/bim/action/ssl.rb +133 -0
- data/lib/bim/action/sync.rb +47 -0
- data/lib/bim/action/vs.rb +31 -0
- data/lib/bim/action.rb +11 -0
- data/lib/bim/cli.rb +19 -0
- data/lib/bim/subcommands/meta.rb +22 -0
- data/lib/bim/subcommands/ssl.rb +116 -0
- data/lib/bim/subcommands/sync.rb +32 -0
- data/lib/bim/subcommands/vs.rb +22 -0
- data/lib/bim/subcommands.rb +11 -0
- data/lib/bim/util.rb +63 -0
- data/lib/bim/version.rb +3 -0
- data/lib/bim.rb +19 -0
- metadata +124 -0
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
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
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
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
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
|
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
|
data/lib/bim/version.rb
ADDED
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: []
|