bbcloud 0.7 → 0.8

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,4 +1,3 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
- lib/bbcloud/vendor/
data/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2010 Brightbox Systems Ltd.
1
+ Copyright (c) 2010 John Leach, Brightbox Systems Ltd <john@brightbox.co.uk>
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
data/README CHANGED
@@ -1,9 +1,11 @@
1
1
  = Brightbox Cloud Command Line Interface
2
2
 
3
- bbcloud is a cli tool to interact with the (forthcoming) Brightbox
4
- cloud API.
3
+ brightbox-cli is a set of cli tools to interact with the Brightbox
4
+ Cloud API.
5
5
 
6
- http://www.brightbox.co.uk
6
+ http://beta.brightbox.com
7
+
8
+ http://docs.brightbox.com/cli
7
9
 
8
10
  == Packaging
9
11
 
@@ -12,11 +14,6 @@ http://www.brightbox.co.uk
12
14
  gems can be vendored into lib/bbcloud/vendor for packaging and will be
13
15
  prioritized over any gems.
14
16
 
15
- === GEM packaging
16
-
17
- The gem currently has our branch of fog vendored, as the official fog
18
- gem doesn't have our work merged in yet.
19
-
20
17
  === Debian/Ubuntu packaging
21
18
 
22
19
  Any gems that have equivalent packages available are set as
@@ -31,4 +28,29 @@ to packaging. These are:
31
28
  * ini
32
29
 
33
30
  Rubygems support can be disabled by defining the DISABLE_RUBYGEMS
34
- constant in lib/bbcloud/os_config.rb
31
+ constant in lib/bbcloud/os_config.rb
32
+
33
+ Ubuntu packaging scripts are available on the packaging-lucid git
34
+ branch.
35
+
36
+ == License
37
+
38
+ Copyright (c) 2010 John Leach, Brightbox Systems Ltd <john@brightbox.co.uk>
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining a copy
41
+ of this software and associated documentation files (the "Software"), to deal
42
+ in the Software without restriction, including without limitation the rights
43
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44
+ copies of the Software, and to permit persons to whom the Software is
45
+ furnished to do so, subject to the following conditions:
46
+
47
+ The above copyright notice and this permission notice shall be included in
48
+ all copies or substantial portions of the Software.
49
+
50
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
56
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,56 @@
1
+ = Brightbox Cloud Command Line Interface
2
+
3
+ brightbox-cli is a set of cli tools to interact with the Brightbox
4
+ Cloud API.
5
+
6
+ http://beta.brightbox.com
7
+
8
+ http://docs.brightbox.com/cli
9
+
10
+ == Packaging
11
+
12
+ === Vendoring libraries
13
+
14
+ gems can be vendored into lib/bbcloud/vendor for packaging and will be
15
+ prioritized over any gems.
16
+
17
+ === Debian/Ubuntu packaging
18
+
19
+ Any gems that have equivalent packages available are set as
20
+ dependencies to the Debian package. Any other gems are vendored prior
21
+ to packaging. These are:
22
+
23
+ * formatador (required by hirb)
24
+ * excon (required by fog)
25
+ * gli
26
+ * fog
27
+ * hirb
28
+ * ini
29
+
30
+ Rubygems support can be disabled by defining the DISABLE_RUBYGEMS
31
+ constant in lib/bbcloud/os_config.rb
32
+
33
+ Ubuntu packaging scripts are available on the packaging-lucid git
34
+ branch.
35
+
36
+ == License
37
+
38
+ Copyright (c) 2010 John Leach, Brightbox Systems Ltd <john@brightbox.co.uk>
39
+
40
+ Permission is hereby granted, free of charge, to any person obtaining a copy
41
+ of this software and associated documentation files (the "Software"), to deal
42
+ in the Software without restriction, including without limitation the rights
43
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
44
+ copies of the Software, and to permit persons to whom the Software is
45
+ furnished to do so, subject to the following conditions:
46
+
47
+ The above copyright notice and this permission notice shall be included in
48
+ all copies or substantial portions of the Software.
49
+
50
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
53
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
54
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
55
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
56
+ THE SOFTWARE.
data/bbcloud.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |s|
21
21
 
22
22
  s.add_dependency 'gli', '1.1.2'
23
23
  s.add_dependency 'hirb', '0.3.5'
24
- s.add_dependency 'brightbox-fog', '0.3.16'
24
+ s.add_dependency 'fog', '=0.3.23'
25
25
  s.add_dependency 'excon', '>=0.2.4'
26
26
  s.add_dependency 'ini', '0.1.1'
27
27
  end
data/lib/bbcloud/api.rb CHANGED
@@ -24,6 +24,8 @@ module Brightbox
24
24
  @fog_model = m
25
25
  @id = m.id
26
26
  end
27
+ CONFIG.cache_id @id unless @id.nil?
28
+ @id
27
29
  end
28
30
 
29
31
  def fog_model
@@ -53,6 +55,8 @@ module Brightbox
53
55
  objects = args.collect do |arg|
54
56
  cached_get(arg)
55
57
  end
58
+ elsif args.respond_to? :to_s
59
+ objects = [cached_get(args.to_s)]
56
60
  end
57
61
  # wrap in our objects
58
62
  objects.collect! { |o| new(o) unless o.nil? }
@@ -87,7 +91,7 @@ module Brightbox
87
91
  if value
88
92
  value
89
93
  else
90
- debug "writing cache entry #{id}"
94
+ CONFIG.cache_id id
91
95
  @cache[id] = get(id)
92
96
  end
93
97
  end
@@ -100,6 +104,7 @@ module Brightbox
100
104
  @cache = {}
101
105
  all.each do |f|
102
106
  @cache[f.id] = f
107
+ CONFIG.cache_id f.id
103
108
  end
104
109
  end
105
110
 
