puter 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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