├── .gitignore
├── Gemfile
├── LICENSE
├── NEVERWINTERDP
├── README.md
├── Rakefile
├── VAGRANT-FLOW
├── create_sample_ansible-inventory_input-file.rb
├── create_sample_hostfile_digitalocean_input-file.rb
├── create_sample_multiinit_input-file.rb
├── create_sample_multiinit_input-file_digitalocean.rb
├── create_sample_playbook_input-file.rb
├── lib
├── vagrant-flow.rb
└── vagrant-flow
│ ├── command
│ ├── ansibleinventory.rb
│ ├── digitalocean_api.rb
│ ├── getDOtoken.rb
│ ├── hostfile.rb
│ ├── installDOToken.rb
│ ├── multicommand.rb
│ ├── multiinit.rb
│ ├── playbook.rb
│ └── root.rb
│ ├── plugin.rb
│ ├── templates
│ └── multiinit.erb
│ └── version.rb
└── vagrant-flow.gemspec
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | *.rbc
3 | .bundle
4 | .config
5 | .yardoc
6 | Gemfile.lock
7 | InstalledFiles
8 | _yardoc
9 | coverage
10 | doc/
11 | lib/bundler/man
12 | pkg
13 | rdoc
14 | spec/reports
15 | test/tmp
16 | test/version_tmp
17 | tmp
18 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source "https://rubygems.org"
2 |
3 | gemspec
4 |
5 | group :development do
6 | # We depend on Vagrant for development, but we don't add it as a
7 | # gem dependency because we expect to be installed within the
8 | # Vagrant environment itself using `vagrant plugin`.
9 |
10 | # Can use for testing
11 | # gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git"
12 | end
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 | A NeverwinterDP and DemandCube Project
633 | Copyright (C) 2012 Steve Morin steve@stevemorin.com and DemandCube Inc steve@demandcube.com
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published by
637 | the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/NEVERWINTERDP:
--------------------------------------------------------------------------------
1 |
2 | /\
3 | / \
4 | / /\ \
5 | / ____ \
6 | /_/ _ \_\_____ ________ _______ _______ _ _ _______ ______ _____ _____ _____
7 | | \ | | ____\ \ / / ____| __ \ \ / /_ _| \ | |__ __| ____| __ \| __ \| __ \
8 | | \| | |__ \ \ / /| |__ | |__) \ \ /\ / / | | | \| | | | | |__ | |__) | | | | |__) |
9 | | . ` | __| \ \/ / | __| | _ / \ \/ \/ / | | | . ` | | | | __| | _ /| | | | ___/
10 | | |\ | |____ \ / | |____| | \ \ \ /\ / _| |_| |\ | | | | |____| | \ \| |__| | |
11 | |_| \_|______| \/ |______|_| \_\ \/ \/ |_____|_| \_| |_| |______|_| \_\_____/|_|
12 | | |
13 | __ _ _ __ __| |
14 | / _` | '_ \ / _` |
15 | | (_| | | | | (_| |
16 | \__,_|_| |_|\__,_|
17 | _____ ______ __ __ _ _ _____ _____ _ _ ____ ______
18 | | __ \| ____| \/ | /\ | \ | | __ \ / ____| | | | _ \| ____|
19 | | | | | |__ | \ / | / \ | \| | | | | | | | | | |_) | |__
20 | | | | | __| | |\/| | / /\ \ | . ` | | | | | | | | | _ <| __|
21 | | |__| | |____| | | |/ ____ \| |\ | |__| | |____| |__| | |_) | |____
22 | |_____/|______|_|_ |_/_/ \_\_| \_|_____/ \_____|\____/|____/|______|
23 | (_) | |
24 | _ __ _ __ ___ _ ___ ___| |_
25 | | '_ \| '__/ _ \| |/ _ \/ __| __|
26 | | |_) | | | (_) | | __/ (__| |_
27 | | .__/|_| \___/| |\___|\___|\__|
28 | | | _/ |
29 | |_| |__/
30 |
31 | http://www.demandcube.com
32 | http://www.neverwinterdp.com
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vagrant-Flow
2 |
3 | Vagrant-Flow enables a seamless development to production workflow.
4 |
5 | Vagrant-Flow is a [vagrant] (http://www.vagrantup.com/) plugin which allows for a separation of ansible playbooks from vagrant, mimicing how development works. It enables the generates ansible inventory files, vagrant templates and inter-machine communication to easily prepare to run ansible playbooks and machine communication.
6 |
7 | - This is part of [NeverwinterDP the Data Pipeline for Hadoop](https://github.com/DemandCube/NeverwinterDP)
8 |
9 |
10 | ## Installation
11 |
12 | ```
13 | #This is so 'vagrant flow hostfile' can automatically connect to digital ocean machines
14 | #Otherwise it will hang when dealing with remote hosts
15 | echo "StrictHostKeyChecking no" >> ~/.ssh/config
16 |
17 | #If you're on OSX
18 | #This step may no longer be necessary as vagrant-digitalocean shouldn't require it anymore
19 | brew install curl-ca-bundle
20 |
21 |
22 | vagrant plugin install vagrant-digitalocean
23 | vagrant plugin install vagrant-flow
24 | vagrant flow installdotoken [your digital ocean token]
25 | ```
26 |
27 | ## Contributing
28 |
29 | See the [NeverwinterDP Guide to Contributing] (https://github.com/DemandCube/NeverwinterDP#how-to-contribute)
30 |
31 |
32 | * * *
33 |
34 | ## Usage and Specs
35 | vagrant-flow has 1 command `flow` and the following subcommands:
36 |
37 | ```
38 | installdotoken
39 | multiinit
40 | hostfile
41 | ansibleinventory
42 | playbook
43 | multicommand
44 | ```
45 | - installdotoken
46 | - Installs your digital ocean token to be able to use the digital ocean provider
47 | - multiinit
48 | - Creates a template Vagrantfile based on the machines you specify
49 | - hostfile
50 | - Creates a hostfile and copies it to each VM so that machine can talk to each other
51 | - ansibleinventory
52 | - Create a ansible machine inventory file so that you can use ansible to provision the machines
53 | - playbook
54 | - Uses a confile to run ansible-play book to provision one or more VM's
55 | - multicommand
56 | - Runs shell command on multiple machines
57 |
58 | Example flow to be enabled
59 | ```
60 | vagrant plugin install vagrant-flow
61 | vagrant flow installdotoken -t xxxxxyyyyyyzzzz123
62 | git clone http://github.com/DemandCube/DeveloperPlaybooks
63 | mkdir devsetup
64 | cd devsetup
65 | vagrant flow multiinit -l boxname1:demandcube/centos-65_x86_64-VB-4.3.8,boxname2:demandcube/centos-65_x86_65-VB-4.3.8
66 | vagrant up
67 | vagrant flow hostfile
68 | vagrant flow ansibleinventory
69 |
70 | # Then
71 |
72 | vagrant flow playbook
73 | # or
74 | ansible-playbook -i ansible-flow_inventoryfile ../DeveloperPlaybooks/site.yml
75 |
76 | vagrant flow multicommand -c "/opt/startserver.sh"
77 |
78 | #communication test
79 | vagrant ssh boxname1 ping boxname2
80 | vagrant ssh boxname2 ping boxname1
81 | ```
82 |
83 | #DemandCube Boxes
84 | Publically available boxes in vagrantcloud from DemandCube:
85 | - vagrant init demandcube/centos-64_x86_64-VB-4.3.8
86 | - vagrant init demandcube/centos-65_x86_64-VB-4.3.8
87 |
88 |
89 |
90 | # Usage
91 |
92 | * * *
93 | ##installdotoken
94 | Usage: vagrant flow multicommand [-qf] -c COMMAND
95 | Installs your digital ocean key for easy vagrant-flow configuration
96 |
97 | -q, --quiet (Optional) Suppress output to STDOUT and STDERR
98 | -t, --token TOKEN (REQUIRED) The token to install
99 | -h, --help Print this help
100 |
101 | Example: This will isntall your token to ~/.vagrant-flow for use in other plugins
102 | ```
103 | vagrant flow installdotoken -t abcddefjdaj1243
104 | ```
105 |
106 | * * *
107 | ## multiinit
108 | ```
109 | Usage: vagrant flow multiinit [-hgliq]
110 | This looks for multiinit.yml as the default configuration
111 |
112 | -g FILEPATH, (Optional) YAML file containing vagrant cloud config
113 | --vagrant_multiinit_config_file
114 | -l hostname:cloud/location,hostname2:cloud/location2,hostname3:cloud/location3,
115 | --list List of cloud config parameters
116 | -i, --vboxintnet NAME (Optional) Custom virtualbox__intnet name for private network
117 | -q, --quiet (Optional) Suppress output to STDOUT and STDERR
118 | -h, --help Print this help
119 | ```
120 |
121 | #### Example usages of multiinit
122 | This will look for a file in the pwd named multiinit.yml and attempt to make the Vagrantfile
123 | ```
124 | vagrant flow multiinit
125 | ```
126 |
127 |
128 |
129 | This will look for a file in the pwd named myOwnGroupConfig.yml and attempt to make the inventory
130 | ```
131 | vagrant flow multiinit -g myOwnMultiInitConfig.yml
132 | ```
133 |
134 |
135 |
136 | This will read in from the command line a list of [vm_name]:[url] combinations. It MUST follow the following format. The -i option will also set the virtualbox__intnet name to a custom option ("virtualboxprivatenet" in this case)
137 | ```
138 | vagrant flow multiinit -l boxname1:demandcube/centos-65_x86_64-VB-4.3.8,boxname2:demandcube/centos-65_x86_65-VB-4.3.8,box3:provider/boxname -i virtualboxprivatenet
139 | ```
140 |
141 |
142 | ### Use case
143 | ```
144 | #Create your multi-box Vagrantfile
145 | vagrant flow multiinit
146 | #Launch the boxes
147 | vagrant up
148 | #Or launch with digitalocean
149 | vagrant up --provider=digital_ocean
150 | ```
151 |
152 | Example multiinitconfig.yml file (for use with no optional command line arguments or by pointing to non-default file with -g option). The format and parameters of this yaml file MUST be followed, but can easily be expanded to include more of fewer machines
153 | ```
154 | ---
155 | :intnetName: neverwinterDP
156 | machines:
157 | #This will use all defaults and create a guest named machine1
158 | - name: machine1
159 | #Create another machine, but specify which .box to use with virtual box
160 | - name: server1
161 | url: demandcube/centos-64_x86_64-VB-4.3.8
162 | - name: jenkinstestmachine
163 | url: demandcube/centos-65_x86_64-VB-4.3.8
164 |
165 | ```
166 |
167 | Example multiinitconfig.yml file for use with virtualbox and digitalocean providers. All the extra parameters are required to make digitalocean work. Get your digitalOcean token by logging in and generating a new token under "Apps & API"
168 |
169 | Details on [vagrant-digitalocean](https://github.com/smdahlen/vagrant-digitalocean)
170 |
171 | ```
172 | ---
173 | #Where your ssh private key lives (for use with digital ocean)
174 | #~/.ssh/id_rsa is the default, so you can omit this value if you want
175 | :sshPrivateKeyPath: ~/.ssh/id_rsa
176 |
177 |
178 | :intnetName: neverwinterDP
179 | machines:
180 | #Create a box with all defaults set for you
181 | - name: fulldefaults
182 |
183 | #Use a custom url for your virtual box image
184 | - name: customvboxurl
185 | url: demandcube/centos-64_x86_64-VB-4.3.8
186 |
187 | #Set custom config for digitalocean
188 | - name: digitaloceancustom
189 | digitalOceanRegion: nyc2
190 | digitalOceanImage: Debian 7.0 x64
191 | #Valid options for digitalOceanRegion:
192 | #nyc1, ams1, sfo1, nyc2, ams2, sgp1, lon1
193 | #Default is sfo1
194 |
195 | #Set custom config for vbox and digitaloceanprovider
196 | - name: digitaloceanvboxcustom
197 | url: demandcube/centos-64_x86_64-VB-4.3.8
198 | digitalOceanRegion: sgp1
199 | digitalOceanImage: Debian 7.0 x64
200 |
201 | #Set custom config for vbox and digitaloceanprovider and sets amount of RAM
202 | - name: digitaloceanvboxcustom
203 | url: demandcube/centos-64_x86_64-VB-4.3.8
204 | digitalOceanRegion: sfo1
205 | digitalOceanImage: Debian 7.0 x64
206 | ram: 2GB
207 | #Valid options for RAM (This is a digital ocean restriction):
208 | # 512MB, 1GB, 2GB, 4GB, 8GB, 16GB, 32GB, 48GB, 64GB
209 | #Default RAM is 512MB
210 |
211 | ```
212 |
213 | * * *
214 | ##hostfile
215 | Usage: vagrant flow hostfile [-qndoh]
216 | Edits all your VMs /etc/hosts file to be able to find all the machines on your private network
217 |
218 | -q, --quiet (Optional) Suppress output to STDOUT and STDERR
219 | -n, --no-write-hosts (Optional) Don't actually write a new hosts file to the guest machine
220 | -d, --digitalocean (Optional) Writes your digital ocean's hostnames and IP addresses to hosts file. Default file is hostfile_do.yml
221 | -o, --digitaloceanfile FILE (Optional) File to read in for -d option instead of hostfile_do.yml
222 | -h, --help Print this help
223 |
224 | #### Example usages of hostfile
225 | This will look through your vagrantfile config, find all the hostnames and IP's configured in your private_network, and append that information to all your machine's /etc/hosts file
226 | ```
227 | vagrant flow hostfile
228 | ```
229 |
230 | This will make an API call to digital ocean (https://developers.digitalocean.com/droplets/), retrieve your list of hostnames and Ip's, and append that information retrieved from DO to the VM's hosts file specified in your Vagrantfile.
231 | This option requires you first run vagrant flow installdotoken -t [your token here]
232 | ```
233 | vagrant flow hostfile -d
234 | ```
235 |
236 | * * *
237 | ## ansibleinventory
238 | ```
239 | Usage: vagrant flow ansibleinventory [-hgpq]
240 | This plugin looks for groupconfig.yml as the default configuration
241 | Do not use -p and -g options together!
242 |
243 | -g, --group_config_file FILEPATH (Optional) YAML file containing group config
244 | -p, --vagrantfileparse (Optional) Read in the VAGRANTFILE's ansible group config
245 | -q, --quiet (Optional) Suppress output to STDOUT and STDERR
246 | -h, --help (Optional) Print this help
247 | ```
248 |
249 | #### Example usages of ansibleinventory
250 | This will look for a file in the pwd named groupconfig.yml and attempt to make the inventory
251 | ```
252 | vagrant flow ansibleinventory
253 | ```
254 |
255 |
256 |
257 | This will look for a file in the pwd named myOwnGroupConfig.yml and attempt to make the inventory
258 | ```
259 | vagrant flow ansibleinventory -g myOwnGroupConfig.yml
260 | ```
261 |
262 |
263 |
264 | This will parse the vagrant file for ansible group configs
265 | ```
266 | vagrant flow ansibleinventory -p
267 | ```
268 |
269 |
270 |
271 |
272 |
273 | ### Use case
274 | ```
275 | #Bring up your vagrant machines
276 | vagrant up
277 | #Run ansible inventory (this assumes the file groupconfig.yml exists)
278 | vagrant flow ansibleinventory
279 | #point ansible-playbook to the generated vagrant-flow_ansible_inventory, and point them to whatever playbook you'd like
280 | ansible-playbook -i path/to/vagrant-flow_ansible_inventory my_playbook.yml
281 | ```
282 |
283 | Example groupconfig.yml file (for use with no optional command line arguments or by pointing to non-default file with -g option)
284 | ```
285 | ---
286 | common:children:
287 | - testgroup
288 | - servergroup
289 | testgroup:
290 | - testbox
291 | servergroup:
292 | - server1
293 | - server2
294 | ```
295 |
296 | Example VAGRANTFILE excerpt (for use with -p option):
297 | ```
298 | config.vm.provision "ansible" do |ansible|
299 | #ansible.playbook is required, but emptyplaybook.yml can do nothing,
300 | #this way we bypass vagrant's embedded ansible plugin
301 | ansible.playbook="emptyplaybook.yml"
302 | ansible.groups = {
303 | "testgroup" => ["testbox"],
304 | "servergroup" => ["server1", "server2"],
305 | "common:children" => ["testgroup","servergroup"] #Common things on per-group basis
306 | }
307 | end
308 | ```
309 |
310 | Example playbook.yml to use after ansible-inventory has run with command `ansible-playbook -i vagrant-flow_ansible_inventory playbook.yml`:
311 | ```
312 | ---
313 | #Configures the groups defined in common:children
314 | - hosts: common
315 | remote_user: root
316 | roles:
317 | - common
318 |
319 | #Configures all machines in the group "testgroup"
320 | - hosts: testgroup
321 | remote_user: root
322 | roles:
323 | - jenkins
324 |
325 | #Configures specific machine server1
326 | - hosts: server1
327 | roles:
328 | - apache
329 | ```
330 |
331 | Example output (file will be called vagrant-flow_ansible_inventory)
332 | ```
333 | # Generated by vagrant-flow, part of NeverwinterDP
334 |
335 | [testgroup]
336 | jenkins ansible_ssh_host=127.0.0.1 ansible_ssh_port=2201 ansible_ssh_user=vagrant ansible_ssh_private_key_file=/Users/rcduar/.vagrant.d/insecure_private_key # Machine Name: jenkins
337 |
338 | [servergroup]
339 | server1 ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 ansible_ssh_user=vagrant ansible_ssh_private_key_file=/Users/user/.vagrant.d/insecure_private_key # Machine Name: server1
340 |
341 | [common:children]
342 | testgroup
343 | servergroup
344 | ```
345 |
346 | * * *
347 | ##playbook
348 | ```
349 | Usage: vagrant flow playbook [-hpf]
350 | Reads in config from flow-playbook.yml by default to be able to run ansible-playbook more easily
351 |
352 | -f, --file-playbook FILE (Optional) Use a specified playbook config file instead of default (flow-playbook.yml)
353 | -p, --print-only (Optional) Don't actually ansible-playbook, but just output what would be run to STDOUT
354 | -q, --quiet (Optional) Suppress output to STDOUT and STDERR
355 | -h, --help Print this help
356 | ```
357 |
358 | This will run ansible-playbook based on the config in flow-playbook.yml
359 | ```
360 | vagrant flow playbook
361 | ```
362 |
363 | This will run ansible-playbook based on the config in myOwnConfig.yml
364 | ```
365 | vagrant flow playbook -f myOwnConfig.yml
366 | ```
367 |
368 | This will not actually run ansible-playbook, but will only output the command it would run to STDOUT
369 | ```
370 | vagrant flow playbook -p
371 | ```
372 | The output from the above command using -p will look like this:
373 | ```
374 | ansible-playbook -i vagrant-flow_ansible_inventory myPlaybooks/main.yml
375 | ```
376 |
377 | ###Expectations:
378 | Example flow-playbook.yml file
379 | ```
380 | ---
381 | :playbook: defaultplaybook.yml #Required
382 | :inventory: vagrant-flow_ansible_inventory #Required
383 | :pattern: '*' #Optional. Will be used in conjunction like so 'ansible-playbook -l [pattern] -i [inventory] -p [playbook]'
384 | ```
385 |
386 | * * *
387 | ##multicommand
388 | ```
389 | Usage: vagrant flow multicommand [-qf] -c COMMAND
390 | Runs a shell command on specified machines in your vagrantfile
391 |
392 | -q, --quiet (Optional) Suppress output to STDOUT and STDERR
393 | -f VMNAME,VNAME2..., (Optional) comma separated list of machines to run command on
394 | --filterMachine
395 | -c, --command COMMAND (REQUIRED) Command to run on the machines
396 | -h, --help Print this help
397 | ```
398 |
399 | This will run a command on all the machines in your Vagrantfile
400 | ```
401 | vagrant flow multicommand -c "ls -la"
402 | ```
403 |
404 | This will run a command ONLY on machines named flowTest1 and flowTest2
405 | ```
406 | vagrant flow multicommand -c "ls -la" -f flowTest1,flowTest2
407 | ```
408 |
409 | * * *
410 |
411 | ## Development Flow
412 |
413 | ```
414 | # cd to vagrant-flow
415 |
416 | # build the plugin
417 |
418 | rake build
419 |
420 | # install the plugin locally
421 |
422 | vagrant plugin install pkg/vagrant-flow-1.0.3.gem
423 |
424 | #
425 | # use it and test
426 | #
427 |
428 | vagrant plugin uninstall vagrant-flow
429 |
430 |
431 | #
432 | # when done testing and ready to publish
433 | #
434 |
435 | rake release
436 |
437 |
438 | # install for real from the repo
439 |
440 | vagrant plugin install vagrant-flow
441 |
442 | ```
443 |
444 | # Background Research
445 |
446 | Vagrant Plugin List
447 | =====
448 | *
449 |
450 | Creating a Gem
451 | =====
452 | * Tutorial <>
453 | *
454 |
455 | Below is how to install as a regular gem which won't work
456 |
457 | Add this line to your application's Gemfile:
458 |
459 | gem 'vagrant-flow'
460 |
461 | And then execute:
462 |
463 | $ bundle
464 |
465 | Or install it yourself as:
466 |
467 | $ gem install vagrant-flow
468 |
469 | * * *
470 |
471 | Commands
472 |
473 | ```
474 |
475 | bundle gem lorem # will generate a directory 'lorem' with stubs for a gem
476 | gem build lorem.gemspec # Build the ruby gem
477 | gem push lorem-0.0.1.gem # Push the gem to rubygems.org
478 | bundle # Uses Gemfile to download and install necessary dependencies
479 | rake -T # Shows tasks in the Rakefile, some added by bundler
480 | # with Bundler::GemHelper.install_tasks
481 | rake build # It's a helper that will build your gem
482 | rake install # It's a helper that will build and install locally
483 | rake release # It's a helper that will push/release to rubygems
484 |
485 | ```
486 |
487 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'bundler'
3 | require 'bundler/setup' # Was in the example
4 | require 'bundler/gem_tasks' # Was in the template version
5 |
6 | # Immediately sync all stdout so that tools like buildbot can
7 | # immediately load in the output.
8 | $stdout.sync = true
9 | $stderr.sync = true
10 |
11 | # Change to the directory of this file.
12 | Dir.chdir(File.expand_path("../", __FILE__))
13 |
14 | # This installs the tasks that help with gem creation and
15 | # publishing.
16 | Bundler::GemHelper.install_tasks
17 |
18 |
19 |
20 | namespace :flow do
21 | desc 'noop does nothing'
22 | task(:noop) do
23 | puts("noop\n")
24 | end
25 |
26 | desc 'Removes testing vagrant box.'
27 | task(:cleanup) do
28 | # example running vagrant tasks
29 | # system('bundle exec vagrant destroy -f')
30 | # system('bundle exec vagrant box remove vagrant_exec virtualbox')
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/VAGRANT-FLOW:
--------------------------------------------------------------------------------
1 | __ __ _____ _____ _ _ _______ ______ _ ______ __
2 | \ \ / /\ / ____| __ \ /\ | \ | |__ __| | ____| | / __ \ \ / /
3 | \ \ / / \ | | __| |__) | / \ | \| | | |______| |__ | | | | | \ \ /\ / /
4 | \ \/ / /\ \| | |_ | _ / / /\ \ | . ` | | |______| __| | | | | | |\ \/ \/ /
5 | \ / ____ \ |__| | | \ \ / ____ \| |\ | | | | | | |___| |__| | \ /\ /
6 | \/_/ \_\_____|_| \_\/_/ \_\_| \_| |_| |_| |______\____/ \/ \/
7 | /\
8 | / \
9 | / /\ \
10 | / ____ \
11 | /_/___ \_\ _ _____ _
12 | | __ \ | |/ ____| | |
13 | | | | | ___ _ __ ___ __ _ _ __ __| | | _ _| |__ ___
14 | | | | |/ _ \ '_ ` _ \ / _` | '_ \ / _` | | | | | | '_ \ / _ \
15 | | |__| | __/ | | | | | (_| | | | | (_| | |___| |_| | |_) | __/
16 | |_____/ \___|_| |_| |_|\__,_|_| |_|\__,_|\_____\__,_|_.__/ \___|
17 | | __ \ (_) | |
18 | | |__) | __ ___ _ ___ ___| |_
19 | | ___/ '__/ _ \| |/ _ \/ __| __|
20 | | | | | | (_) | | __/ (__| |_
21 | |_| |_| \___/| |\___|\___|\__|
22 | _/ |
23 | |__/
--------------------------------------------------------------------------------
/create_sample_ansible-inventory_input-file.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 |
4 |
5 | ###This shows how to make a valid configuration file in YAML format for vagrant-flow to consume with the ansible-inventory command
6 |
7 | x = {
8 | "common:children"=>["jenkins","server"],
9 | "jenkins"=>["jenkinsdp"],
10 | "server"=>["sparkngin1","sparkngin2"],
11 | }
12 |
13 | begin
14 | File.open('groupconfig.yml', 'w') {|f| f.write x.to_yaml }
15 | rescue
16 | warn "Could not write file groupconfig.yml"
17 | end
18 |
19 | y = YAML.load(x.to_yaml)
20 |
21 | y.each {|key,value|
22 | puts key
23 | puts value
24 | puts "\n"
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/create_sample_hostfile_digitalocean_input-file.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 |
4 |
5 | ###This shows how to make a valid configuration file in YAML format for vagrant-flow to consume with the ansible-inventory command
6 |
7 | x = {
8 | :api_key => "apikeygoeshere",
9 | :client_id => "clientidgoeshere",
10 | }
11 |
12 | begin
13 | File.open('hostfile_do.yml', 'w') {|f| f.write x.to_yaml }
14 | rescue
15 | warn "Could not write file hostfile_do.yml"
16 | end
17 |
18 | y = YAML.load(x.to_yaml)
19 |
20 | y.each {|key,value|
21 | puts key
22 | puts value
23 | puts "\n"
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/create_sample_multiinit_input-file.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 |
4 |
5 | ###This shows how to make a valid configuration file in YAML format for vagrant-flow to consume with the ansible-inventory command
6 | x = {
7 | :intnetName=>"neverwinterDP",
8 | "machines" => [
9 | {"name"=>"sparkngin1", "url"=>"demandcube/centos-65_x86_64-VB-4.3.8"},
10 | {"name"=>"sparkngin2", "url"=>"demandcube/centos-65_x86_64-VB-4.3.8"},
11 | {"name"=>"jenkinsdp", "url"=>"demandcube/centos-65_x86_64-VB-4.3.8"},
12 | ]
13 | }
14 |
15 | begin
16 | File.open('multiinitconfig.yml', 'w') {|f|
17 | f.write x.to_yaml
18 | }
19 | rescue
20 | warn "Could not write file multiinit.yml"
21 | end
22 |
23 |
24 | y = YAML.load(x.to_yaml)
25 |
26 | y.each {|key,value|
27 | puts key
28 | puts value
29 | puts "\n"
30 | }
31 |
--------------------------------------------------------------------------------
/create_sample_multiinit_input-file_digitalocean.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 |
4 |
5 | ###This shows how to make a valid configuration file in YAML format for vagrant-flow to consume with the ansible-inventory command
6 | x = {
7 | #~/.ssh/id_rsa is also the default
8 | :sshPrivateKeyPath =>"~/.ssh/id_rsa",
9 |
10 | #These two keys must be set for digitalocean to work
11 | #Omit them if you don't want digitalocean as a provider option in your vagrantfile
12 | :digitalOceanApiKey => "123456789098765432",
13 | :digitalOceanClientId => "fytudisughfsdalk",
14 |
15 | :intnetName=>"neverwinterDP",
16 | "machines" => [
17 | {"name"=>"fulldefaults"},
18 | {"name"=>"customvboxurl", "url"=>"demandcube/centos-64_x86_64-VB-4.3.8",},
19 | {"name"=> "digitaloceancustom", "digitalOceanRegion" => "New York 2", "digitalOceanImage"=>"Debian 7.0 x64"},
20 | {"name"=> "digitaloceanvboxcustom", "url"=>"demandcube/centos-64_x86_64-VB-4.3.8", "digitalOceanRegion" => "New York 2", "digitalOceanImage"=>"Debian 7.0 x64" },
21 | {"name"=> "digitaloceanvboxcustomwithRam", "url"=>"demandcube/centos-64_x86_64-VB-4.3.8", "digitalOceanRegion" => "New York 2", "digitalOceanImage"=>"Debian 7.0 x64", "ram"=>"2GB" },
22 | ]
23 | }
24 |
25 | begin
26 | File.open('multiinitconfig.yml', 'w') {|f|
27 | f.write x.to_yaml
28 | }
29 | rescue
30 | warn "Could not write file multiinit.yml"
31 | end
32 |
33 |
34 | y = YAML.load(x.to_yaml)
35 |
36 | y.each {|key,value|
37 | puts key
38 | puts value
39 | puts "\n"
40 | }
41 |
--------------------------------------------------------------------------------
/create_sample_playbook_input-file.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 |
4 |
5 | ###This shows how to make a valid configuration file in YAML format for vagrant-flow to consume with the ansible-inventory command
6 | x = {
7 | :playbook => "defaultplaybook.yml",
8 | :inventory => "vagrant-flow_ansible_inventory",
9 | #:pattern => "*", #:pattern is optional
10 | }
11 |
12 | begin
13 | File.open('flow-playbook.yml', 'w') {|f|
14 | f.write x.to_yaml
15 | }
16 | rescue
17 | warn "Could not write file flow-playbook.yml"
18 | end
19 |
20 |
21 | y = YAML.load(x.to_yaml)
22 |
23 | y.each {|key,value|
24 | puts key
25 | puts value
26 | puts "\n"
27 | }
28 |
--------------------------------------------------------------------------------
/lib/vagrant-flow.rb:
--------------------------------------------------------------------------------
1 | require 'vagrant'
2 |
3 | require 'vagrant-flow/plugin'
4 | require 'vagrant-flow/version'
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/ansibleinventory.rb:
--------------------------------------------------------------------------------
1 | require 'optparse'
2 | require "vagrant"
3 | require "yaml"
4 |
5 | module VagrantPlugins
6 | module CommandVagrantFlow
7 | module Command
8 | class AnsibleInventory < Vagrant.plugin("2", :command)
9 |
10 | # Builtin from Command class
11 | # Must override to provide a description
12 | def self.synopsis
13 | "generates a ansible inventory file from the vagrant environment"
14 | end
15 |
16 |
17 | # Builtin from Command class
18 | # Must override to provide core functionality
19 | def execute
20 |
21 | machines_configs = {}
22 | inventory_configs = {}
23 |
24 | default_group_config_file = "groupconfig.yml"
25 | options = {}
26 | options[:destroy_on_error] = true
27 | options[:parallel] = false
28 | options[:provision_ignore_sentinel] = false
29 | options[:quiet] = false
30 |
31 | #Setting to read in a file other than default_group_config_File
32 | options[:custom_config_file] = false
33 | #Setting to parse the VAGRANTFILE's ansible group config
34 | options[:vagrantFileAnsibleConfig] = false
35 |
36 | #Parse option, look up OptionParser documentation
37 | opts = OptionParser.new do |o|
38 | # o.banner = "Usage: vagrant ansible-inventory [vm-name] [options] [-h]"
39 | o.banner = "A NeverWinterDP technology from the Department of Badass.\n\n"+
40 | "Usage: vagrant flow ansibleinventory [-hgpq]\nThis looks for groupconfig.yml as the default configuration\n"+
41 | "Do not use -p and -g options together!"
42 | o.separator ""
43 | o.on("-g", "--group_config_file FILEPATH", "(Optional) YAML file containing group config") do |f|
44 | options[:custom_config_file] = f
45 | end
46 |
47 | o.on("-p", "--vagrantfileparse", "(Optional) Read in the VAGRANTFILE's ansible group config") do |f|
48 | options[:vagrantFileAnsibleConfig] = true
49 | end
50 |
51 | o.on("-q", "--quiet", "(Optional) Suppress output to STDOUT and STDERR") do |f|
52 | options[:quiet] = true
53 | end
54 |
55 | end
56 |
57 | # Parse the options # Builtin from the Command Class
58 | # Will safely parse the arguments and
59 | # Automatically detects -h for help
60 | argv = parse_options(opts)
61 | return if !argv
62 |
63 |
64 |
65 | # The following are already setup by the parent class
66 | # @env
67 | # @logger
68 | # @argv
69 |
70 | # Go over each VM and bring it up
71 | @logger.debug("'ansible-inventory' created for the whole env")
72 |
73 | #Initialize group_machines, the has containing group=>machinename configs
74 | group_machines={}
75 |
76 | #Get info about the vagrant boxes
77 | with_target_vms(argv, :provider => options[:provider]) do |machine|
78 | # @env.ui
79 | # output methods: :ask, :detail, :warn, :error, :info, :output, :success
80 | # https://github.com/mitchellh/vagrant/blob/master/lib/vagrant/ui.rb
81 |
82 | ssh_info = machine.ssh_info
83 | raise Vagrant::Errors::SSHNotReady if ssh_info.nil?
84 |
85 | variables = {
86 | :host_key => options[:host] || machine.name || "vagrant",
87 | :ssh_host => ssh_info[:host],
88 | :ssh_port => ssh_info[:port],
89 | :ssh_user => ssh_info[:username],
90 | :private_key_path => ssh_info[:private_key_path],
91 | :forward_agent => ssh_info[:forward_agent],
92 | :forward_x11 => ssh_info[:forward_x11]
93 | }
94 | # Outputs to the stdout
95 |
96 | inventory_configs = {
97 | :vagrant_file_dir => machine.env.root_path,
98 | :vagrant_flow_file => machine.env.root_path.join("vagrant-flow_ansible_inventory")
99 | }
100 |
101 | machines_configs[variables[:host_key]]= variables
102 | end
103 |
104 | #Hash containing group/machine configuration
105 | group_machines={}
106 | #Determine group_machines based on what config options are passed in
107 | #Read in config from vagrantfile's ansible config
108 | if options[:vagrantFileAnsibleConfig] == true
109 | provisioners = []
110 | with_target_vms(argv, :provider => options[:provider]) do |machine|
111 | #The provisioning information from teh vagrant file, this will contain our defined ansible groups
112 | #Concatenate all the provisioner configs together
113 | if machine.config.vm.provisioners
114 | provisioners.concat(machine.config.vm.provisioners)
115 | end
116 | end
117 | #Since Vagrant machines will likely contain the same configs,
118 | #Merge the config together to remove duplicate entries in our
119 | #group/machine configuration
120 | provisioners.each {|prov|
121 | group_machines = group_machines.merge(prov.config.groups)
122 | }
123 | #Read in config from yaml file
124 | else
125 | #Use config option if specified
126 | if options[:custom_config_file] != false
127 | default_group_config_file = options[:custom_config_file]
128 | end
129 | begin
130 | #Load YAML
131 | group_machines = YAML.load_file(default_group_config_file)
132 | rescue
133 | #Give warning if no file could be found
134 | if not options[:quiet]
135 | warn "Could not open file: "+default_group_config_file.to_s
136 | end
137 | end
138 | end
139 |
140 |
141 |
142 | # Outputs to the stdout
143 | # @env.ui.info(machine.name)
144 |
145 | # From - Vagrant::Util::SafePuts
146 | # Template is erb
147 |
148 | # Implementation picks the first key
149 | # ssh_info[:private_key_path] returns an array
150 |
151 | #outputs is going to contain our strings that are the formatted ansible configs
152 | #the key will be the vm name, the value will the be formatted sring
153 | outputs = {}
154 |
155 | inventory_configs[:vagrant_flow_file].open('w') do |file|
156 | machines_configs.each do |host, variables|
157 | ansible_template = '<%= host_key %> ansible_ssh_host=<%= ssh_host %> ansible_ssh_port=<%= ssh_port %> ansible_ssh_user=<%= ssh_user %> ansible_ssh_private_key_file=<%= private_key_path[0] %> # Machine Name: <%= host_key %>'
158 | outputs[variables[:host_key]] = Vagrant::Util::TemplateRenderer.render_string(ansible_template, variables)
159 | #safe_puts(host_txt)
160 | #file.write("#{host_txt}\n")
161 | end
162 | end
163 |
164 | #require 'pp'
165 | #puts "PROVISIONERS"
166 | #PP.pp(provisioners)
167 | #puts "OUTPUTS"
168 | #PP.pp(outputs)
169 | #puts "\n\n"
170 |
171 |
172 |
173 | inventory_configs[:vagrant_flow_file].open('w') do |file|
174 | header_txt="# Generated by vagrant-flow, part of NeverwinterDP\n\n"
175 | if not options[:quiet]
176 | safe_puts(header_txt)
177 | end
178 | file.write(header_txt)
179 |
180 | #Now we maps from our VAGRANTFILE defined groups in our provisioners.config.groups
181 | #To our configuration strings we got from outputs
182 | group_machines.each do |groupname,machines|
183 | if not options[:quiet]
184 | puts "["+groupname+"]\n"
185 | end
186 | file.write "["+groupname+"]\n"
187 | machines.each do |machinename|
188 | #if we match :children, then we have an ansible config that's
189 | #pointing to another group, not a specific machine
190 | if /:children/.match(groupname)
191 | if not options[:quiet]
192 | puts machinename
193 | end
194 | file.write machinename+"\n"
195 | else
196 | if not options[:quiet]
197 | puts outputs[machinename.to_sym]+"\n"
198 | end
199 | file.write outputs[machinename.to_sym]+"\n"
200 | end
201 | end
202 | if not options[:quiet]
203 | puts "\n"
204 | end
205 | file.write "\n"
206 | end
207 | end
208 | 0
209 | end # End Execute
210 |
211 |
212 | # Documentation reference
213 | # http://docs.ansible.com/intro_inventory.html
214 |
215 | #def setup_inventory_file(machine)
216 | # return machine.config.inventory_path if machine.config.inventory_path
217 | #
218 | # ssh = machine.ssh_info
219 | #
220 | # generated_inventory_file =
221 | # machine.env.root_path.join("vagrant-flow_ansible_inventory")
222 | #
223 | # generated_inventory_file.open('w') do |file|
224 | # file.write("# Generated by Vagrant\n\n")
225 | # file.write("#{machine.name} ansible_ssh_host=#{ssh[:host]} ansible_ssh_port=#{ssh[:port]}\n")
226 | #
227 | # # Write out groups information. Only include current
228 | # # machine and its groups to avoid Ansible errors on
229 | # # provisioning.
230 | # groups_of_groups = {}
231 | # included_groups = []
232 | #
233 | # config.groups.each_pair do |gname, gmembers|
234 | # if gname.end_with?(":children")
235 | # groups_of_groups[gname] = gmembers
236 | # elsif gmembers.include?("#{machine.name}")
237 | # included_groups << gname
238 | # file.write("\n[#{gname}]\n")
239 | # file.write("#{machine.name}\n")
240 | # end
241 | # end
242 | #
243 | # groups_of_groups.each_pair do |gname, gmembers|
244 | # unless (included_groups & gmembers).empty?
245 | # file.write("\n[#{gname}]\n")
246 | # gmembers.each do |gm|
247 | # file.write("#{gm}\n") if included_groups.include?(gm)
248 | # end
249 | # end
250 | # end
251 | # end
252 | #
253 | # return generated_inventory_file.to_s
254 | #end
255 | end
256 | end
257 | end
258 | end
259 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/digitalocean_api.rb:
--------------------------------------------------------------------------------
1 | require "net/http"
2 | require "uri"
3 | require "json"
4 |
5 | class DigitalOcean_Api
6 |
7 | def initialize(digitaloceanurl= 'https://api.digitalocean.com', digitaloceanpath="/v2/droplets")
8 | @DIGITALOCEAN_URL=digitaloceanurl
9 | @DIGITALOCEAN_PATH=digitaloceanpath
10 | end
11 |
12 | #params should be a hash that will be in the form of
13 | #{"Authorization"=>"Bearer ~~DIGITALOCEANTOKEN~~"}
14 | def makeApiCall(params)
15 |
16 | uri = URI.parse(@DIGITALOCEAN_URL)
17 | http = Net::HTTP.new(uri.host,uri.port)
18 | http.use_ssl = true
19 | request = Net::HTTP::Get.new(@DIGITALOCEAN_PATH)
20 |
21 | request.initialize_http_header(params)
22 | response = http.request(request)
23 | return JSON.parse(response.body)
24 | end
25 |
26 |
27 | #returns parsed hash object from returned json
28 | def showAllActiveDroplets(token)
29 | x = {
30 | "Authorization" => "Bearer "+token
31 | }
32 | return makeApiCall(x)
33 | end
34 |
35 | #Calls showAllActiveDroplets and then parses the info for just hostname and ip
36 | def getHostNamesAndIps(token)
37 | hash = showAllActiveDroplets(token)
38 | returnHash = []
39 |
40 | hash["droplets"].each {|droplet|
41 | #Grab the IP information for each droplet
42 | #Each IP is contained in an array, so extract that
43 | ip = []
44 | droplet["networks"]["v4"].each do |x|
45 | ip.push(x["ip_address"])
46 | end
47 |
48 | #Only use one IP address to avoid confusing etc hosts
49 | ip = ip[ip.length-1]
50 |
51 |
52 | returnHash.push({
53 | :hostname => droplet["name"],
54 | :ip => ip
55 | })
56 | }
57 | return returnHash
58 | end
59 |
60 | end
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/getDOtoken.rb:
--------------------------------------------------------------------------------
1 | require 'yaml'
2 |
3 | ##Example usage:
4 | ##Require my library for talking to digitalocean
5 | ##require File.expand_path(File.dirname(__FILE__) ) +"/getDOToken"
6 | ##puts GetDOToken.getToken()
7 |
8 | class GetDOToken
9 |
10 | #Returns digital ocean token that's been installed
11 | #Returns nil if its not present
12 | def self.getToken()
13 | filename = ENV['HOME']+"/.vagrant-flow"
14 | if File.exists?(filename)
15 | x = YAML::load_file(filename)
16 | if x.has_key?(:digitalOceanToken)
17 | return x[:digitalOceanToken]
18 | end
19 | end
20 | return nil
21 | end
22 | end
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/hostfile.rb:
--------------------------------------------------------------------------------
1 | require "vagrant"
2 | require 'optparse'
3 | require 'tempfile'
4 | require 'yaml'
5 |
6 | #Require my library for talking to digitalocean
7 | require File.expand_path(File.dirname(__FILE__) ) +"/digitalocean_api"
8 |
9 | #Require my library for grabbing installed DO Token
10 | require File.expand_path(File.dirname(__FILE__) ) +"/getDOToken"
11 |
12 | module VagrantPlugins
13 | module CommandVagrantFlow
14 | module Command
15 | class HostFile < Vagrant.plugin("2", :command)
16 | @@begin_tag_line = "##BEGIN: ADDED BY NEVERWINTERDP'S VAGRANT-FLOW HOSTFILE COMMAND"
17 | @@end_tag_line = "##END: ADDED BY NEVERWINTERDP'S VAGRANT-FLOW HOSTFILE COMMAND"
18 |
19 | # Builtin from Command class
20 | # Must override to provide a description
21 | def self.synopsis
22 | "Sets /etc/hosts so that all your machines can communicate with each other"
23 | end
24 |
25 |
26 | # Builtin from Command class
27 | # Must override to provide core functionality
28 | def execute
29 | options = {}
30 | options[:destroy_on_error] = true
31 | options[:parallel] = false
32 | options[:provision_ignore_sentinel] = false
33 | options[:nowrite] = false
34 | options[:quiet] = false
35 | options[:digitalocean] = false
36 |
37 | #Parse option, look up OptionParser documentation
38 | opts = OptionParser.new do |o|
39 | # o.banner = "Usage: vagrant ansible-inventory [vm-name] [options] [-h]"
40 | o.banner = "A NeverWinterDP technology from the Department of Badass.\n\n"+
41 | "Usage: vagrant flow hostfile [-qndoh]\n"+
42 | "Edits all your VMs /etc/hosts file to be able to find all the machines on your private network"
43 | o.separator ""
44 |
45 | o.on("-q", "--quiet", "(Optional) Suppress output to STDOUT and STDERR") do |f|
46 | options[:quiet] = true
47 | end
48 |
49 | o.on("-n", "--no-write-hosts", "(Optional) Don't actually write a new hosts file to the guest machine") do |f|
50 | options[:nowrite] = true
51 | end
52 |
53 | o.on("-d", "--digitalocean", "(Optional) Writes your digital ocean's hostnames and IP addresses to the host files of your machines. Default file is multiinitconfig.yml") do |f|
54 | options[:digitalocean] = true
55 | end
56 |
57 | end
58 | argv = parse_options(opts)
59 | return if !argv
60 |
61 |
62 |
63 | hostinfo=[]
64 | #Go through config
65 | #Map hostnames to IP's
66 | if options[:digitalocean]
67 | digitalocean = DigitalOcean_Api.new()
68 | hostinfo = digitalocean.getHostNamesAndIps(GetDOToken.getToken())
69 | else
70 | with_target_vms(argv, :provider => options[:provider]) do |machine|
71 | return unless machine.communicate.ready?
72 | hostname = machine.config.vm.hostname
73 | machine.config.vm.networks.each {|networks|
74 | networks.each {|net|
75 | if net.is_a?(Hash) and net.has_key?(:ip)
76 | hostinfo.push(
77 | {
78 | :hostname=>hostname,
79 | :ip=>net[:ip]
80 | })
81 | end
82 | }
83 | }
84 | end
85 | end
86 |
87 |
88 | #Print out Hostname and IP
89 | if not options[:quiet]
90 | puts "HOSTS FILE INFO:"
91 | hostinfo.each {|x|
92 | puts x[:hostname]+": "+x[:ip]
93 | }
94 | end
95 |
96 | #What we're going to add to the end of the guest's hostfile
97 | #A combination of IP's and hostnames
98 | toconcatenate="\n"+@@begin_tag_line+"\n"
99 | hostinfo.each {|x|
100 | toconcatenate += x[:ip]+" "+x[:hostname]+"\n"
101 | }
102 | toconcatenate += @@end_tag_line+"\n"
103 |
104 | #Read in guest's current hosts file
105 | #Append our new entries to it
106 | #Write it out onto the guest's hosts file
107 | with_target_vms(argv, :provider => options[:provider]) do |machine|
108 | return unless machine.communicate.ready?
109 |
110 | #This block of code was shamelessly stolen from
111 | #https://github.com/smdahlen/vagrant-hostmanager/blob/master/lib/vagrant-hostmanager/hosts_file.rb
112 | #Why reinvent the wheel?
113 | #Determines what the move command and where /etc/hosts should be for linux, windows, and sunOS
114 | if (machine.communicate.test("uname -s | grep SunOS"))
115 | realhostfile = '/etc/inet/hosts'
116 | move_cmd = 'mv'
117 | elsif (machine.communicate.test("test -d $Env:SystemRoot"))
118 | realhostfile = "#{ENV['WINDIR']}\\System32\\drivers\\etc\\hosts"
119 | move_cmd = 'mv -force'
120 | else
121 | realhostfile = '/etc/hosts'
122 | move_cmd = 'mv'
123 | end
124 |
125 | #Back to my code
126 | #Grab Vagrant's temp file location
127 | guesthostfilepath_original = @env.tmp_path.join("hosts."+machine.config.vm.hostname+".og")
128 | guesthostfilepath = @env.tmp_path.join("hosts."+machine.config.vm.hostname)
129 |
130 | #Download guest's hosts file
131 | machine.communicate.download(realhostfile, guesthostfilepath_original)
132 |
133 | #Skip everything between ##BEGIN and ##END
134 | guesthostfile = File.open(guesthostfilepath, "w")
135 | skip = false
136 | File.open(guesthostfilepath_original, "r") do |infile|
137 | while (line = infile.gets)
138 | if line.strip() == @@begin_tag_line
139 | skip = true
140 | elsif line.strip() == @@end_tag_line
141 | skip = false
142 | else
143 | guesthostfile.write(line) if not skip
144 | end
145 | end
146 | end
147 |
148 | #Append our hostname/IP info to the end of the hosts file
149 | guesthostfile.write(toconcatenate)
150 | guesthostfile.close()
151 |
152 | if not options[:nowrite]
153 | #Upload updated hosts file to guest to temp location
154 | machine.communicate.upload(guesthostfile.path, '/tmp/hosts')
155 | #Move temp file over on top of hosts file
156 | machine.communicate.sudo(move_cmd+" /tmp/hosts "+realhostfile)
157 | end
158 | end
159 |
160 |
161 |
162 | end
163 |
164 | end
165 | end
166 | end
167 | end
168 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/installDOToken.rb:
--------------------------------------------------------------------------------
1 | require "vagrant"
2 | require 'optparse'
3 | require 'yaml'
4 |
5 |
6 | module VagrantPlugins
7 | module CommandVagrantFlow
8 | module Command
9 | class InstallDOToken < Vagrant.plugin("2", :command)
10 |
11 | # Builtin from Command class
12 | # Must override to provide a description
13 | def self.synopsis
14 | "Installs your digital ocean key to ~/.vagrant-flow"
15 | end
16 |
17 | def commandThread(machine,command, quiet)
18 | begin
19 | machine.communicate.execute(command)
20 | if !quiet
21 | puts "Command was ran successfully on: "+machine.config.vm.hostname
22 | end
23 | rescue
24 | if !quiet
25 | puts "Command FAILED on: "+machine.config.vm.hostname
26 | @error_message="#{$!}"
27 | puts @error_message
28 | end
29 | ensure
30 | if !quiet
31 | puts "----"
32 | end
33 | end
34 | end
35 |
36 | # Builtin from Command class
37 | # Must override to provide core functionality
38 | def execute
39 | options = {}
40 | options[:destroy_on_error] = true
41 | options[:parallel] = false
42 | options[:provision_ignore_sentinel] = false
43 | options[:quiet] = false
44 | options[:token] = nil
45 |
46 | opts = OptionParser.new do |o|
47 | o.banner = "A NeverWinterDP technology from the Department of Badass.\n\n"+
48 | "Usage: vagrant flow multicommand [-q] -t TOKEN\n"+
49 | "Installs your digital ocean key for easy vagrant-flow configuration"
50 | o.separator ""
51 |
52 | o.on("-q", "--quiet", "(Optional) Suppress output to STDOUT and STDERR") do |f|
53 | options[:quiet] = true
54 | end
55 |
56 | o.on("-t", "--token TOKEN", "(REQUIRED) The token to install") do |f|
57 | options[:token] = f
58 | end
59 | end
60 |
61 | argv = parse_options(opts)
62 | return if !argv
63 | raise OptionParser::MissingArgument if options[:token].nil?
64 | x = {
65 | :digitalOceanToken=>options[:token],
66 | }
67 |
68 | filename = ENV['HOME']+"/.vagrant-flow"
69 | begin
70 | File.open(filename, 'w') { |file| file.write (x.to_yaml ) }
71 | if !options[:quiet]
72 | puts "Success!"
73 | end
74 | rescue
75 | if !options[:quiet]
76 | @error_message="#{$!}"
77 | $stderr.puts "Could not write to "+filename
78 | $stderr.puts @error_message
79 | end
80 | end
81 |
82 |
83 | end
84 | end
85 | end
86 | end
87 | end
88 |
89 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/multicommand.rb:
--------------------------------------------------------------------------------
1 | require "vagrant"
2 | require 'optparse'
3 | require 'tempfile'
4 | require 'yaml'
5 |
6 | #Require my library for talking to digitalocean
7 | require File.expand_path(File.dirname(__FILE__) ) +"/digitalocean_api"
8 |
9 | module VagrantPlugins
10 | module CommandVagrantFlow
11 | module Command
12 | class MultiCommand < Vagrant.plugin("2", :command)
13 |
14 | # Builtin from Command class
15 | # Must override to provide a description
16 | def self.synopsis
17 | "Runs a command on all the machines in your vagrantfile"
18 | end
19 |
20 | def commandThread(machine,command, quiet)
21 | begin
22 | machine.communicate.execute(command)
23 | if !quiet
24 | puts "Command was ran successfully on: "+machine.config.vm.hostname
25 | end
26 | rescue
27 | if !quiet
28 | puts "Command FAILED on: "+machine.config.vm.hostname
29 | @error_message="#{$!}"
30 | puts @error_message
31 | end
32 | ensure
33 | if !quiet
34 | puts "----"
35 | end
36 | end
37 | end
38 |
39 | # Builtin from Command class
40 | # Must override to provide core functionality
41 | def execute
42 | options = {}
43 | options[:destroy_on_error] = true
44 | options[:parallel] = false
45 | options[:provision_ignore_sentinel] = false
46 | options[:quiet] = false
47 | options[:filter] = []
48 |
49 | opts = OptionParser.new do |o|
50 | o.banner = "A NeverWinterDP technology from the Department of Badass.\n\n"+
51 | "Usage: vagrant flow multicommand [-qf] -c COMMAND\n"+
52 | "Runs a shell command on specified machines in your vagrantfile"
53 | o.separator ""
54 |
55 | o.on("-q", "--quiet", "(Optional) Suppress output to STDOUT and STDERR") do |f|
56 | options[:quiet] = true
57 | end
58 |
59 | o.on("-f", "--filterMachine VMNAME,VNAME2...", Array, "(Optional) comma separated list of machines to run command on") do |f|
60 | options[:filter] = f
61 | end
62 |
63 | o.on("-c", "--command COMMAND", "(REQUIRED) Command to run on the machines") do |f|
64 | options[:command] = f
65 | end
66 | end
67 | argv = parse_options(opts)
68 | return if !argv
69 | raise OptionParser::MissingArgument if options[:command].nil?
70 |
71 | threads = []
72 |
73 | with_target_vms(argv, :provider => options[:provider]) do |machine|
74 | #return unless machine.communicate.ready?
75 | if options[:filter].empty? or options[:filter].include? machine.config.vm.hostname
76 | threads.push(Thread.new{commandThread(machine,options[:command],options[:quiet])})
77 | end
78 | end
79 |
80 | threads.each {|t|
81 | t.join
82 | }
83 |
84 | end
85 | end
86 | end
87 | end
88 | end
89 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/multiinit.rb:
--------------------------------------------------------------------------------
1 | require "vagrant"
2 | require 'optparse'
3 | require "yaml"
4 | require 'erubis'
5 | require "ipaddr"
6 |
7 | #Require my library for grabbing installed DO Token
8 | require File.expand_path(File.dirname(__FILE__) ) +"/getDOToken"
9 |
10 | module VagrantPlugins
11 | module CommandVagrantFlow
12 | module Command
13 | class MultiInit < Vagrant.plugin("2", :command)
14 |
15 | # Builtin from Command class
16 | # Must override to provide a description
17 | def self.synopsis
18 | "Grabs a multitude of vagrant cloud boxes"
19 | end
20 |
21 |
22 | # Builtin from Command class
23 | # Must override to provide core functionality
24 | def execute
25 | default_group_config_file = "multiinitconfig.yml"
26 | options = {}
27 | options[:destroy_on_error] = true
28 | options[:parallel] = false
29 | options[:provision_ignore_sentinel] = false
30 | options[:quiet] = false
31 |
32 |
33 | #Defaults for machine and configs
34 | default_sshPrivateKeyPath ="~/.ssh/id_rsa"
35 | machineDefaults = {
36 | "url" => "demandcube/centos-65_x86_64-VB-4.3.8",
37 | "digitalOceanImage" =>"CentOS 6.5 x64",
38 | "digitalOceanRegion" => "sfo1",
39 | "ram" => "512MB",
40 | }
41 |
42 | #Valid values for amount of RAM
43 | allowedRam = ["512MB","1GB","2GB","4GB","8GB","16GB","32GB","48GB","64GB"]
44 | allowedRamConversion = {
45 | "512MB"=> "512",
46 | "1GB" => "1024",
47 | "2GB" => "2048",
48 | "4GB" => "4096",
49 | "8GB" => "8192",
50 | "16GB" => "16384",
51 | "32GB" => "32768",
52 | "48GB" => "49152",
53 | "64GB" => "65536",
54 | }
55 |
56 | #valid values for digitalOceanRegion
57 | allowedDORegions = ["nyc1","ams1","sfo1","nyc2","ams2","sgp1","lon1",]
58 |
59 | #Default virtualbox__intnet name for private network
60 | options[:vboxintnet] = "neverwinterDP"
61 |
62 | #Setting to read in a file other than default_group_config_File
63 | options[:vagrant_cloud_config_file] = false
64 |
65 | #Parse option, look up OptionParser documentation
66 | opts = OptionParser.new do |o|
67 | # o.banner = "Usage: vagrant ansible-inventory [vm-name] [options] [-h]"
68 | o.banner = "A NeverWinterDP technology from the Department of Badass.\n\n"+
69 | "Usage: vagrant flow multiinit [-hgliq]\nThis looks for multiinit.yml as the default configuration\n"
70 | o.separator ""
71 | o.on("-g", "--vagrant_multiinit_config_file FILEPATH", "(Optional) YAML file containing vagrant cloud config") do |f|
72 | options[:vagrant_cloud_config_file] = f
73 | end
74 |
75 | o.on( '-l', '--list hostname:cloud/location,hostname2:cloud/location2,hostname3:cloud/location3', Array, "List of cloud config parameters" ) do|f|
76 | options[:vagrant_cloud_list] = f
77 | end
78 |
79 | o.on("-i", "--vboxintnet NAME", "(Optional) Custom virtualbox__intnet name for private network") do |f|
80 | options[:vboxintnet] = f
81 | end
82 |
83 | o.on("-q", "--quiet", "(Optional) Suppress output to STDOUT and STDERR") do |f|
84 | options[:quiet] = true
85 | end
86 |
87 | end
88 |
89 | # Parse the options # Builtin from the Command Class
90 | # Will safely parse the arguments and
91 | # Automatically detects -h for help
92 | argv = parse_options(opts)
93 | return if !argv
94 |
95 |
96 | #If no options are given, set the config file to the default
97 | #and continue on our merry way
98 | if not options[:vagrant_cloud_config_file] and not options[:vagrant_cloud_list]
99 | options[:vagrant_cloud_config_file] = default_group_config_file
100 | end
101 |
102 | #Get machine configs from config file or from command line
103 | content = {}
104 | if options[:vagrant_cloud_config_file]
105 | begin
106 | #Load YAML
107 | content = YAML.load_file(options[:vagrant_cloud_config_file])
108 | rescue
109 | puts $!, $@
110 | #Give warning if no file could be found
111 | if not options[:quiet]
112 | warn "Could not open file: "+options[:vagrant_cloud_config_file].to_s
113 | end
114 | end
115 |
116 | #Set intnetName if its not in the config
117 | if not content.has_key?(:intnetName)
118 | content[:intnetName]=options[:vboxintnet]
119 | end
120 |
121 | end
122 |
123 | #Read in command line config
124 | if options[:vagrant_cloud_list]
125 | machines = []
126 | options[:vagrant_cloud_list].each {|item|
127 | split = item.split(":")
128 | machines.push({
129 | "name"=>split[0],
130 | "url"=>split[1],
131 | })
132 | }
133 | content = {
134 | :intnetName=>options[:vboxintnet],
135 | "machines" => machines,
136 | }
137 | end
138 |
139 | #Bail out here if content is fubar
140 | if not content.has_key?("machines")
141 | return
142 | end
143 |
144 | #Set digitalocean token if its installed
145 | token= GetDOToken.getToken()
146 | if ! token.nil?
147 | content[:digitalOceanToken] = token
148 | end
149 |
150 | #Set IP's for private network
151 | #Start at 192.168.1.0 and increment up
152 | #using the IPAddr class
153 | ip= IPAddr.new("192.168.1.0")
154 | content["machines"].each {|machine|
155 | ip = IPAddr.new(ip.to_s).succ
156 |
157 | #If IP ends in x.x.x.0 or x.x.x.1, keep going one more
158 | #to avoid conflicts with routers/gateways/etc
159 | if ip.to_s.split(//).last(2) == [".","0"]
160 | ip = IPAddr.new(ip.to_s).succ
161 | end
162 | if ip.to_s.split(//).last(2) == [".","1"]
163 | ip = IPAddr.new(ip.to_s).succ
164 | end
165 | machine["ip"] = ip.to_s
166 | }
167 |
168 | #Set default ssh private key (used by digitalocean provider option)
169 | if not content.has_key?(:sshPrivateKeyPath)
170 | content[:sshPrivateKeyPath] = default_sshPrivateKeyPath
171 | end
172 |
173 |
174 | content["machines"].each {|machine|
175 | #Set defaults for digital ocean provicder if they're not provided in the config
176 | machineDefaults.each {|key,val|
177 | if not machine.has_key?(key)
178 | machine[key] = val
179 | end
180 | }
181 |
182 | #Check if RAM value is valid (Digital Ocean restriction)
183 | if not allowedRam.include?(machine["ram"])
184 | STDERR.puts "ram option not valid: "+machine["ram"]+"\nSetting to "+machineDefaults["ram"]
185 | machine["ram"]=machineDefaults["ram"]
186 | end
187 |
188 | #Vagrant requires the amount of RAM to be written in MB, so do the conversion
189 | machine["vagrantram"]= allowedRamConversion[machine["ram"]]
190 |
191 | #Make sure the digitalOceanRegion is correct
192 | if not allowedDORegions.include?(machine["digitalOceanRegion"])
193 | STDERR.puts "digitalOceanRegion option not valid: "+machine["digitalOceanRegion"]+"\nSetting to "+machineDefaults["digitalOceanRegion"]
194 | machine["digitalOceanRegion"]=machineDefaults["digitalOceanRegion"]
195 | end
196 |
197 | }
198 |
199 |
200 |
201 | #Put Vagrantfile in pwd
202 | save_path = Pathname.new("Vagrantfile").expand_path(@env.cwd)
203 |
204 | #Error out if Vagrantfile already exists
205 | raise Vagrant::Errors::VagrantfileExistsError if save_path.exist?
206 |
207 | #Get current directory, go up one directory, then append path to templates/cloudbox.erb
208 | template_path = File.join(File.expand_path("..",File.dirname(__FILE__)) , ("templates/multiinit.erb"))
209 |
210 | #Load template file and write contents
211 | eruby = Erubis::Eruby.new(File.read(template_path))
212 | begin
213 | save_path.open("w+") do |f|
214 | f.write(eruby.evaluate(content))
215 | end
216 | rescue Errno::EACCES
217 | raise Vagrant::Errors::VagrantfileWriteError
218 | end
219 |
220 | end
221 | end
222 | end
223 | end
224 | end
225 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/playbook.rb:
--------------------------------------------------------------------------------
1 | #Flush stdout immediately
2 | $stdout.sync = true
3 |
4 | require "vagrant"
5 | require 'optparse'
6 | require 'yaml'
7 | require 'pty'
8 |
9 | module VagrantPlugins
10 | module CommandVagrantFlow
11 | module Command
12 | class Playbook < Vagrant.plugin("2", :command)
13 |
14 | # Builtin from Command class
15 | # Must override to provide a description
16 | def self.synopsis
17 | "Runs ansible-playbook so you don't have to!"
18 | end
19 |
20 |
21 | # Builtin from Command class
22 | # Must override to provide core functionality
23 | def execute
24 | options = {}
25 | options[:destroy_on_error] = true
26 | options[:parallel] = false
27 | options[:provision_ignore_sentinel] = false
28 | options[:configfile] = "flow-playbook.yml"
29 | options[:print] = false
30 | options[:quiet] = false
31 |
32 | #Parse option, look up OptionParser documentation
33 | opts = OptionParser.new do |o|
34 | o.banner = "A NeverWinterDP technology from the Department of Badass.\n\n"+
35 | "Usage: vagrant flow playbook [-hfpq]\n"+
36 | "Reads in config from flow-playbook.yml by default to be able to run ansible-playbook more easily"
37 | o.separator ""
38 |
39 | o.on("-f", "--file-playbook FILE", "(Optional) Use a specified playbook config file instead of default (flow-playbook.yml)") do |f|
40 | options[:configfile] = f
41 | end
42 |
43 | o.on("-p", "--print-only", "(Optional) Don't actually ansible-playbook, but just output what would be run to STDOUT") do |f|
44 | options[:print] = true
45 | end
46 |
47 | o.on("-q", "--quiet", "(Optional) Suppress output to STDOUT and STDERR") do |f|
48 | options[:quiet] = true
49 | end
50 |
51 | end
52 | argv = parse_options(opts)
53 | return if !argv
54 |
55 | config={}
56 | begin
57 | #Load YAML
58 | config = YAML.load_file(options[:configfile])
59 | rescue
60 | #Give warning if no file could be found
61 | if not options[:quiet]
62 | warn "Could not open file: "+options[:configfile].to_s
63 | end
64 | end
65 |
66 | #Bail out if config is fubar
67 | if not config.has_key?(:playbook)
68 | if not options[:quiet]
69 | warn options[:configfile].to_s+" is missing \":playbook\" key"
70 | end
71 | return
72 | end
73 |
74 | if not config.has_key?(:inventory)
75 | if not options[:quiet]
76 | warn options[:configfile].to_s+" is missing \":inventory\" key"
77 | end
78 | return
79 | end
80 |
81 | #Build the ansible-playbook command
82 | command = "ansible-playbook "
83 | if config.has_key?(:pattern)
84 | command+= "-l "+config[:pattern]+" "
85 | end
86 | command+= "-i "+config[:inventory]+" "
87 | command+= config[:playbook]
88 |
89 | #If print is specified, only output the command
90 | if options[:print]
91 | #But only print if the quiet command isn't specified
92 | if not options[:quiet]
93 | puts command
94 | end
95 | else
96 |
97 |
98 | #Run the command
99 | #this fancy block of code outputs the output in real time
100 | begin
101 | PTY.spawn( "#{command}" ) do |stdin, stdout, pid|
102 | begin
103 | stdin.each { |line|
104 | if not options[:quiet]
105 | puts line
106 | end
107 | }
108 | #This wait() is required to set the exit code
109 | Process.wait(pid)
110 | rescue Errno::EIO
111 | end
112 | end
113 | rescue PTY::ChildExited
114 | #If there was an error, throw an error ourselves
115 | raise Vagrant::Errors::AnsibleFailed
116 | end
117 |
118 | #If there was an error, throw an error ourselves
119 | raise Vagrant::Errors::AnsibleFailed if not $?.success?
120 |
121 | end
122 | end
123 |
124 | end
125 | end
126 | end
127 | end
128 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/command/root.rb:
--------------------------------------------------------------------------------
1 | require 'optparse'
2 |
3 | module VagrantPlugins
4 | module CommandVagrantFlow
5 | module Command
6 | class Root < Vagrant.plugin("2", :command)
7 | def self.synopsis
8 | "manages vagrantflow"
9 | end
10 |
11 | def initialize(argv, env)
12 | super
13 |
14 | @main_args, @sub_command, @sub_args = split_main_and_subcommand(argv)
15 |
16 | @subcommands = Vagrant::Registry.new
17 | @subcommands.register(:ansibleinventory) do
18 | require_relative "ansibleinventory"
19 | AnsibleInventory
20 | end
21 |
22 | @subcommands.register(:multiinit) do
23 | require_relative "multiinit"
24 | MultiInit
25 | end
26 |
27 | @subcommands.register(:hostfile) do
28 | require_relative "hostfile"
29 | HostFile
30 | end
31 |
32 | @subcommands.register(:playbook) do
33 | require_relative "playbook"
34 | Playbook
35 | end
36 |
37 | @subcommands.register(:multicommand) do
38 | require_relative "multicommand"
39 | MultiCommand
40 | end
41 |
42 | @subcommands.register(:installdotoken) do
43 | require_relative "installdotoken"
44 | InstallDOToken
45 | end
46 |
47 | end
48 |
49 | def execute
50 | if @main_args.include?("-h") || @main_args.include?("--help")
51 | # Print the help for all the sub-commands.
52 | return help
53 | end
54 |
55 | # If we reached this far then we must have a subcommand. If not,
56 | # then we also just print the help and exit.
57 | command_class = @subcommands.get(@sub_command.to_sym) if @sub_command
58 | return help if !command_class || !@sub_command
59 | @logger.debug("Invoking command class: #{command_class} #{@sub_args.inspect}")
60 |
61 | # Initialize and execute the command class
62 | command_class.new(@sub_args, @env).execute
63 | end
64 |
65 | # Prints the help out for this command
66 | def help
67 | opts = OptionParser.new do |o|
68 | o.banner = "Usage: vagrant flow []"
69 | o.separator ""
70 | o.separator "Available subcommands: ansibleinventory,"
71 |
72 | # Add the available subcommands as separators in order to print them
73 | # out as well.
74 | keys = []
75 | @subcommands.each { |key, value| keys << key.to_s }
76 |
77 | keys.sort.each do |key|
78 | o.separator " #{key}"
79 | end
80 |
81 | o.separator ""
82 | o.separator "For help on any individual command run `vagrant flow COMMAND -h`"
83 | end
84 |
85 | @env.ui.info(opts.help, :prefix => false)
86 | end
87 | end
88 | end
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/plugin.rb:
--------------------------------------------------------------------------------
1 | require "vagrant"
2 |
3 | module VagrantPlugins
4 | module CommandVagrantFlow
5 | class Plugin < Vagrant.plugin(2)
6 |
7 | name 'vagrant-flow'
8 | description 'Plugin allows to generate a ansible inventory file.'
9 |
10 | # config :exec do
11 | # require_relative 'config'
12 | # Config
13 | # end
14 |
15 | #command("ansible-inventory") do
16 | # require_relative 'command'
17 | # Command
18 | #end
19 |
20 |
21 | command("flow") do
22 | require File.expand_path("../command/root.rb", __FILE__)
23 | Command::Root
24 | end
25 |
26 | end # Plugin
27 | end # Exec
28 | end # VagrantPlugins
29 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/templates/multiinit.erb:
--------------------------------------------------------------------------------
1 | # -*- mode: ruby -*-
2 | # vi: set ft=ruby :
3 |
4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
5 | VAGRANTFILE_API_VERSION = "2"
6 |
7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
8 |
9 | Vagrant.require_version ">= 1.4.3"
10 |
11 |
12 | <% for machine in @machines %>
13 |
14 | config.vm.define :<%= machine["name"]%> do | <%= machine["name"]%> |
15 | <% if machine.has_key?("name") and machine.has_key?("url") %>
16 | <%= machine["name"]%>.vm.box = "<%= machine["url"]%>"
17 | <% end %>
18 |
19 | # Create a private network
20 | <%= machine["name"]%>.vm.network :private_network, ip: "<%= machine["ip"]%>", virtualbox__intnet: "<%= @intnetName %>"
21 | <%= machine["name"]%>.vm.hostname = "<%= machine["name"]%>"
22 |
23 | <%= machine["name"]%>.vm.synced_folder ".", "/vagrant", disabled: true
24 |
25 | <% if machine.has_key?("digitalOceanImage") and machine.has_key?("digitalOceanRegion") and @digitalOceanToken and @sshPrivateKeyPath %>
26 | #digitalOcean provider
27 | <%= machine["name"]%>.vm.provider :digital_ocean do |provider, override|
28 | override.ssh.private_key_path = '<%= @sshPrivateKeyPath %>'
29 | provider.token = '<%= @digitalOceanToken %>'
30 | provider.region = '<%=machine["digitalOceanRegion"] %>'
31 | provider.image = '<%= machine["digitalOceanImage"] %>'
32 | provider.size = '<%= machine["ram"] %>'
33 | end
34 | <% end %>
35 |
36 | <% if machine.has_key?("name") and machine.has_key?("url") %>
37 | #VirtualBox provider
38 | <%= machine["name"]%>.vm.provider :virtualbox do |vb|
39 | vb.name = "<%= machine["name"]%>"
40 | vb.customize ["modifyvm", :id, "--memory", "<%= machine["vagrantram"] %>"]
41 | # vb.customize ["modifyvm", :id, "--cpus", "2"]
42 | end
43 | <% end %>
44 |
45 | end
46 | <% end %>
47 | end
48 |
49 |
--------------------------------------------------------------------------------
/lib/vagrant-flow/version.rb:
--------------------------------------------------------------------------------
1 | module VagrantPlugins
2 | module VagrantFlow
3 | VERSION = "1.0.27"
4 | end
5 | end
6 |
--------------------------------------------------------------------------------
/vagrant-flow.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 |
3 | # coding: utf-8
4 | lib = File.expand_path('../lib', __FILE__)
5 | $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6 | require 'vagrant-flow/version'
7 |
8 | Gem::Specification.new do |s|
9 | s.name = "vagrant-flow"
10 | s.version = VagrantPlugins::VagrantFlow::VERSION
11 |
12 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
13 | s.authors = ["Steve Morin"]
14 | s.date = "2014-02-23"
15 | s.summary = %q{Enables Vagrant to Generate Ansible Inventory Files.}
16 | s.description = s.summary
17 | s.email = "steve@stevemorin.com"
18 | s.homepage = "http://github.com/DemandCube/vagrant-flow"
19 | s.licenses = ["AGPL"]
20 |
21 | s.rubyforge_project = "vagrant-flow"
22 | s.rubygems_version = "2.0.14"
23 |
24 |
25 | s.files = `git ls-files -z`.split("\x0")
26 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
27 | s.test_files = s.files.grep(%r{^(test|spec|features)/})
28 | s.require_paths = ["lib"]
29 |
30 | s.add_development_dependency "bundler", "~> 1.5"
31 | s.add_development_dependency "rake"
32 | end
33 |
--------------------------------------------------------------------------------