data/lib/bbcloud/cli.rb CHANGED
@@ -1,7 +1,10 @@
1
1
  os_config = File.join(File.dirname(__FILE__), 'os_config.rb')
2
2
  require os_config if File.exist? os_config
3
3
 
4
- require "rubygems" unless defined?(DISABLE_RUBYGEMS)
4
+ unless defined?(DISABLE_RUBYGEMS)
5
+ require "rubygems"
6
+ gem "fog", "=0.3.23"
7
+ end
5
8
 
6
9
  # Add any vendored libraries into search path
7
10
  Dir.glob(File.join(File.dirname(__FILE__), 'vendor/*')).each do |f|
@@ -17,7 +20,7 @@ end
17
20
  require 'date'
18
21
  require 'gli'
19
22
  require 'bbcloud/tables'
20
- require 'brightbox-fog'
23
+ require 'fog'
21
24
 
22
25
  %w{api servers images types zones cloud_ips users accounts config version}.each do |f|
23
26
  require File.join(File.dirname(__FILE__), f)
@@ -120,7 +123,7 @@ end
120
123
  desc 'Display version information'
121
124
  command [:version] do |c|
122
125
  c.action do |global_options, options, args|
123
- info "Brightbox CLI version: #{Brightbox::VERSION}"
126
+ info "Brightbox CLI version: #{Brightbox::VERSION}, Fog version: #{Fog::VERSION}"
124
127
  end
125
128
  end
126
129
 
@@ -0,0 +1,22 @@
1
+ desc 'Lists the api clients defined in the config'
2
+ command [:client_list] do |c|
3
+
4
+ c.action do |global_options, options, args|
5
+
6
+ info "Using config file #{CONFIG.config_filename}"
7
+
8
+ clients = CONFIG.clients.collect do |calias|
9
+ c = CONFIG[calias]
10
+ calias = calias + "*" if CONFIG.client_name == calias and CONFIG.clients.size > 1
11
+ {
12
+ :alias => calias,
13
+ :client_id => c["client_id"],
14
+ :secret => c["secret"],
15
+ :api_url => c["api_url"],
16
+ :auth_url => c["auth_url"] || c["api_url"]
17
+ }
18
+ end
19
+
20
+ render_table clients, :fields => [:alias, :client_id, :secret, :api_url, :auth_url]
21
+ end
22
+ end
@@ -1,6 +1,7 @@
1
1
  desc 'Create servers'
2
2
  arg_name 'image_id'
3
3
  command [:create] do |c|
4
+
4
5
  c.desc "Number of servers to create"
5
6
  c.default_value 1
6
7
  c.flag [:i, "server-count"]
@@ -15,6 +16,14 @@ command [:create] do |c|
15
16
  c.desc "Friendly name of server"
16
17
  c.flag [:n, :name]
17
18
 
19
+ c.desc "Specify user data"
20
+ c.flag [:m, :user_data]
21
+
22
+ c.desc "Specify the user data from a local file"
23
+ c.flag [:f, :user_data_file]
24
+
25
+ c.desc "Don't base64 encode the user data"
26
+ c.switch [:e, :no_base64]
18
27
 
19
28
  c.action do |global_options, options, args|
20
29
 
@@ -50,15 +59,37 @@ command [:create] do |c|
50
59
  end
51
60
  raise "Couldn't find server type #{type_id}" unless type
52
61
 
53
- msg = "Creating #{options[:i]} '#{type.handle}' (#{type.id}) server#{options[:i] > 1 ? 's' : ''} with image #{image.name.strip} (#{image.id})"
62
+ user_data = options[:m]
63
+ user_data_file = options[:f]
64
+
65
+ if user_data_file
66
+ raise "Cannot specify user data on command line and in file at same time" if user_data
67
+ File.open(user_data_file, "r") do |f|
68
+ raise "User data file too big (>16k)" if f.size > 16 * 1024
69
+ user_data = f.read
70
+ end
71
+ end
72
+
73
+ if user_data
74
+ unless options[:e]
75
+ require 'base64'
76
+ user_data = Base64.encode64(user_data)
77
+ end
78
+ raise "User data too big (>16k)" if user_data.size > 16 * 1024
79
+ end
80
+
81
+ msg = "Creating #{options[:i] > 1 ? options[:i] : 'a'} #{type.handle} (#{type.id})"
82
+ msg << " server#{options[:i] > 1 ? 's' : ''} with image #{image.name.strip} (#{image.id})"
54
83
  msg << " in zone #{zone.handle} (#{zone})" if zone
84
+ msg << " with #{user_data.size / 1024}k of user data" if user_data
55
85
  info msg
56
86
  servers = []
57
87
  options[:i].times do
58
88
  servers << Server.create(:image_id => image.id,
59
89
  :flavor_id => type.id,
60
90
  :zone_id => zone.to_s,
61
- :name => options[:n])
91
+ :name => options[:n],
92
+ :user_data => user_data)
62
93
  end
63
94
  render_table(servers, global_options)
64
95
  end
@@ -7,10 +7,10 @@ command [:destroy] do |c|
7
7
  raise "you must specify the id of the server(s) you want to destroy"
8
8
  end
9
9
 
10
-
11
10
  servers = args.collect do |sid|
12
11
  info "Destroying server #{sid}"
13
12
  server = Server.find sid
13
+ raise "Server #{sid} does not exist" if server.nil?
14
14
  begin
15
15
  server.destroy
16
16
  rescue Brightbox::Api::Conflict => e
@@ -36,6 +36,25 @@ class BBConfig
36
36
  @config_filename
37
37
  end
38
38
 
