lxc 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,5 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ *log
19
+ .rvmrc
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -c -b -fd
data/.rvmrc.template ADDED
@@ -0,0 +1 @@
1
+ rvm use ruby-1.9.3@lxc --create
data/.travis.yml ADDED
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - 2.0.0
7
+
8
+ before_install:
9
+ - sudo apt-get -qq --force-yes update
10
+
11
+ bundler_args: --binstubs
12
+
13
+ script: "bin/rake test"
14
+
15
+ notifications:
16
+ irc: "irc.freenode.net#jovelabs"
data/LICENSE CHANGED
@@ -1,22 +1,202 @@
1
- Copyright (c) 2012 Zachary Patten
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.
1
+
2
+ Apache License
3
+ Version 2.0, January 2004
4
+ http://www.apache.org/licenses/
5
+
6
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7
+
8
+ 1. Definitions.
9
+
10
+ "License" shall mean the terms and conditions for use, reproduction,
11
+ and distribution as defined by Sections 1 through 9 of this document.
12
+
13
+ "Licensor" shall mean the copyright owner or entity authorized by
14
+ the copyright owner that is granting the License.
15
+
16
+ "Legal Entity" shall mean the union of the acting entity and all
17
+ other entities that control, are controlled by, or are under common
18
+ control with that entity. For the purposes of this definition,
19
+ "control" means (i) the power, direct or indirect, to cause the
20
+ direction or management of such entity, whether by contract or
21
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
22
+ outstanding shares, or (iii) beneficial ownership of such entity.
23
+
24
+ "You" (or "Your") shall mean an individual or Legal Entity
25
+ exercising permissions granted by this License.
26
+
27
+ "Source" form shall mean the preferred form for making modifications,
28
+ including but not limited to software source code, documentation
29
+ source, and configuration files.
30
+
31
+ "Object" form shall mean any form resulting from mechanical
32
+ transformation or translation of a Source form, including but
33
+ not limited to compiled object code, generated documentation,
34
+ and conversions to other media types.
35
+
36
+ "Work" shall mean the work of authorship, whether in Source or
37
+ Object form, made available under the License, as indicated by a
38
+ copyright notice that is included in or attached to the work
39
+ (an example is provided in the Appendix below).
40
+
41
+ "Derivative Works" shall mean any work, whether in Source or Object
42
+ form, that is based on (or derived from) the Work and for which the
43
+ editorial revisions, annotations, elaborations, or other modifications
44
+ represent, as a whole, an original work of authorship. For the purposes
45
+ of this License, Derivative Works shall not include works that remain
46
+ separable from, or merely link (or bind by name) to the interfaces of,
47
+ the Work and Derivative Works thereof.
48
+
49
+ "Contribution" shall mean any work of authorship, including
50
+ the original version of the Work and any modifications or additions
51
+ to that Work or Derivative Works thereof, that is intentionally
52
+ submitted to Licensor for inclusion in the Work by the copyright owner
53
+ or by an individual or Legal Entity authorized to submit on behalf of
54
+ the copyright owner. For the purposes of this definition, "submitted"
55
+ means any form of electronic, verbal, or written communication sent
56
+ to the Licensor or its representatives, including but not limited to
57
+ communication on electronic mailing lists, source code control systems,
58
+ and issue tracking systems that are managed by, or on behalf of, the
59
+ Licensor for the purpose of discussing and improving the Work, but
60
+ excluding communication that is conspicuously marked or otherwise
61
+ designated in writing by the copyright owner as "Not a Contribution."
62
+
63
+ "Contributor" shall mean Licensor and any individual or Legal Entity
64
+ on behalf of whom a Contribution has been received by Licensor and
65
+ subsequently incorporated within the Work.
66
+
67
+ 2. Grant of Copyright License. Subject to the terms and conditions of
68
+ this License, each Contributor hereby grants to You a perpetual,
69
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70
+ copyright license to reproduce, prepare Derivative Works of,
71
+ publicly display, publicly perform, sublicense, and distribute the
72
+ Work and such Derivative Works in Source or Object form.
73
+
74
+ 3. Grant of Patent License. Subject to the terms and conditions of
75
+ this License, each Contributor hereby grants to You a perpetual,
76
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77
+ (except as stated in this section) patent license to make, have made,
78
+ use, offer to sell, sell, import, and otherwise transfer the Work,
79
+ where such license applies only to those patent claims licensable
80
+ by such Contributor that are necessarily infringed by their
81
+ Contribution(s) alone or by combination of their Contribution(s)
82
+ with the Work to which such Contribution(s) was submitted. If You
83
+ institute patent litigation against any entity (including a
84
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
85
+ or a Contribution incorporated within the Work constitutes direct
86
+ or contributory patent infringement, then any patent licenses
87
+ granted to You under this License for that Work shall terminate
88
+ as of the date such litigation is filed.
89
+
90
+ 4. Redistribution. You may reproduce and distribute copies of the
91
+ Work or Derivative Works thereof in any medium, with or without
92
+ modifications, and in Source or Object form, provided that You
93
+ meet the following conditions:
94
+
95
+ (a) You must give any other recipients of the Work or
96
+ Derivative Works a copy of this License; and
97
+
98
+ (b) You must cause any modified files to carry prominent notices
99
+ stating that You changed the files; and
100
+
101
+ (c) You must retain, in the Source form of any Derivative Works
102
+ that You distribute, all copyright, patent, trademark, and
103
+ attribution notices from the Source form of the Work,
104
+ excluding those notices that do not pertain to any part of
105
+ the Derivative Works; and
106
+
107
+ (d) If the Work includes a "NOTICE" text file as part of its
108
+ distribution, then any Derivative Works that You distribute must
109
+ include a readable copy of the attribution notices contained
110
+ within such NOTICE file, excluding those notices that do not
111
+ pertain to any part of the Derivative Works, in at least one
112
+ of the following places: within a NOTICE text file distributed
113
+ as part of the Derivative Works; within the Source form or
114
+ documentation, if provided along with the Derivative Works; or,
115
+ within a display generated by the Derivative Works, if and
116
+ wherever such third-party notices normally appear. The contents
117
+ of the NOTICE file are for informational purposes only and
118
+ do not modify the License. You may add Your own attribution
119
+ notices within Derivative Works that You distribute, alongside
120
+ or as an addendum to the NOTICE text from the Work, provided
121
+ that such additional attribution notices cannot be construed
122
+ as modifying the License.
123
+
124
+ You may add Your own copyright statement to Your modifications and
125
+ may provide additional or different license terms and conditions
126
+ for use, reproduction, or distribution of Your modifications, or
127
+ for any such Derivative Works as a whole, provided Your use,
128
+ reproduction, and distribution of the Work otherwise complies with
129
+ the conditions stated in this License.
130
+
131
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
132
+ any Contribution intentionally submitted for inclusion in the Work
133
+ by You to the Licensor shall be under the terms and conditions of
134
+ this License, without any additional terms or conditions.
135
+ Notwithstanding the above, nothing herein shall supersede or modify
136
+ the terms of any separate license agreement you may have executed
137
+ with Licensor regarding such Contributions.
138
+
139
+ 6. Trademarks. This License does not grant permission to use the trade
140
+ names, trademarks, service marks, or product names of the Licensor,
141
+ except as required for reasonable and customary use in describing the
142
+ origin of the Work and reproducing the content of the NOTICE file.
143
+
144
+ 7. Disclaimer of Warranty. Unless required by applicable law or
145
+ agreed to in writing, Licensor provides the Work (and each
146
+ Contributor provides its Contributions) on an "AS IS" BASIS,
147
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148
+ implied, including, without limitation, any warranties or conditions
149
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150
+ PARTICULAR PURPOSE. You are solely responsible for determining the
151
+ appropriateness of using or redistributing the Work and assume any
152
+ risks associated with Your exercise of permissions under this License.
153
+
154
+ 8. Limitation of Liability. In no event and under no legal theory,
155
+ whether in tort (including negligence), contract, or otherwise,
156
+ unless required by applicable law (such as deliberate and grossly
157
+ negligent acts) or agreed to in writing, shall any Contributor be
158
+ liable to You for damages, including any direct, indirect, special,
159
+ incidental, or consequential damages of any character arising as a
160
+ result of this License or out of the use or inability to use the
161
+ Work (including but not limited to damages for loss of goodwill,
162
+ work stoppage, computer failure or malfunction, or any and all
163
+ other commercial damages or losses), even if such Contributor
164
+ has been advised of the possibility of such damages.
165
+
166
+ 9. Accepting Warranty or Additional Liability. While redistributing
167
+ the Work or Derivative Works thereof, You may choose to offer,
168
+ and charge a fee for, acceptance of support, warranty, indemnity,
169
+ or other liability obligations and/or rights consistent with this
170
+ License. However, in accepting such obligations, You may act only
171
+ on Your own behalf and on Your sole responsibility, not on behalf
172
+ of any other Contributor, and only if You agree to indemnify,
173
+ defend, and hold each Contributor harmless for any liability
174
+ incurred by, or claims asserted against, such Contributor by reason
175
+ of your accepting any such warranty or additional liability.
176
+
177
+ END OF TERMS AND CONDITIONS
178
+
179
+ APPENDIX: How to apply the Apache License to your work.
180
+
181
+ To apply the Apache License to your work, attach the following
182
+ boilerplate notice, with the fields enclosed by brackets "[]"
183
+ replaced with your own identifying information. (Don't include
184
+ the brackets!) The text should be enclosed in the appropriate
185
+ comment syntax for the file format. We also recommend that a
186
+ file or class name and description of purpose be included on the
187
+ same "printed page" as the copyright notice for easier
188
+ identification within third-party archives.
189
+
190
+ Copyright [yyyy] [name of copyright owner]
191
+
192
+ Licensed under the Apache License, Version 2.0 (the "License");
193
+ you may not use this file except in compliance with the License.
194
+ You may obtain a copy of the License at
195
+
196
+ http://www.apache.org/licenses/LICENSE-2.0
197
+
198
+ Unless required by applicable law or agreed to in writing, software
199
+ distributed under the License is distributed on an "AS IS" BASIS,
200
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201
+ See the License for the specific language governing permissions and
202
+ limitations under the License.
data/README.md CHANGED
@@ -1,29 +1,41 @@
1
+ [![Build Status](https://secure.travis-ci.org/zpatten/lxc.png)](http://travis-ci.org/zpatten/lxc)
2
+ [![Code Climate](https://codeclimate.com/github/zpatten/lxc.png)](https://codeclimate.com/github/zpatten/lxc)
3
+ [![Dependency Status](https://gemnasium.com/zpatten/lxc.png)](https://gemnasium.com/zpatten/lxc)
4
+
1
5
  # LXC
2
6
 
3
- Gem for controlling local or remote Linux Containers (LXC)
7
+ An interface for controlling local or remote Linux Containers (LXC).
8
+
9
+ # RESOURCES
10
+
11
+ Documentation:
4
12
 
5
- ## Installation
13
+ * http://zpatten.github.io/lxc/
6
14
 
7
- Add this line to your application's Gemfile:
15
+ Source:
8
16
 
9
- gem 'lxc'
17
+ * https://github.com/zpatten/lxc
10
18
 
11
- And then execute:
19
+ Issues:
12
20
 
13
- $ bundle
21
+ * https://github.com/zpatten/lxc/issues
14
22
 
15
- Or install it yourself as:
23
+ # LICENSE
16
24
 
17
- $ gem install lxc
25
+ LXC - An interface for controlling local or remote Linux Containers (LXC)
18
26
 
19
- ## Usage
27
+ * Author: Zachary Patten <zachary@jovelabs.com> [![endorse](http://api.coderwall.com/zpatten/endorsecount.png)](http://coderwall.com/zpatten)
28
+ * Copyright: Copyright (c) Zachary Patten
29
+ * License: Apache License, Version 2.0
20
30
 
21
- TODO: Write usage instructions here
31
+ Licensed under the Apache License, Version 2.0 (the "License");
32
+ you may not use this file except in compliance with the License.
33
+ You may obtain a copy of the License at
22
34
 
23
- ## Contributing
35
+ http://www.apache.org/licenses/LICENSE-2.0
24
36
 
25
- 1. Fork it
26
- 2. Create your feature branch (`git checkout -b my-new-feature`)
27
- 3. Commit your changes (`git commit -am 'Added some feature'`)
28
- 4. Push to the branch (`git push origin my-new-feature`)
29
- 5. Create new Pull Request
37
+ Unless required by applicable law or agreed to in writing, software
38
+ distributed under the License is distributed on an "AS IS" BASIS,
39
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
40
+ See the License for the specific language governing permissions and
41
+ limitations under the License.
data/Rakefile CHANGED
@@ -1,2 +1,82 @@
1
- #!/usr/bin/env rake
2
- require "bundler/gem_tasks"
1
+ ################################################################################
2
+ #
3
+ # Author: Zachary Patten <zachary@jovelabs.net>
4
+ # Copyright: Copyright (c) Zachary Patten
5
+ # License: Apache License, Version 2.0
6
+ #
7
+ # Licensed under the Apache License, Version 2.0 (the "License");
8
+ # you may not use this file except in compliance with the License.
9
+ # You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS,
15
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ # See the License for the specific language governing permissions and
17
+ # limitations under the License.
18
+ #
19
+ ################################################################################
20
+
21
+ require 'bundler/gem_tasks'
22
+
23
+ ################################################################################
24
+
25
+ require 'rspec/core/rake_task'
26
+ RSpec::Core::RakeTask.new(:spec)
27
+ task :default => :spec
28
+ task :test => :spec
29
+
30
+ ################################################################################
31
+
32
+ desc "Run RSpec with code coverage"
33
+ task :coverage do
34
+ `rake spec COVERAGE=true`
35
+ case RUBY_PLATFORM
36
+ when /darwin/
37
+ `open coverage/index.html`
38
+ when /linux/
39
+ `google-chrome coverage/index.html`
40
+ end
41
+ end
42
+
43
+ ################################################################################
44
+
45
+ require 'yard'
46
+ require 'yard/rake/yardoc_task'
47
+
48
+ GEM_NAME = File.basename(Dir.pwd)
49
+ DOC_PATH = File.expand_path(File.join("..", "/", "#{GEM_NAME}.doc"))
50
+
51
+ namespace :doc do
52
+ YARD::Rake::YardocTask.new(:pages) do |t|
53
+
54
+ # t.files = ['lib/**/*.rb']
55
+ t.options = ['--verbose', '-o', DOC_PATH]
56
+ end
57
+
58
+ namespace :pages do
59
+
60
+ desc 'Generate and publish YARD Documentation to GitHub pages'
61
+ task :publish => ['doc:pages'] do
62
+ describe = %x(git describe).chomp
63
+ stats = %x(bundle exec yard stats).chomp
64
+
65
+ commit_message = Array.new
66
+ commit_message << "Generated YARD Documentation for #{GEM_NAME.upcase} #{describe}\n\n"
67
+ commit_message << stats
68
+
69
+ Dir.chdir(DOC_PATH) do
70
+ puts(%x{git add -Av})
71
+ puts(%x{git commit -m"#{commit_message.join}"})
72
+ puts(%x{git push origin gh-pages})
73
+ end
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ desc 'Alias to doc:yard'
80
+ task 'doc' => 'doc:yard'
81
+
82
+ ################################################################################
data/bin/lxc-console ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ def lxc_console
4
+ require 'pry'
5
+ require 'lxc'
6
+
7
+ ##
8
+ #
9
+ # Welcome to the LXC RubyGem console!
10
+ #
11
+ ##
12
+ binding.pry
13
+ end
14
+
15
+ begin
16
+ lxc_console
17
+ rescue LoadError => e
18
+ puts "This command should only be executed in development environments; this does not appear to be one!"
19
+ end
data/lib/lxc.rb CHANGED
@@ -1,5 +1,180 @@
1
- require "lxc/version"
1
+ require 'ztk'
2
+
3
+ require 'lxc/version'
4
+
5
+ # Main LXC (Linux Container) Class
6
+ #
7
+ # @author Zachary Patten <zachary@jovelabs.net>
8
+ class LXC
9
+
10
+ # Top-Level Error Class
11
+ class Error < StandardError; end
12
+
13
+ autoload :Container, 'lxc/container'
14
+
15
+ # Controls if sudo is prefixed on all executed commands.
16
+ #
17
+ # @overload use_sudo=(value)
18
+ # Sets if all executed commands should be prefixed with sudo.
19
+ # @param [Boolean] value
20
+ #
21
+ # @overload use_sudo
22
+ # Gets if we are prefixing all executed commands with sudo.
23
+ #
24
+ # @return [Boolean] Returns true if we are prefixing commands with "sudo";
25
+ # otherwise false.
26
+ attr_accessor :use_sudo
27
+
28
+ # Controls if executed commands run locally or remotely via a Net::SSH
29
+ # Session.
30
+ #
31
+ # @overload use_ssh=(value)
32
+ # Sets if all executed commands should be run locally or remotely.
33
+ # To force commands to run locally, assign a value of nil (default).
34
+ # To force commands to run remotely, assign a valid, active, Net::SSH
35
+ # Session.
36
+ #
37
+ # @overload use_ssh
38
+ # Gets if we are executing commands locally or remotely.
39
+ #
40
+ # @return [Net::SSH::Connection::Session] Returns nil if disabled; otherwise
41
+ # returns the assigned Net::SSH Session object.
42
+ attr_accessor :use_ssh
43
+
44
+ # RegEx pattern for extracting the LXC Version from the "lxc-version" command
45
+ # output.
46
+ REGEX_VERSION = /^lxc version:\s+([\w\W]+)$/
47
+
48
+ def initialize
49
+ @use_sudo = false
50
+ @use_ssh = nil
51
+ end
52
+
53
+ # Initialize container object
54
+ #
55
+ # Initalizes an LXC::Container class for the supplied container name.
56
+ #
57
+ # @param [String] name The container name to initalize.
58
+ # @return [LXC::Container] Returns the container object.
59
+ def container(name)
60
+ LXC::Container.new(self, name)
61
+ end
62
+
63
+ # Current containers
64
+ #
65
+ # Initalizes an LXC::Container object for all containers and returns them in
66
+ # an Array.
67
+ #
68
+ # @return [Array<LXC::Container>]
69
+ def containers
70
+ container_names = self.ls
71
+ container_names.map do |container_name|
72
+ LXC::Container.new(self, container_name)
73
+ end
74
+ end
75
+
76
+ # List of containers
77
+ #
78
+ # Runs the "lxc-ls" command.
79
+ #
80
+ # @param [Array] args Additional command-line arguments.
81
+ # @return [Array<String>] A list of container names.
82
+ def ls(*args)
83
+ self.exec("ls", *args).split("\n").uniq
84
+ end
85
+
86
+ # Check if a container exists
87
+ #
88
+ # Checks the container name list to see if the name supplied is an existing
89
+ # container.
90
+ #
91
+ # @param [String] name The name of the container to check.
92
+ # @return [Boolean] Returns true of the container exists, false otherwise.
93
+ def exists?(name)
94
+ self.ls.include?(name)
95
+ end
96
+
97
+ # Linux container processes
98
+ #
99
+ # Runs the "lxc-ps" command.
100
+ #
101
+ # @param [Array] args Additional command-line arguments.
102
+ # @return [Array<String>] Output text of the "lxc-ps" command.
103
+ def ps(*args)
104
+ self.exec("ps", *args).split("\n")
105
+ end
106
+
107
+ # Linux container version
108
+ #
109
+ # Runs the "lxc-version" command.
110
+ #
111
+ # @param [Array] args Additional command-line arguments.
112
+ # @return [String] The installed version of LXC.
113
+ def version(*args)
114
+ result = self.exec("version", *args).scan(REGEX_VERSION)
115
+ result.flatten!.compact!
116
+
117
+ result.first.strip
118
+ end
119
+
120
+ # Linux container configuration check
121
+ #
122
+ # Runs the "lxc-checkconfig" command.
123
+ #
124
+ # @param [Array] args Additional command-line arguments.
125
+ # @return [Array<String>] Output text of the "lxc-ps" command.
126
+ def checkconfig(*args)
127
+ self.exec("checkconfig", *args).split("\n")
128
+ end
129
+
130
+ # Linux container command execution wrapper
131
+ #
132
+ # Runs the supplied LXC command. The first element in the "args" splat is the
133
+ # command to be execute, the rest of the elements are treated as command line
134
+ # arguments.
135
+ #
136
+ # If use_sudo is true then all commands will be prefix with "sudo".
137
+ # If use_ssh is non-nil then all commands will be execute via the assigned
138
+ # Net::SSH Session.
139
+ #
140
+ # No internal checking is performed against the object assigned to use_ssh as
141
+ # to avoid an un-necessary direct dependency on the net-ssh gems.
142
+ #
143
+ # @param [Array] args Additional command-line arguments.
144
+ # @return [Array<String>] Stripped output text of the executed command.
145
+ def exec(*args)
146
+ command = args.shift
147
+
148
+ arguments = Array.new
149
+ arguments << "sudo" if (@use_sudo == true)
150
+ arguments << "lxc-#{command}"
151
+ arguments << args
152
+ arguments = arguments.flatten.compact.join(' ')
153
+
154
+ output = Array.new
155
+
156
+ if @use_ssh.nil?
157
+ ::ZTK::PTY.spawn(arguments) do |reader, writer, pid|
158
+ while (buffer = reader.readpartial(1024))
159
+ output << buffer
160
+ end
161
+ end
162
+ else
163
+ output << @use_ssh.exec!(arguments)
164
+ end
165
+
166
+ output.join.strip
167
+ end
168
+
169
+ # Provides a concise string representation of the class
170
+ # @return [String]
171
+ def inspect
172
+ tags = Array.new
173
+ tags << "use_sudo=#{@use_sudo}" if @use_sudo
174
+ tags << (@use_ssh.nil? ? "use_ssh=false" : "use_ssh=true")
175
+ tags = tags.join(' ')
176
+
177
+ "#<LXC #{tags}>"
178
+ end
2
179
 
3
- module Lxc
4
- # Your code goes here...
5
180
  end