sistero 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6d0e4052c83f912c94333a772ed817a0282d746d
4
+ data.tar.gz: 71d6f551dbd78eb16b725ac74dfce229a4e0ae21
5
+ SHA512:
6
+ metadata.gz: dcc6905a2a1fbd1b5ce647bcd272f8915d486a7b620f1ac31b736c6bdde61bb0444c95ff52d88eb77a7af21fba59c0da02727c001849e07174dc5af41f61030a
7
+ data.tar.gz: 1d848ef6b6594fd786b16f23099bfe2cce7b96615796b7a5918489e46b9be7a38a087ee123daf7bcf9e58fcc7138020b921085535de637ee8ad8d35e1334415e
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.3
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in sistero.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,36 @@
1
+ # Sistero
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/sistero`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'sistero'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install sistero
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sistero.
36
+
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/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "sistero"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
data/bin/sistero ADDED
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'sistero'
5
+ require 'optparse/subcommand'
6
+
7
+ module Sistero::Command
8
+ @config = OpenStruct.new
9
+ @subcommands = []
10
+ @op = nil
11
+
12
+ def self.subcommand name, banner
13
+ @subcommands.push({ name: name, banner: banner })
14
+ @op.subcommand name do |subop|
15
+ @config.action = name
16
+ subop.banner = banner
17
+ with_help subop
18
+ yield subop if block_given?
19
+ end
20
+ end
21
+
22
+ def self.with_help help_op
23
+ help_op.on '-h', '--help', 'show this help message' do
24
+ puts help_op
25
+ exit
26
+ end
27
+ end
28
+
29
+ def self.run
30
+ OptionParser.new do |op|
31
+ @op = op
32
+
33
+ op.banner = 'usage: sistero [global options] command [command options]'
34
+ op.on '-h', '--help', 'show this help message' do
35
+ max_len = @subcommands.map { |subcommand| subcommand[:name].length }.max
36
+
37
+ puts op
38
+ puts "\ncommands:"
39
+ @subcommands.each do |subcommand|
40
+ prefix = subcommand[:name]
41
+ prefix += ' ' * (max_len - prefix.length + 2)
42
+ puts " #{prefix} #{subcommand[:banner]}"
43
+ end
44
+ exit
45
+ end
46
+
47
+ subcommand 'ssh', 'ssh to vm' do |subop|
48
+ subop.on '-o val', 'add ssh options' do |ssh_options|
49
+ @config.ssh_options = ssh_options
50
+ end
51
+ end
52
+
53
+ subcommand 'create', 'create vm'
54
+
55
+ subcommand 'destroy', 'destroy vm'
56
+
57
+ subcommand 'list', 'list vms'
58
+
59
+ op.parse!
60
+ end
61
+
62
+ unless @config.action
63
+ puts 'please supply a command, see --help'
64
+ exit
65
+ end
66
+
67
+ sistero = Sistero::Instance.new
68
+ case @config.action
69
+ when 'ssh'
70
+ sistero.ssh_to_vm(ssh_options: @config.ssh_options)
71
+ when 'create'
72
+ sistero.create_vm()
73
+ when 'destroy'
74
+ sistero.destroy_vm()
75
+ when 'list'
76
+ sistero.list_vms()
77
+ end
78
+ end
79
+ end
80
+
81
+ Sistero::Command::run
@@ -0,0 +1,3 @@
1
+ module Sistero
2
+ VERSION = "0.1.0"
3
+ end
data/lib/sistero.rb ADDED
@@ -0,0 +1,130 @@
1
+ require "sistero/version"
2
+ require "yaml"
3
+ require "droplet_kit"
4
+
5
+ APP_NAME = "sistero"
6
+
7
+ module Sistero
8
+ class Config
9
+ DEFAULTS = {
10
+ :access_token => nil,
11
+ :ssh_keys => [],
12
+ :ssh_options => '',
13
+ :vm_name => nil,
14
+ :vm_size => 512,
15
+ :vm_region => 'nyc3',
16
+ :vm_image => 'ubuntu-14-04-x64',
17
+ }
18
+
19
+ attr_accessor *DEFAULTS.keys
20
+
21
+ def write_yaml(path, opts)
22
+ File.open(path, 'w') { |f| f.write opts.to_yaml }
23
+ end
24
+
25
+ def initialize(opts = {})
26
+ # read defaults from config file
27
+ cfg_file_path = "#{ENV['HOME']}/.config/#{APP_NAME}"
28
+ file_opts = {}
29
+ file_opts = YAML.load_file cfg_file_path if File.exists? cfg_file_path
30
+
31
+ dirty = false
32
+ DEFAULTS.each do |key, default|
33
+ next if file_opts[key]
34
+ dirty = true
35
+ if default
36
+ print "#{key} [#{default}] = "
37
+ val = gets.strip
38
+ val = default if val == ''
39
+ else
40
+ print "#{key} = "
41
+ val = gets.strip
42
+ end
43
+ file_opts[key] = val
44
+ end
45
+ write_yaml(cfg_file_path, file_opts) if dirty
46
+
47
+ file_opts.merge! opts
48
+ file_opts.each { |k, v| send("#{k}=", v) }
49
+ end
50
+ end
51
+
52
+ class Instance
53
+ def initialize(opts = {})
54
+ @config = Config.new(opts)
55
+ @client = DropletKit::Client.new(access_token: @config.access_token)
56
+ end
57
+
58
+ def find_vm(vm_name: @config.vm_name)
59
+ @client.droplets.all.find { |vm| vm.name == vm_name }
60
+ end
61
+
62
+ def list_vms()
63
+ @client.droplets.all.each do |vm|
64
+ puts "#{vm.name} - #{vm.networks[0][0].ip_address}"
65
+ end
66
+ end
67
+
68
+ def create_vm(vm_name: @config.vm_name)
69
+ puts "creating vm: #{vm_name}"
70
+ vm = DropletKit::Droplet.new(
71
+ name: vm_name, region: @config.vm_region, size: "#{@config.vm_size}mb", image: @config.vm_image, ssh_keys: @config.ssh_keys
72
+ )
73
+ vm = @client.droplets.create(vm)
74
+ puts "created vm: #{vm_name}"
75
+ vm
76
+ end
77
+
78
+ def is_port_open?(ip, port)
79
+ begin
80
+ Timeout::timeout(1) do
81
+ begin
82
+ s = TCPSocket.new(ip, port)
83
+ s.close
84
+ return true
85
+ rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
86
+ return false
87
+ end
88
+ end
89
+ rescue Timeout::Error ; end
90
+
91
+ return false
92
+ end
93
+
94
+ def ssh_to_vm(vm_name: @config.vm_name, ssh_options: @config.ssh_options)
95
+ ssh_options = @config.ssh_options if ssh_options == nil
96
+ vm = find_vm(vm_name: vm_name) || create_vm(vm_name: vm_name)
97
+ public_network = vm.networks.v4.find { |network| network.type == 'public' }
98
+ until public_network
99
+ puts "no public interfaces, trying again in a second"
100
+ sleep 1
101
+ vm = find_vm(vm_name: vm_name)
102
+ public_network = vm.networks.v4.find { |network| network.type == 'public' }
103
+ end
104
+ ip = public_network.ip_address
105
+
106
+ unless is_port_open? ip, 22
107
+ puts "waiting for ssh port to open"
108
+ sleep 1
109
+ until is_port_open? ip, 22 do
110
+ sleep 1
111
+ end
112
+ end
113
+
114
+ # TODO: wait for ssh port to be open
115
+ cmd = "ssh -o 'StrictHostKeyChecking no' #{ssh_options} root@#{ip}"
116
+ puts cmd
117
+ exec cmd
118
+ end
119
+
120
+ def destroy_vm(vm_name: @config.vm_name)
121
+ vm = find_vm(vm_name: vm_name)
122
+ if vm
123
+ puts "destroying #{vm.id}"
124
+ @client.droplets.delete(id: vm.id)
125
+ else
126
+ puts "vm not found"
127
+ end
128
+ end
129
+ end
130
+ end
data/sistero.gemspec ADDED
@@ -0,0 +1,35 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sistero/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "sistero"
8
+ spec.version = Sistero::VERSION
9
+ spec.authors = ["James Pike"]
10
+ spec.email = ["github@chilon.net"]
11
+
12
+ spec.summary = %q{DigitalOcean developer tools.}
13
+ spec.description = %q{Commands for dealing with temporary digital ocean VMs.}
14
+ spec.homepage = "http://github.com/ohjames/sistero"
15
+
16
+ # Prevent pushing this gem to RubyGems.org by setting 'allowed_push_host', or
17
+ # delete this section to allow pushing this gem to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.10"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ spec.add_development_dependency "rspec"
32
+
33
+ spec.add_development_dependency "droplet_kit", "~> 1.3"
34
+ spec.add_development_dependency "optparse-subcommand"
35
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sistero
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - James Pike
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2015-11-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.10'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.10'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
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: droplet_kit
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: optparse-subcommand
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Commands for dealing with temporary digital ocean VMs.
84
+ email:
85
+ - github@chilon.net
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".travis.yml"
93
+ - Gemfile
94
+ - README.md
95
+ - Rakefile
96
+ - bin/console
97
+ - bin/setup
98
+ - bin/sistero
99
+ - lib/sistero.rb
100
+ - lib/sistero/version.rb
101
+ - sistero.gemspec
102
+ homepage: http://github.com/ohjames/sistero
103
+ licenses: []
104
+ metadata:
105
+ allowed_push_host: https://rubygems.org
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.4.5.1
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: DigitalOcean developer tools.
126
+ test_files: []