39
+ def cache_path
40
+ if @cache_path
41
+ @cache_path
42
+ else
43
+ @cache_path = File.join(@dir, 'cache')
44
+ unless File.exists? @cache_path
45
+ begin
46
+ FileUtils.mkdir @cache_path
47
+ rescue Errno::EEXIST
48
+ end
49
+ end
50
+ @cache_path
51
+ end
52
+ end
53
+
54
+ def cache_id(cid)
55
+ FileUtils.touch(File.join(cache_path, cid)) unless cid.nil?
56
+ end
57
+
39
58
  def config
40
59
  return @config if @config
41
60
  return {} if @config == false
@@ -16,7 +16,6 @@ module Brightbox
16
16
  def attributes
17
17
  a = fog_model.attributes
18
18
  a[:image] = image
19
- a[:description] = description.to_s.strip
20
19
  a[:created_at] = created_at
21
20
  a[:created_on] = fog_model.created_at.strftime("%Y-%m-%d")
22
21
  a[:type] = server_type
@@ -0,0 +1,113 @@
1
+
2
+ = Conventional INI File Parsing and Writing
3
+
4
+ == Introduction
5
+
6
+ Ah yes, INI files. We love them. We hate them. We cannot escape
7
+ them. Originally made popular by Windows, INI files are everywhere
8
+ including in Samba[www.samba.org] and Trac[trac.edgewall.org]. This
9
+ gem has one goal: make INI file, structure, and stream manipulation
10
+ as fast, safe, and simple as possible. We take a modal approach
11
+ with a pluggable parser class.
12
+
13
+ == Sample File
14
+
15
+ ; some comment about section1
16
+ [section1]
17
+ var1 = foo
18
+ var2 = doodle
19
+
20
+ [section2]
21
+
22
+ ; some comment about var1
23
+ var1 = baz
24
+
25
+ ; some comment about var2
26
+ var2 = shoodle
27
+
28
+ == Conventional Format
29
+
30
+ There is no formal INI specification but most parsers observe the
31
+ following so we do also by default:
32
+
33
+ === Sections
34
+
35
+ Section declarations are wrapped in square brackets
36
+ (<tt>[section1]</tt>) with no spaces surrounding the section
37
+ name. Duplicate sections are discouraged but if included are merged.
38
+
39
+ === Parameters
40
+
41
+ The <tt>var1 = foo</tt> above is an example of a parameter, also
42
+ frequently referred to a property, item, or pair. Each parameter is
43
+ made up of a key name (<tt>var1</tt>), an equals sign (<tt>=</tt>),
44
+ and a value (<tt>foo</tt>) with optional spaces. Leading spaces
45
+ before the key name are allowed and leading spaces before or after
46
+ the value are trimmed. Values are literally the characters that
47
+ remain, even if quoted (<tt>var1 = "foo"</tt> would include the
48
+ quotes in the value). Duplicate parameters, either in the same
49
+ section or merged duplicate sections, play 'last one wins'.
50
+
51
+ === Comments
52
+
53
+ All lines starting with a semicolon (<tt>;</tt>) are assumed to be
54
+ comments and are ignored. This character must be the first on the line.
55
+
56
+ === Blank Lines
57
+
58
+ All lines that contain nothing but spaces are ignored.
59
+
60
+ === Line Endings
61
+
62
+ Lines end at either a CRLF or just a LF (CR=\015, LF=\012). Files
63
+ may mix the two within the same file to accomodate edits from
64
+ different platforms.
65
+
66
+ === Format Variations Supported
67
+
68
+ Because INI format is not formally specified, many variations exist
69
+ in the wild. Some of these are supported by extra parsers that are
70
+ included and set by changing the <tt>mode</tt> of the <ini> instance.
71
+
72
+ To maintain backward compatibility with the original 'inifile' gem,
73
+ the following variations are supported by the default parser:
74
+
75
+ * <b>Comments:</b> the comment character can be specified when an instance is created
76
+ * <b>Parameters:</b> separator character can be specified when an instance is created
77
+ * <b>Duplicate Sections:</b> merged
78
+ * <b>Duplicate Parameters:</b> the last one wins
79
+
80
+ === Currently Unsupported Format Variations
81
+
82
+ If it isn't listed above, chances are it isn't supported. But here
83
+ are some specific variations in case you are wondering (and, yes,
84
+ we do have plans eventually support them, either as defaults or options):
85
+
86
+ * Parameter value continuation with backslash (<tt>\\</tt>)
87
+ * Parameter value double-quoting with escapes (<tt>foo = "value with \\n in it"</tt>)
88
+ * Parameter values using braces (<tt>{}</tt>)
89
+ * Parameter values using simple commas parsing into arrays
90
+
91
+ == Copyright and License
92
+
93
+ Copyright (c) 2006-2007 The 'ini' and 'inifile' Gem Team
94
+
95
+ Permission is hereby granted, free of charge, to any person obtaining
96
+ a copy of this software and associated documentation files (the
97
+ "Software"), to deal in the Software without restriction, including
98
+ without limitation the rights to use, copy, modify, merge, publish,
99
+ distribute, sublicense, and/or sell copies of the Software, and to
100
+ permit persons to whom the Software is furnished to do so, subject to
101
+ the following conditions:
102
+
103
+ The above copyright notice and this permission notice shall be
104
+ included in all copies or substantial portions of the Software.
105
+
106
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
107
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
108
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
109
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
110
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
111
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
112
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
113
+
@@ -0,0 +1,266 @@
1
+ # $Id: ini.rb 1 2007-01-17 15:21:30Z ironmo $
2
+
3
+ #
4
+ # This class represents the INI file and can be used to parse, modify,
5
+ # and write INI files.
6
+ #
7
+ class Ini
8
+
9
+ # :stopdoc:
10
+ class Error < StandardError; end
11
+ # :startdoc:
12
+
13
+ #
14
+ # call-seq:
15
+ # IniFile.load( filename )
16
+ # IniFile.load( filename, options )
17
+ #
18
+ # Open the given _filename_ and load the contetns of the INI file.
19
+ # The following _options_ can be passed to this method:
20
+ #
21
+ # :comment => ';' The line comment character(s)
22
+ # :parameter => '=' The parameter / value separator
23
+ #
24
+ def self.load( filename, opts = {} )
25
+ new(filename, opts)
26
+ end
27
+
28
+ #
29
+ # call-seq:
30
+ # IniFile.new( filename )
31
+ # IniFile.new( filename, options )
32
+ #
33
+ # Create a new INI file using the given _filename_. If _filename_
34
+ # exists and is a regular file, then its contents will be parsed.
35
+ # The following _options_ can be passed to this method:
36
+ #
37
+ # :comment => ';' The line comment character(s)
38
+ # :parameter => '=' The parameter / value separator
39
+ #
40
+ def initialize( filename, opts = {} )
41
+ @fn = filename
42
+ @comment = opts[:comment] || ';'
43
+ @param = opts[:parameter] || '='
44
+ @ini = Hash.new {|h,k| h[k] = Hash.new}
45
+
46
+ @rgxp_comment = %r/\A\s*\z|\A\s*[#{@comment}]/
47
+ @rgxp_section = %r/\A\s*\[([^\]]+)\]/o
48
+ @rgxp_param = %r/\A([^#{@param}]+)#{@param}(.*)\z/
49
+
50
+ parse
51
+ end
52
+
53
+ #
54
+ # call-seq:
55
+ # write
56
+ # write( filename )
57
+ #
58
+ # Write the INI file contents to the filesystem. The given _filename_
59
+ # will be used to write the file. If _filename_ is not given, then the
60
+ # named used when constructing this object will be used.
61
+ #
62
+ def write( filename = nil )
63
+ @fn = filename unless filename.nil?
64
+
65
+ ::File.open(@fn, 'w') do |f|
66
+ @ini.each do |section,hash|
67
+ f.puts "[#{section}]"
68
+ hash.each {|param,val| f.puts "#{param} #{@param} #{val}"}
69
+ f.puts
70
+ end
71
+ end
72
+ self
73
+ end
74
+ alias :save :write
75
+
76
+ #
77
+ # call-seq:
78
+ # each {|section, parameter, value| block}
79
+ #
80
+ # Yield each _section_, _parameter_, _value_ in turn to the given
81
+ # _block_. The method returns immediately if no block is supplied.
82
+ #
83
+ def each
84
+ return unless block_given?
85
+ @ini.each do |section,hash|
86
+ hash.each do |param,val|
87
+ yield section, param, val
88
+ end
89
+ end
90
+ self
91
+ end
92
+
93
+ #
94
+ # call-seq:
95
+ # each_section {|section| block}
96
+ #
97
+ # Yield each _section_ in turn to the given _block_. The method returns
98
+ # immediately if no block is supplied.
99
+ #
100
+ def each_section
101
+ return unless block_given?
102
+ @ini.each_key {|section| yield section}
103
+ self
104
+ end
105
+
106
+ #
107
+ # call-seq:
108
+ # delete_section( section )
109
+ #
110
+ # Deletes the named _section_ from the INI file. Returns the
111
+ # parameter / value pairs if the section exists in the INI file. Otherwise,
112
+ # returns +nil+.
113
+ #
114
+ def delete_section( section )
115
+ @ini.delete section.to_s
116
+ end
117
+
118
+ #
119
+ # call-seq:
120
+ # ini_file[section]
121
+ #
122
+ # Get the hash of parameter/value pairs for the given _section_. If the
123
+ # _section_ hash does not exist it will be created.
124
+ #
125
+ def []( section )
126
+ return nil if section.nil?
127
+ @ini[section.to_s]
128
+ end
129
+
130
+ #
131
+ # call-seq:
132
+ # has_section?( section )
133
+ #
134
+ # Returns +true+ if the named _section_ exists in the INI file.
135
+ #
136
+ def has_section?( section )
137
+ @ini.has_key? section.to_s
138
+ end
139
+
140
+ #
141
+ # call-seq:
142
+ # sections
143
+ #
144
+ # Returns an array of the section names.
145
+ #
146
+ def sections
147
+ @ini.keys
148
+ end
149
+
150
+ #
151
+ # call-seq:
152
+ # freeze
153
+ #
154
+ # Freeze the state of the +IniFile+ object. Any attempts to change the
155
+ # object will raise an error.
156
+ #
157
+ def freeze
158
+ super
159
+ @ini.each_value {|h| h.freeze}
160
+ @ini.freeze
161
+ self
162
+ end
163
+
164
+ #
165
+ # call-seq:
166
+ # taint
167
+ #
168
+ # Marks the INI file as tainted -- this will traverse each section marking
169
+ # each section as tainted as well.
170
+ #
171
+ def taint
172
+ super
173
+ @ini.each_value {|h| h.taint}
174
+ @ini.taint
175
+ self
176
+ end
177
+
178
+ #
179
+ # call-seq:
180
+ # dup
181
+ #
182
+ # Produces a duplicate of this INI file. The duplicate is independent of the
183
+ # original -- i.e. the duplicate can be modified without changing the
184
+ # orgiinal. The tainted state of the original is copied to the duplicate.
185
+ #
186
+ def dup
187
+ other = super
188
+ other.instance_variable_set(:@ini, Hash.new {|h,k| h[k] = Hash.new})
189
+ @ini.each_pair {|s,h| other[s].merge! h}
190
+ other.taint if self.tainted?
191
+ other
192
+ end
193
+
194
+ #
195
+ # call-seq:
196
+ # clone
197
+ #
198
+ # Produces a duplicate of this INI file. The duplicate is independent of the
199
+ # original -- i.e. the duplicate can be modified without changing the
200
+ # orgiinal. The tainted state and the frozen state of the original is copied
201
+ # to the duplicate.
202
+ #
203
+ def clone
204
+ other = dup
205
+ other.freeze if self.frozen?
206
+ other
207
+ end
208
+
209
+ #
210
+ # call-seq:
211
+ # eql?( other )
212
+ #
213
+ # Returns +true+ if the _other_ object is equivalent to this INI file. For
214
+ # two INI files to be equivalent, they must have the same sections with the
215
+ # same parameter / value pairs in each section.
216
+ #
217
+ def eql?( other )
218
+ return true if equal? other
219
+ return false unless other.instance_of? self.class
220
+ @ini == other.instance_variable_get(:@ini)
221
+ end
222
+ alias :== :eql?
223
+
224
+
225
+ private
226
+ #
227
+ # call-seq
228
+ # parse
229
+ #
230
+ # Parse the ini file contents.
231
+ #
232
+ def parse
233
+ return unless ::Kernel.test ?f, @fn
234
+ section = nil
235
+
236
+ ::File.open(@fn, 'r') do |f|
237
+ while line = f.gets
238
+ line = line.chomp
239
+
240
+ case line
241
+ # ignore blank lines and comment lines
242
+ when @rgxp_comment
243
+ next
244
+
245
+ # this is a section declaration
246
+ when @rgxp_section
247
+ section = @ini[$1.strip]
248
+
249
+ # otherwise we have a parameter
250
+ when @rgxp_param
251
+ begin
252
+ section[$1.strip] = $2.strip
253
+ rescue NoMethodError
254
+ raise Error, "parameter encountered before first section"
255
+ end
256
+
257
+ else
258
+ raise Error, "could not parse line '#{line}"
259
+ end
260
+ end # while
261
+ end # File.open
262
+ end
263
+
264
+ end
265
+
266
+ # EOF
@@ -0,0 +1,10 @@
1
+ # $Id: inifile.rb 1 2007-01-17 15:21:30Z ironmo $
2
+
3
+ # The 'inifile' gem will eventually be deprecated in favor of the
4
+ # 'ini' gem as it becomes able to handle streams, stringio and string buffers of INI
5
+ # formatted data.
6
+
7
+ require 'ini'
8
+
9
+ class IniFile < Ini
10
+ end
@@ -0,0 +1,6 @@
1
+ ; having a paramater / value pair outside a section is an error
2
+ one = 1
3
+
4
+ [section_one]
5
+ one = 1
6
+ two = 2
@@ -0,0 +1,6 @@
1
+ [section_one]
2
+ one = 1
3
+ two = 2
4
+
5
+ ; the following is not a valid line
6
+ invalid line
@@ -0,0 +1,5 @@
1
+ # comments should be ignored
2
+ [section_one]
3
+ one = 1
4
+ two = 2
5
+
@@ -0,0 +1,17 @@
1
+ [section_one]
2
+ one = 1
3
+ two = 2
4
+
5
+ [section_two]
6
+ three = 3
7
+
8
+ ; comments should be ignored
9
+ [section three]
10
+ four =4
11
+ five=5
12
+ six =6
13
+
14
+ [section_four]
15
+ [section_five]
16
+ seven and eight= 7 & 8
17
+
@@ -0,0 +1,7 @@
1
+ # comments should be ignored
2
+ ; multiple comments characeters are supported
3
+ ; (I'm lookin' at you, samba)
4
+ [section_one]
5
+ one = 1
6
+ two = 2
7
+
@@ -0,0 +1,5 @@
1
+ ; comments should be ignored
2
+ [section_one]
3
+ one : 1
4
+ two:2
5
+
@@ -0,0 +1,273 @@
1
+ # Code Generated by ZenTest v. 3.3.0
2
+ # classname: asrt / meth = ratio%
3
+ # Rini::IniFile: 0 / 9 = 0.00%
4
+
5
+ $:.unshift(File.expand_path(File.dirname(__FILE__) + "/../lib"))
6
+ require "inifile"
7
+
8
+ begin; require 'turn'; rescue LoadError; end
9
+ require 'test/unit' unless defined? $ZENTEST and $ZENTEST
10
+
11
+ class TestIniFile < Test::Unit::TestCase
12
+
13
+ def setup
14
+ @ini_file = ::IniFile.new 'test/data/good.ini'
15
+ @contents = [
16
+ ['section_one', 'one', '1'],
17
+ ['section_one', 'two', '2'],
18
+ ['section_two', 'three', '3'],
19
+ ['section three', 'four', '4'],
20
+ ['section three', 'five', '5'],
21
+ ['section three', 'six', '6'],
22
+ ['section_five', 'seven and eight', '7 & 8']
23
+ ].sort
24
+ end
25
+
26
+ def test_class_load
27
+ ini_file = ::IniFile.load 'test/data/good.ini'
28
+ assert_instance_of ::IniFile, ini_file
29
+
30
+ # see if we can parse different style comments
31
+ assert_raise(::IniFile::Error) {::IniFile.load 'test/data/comment.ini'}
32
+
33
+ ini_file = ::IniFile.load 'test/data/comment.ini', :comment => '#'
34
+ assert_instance_of ::IniFile, ini_file
35
+
36
+ # see if we can parse mixed style comments
37
+ assert_raise(::IniFile::Error) {::IniFile.load 'test/data/mixed_comment.ini'}
38
+
39
+ ini_file = ::IniFile.load 'test/data/mixed_comment.ini', :comment => ';#'
40
+ assert_instance_of ::IniFile, ini_file
41
+
42
+ # see if we can parse different style param separators
43
+ assert_raise(::IniFile::Error) {::IniFile.load 'test/data/param.ini'}
44
+
45
+ ini_file = ::IniFile.load 'test/data/param.ini', :parameter => ':'
46
+ assert_instance_of ::IniFile, ini_file
47
+
48
+ # make sure we error out on files with bad lines
49
+ assert_raise(::IniFile::Error) {::IniFile.load 'test/data/bad_1.ini'}
50
+ assert_raise(::IniFile::Error) {::IniFile.load 'test/data/bad_2.ini'}
51
+ end
52
+
53
+ def test_clone
54
+ clone = @ini_file.clone
55
+ assert_equal @ini_file, clone
56
+ assert !clone.tainted?
57
+ assert !clone.frozen?
58
+
59
+ # the clone should be completely independent of the original
60
+ clone['new_section']['one'] = 1
61
+ assert_not_equal @ini_file, clone
62
+
63
+ # the tainted state is copied to clones
64
+ @ini_file.taint
65
+ assert @ini_file.tainted?
66
+
67
+ clone = @ini_file.clone
68
+ assert clone.tainted?
69
+
70
+ # the frozen state is also copied to clones
71
+ @ini_file.freeze
72
+ assert @ini_file.frozen?
73
+
74
+ clone = @ini_file.clone
75
+ assert clone.tainted?
76
+ assert clone.frozen?
77
+ end
78
+
79
+ def test_delete_section
80
+ assert_nil @ini_file.delete_section('section_nil')
81
+
82
+ h = {'one' => '1', 'two' => '2'}
83
+ assert_equal true, @ini_file.has_section?('section_one')
84
+ assert_equal h, @ini_file.delete_section('section_one')
85
+ assert_equal false, @ini_file.has_section?('section_one')
86
+ assert_nil @ini_file.delete_section('section_one')
87
+ end
88
+
89
+ def test_dup
90
+ dup = @ini_file.dup
91
+ assert_equal @ini_file, dup
92
+ assert !dup.tainted?
93
+ assert !dup.frozen?
94
+
95
+ # the duplicate should be completely independent of the original
96
+ dup['new_section']['one'] = 1
97
+ assert_not_equal @ini_file, dup
98
+
99
+ # the tainted state is copied to duplicates
100
+ @ini_file.taint
101
+ assert @ini_file.tainted?
102
+
103
+ dup = @ini_file.dup
104
+ assert dup.tainted?
105
+
106
+ # the frozen state, however, is not
107
+ @ini_file.freeze
108
+ assert @ini_file.frozen?
109
+
110
+ dup = @ini_file.dup
111
+ assert dup.tainted?
112
+ assert !dup.frozen?
113
+ end
114
+
115
+ def test_each
116
+ ary = []
117
+ @ini_file.each {|*args| ary << args}
118
+
119
+ assert_equal @contents, ary.sort
120
+
121
+ ary = []
122
+ ::IniFile.new('temp.ini').each {|*args| ary << args}
123
+ assert_equal [], ary
124
+ end
125
+
126
+ def test_each_section
127
+ expected = [
128
+ 'section_one', 'section_two', 'section three',
129
+ 'section_four', 'section_five'
130
+ ].sort
131
+
132
+ ary = []
133
+ @ini_file.each_section {|section| ary << section}
134
+
135
+ assert_equal expected, ary.sort
136
+
137
+ ary = []
138
+ ::IniFile.new('temp.ini').each_section {|section| ary << section}
139
+ assert_equal [], ary
140
+ end
141
+
142
+ def test_eql_eh
143
+ assert @ini_file.eql?(@ini_file)
144
+ assert @ini_file.eql?(@ini_file.clone)
145
+ assert !@ini_file.eql?('string')
146
+ assert !@ini_file.eql?(IniFile.new(''))
147
+ end
148
+
149
+ def test_freeze
150
+ assert_equal false, @ini_file.frozen?
151
+ @ini_file.each_section do |s|
152
+ assert_equal false, @ini_file[s].frozen?
153
+ end
154
+
155
+ @ini_file.freeze
156
+
157
+ assert_equal true, @ini_file.frozen?
158
+ @ini_file.each_section do |s|
159
+ assert_equal true, @ini_file[s].frozen?
160
+ end
161
+ end
162
+
163
+ def test_has_section_eh
164
+ assert_equal true, @ini_file.has_section?('section_one')
165
+ assert_equal false, @ini_file.has_section?('section_ten')
166
+ assert_equal true, @ini_file.has_section?(:section_two)
167
+ assert_equal false, @ini_file.has_section?(nil)
168
+
169
+ ini_file = ::IniFile.new 'temp.ini'
170
+ assert_equal false, ini_file.has_section?('section_one')
171
+ assert_equal false, ini_file.has_section?('one')
172
+ assert_equal false, ini_file.has_section?('two')
173
+ end
174
+
175
+ def test_index
176
+ expected = {
177
+ 'one' => '1',
178
+ 'two' => '2'
179
+ }
180
+ assert_equal expected, @ini_file[:section_one]
181
+
182
+ expected = {'three' => '3'}
183
+ assert_equal expected, @ini_file['section_two']
184
+
185
+ expected = {
186
+ 'four' => '4',
187
+ 'five' => '5',
188
+ 'six' => '6',
189
+ }
190
+ assert_equal expected, @ini_file['section three']
191
+
192
+ expected = {}
193
+ assert_equal expected, @ini_file['section_four']
194
+
195
+ expected = {'seven and eight' => '7 & 8'}
196
+ assert_equal expected, @ini_file['section_five']
197
+
198
+ expected = {}
199
+ assert_equal expected, @ini_file['section_six']
200
+
201
+ assert_nil @ini_file[nil]
202
+
203
+ expected = {}
204
+ ini_file = ::IniFile.new 'temp.ini'
205
+ assert_equal expected, ini_file['section_one']
206
+ assert_equal expected, ini_file['one']
207
+ assert_nil ini_file[nil]
208
+ end
209
+
210
+ def test_initialize
211
+ # see if we can parse different style comments
212
+ assert_raise(::IniFile::Error) {::IniFile.new 'test/data/comment.ini'}
213
+
214
+ ini_file = ::IniFile.new 'test/data/comment.ini', :comment => '#'
215
+ assert_equal true, ini_file.has_section?('section_one')
216
+
217
+ # see if we can parse different style param separators
218
+ assert_raise(::IniFile::Error) {::IniFile.new 'test/data/param.ini'}
219
+
220
+ ini_file = ::IniFile.new 'test/data/param.ini', :parameter => ':'
221
+ assert_equal true, ini_file.has_section?('section_one')
222
+ assert_equal '1', ini_file['section_one']['one']
223
+ assert_equal '2', ini_file['section_one']['two']
224
+
225
+ # make sure we error out on files with bad lines
226
+ assert_raise(::IniFile::Error) {::IniFile.new 'test/data/bad_1.ini'}
227
+ assert_raise(::IniFile::Error) {::IniFile.new 'test/data/bad_2.ini'}
228
+ end
229
+
230
+ def test_sections
231
+ expected = [
232
+ 'section_one', 'section_two', 'section three',
233
+ 'section_four', 'section_five'
234
+ ].sort
235
+
236
+ assert_equal expected, @ini_file.sections.sort
237
+
238
+ ini_file = ::IniFile.new 'temp.ini'
239
+ assert_equal [], ini_file.sections
240
+ end
241
+
242
+ def test_taint
243
+ assert_equal false, @ini_file.tainted?
244
+ @ini_file.each_section do |s|
245
+ assert_equal false, @ini_file[s].tainted?
246
+ end
247
+
248
+ @ini_file.taint
249
+
250
+ assert_equal true, @ini_file.tainted?
251
+ @ini_file.each_section do |s|
252
+ assert_equal true, @ini_file[s].tainted?
253
+ end
254
+ end
255
+
256
+ def test_write
257
+ tmp = 'test/data/temp.ini'
258
+ ::File.delete tmp if ::Kernel.test(?f, tmp)
259
+
260
+ @ini_file.save tmp
261
+ assert_equal true, ::Kernel.test(?f, tmp)
262
+
263
+ ::File.delete tmp if ::Kernel.test(?f, tmp)
264
+
265
+ ini_file = ::IniFile.new tmp
266
+ ini_file.save
267
+ assert_nil ::Kernel.test(?s, tmp)
268
+
269
+ ::File.delete tmp if ::Kernel.test(?f, tmp)
270
+ end
271
+ end
272
+
273
+ # EOF
@@ -1,3 +1,3 @@
1
1
  module Brightbox
2
- VERSION = "0.7"
2
+ VERSION = "0.8"
3
3
  end
@@ -0,0 +1,92 @@
1
+ # brightbox cli tools completion
2
+ #
3
+
4
+ _brightbox()
5
+ {
6
+ local cur prev
7
+
8
+ COMPREPLY=()
9
+ _get_comp_words_by_ref cur prev
10
+
11
+ command=''
12
+ for (( i=1; i < COMP_CWORD; i++ )); do
13
+ if [[ "${COMP_WORDS[i]}" != -* ]]; then
14
+ command=${COMP_WORDS[i]}
15
+ break
16
+ fi
17
+ done
18
+
19
+ case $1 in
20
+ brightbox-servers)
21
+ case $command in
22
+ create)
23
+ if [[ "$cur" == -* ]] ; then
24
+ COMPREPLY=( $( compgen -W '--name --type --zone --server-count --user-data-file --user-data --no-base64' -- "$cur" ) )
25
+ else
26
+ test -d ~/.brightbox/cache && COMPREPLY=( $( compgen -W '`ls ~/.brightbox/cache/`' -- "$cur" ) )
27
+ fi
28
+ ;;
29
+ destroy|list|show|shutdown|snapshot|start|stop)
30
+ test -d ~/.brightbox/cache && COMPREPLY=( $( compgen -W '`ls ~/.brightbox/cache/`' -- "$cur" ) )
31
+ ;;
32
+ *)
33
+ COMPREPLY=( $( compgen -W 'create destroy help list show shutdown snapshot start stop' -- "$cur" ) )
34
+ ;;
35
+ esac
36
+ ;;
37
+ brightbox-images)
38
+ case $command in
39
+ destroy|list|show)
40
+ test -d ~/.brightbox/cache && COMPREPLY=( $( compgen -W '`ls ~/.brightbox/cache/`' -- "$cur" ) )
41
+ ;;
42
+ *)
43
+ COMPREPLY=( $( compgen -W 'destroy help list show' -- "$cur" ) )
44
+ ;;
45
+ esac
46
+ ;;
47
+ brightbox-cloudips)
48
+ case $command in
49
+ map)
50
+ if [[ "$cur" == -* ]] ; then
51
+ COMPREPLY=( $( compgen -W '--unmap' -- "$cur" ) )
52
+ else
53
+ test -d ~/.brightbox/cache && COMPREPLY=( $( compgen -W '`ls ~/.brightbox/cache/`' -- "$cur" ) )
54
+ fi
55
+ ;;
56
+ create|destroy|list|unmap|show)
57
+ test -d ~/.brightbox/cache && COMPREPLY=( $( compgen -W '`ls ~/.brightbox/cache/`' -- "$cur" ) )
58
+ ;;
59
+ *)
60
+ COMPREPLY=( $( compgen -W 'create destroy list ummap show map help' -- "$cur" ) )
61
+ ;;
62
+ esac
63
+ ;;
64
+ brightbox-config)
65
+ case $command in
66
+ client_add)
67
+ if [[ "$cur" == -* ]] ; then
68
+ COMPREPLY=( $( compgen -W '--alias --auth-url' -- "$cur" ) )
69
+ fi
70
+ ;;
71
+ client_default|client_remove|client_list)
72
+ ;;
73
+ *)
74
+ COMPREPLY=( $( compgen -W 'client_add client_remove client_default help' -- "$cur" ) )
75
+ ;;
76
+ esac
77
+ ;;
78
+ esac
79
+
80
+ }
81
+ complete -F _brightbox -o filenames brightbox-servers
82
+ complete -F _brightbox -o filenames brightbox-images
83
+ complete -F _brightbox -o filenames brightbox-cloudips
84
+ complete -F _brightbox -o filenames brightbox-config
85
+
86
+ # Local variables:
87
+ # mode: shell-script
88
+ # sh-basic-offset: 4
89
+ # sh-indent-comment: t
90
+ # indent-tabs-mode: nil
91
+ # End:
92
+ # ex: ts=4 sw=4 et filetype=sh
metadata CHANGED
@@ -1,12 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bbcloud
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 7
9
- version: "0.7"
7
+ - 8
8
+ version: "0.8"
10
9
  platform: ruby
