puter 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: fd5bc41c2b68e84e15dae9f1944aea76afdf75af
4
+ data.tar.gz: b6651d0335a77c943ce1586b8841863218a4c8c5
5
+ SHA512:
6
+ metadata.gz: 11708fe516cecaa0344435886ee282af29e34ff93aafd4726c12a69acd0c5cfb6cbeca9084c06485a417b2e7686aca21b2c934a9ac7c8d9667d5e3bb11a24817
7
+ data.tar.gz: 7cc8e3654e93c4cc889ac8a4c047aadb248c93deae086d01f56d715fe1f26756d341aa93331eb41e1679a5ac5f443e15aa98e96055efa317a5efb1ad7316649f
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in puter.gemspec
4
+ gemspec
5
+
6
+ # gem 'vmonkey', path: '../vmonkey'
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 TODO: Write your name
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.
@@ -0,0 +1,54 @@
1
+ ## What's been implemented
2
+
3
+ VMware provider, using the vmonkey and rbvmomi APIs.
4
+ Puterfile instructions: FROM, RUN, and COPY
5
+ puter vm sub-commands: images, build, rmi, ps, create, start, stop, rm, apply
6
+
7
+ ## What needs to be implemented
8
+
9
+ ### Enhance puter sub-commands
10
+
11
+ `ps` - detailed output, currently only names are output.
12
+ `images` - detailed output, currently only names are output.
13
+
14
+ ### Implement puter sub-commands
15
+
16
+ `version` -
17
+ `run` - convenience for create & start
18
+ `restart` - guest OS restart
19
+ `exec` - run a command on the guest OS
20
+ `inspect` - detailed metadata of an image/instance
21
+ `implode` - completely remove all Puter images, instances, and provider-specific metadata
22
+
23
+ `tag` - maybe?
24
+ `import` - maybe? dups an existing non-Puter image (template, ami) into the set of Puter Images
25
+ `export` - maybe? dups an existing Puter Image to a non-Puter image (template, ami)
26
+
27
+
28
+ ### Implement Puterfile instructions
29
+
30
+ `MAINTAINER`
31
+ `USER`
32
+ `ENV`
33
+ `VOLUME`
34
+ `ADD`
35
+ `EXPOSE`
36
+ `ONBUILD`
37
+
38
+ ### Implement an AWS provider
39
+
40
+
41
+ ## VMware provider
42
+
43
+ ### VMware Puter structure within a Datacenter
44
+
45
+ <datacenter>/ # VMonkey config specifies the specific Datacenter to operate from
46
+ vmFolder/ #
47
+ Puter/ # top-level vSphere Folder - 'puter vm init' creates this folder
48
+ Build/ # this folder is used by 'puter vm build' as a working folder
49
+ Images/ # this folder is where Puter Images (VM templates) are stored
50
+ Instances/ # this folder is where Puter Images (running and stopped VMs) are stored
51
+
52
+ ## AWS Puter Structure, within an EC2 Region
53
+
54
+ tbd
@@ -0,0 +1,124 @@
1
+ # Puter: provision VMs in a Docker-like way
2
+
3
+ Puter is a tool to quickly and easily provision virtual machine images and
4
+ instances directly on virtualization and cloud providers.
5
+
6
+ Using a Puterfile syntax that closely resembles Dockerfile syntax, Puter makes
7
+ it easy and familiar to create new base VM images.
8
+
9
+ ### Example Puterfile
10
+
11
+ ## Usage Example
12
+ Given a repo with the following structure:
13
+
14
+ example/
15
+ |-- Puterfile
16
+ |-- localfile.txt
17
+ |-- localfile_with_a_really_really_longname.txt
18
+
19
+ ### Puterfile
20
+ FROM myorg.tld/baseos
21
+ # Start with any base image on your virtualization provider
22
+
23
+ # Run some simple commands
24
+ RUN touch /tmp/puter.txt
25
+ RUN userdel -f puter1; useradd puter1
26
+ RUN sudo -u puter1 whoami
27
+
28
+ # Copy some files to the new machine
29
+ COPY localfile.txt /tmp/explicit_name.txt
30
+
31
+ # Extend long lines with \ syntax
32
+ COPY localfile_with_a_really_really_longname.txt \
33
+ /home/puter1/
34
+
35
+ # Don't fear shell redirection and special characters
36
+ RUN touch /tmp/puter.txt && \
37
+ echo more commands > /tmp/puter.txt && \
38
+ echo done
39
+ RUN echo puter1 >> /tmp/puter.txt
40
+
41
+ # output from long running commands is visible along the way
42
+ RUN for i in `seq 1 5`; do echo $i; sleep 1; done;
43
+
44
+ RUN echo complete
45
+
46
+
47
+ ### Build an image
48
+ $ puter vm build myorg.tld/puterWithStuff examples
49
+ Building '/Puter/Images/myorg.tld/puterWithStuff' FROM '/Puter/Images/c65.small'
50
+ Waiting for SSH
51
+ Applying '/Users/pairing/projects/puter/examples/Puterfile' to '/Puter/Build/myorg.tld/puterWithStuff' at 10.0.0.123
52
+ Step 0 : FROM myorg.tld/baseos
53
+ Step 1 : RUN touch /tmp/puter.txt
54
+ Step 2 : RUN userdel -f puter1; useradd puter1
55
+ userdel: user 'puter1' does not exist
56
+ Step 3 : RUN sudo -u puter1 whoami
57
+ puter1
58
+ Step 4 : COPY localfile.txt /tmp/explicit_name.txt
59
+ Step 5 : COPY localfile_with_a_really_really_longname.txt /home/puter1/
60
+ Step 6 : RUN touch /tmp/puter.txt && echo more commands > /tmp/puter.txt && echo done
61
+ done
62
+ Step 7 : RUN echo puter1 >> /tmp/puter.txt
63
+ Step 8 : RUN for i in `seq 1 5`; do echo $i; sleep 1; done;
64
+ 1
65
+ 2
66
+ 3
67
+ 4
68
+ 5
69
+ Step 9 : RUN echo complete
70
+ complete
71
+ Stopping '/Puter/Build/myorg.tld/puterWithStuff' and moving to '/Puter/Images/myorg.tld/puterWithStuff'
72
+ Successfully built 'myorg.tld/puterWithStuff'
73
+
74
+ ### Build an image
75
+
76
+
77
+ ### Create and start an instance
78
+ $ puter vm create myorg.tld/puterWithStuff puter1
79
+ Created instance '/Puter/Instances/puter1' from '/Puter/Images/myorg.tld/puterWithStuff'
80
+
81
+ $ puter vm start puter1
82
+ Starting instance '/Puter/Instances/puter1', waiting for SSH...
83
+ Started '/Puter/Instances/puter1' at 10.32.30.126.
84
+
85
+
86
+ ### Virtualization providers
87
+ Currently only VMware vSphere is supported.
88
+ Amazon AWS support is planned.
89
+
90
+ ## Installation
91
+
92
+ Add this line to your application's Gemfile:
93
+
94
+ ```ruby
95
+ gem 'puter'
96
+ ```
97
+
98
+ And then execute:
99
+
100
+ $ bundle
101
+
102
+ Or install it yourself as:
103
+
104
+ $ gem install puter
105
+
106
+ ## Usage
107
+
108
+ $ puter help
109
+ Commands:
110
+ puter help [COMMAND] # Describe available commands or one specific command
111
+ puter version # Display puter version.
112
+ puter vm # VMware vSphere related tasks. Type puter vm for more help.
113
+
114
+ Options:
115
+ [--version], [--no-version] # Show program version
116
+
117
+
118
+ ## Contributing
119
+
120
+ 1. Fork it ( https://github.com/[my-github-username]/puter/fork )
121
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
122
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
123
+ 4. Push to the branch (`git push origin my-new-feature`)
124
+ 5. Create a new Pull Request
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $:.push File.expand_path("../../lib", __FILE__)
3
+ require 'puter'
4
+
5
+ Puter::CLI::Cli.start
@@ -0,0 +1,25 @@
1
+ FROM c65.small
2
+ # Start with any base image on your virtualization provider
3
+
4
+ # Run some simple commands
5
+ RUN touch /tmp/puter.txt
6
+ RUN userdel -f puter1; useradd puter1
7
+ RUN sudo -u puter1 whoami
8
+
9
+ # Copy some files to the new machine
10
+ COPY localfile.txt /tmp/explicit_name.txt
11
+
12
+ # Extend long lines with \ syntax
13
+ COPY localfile_with_a_really_really_longname.txt \
14
+ /home/puter1/
15
+
16
+ # Don't fear shell redirection and special characters
17
+ RUN touch /tmp/puter.txt && \
18
+ echo more commands > /tmp/puter.txt && \
19
+ echo done
20
+ RUN echo puter1 >> /tmp/puter.txt
21
+
22
+ # output from long running commands is visible along the way
23
+ RUN for i in `seq 1 5`; do echo $i; sleep 1; done;
24
+
25
+ RUN echo complete
@@ -0,0 +1 @@
1
+ from the Puter context
@@ -0,0 +1 @@
1
+ from the Puter context
@@ -0,0 +1,23 @@
1
+ require 'thor'
2
+
3
+ module Puter
4
+ autoload :CLI, 'puter/cli'
5
+ autoload :UI, 'puter/ui'
6
+
7
+ Thor::Base.shell.send(:include, Puter::UI)
8
+
9
+ class << self
10
+ def root
11
+ @root ||= Pathname.new(File.expand_path('../', File.dirname(__FILE__)))
12
+ end
13
+
14
+ def executable_name
15
+ File.basename($PROGRAM_NAME)
16
+ end
17
+
18
+ def ui
19
+ @ui ||= Thor::Base.shell.new
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,69 @@
1
+ require 'net/ssh'
2
+ require 'net/scp'
3
+
4
+ module Puter
5
+ module Backend
6
+ class SshError < Exception
7
+ end
8
+
9
+ # TODO - pass in a logger, so that stdout and stderr can stream out directly?
10
+
11
+ class Ssh
12
+ def initialize(host, ssh_opts = {})
13
+ @ssh = Net::SSH.start( host, ssh_opts[:user] || 'root', ssh_opts )
14
+ @scp = Net::SCP.new(@ssh)
15
+ end
16
+
17
+ def run(command, user='root', opts={}, &output)
18
+ actual_cmd = "sudo -u #{user} -s -- sh -c '#{command}'"
19
+ stdout_data = ''
20
+ stderr_data = ''
21
+ exit_status = nil
22
+ exit_signal = nil
23
+
24
+ @ssh.open_channel do |channel|
25
+ # TODO - make request_pty user controllable:
26
+ # without a pty, RHEL default configs fail to allow sudo
27
+ # with a pty, openssh comingles stdout and stderr onto stdout
28
+ channel.request_pty do |ch, success|
29
+ raise SshError.new "Could not obtain SSH pty " if !success
30
+ end
31
+
32
+ channel.exec(actual_cmd) do |ch, success|
33
+ raise SshError.new "Could not execute command [ #{actual_cmd} ]" if !success
34
+ channel.on_data do |ch, data|
35
+ if output
36
+ output.call(:stdout, data) if output
37
+ else
38
+ stdout_data += data
39
+ end
40
+ end
41
+
42
+ channel.on_extended_data do |ch, type, data|
43
+ if output
44
+ output.call(:stderr, data) if output
45
+ else
46
+ stderr_data += data
47
+ end
48
+ end
49
+
50
+ channel.on_request("exit-status") do |ch, data|
51
+ exit_status = data.read_long
52
+ end
53
+
54
+ channel.on_request("exit-signal") do |ch, data|
55
+ exit_signal = data.read_long
56
+ end
57
+ end
58
+ end
59
+ @ssh.loop
60
+ { :cmd => actual_cmd, :stdout => stdout_data, :stderr => stderr_data, :exit_status => exit_status, :exit_signal => exit_signal }
61
+ end
62
+
63
+ def copy(from, to)
64
+ @scp.upload! from, to
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,57 @@
1
+ require 'puter/version'
2
+ require 'puter/cli/vm'
3
+ require 'puter/cli/aws'
4
+
5
+ module Puter
6
+ module CLI
7
+ EXIT_CODE_ERR = 1
8
+
9
+ SSH_OPTS = {}
10
+ SSH_OPTS[:user] = ENV['SSH_USER'] || 'root'
11
+ SSH_OPTS[:password] = ENV['SSH_PASSWORD'] if ENV['SSH_PASSWORD']
12
+ SSH_OPTS[:port] = ENV['SSH_PORT'].to_i if ENV['SSH_PORT']
13
+ SSH_OPTS[:paranoid] = (ENV['SSH_PARANOID'] == '1') if ENV['SSH_PARANOID']
14
+ SSH_OPTS[:user_known_hosts_file] = ENV['SSH_KNOWN_HOSTS'] if ENV['SSH_KNOWN_HOSTS']
15
+
16
+ def self.run_cli(&block)
17
+ begin
18
+ block.call
19
+ rescue Puter::RunError => re
20
+ Puter.ui.error re.message
21
+ Puter.ui.error "[ #{re.cmd} ] returned [ #{re.exit_status} ]"
22
+ exit re.exit_status
23
+ rescue Exception => e
24
+ Puter.ui.error e.message
25
+ Puter.ui.error e.backtrace.join "\n"
26
+ exit EXIT_CODE_ERR
27
+ end
28
+ exit 0
29
+ end
30
+
31
+ class Cli < Thor
32
+ def self.exit_on_failure?
33
+ true
34
+ end
35
+
36
+ ALIASES = {
37
+ '-T' => 'help',
38
+ '--version' => 'version',
39
+ '-V' => 'version'
40
+ }
41
+
42
+ map ALIASES
43
+
44
+ desc 'vm', "VMware vSphere related tasks. Type #{Puter.executable_name} vm for more help."
45
+ subcommand 'vm', Vm
46
+
47
+ desc 'aws', "Amazon AWS related tasks. Type #{Puter.executable_name} aws for more help. NOT IMPLEMENTED."
48
+ subcommand 'aws', Aws
49
+
50
+ class_option :version, :type => :boolean, :desc => 'Show program version'
51
+ desc 'version', 'Display puter version.'
52
+ def version
53
+ Puter.ui.info "#{Puter.executable_name} #{Puter::VERSION}"
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,18 @@
1
+ module Puter
2
+ module CLI
3
+ class Aws < Thor
4
+ desc 'images', 'Lists available puter images.'
5
+ long_desc <<-LONGDESC
6
+ Lists available puter images.
7
+
8
+ With --region option, lists images found in the given AWS region.
9
+ LONGDESC
10
+ option :region, :type => :string, :default => 'us-west-1', :banner => 'aws-region-name'
11
+ def images(region_name = options[:region])
12
+ CLI.run_cli do
13
+ raise 'NOT IMPLEMENTED'
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end