smartos-manager 0.0.1

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: 1858acd53ee91b3606fa545516a45426d2aa7d06
4
+ data.tar.gz: 3a3653d85a6f5f8ccd884135281e083815530fb7
5
+ SHA512:
6
+ metadata.gz: c49425bb81256d8c32066294d6c536aca18768d4aa7d7539fd6b31f12783ef10771c86b3d80eff4f039bcb47978b4c1c6e909c67c3bfea90934490d1fbf3f52d
7
+ data.tar.gz: 0ab88b9f5191d54230cdd78f05d16631cdb3f0ab4d3022ec60e1ebc7dffc88c6223352804b7425ee8b6b37dc9a58b331ebbaeb234452690c36855d93148f7428
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ Gemfile.lock
5
+ coverage/
6
+ doc/
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+
7
+ group(:test) do
8
+ gem 'eetee', '~> 0.0.4'
9
+ gem 'mocha', '~> 0.12.0'
10
+ # gem 'factory_girl'
11
+ gem 'rb-blink1'
12
+
13
+ gem 'simplecov'
14
+ gem 'guard'
15
+ gem 'rb-fsevent'
16
+ gem 'growl'
17
+ end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+
2
+ require 'eetee'
3
+ require 'blink1'
4
+
5
+ guard 'eetee', blink1: true do
6
+ watch(%r{^lib/smartos-manager/(.+)\.rb$}) { |m| "specs/unit/#{m[1]}_spec.rb" }
7
+ watch(%r{specs/.+\.rb$})
8
+ end
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013-2014 Julien Ammous
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,27 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+ require "bundler/gem_tasks"
4
+
5
+ task :default => :test
6
+
7
+ task :test do
8
+
9
+ # do not generate coverage report under travis
10
+ unless ENV['TRAVIS']
11
+
12
+ require 'simplecov'
13
+ SimpleCov.command_name "E.T."
14
+ SimpleCov.start do
15
+ add_filter ".*_spec"
16
+ add_filter "/specs/helpers/"
17
+ add_filter "/example/"
18
+ end
19
+ end
20
+
21
+ require 'eetee'
22
+
23
+ runner = EEtee::Runner.new
24
+ runner.run_pattern('specs/**/*_spec.rb')
25
+ runner.report_results()
26
+
27
+ end
data/bin/smanager ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+ require File.expand_path('../../lib/smartos-manager', __FILE__)
4
+
5
+
6
+ AppCLI.start(ARGV)
@@ -0,0 +1,42 @@
1
+ # what is this ?
2
+
3
+ a command line tool to manage SmartOS hosts.
4
+
5
+
6
+ # Prerequisites
7
+
8
+ - you have an ssh key
9
+ - your ssh public key is in authorized_keys on the server to allow passwordless login
10
+
11
+
12
+ # Usage
13
+
14
+ first you need to create a config file to define your environment:
15
+
16
+ ```toml
17
+ [global]
18
+ # gateway_user = "root"
19
+ gateway = "x.x.x.x"
20
+
21
+ [vmhost1]
22
+ # user = "root"
23
+ # gateway = "a.b.c.d"
24
+ # gateway_user = "root"
25
+ address = "y.y.y.y"
26
+
27
+ [vmhost2]
28
+ # user = "root"
29
+ # gateway = "a.b.c.d"
30
+ # gateway_user = "root"
31
+ address = "z.z.z.z"
32
+
33
+ ```
34
+
35
+ All options except address (which makes no sense) can be defined in a global section, if present a host section this one will be used, otherwise the global one will be used.
36
+
37
+ Once you have your file you can use the smanager command:
38
+
39
+ ```bash
40
+ $ smanager list
41
+ ```
42
+
@@ -0,0 +1,55 @@
1
+
2
+ require File.expand_path('../core', __FILE__)
3
+ require 'thor'
4
+ require 'colored'
5
+
6
+ class AppCLI < Thor
7
+ desc "list", "List all vms"
8
+ def list
9
+ registry = HostRegistry.new('hosts.toml')
10
+ ret = registry.list_vms()
11
+
12
+ sysinfos = registry.sysinfo()
13
+
14
+ p_vm_list("Memory", "Name", "Type", "UUID", "State", "Admin IP")
15
+
16
+ ret.each do |host, vms|
17
+ mem = sysinfos[host][:memory]
18
+ vm_memory = 0
19
+
20
+ vms.each{|vm| vm_memory += vm.memory }
21
+ avail = (mem - vm_memory) - (20 * mem/100.0)
22
+
23
+ puts "\n#{host.name} (#{host.address}) (#{vms.size} vms) (Total RAM: #{mem.human_size(1).green}, Avail: #{avail.human_size(1).magenta})"
24
+ vms.each do |vm|
25
+ p_vm_list(vm.memory.human_size(1), vm.name, vm.type, vm.uid, printable_state(vm.state), vm.admin_ip)
26
+ end
27
+
28
+ if vms.empty?
29
+ puts " [ no VMS ]"
30
+ end
31
+
32
+ # avail = (mem - vm_memory) - (20 * mem/100)
33
+ # puts " Available Memory: #{avail.human_size(1)}".magenta()
34
+ end
35
+
36
+ end
37
+
38
+
39
+ no_tasks do
40
+
41
+ def p_vm_list(size, name, type, uuid, state, admin_ip)
42
+ puts " [ #{size.rjust(6)} #{name.rjust(15)} - #{uuid.ljust(37)}][ #{admin_ip.ljust(15).cyan} ][ #{state} ]"
43
+ end
44
+
45
+ def printable_state(state)
46
+ if state =='running'
47
+ state.green()
48
+ else
49
+ state.red()
50
+ end
51
+ end
52
+
53
+ end
54
+ end
55
+
@@ -0,0 +1,164 @@
1
+
2
+ require 'net/ssh'
3
+ require 'net/ssh/multi'
4
+ require 'net/ssh/gateway'
5
+ require 'toml'
6
+ require 'size_units'
7
+
8
+
9
+ class SSHHost
10
+ attr_reader :name
11
+ attr_reader :address, :user
12
+ attr_reader :gateway
13
+
14
+ def self.from_hash(name, h, global_h)
15
+ new(
16
+ name: name,
17
+ address: h['address'],
18
+ gateway: h['gateway'] || global_h['gateway'],
19
+ user: h['user'] || global_h['user'],
20
+ gateway_user: h['gateway_user'] || global_h['gateway_user']
21
+ )
22
+ end
23
+
24
+ def initialize(name: nil, address: nil, gateway: nil, user: nil, gateway_user: nil)
25
+ raise "address required" unless address
26
+
27
+ @name= name
28
+
29
+ @address = address
30
+ @user = user
31
+
32
+ @gateway = gateway
33
+ @gateway_user = gateway_user
34
+ end
35
+
36
+ def user
37
+ @user || 'root'
38
+ end
39
+
40
+ def gateway_user
41
+ @gateway_user || user
42
+ end
43
+
44
+ # private
45
+ # def connection
46
+ # unless @connection
47
+ # if @gateway
48
+ # @gateway_obj = Net::SSH::Gateway.new(@gateway, @user)
49
+ # @connection = @gateway_obj.ssh(@address, @gateway_user || @user, SSH_OPTIONS)
50
+
51
+ # else
52
+ # @connection = Net::SSH.start(@address, @user, SSH_OPTIONS)
53
+
54
+ # end
55
+
56
+ # end
57
+
58
+ # @connection
59
+ # end
60
+ end
61
+
62
+
63
+ class VirtualMachine
64
+ attr_reader :uid, :type, :memory, :state, :name, :admin_ip
65
+
66
+ def initialize(uid, type, memory, state, name, admin_ip)
67
+ @uid = uid
68
+ @type = type
69
+ @memory = memory.to_i.megabytes
70
+ @state = state
71
+ @name = name
72
+ @admin_ip = admin_ip
73
+ end
74
+
75
+ # 4c1ae27f-a986-4189-a2b7-5c5e6d2e26ef:OS:300:running:backup
76
+ def self.from_line(line)
77
+ new(*line.split(':'))
78
+ end
79
+ end
80
+
81
+ class HostRegistry
82
+ def initialize(path)
83
+ @registry = {}
84
+ @gateways = {}
85
+ @hosts = {}
86
+
87
+ @connection = Net::SSH::Multi.start()
88
+
89
+ # data = Psych.load_file(path)
90
+ # data = TOML::Parser.new( File.read(path) ).parsed
91
+ data = TOML.load_file(path)
92
+
93
+ global_data = data.delete('global')
94
+
95
+ data.each do |name, opts|
96
+ host = SSHHost.from_hash(name, opts, global_data)
97
+
98
+ @hosts[host.address] = host
99
+
100
+ @connection.use(host.address,
101
+ via: gateway_for(host.gateway, host.gateway_user),
102
+ # via: @gateways[host.gateway],
103
+ user: host.user,
104
+ compression: false
105
+ )
106
+ end
107
+
108
+ end
109
+
110
+ def run_on_all(cmd)
111
+ ret = {}
112
+
113
+ # setthe keys in cas we get nothing back
114
+ @hosts.each do |_, h|
115
+ ret[h] = ""
116
+ end
117
+
118
+ channel = @connection.exec(cmd) do |ch, stream, data|
119
+ host = @hosts[ch[:host]]
120
+ ret[host] << data
121
+ end
122
+
123
+ channel.wait()
124
+ ret
125
+ end
126
+
127
+ def list_vms
128
+ vms = run_on_all("vmadm list -o uuid,type,ram,state,alias,nics.0.ip -p")
129
+ vms.each do |host, data|
130
+ if data
131
+ vms[host] = data.split("\n").map! do |line|
132
+ VirtualMachine.from_line(line)
133
+ end
134
+ else
135
+ vms[host] = []
136
+ end
137
+ end
138
+
139
+ end
140
+
141
+
142
+ def sysinfo
143
+ ret = {}
144
+
145
+ # Memory size: 8157 Megabytes
146
+ hosts = run_on_all("prtconf | head -3 | grep Mem")
147
+ hosts.each do |host, data|
148
+ _, _, mem, _ = data.split(" ")
149
+ ret[host] = {memory: mem.to_i.megabytes}
150
+ end
151
+
152
+ ret
153
+ end
154
+
155
+ private
156
+ def gateway_for(host, user)
157
+ @gateways[host] ||= Net::SSH::Gateway.new(
158
+ host,
159
+ user,
160
+ compression: false
161
+ )
162
+ end
163
+
164
+ end
@@ -0,0 +1,3 @@
1
+ module SmartosManager
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,3 @@
1
+ require File.expand_path('../smartos-manager/version', __FILE__)
2
+ require File.expand_path('../smartos-manager/cli', __FILE__)
3
+
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/smartos-manager/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["Julien Ammous"]
6
+ gem.email = ["schmurfy@gmail.com"]
7
+ gem.description = %q{...}
8
+ gem.summary = %q{... .}
9
+ gem.homepage = ""
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = %(smanager)
13
+ gem.name = "smartos-manager"
14
+ gem.license = 'MIT'
15
+ gem.require_paths = ["lib"]
16
+ gem.version = SmartosManager::VERSION
17
+
18
+ gem.add_dependency 'toml-rb'
19
+ gem.add_dependency 'thor'
20
+ gem.add_dependency 'net-ssh'
21
+ gem.add_dependency 'net-ssh-gateway'
22
+ gem.add_dependency 'net-ssh-multi'
23
+ gem.add_dependency 'colored'
24
+ gem.add_dependency 'size_units'
25
+
26
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'eetee'
5
+
6
+ $LOAD_PATH.unshift( File.expand_path('../../lib' , __FILE__) )
7
+ require 'smartos-manager'
8
+
9
+ # require 'eetee/ext/mocha'
10
+ # require 'eetee/ext/em'
11
+
12
+ # Thread.abort_on_exception = true
metadata ADDED
@@ -0,0 +1,156 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smartos-manager
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Julien Ammous
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-01-27 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: toml-rb
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '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'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-ssh
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: net-ssh-gateway
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'
69
+ - !ruby/object:Gem::Dependency
70
+ name: net-ssh-multi
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: colored
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: size_units
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ description: "..."
112
+ email:
113
+ - schmurfy@gmail.com
114
+ executables:
115
+ - smanager
116
+ extensions: []
117
+ extra_rdoc_files: []
118
+ files:
119
+ - ".gitignore"
120
+ - Gemfile
121
+ - Guardfile
122
+ - LICENSE
123
+ - Rakefile
124
+ - bin/smanager
125
+ - lib/smartos-manager.rb
126
+ - lib/smartos-manager/README.md
127
+ - lib/smartos-manager/cli.rb
128
+ - lib/smartos-manager/core.rb
129
+ - lib/smartos-manager/version.rb
130
+ - smartos-manager.gemspec
131
+ - specs/spec_helper.rb
132
+ homepage: ''
133
+ licenses:
134
+ - MIT
135
+ metadata: {}
136
+ post_install_message:
137
+ rdoc_options: []
138
+ require_paths:
139
+ - lib
140
+ required_ruby_version: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ required_rubygems_version: !ruby/object:Gem::Requirement
146
+ requirements:
147
+ - - ">="
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
150
+ requirements: []
151
+ rubyforge_project:
152
+ rubygems_version: 2.2.0
153
+ signing_key:
154
+ specification_version: 4
155
+ summary: "... ."
156
+ test_files: []