11
10
  authors:
12
11
  - John Leach
@@ -14,7 +13,7 @@ autorequire:
14
13
  bindir: bin
15
14
  cert_chain: []
16
15
 
17
- date: 2010-11-16 00:00:00 +00:00
16
+ date: 2010-11-20 00:00:00 +00:00
18
17
  default_executable:
19
18
  dependencies:
20
19
  - !ruby/object:Gem::Dependency
@@ -25,7 +24,6 @@ dependencies:
25
24
  requirements:
26
25
  - - "="
27
26
  - !ruby/object:Gem::Version
28
- hash: 23
29
27
  segments:
30
28
  - 1
31
29
  - 1
@@ -41,7 +39,6 @@ dependencies:
41
39
  requirements:
42
40
  - - "="
43
41
  - !ruby/object:Gem::Version
44
- hash: 25
45
42
  segments:
46
43
  - 0
47
44
  - 3
@@ -50,19 +47,18 @@ dependencies:
50
47
  type: :runtime
51
48
  version_requirements: *id002
52
49
  - !ruby/object:Gem::Dependency
53
- name: brightbox-fog
50
+ name: fog
54
51
  prerelease: false
55
52
  requirement: &id003 !ruby/object:Gem::Requirement
56
53
  none: false
57
54
  requirements:
58
55
  - - "="
59
56
  - !ruby/object:Gem::Version
60
- hash: 51
61
57
  segments:
62
58
  - 0
63
59
  - 3
64
- - 16
65
- version: 0.3.16
60
+ - 23
61
+ version: 0.3.23
66
62
  type: :runtime
67
63
  version_requirements: *id003
68
64
  - !ruby/object:Gem::Dependency
@@ -73,7 +69,6 @@ dependencies:
73
69
  requirements:
74
70
  - - ">="
75
71
  - !ruby/object:Gem::Version
76
- hash: 31
77
72
  segments:
78
73
  - 0
79
74
  - 2
@@ -89,7 +84,6 @@ dependencies:
89
84
  requirements:
90
85
  - - "="
91
86
  - !ruby/object:Gem::Version
92
- hash: 25
93
87
  segments:
94
88
  - 0
95
89
  - 1
@@ -117,6 +111,7 @@ files:
117
111
  - .gitignore
118
112
  - LICENSE
119
113
  - README
114
+ - README.rdoc
120
115
  - Rakefile
121
116
  - bbcloud.gemspec
122
117
  - bin/brightbox-accounts
@@ -142,6 +137,7 @@ files:
142
137
  - lib/bbcloud/commands/cloudips-unmap.rb
143
138
  - lib/bbcloud/commands/config-client-add.rb
144
139
  - lib/bbcloud/commands/config-client-default.rb
140
+ - lib/bbcloud/commands/config-client-list.rb
145
141
  - lib/bbcloud/commands/config-client-remove.rb
146
142
  - lib/bbcloud/commands/images-destroy.rb
147
143
  - lib/bbcloud/commands/images-list.rb
@@ -166,8 +162,19 @@ files:
166
162
  - lib/bbcloud/tables.rb
167
163
  - lib/bbcloud/types.rb
168
164
  - lib/bbcloud/users.rb
165
+ - lib/bbcloud/vendor/brightbox-ini/README
166
+ - lib/bbcloud/vendor/brightbox-ini/lib/ini.rb
167
+ - lib/bbcloud/vendor/brightbox-ini/lib/inifile.rb
168
+ - lib/bbcloud/vendor/brightbox-ini/test/data/bad_1.ini
169
+ - lib/bbcloud/vendor/brightbox-ini/test/data/bad_2.ini
170
+ - lib/bbcloud/vendor/brightbox-ini/test/data/comment.ini
171
+ - lib/bbcloud/vendor/brightbox-ini/test/data/good.ini
172
+ - lib/bbcloud/vendor/brightbox-ini/test/data/mixed_comment.ini
173
+ - lib/bbcloud/vendor/brightbox-ini/test/data/param.ini
174
+ - lib/bbcloud/vendor/brightbox-ini/test/test_inifile.rb
169
175
  - lib/bbcloud/version.rb
170
176
  - lib/bbcloud/zones.rb
177
+ - tools/bash_completion_script
171
178
  has_rdoc: true
172
179
  homepage: http://docs.brightbox.com/cli
173
180
  licenses: []
@@ -182,7 +189,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
182
189
  requirements:
183
190
  - - ">="
184
191
  - !ruby/object:Gem::Version
185
- hash: 3
186
192
  segments:
187
193
  - 0
188
194
  version: "0"
@@ -191,7 +197,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
191
197
  requirements:
192
198
  - - ">="
193
199
  - !ruby/object:Gem::Version
194
- hash: 3
195
200
  segments:
196
201
  - 0
197
202
  version: "0"