├── .config └── cucumber.yml ├── .gitignore ├── CHANGELOG.adoc ├── Gemfile ├── LICENSE ├── MAINTAINERS ├── README.adoc ├── Rakefile ├── features ├── proxy.feature ├── registration.feature ├── step_definitions │ ├── proxy_steps.rb │ └── registration_steps.rb └── support │ └── env.rb ├── lib ├── vagrant-registration.rb └── vagrant-registration │ ├── action.rb │ ├── action │ ├── register.rb │ ├── unregister_on_destroy.rb │ └── unregister_on_halt.rb │ ├── config.rb │ ├── plugin.rb │ └── version.rb ├── locales └── en.yml ├── plugins └── guests │ └── redhat │ ├── cap │ ├── registration.rb │ ├── rhn_register.rb │ └── subscription_manager.rb │ └── plugin.rb ├── resources └── rhn_unregister.py ├── test ├── support │ └── fake_ui.rb ├── test_helper.rb └── vagrant-registration │ └── cap │ └── redhat │ ├── rhn_register_test.rb │ └── subscription_manager_test.rb └── vagrant-registration.gemspec /.config/cucumber.yml: -------------------------------------------------------------------------------- 1 | # config/cucumber.yml 2 | ##YAML Template 3 | --- 4 | default: --profile html 5 | 6 | pretty: --format pretty -b 7 | html: --format progress --format html --out=build/features_report.html -b 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.gem 2 | *.rbc 3 | *~ 4 | *.swp 5 | /coverage/ 6 | /InstalledFiles 7 | /spec/reports/ 8 | /pkg/ 9 | /test/tmp/ 10 | /test/version_tmp/ 11 | /tmp/ 12 | .idea/ 13 | *.iml 14 | 15 | ## Specific to RubyMotion: 16 | .dat* 17 | .repl_history 18 | build/ 19 | 20 | ## Documentation cache and generated files: 21 | /.yardoc/ 22 | /_yardoc/ 23 | /doc/ 24 | /rdoc/ 25 | 26 | ## Environment normalisation: 27 | /.bundle/ 28 | /lib/bundler/man/ 29 | 30 | # for a library or gem, you might want to ignore these files since the code is 31 | # intended to run in multiple environments; otherwise, check them in: 32 | Gemfile.lock 33 | .ruby-version 34 | .ruby-gemset 35 | 36 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 37 | .rvmrc 38 | -------------------------------------------------------------------------------- /CHANGELOG.adoc: -------------------------------------------------------------------------------- 1 | = Revision History 2 | :toc: 3 | 4 | [[section]] 5 | == 1.3.1 6 | 7 | * Fix #111 Default response (yes) for registration prompt not working 8 | * Fixing rhn_register upload certificate fail #114 9 | * Converted docs from markdown to asciidoc and format tweaks 10 | * Fix #117 Updating gemspec file after doc format changes to adoc 11 | 12 | [[section-1]] 13 | == 1.3.0 14 | 15 | * Fixed formatting, typo, grammar in README 16 | * Added MAINTAINERS file 17 | * Fix #44 allow more than one try to fill username and password 18 | * Fixes #99 using proxy info to unregister 19 | * Fix #107 register when passing credentials as env variables 20 | 21 | [[section-2]] 22 | == 1.2.3 23 | 24 | * Issue #90 Use locale based messaging 25 | * Issue #65 Adding cucumber tests for proxy settings 26 | * Issue #65 Adding proxy options to rhn_register and 27 | subscription_manager 28 | * Adding minitest as unit test framework and setting up basic test 29 | harness for Vagrant plugins 30 | * Issue #65 Removing obsolete bash tests 31 | 32 | [[section-3]] 33 | == 1.2.2 34 | 35 | * Introducing Cucumber based acceptance tests. 36 | * Fix: Handling of vagrant-registration action hooks depending on 37 | provider used. 38 | 39 | [[section-4]] 40 | == 1.2.1 41 | 42 | * Fix regression: Use sudo when asking on registration managers being 43 | present 44 | 45 | [[section-5]] 46 | == 1.2.0 47 | 48 | * Fix: `vagrant destroy` not triggering subscription deactivation and 49 | removal, issue #57 50 | * Fix: Allow auto-attach and force options to be configured 51 | * Fix: Remove unnecessary shebang from python script 52 | * Support for attaching to specified subscription pool(s), issue #36 53 | * Fix: rhn_register upload certificate fails, issue #60 54 | 55 | [[section-6]] 56 | == 1.1.0 57 | 58 | * Print warning if specifically selected manager is not available 59 | * Support running alongside vagrant-vbguest, issue #40 60 | * Support rhn_register manager 61 | * Fix: Handle various types of configuration option values, issue #48 62 | * Fix: Hide password on registration failure, issue #47 63 | 64 | [[section-7]] 65 | == 1.0.1 66 | 67 | * Fix: Set repo_ca_cert option in /etc/rhsm/rhsm.conf after uploading a 68 | certificate 69 | 70 | [[section-8]] 71 | == 1.0.0 72 | 73 | * Support providing a CA certificate via `config.registration.ca_cert` 74 | option 75 | * Issue warnings on unsupported configuration options 76 | * Do not ship tests 77 | 78 | [[section-9]] 79 | == 0.0.19 80 | 81 | * Remove extra files from installation 82 | 83 | [[section-20]] 84 | == 0.0.18 85 | 86 | * Support `config.registration.unregister_on_halt` option 87 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | group :development do 4 | gem 'vagrant', 5 | :git => 'git://github.com/mitchellh/vagrant.git', 6 | :ref => 'v1.9.8' 7 | 8 | # test dependencies 9 | gem 'minitest' 10 | gem 'mocha' 11 | 12 | gem 'cucumber', '~> 2.1' 13 | gem 'aruba', '~> 0.13' 14 | gem 'komenda', '~> 0.1.6' 15 | gem 'launchy' 16 | gem 'gem-compare' 17 | gem 'mechanize' 18 | 19 | # build tool 20 | gem 'rake' 21 | gem 'yard' 22 | 23 | # virtualization providers (for testing) 24 | gem 'vagrant-vbguest' 25 | gem 'vagrant-libvirt' if RUBY_PLATFORM =~ /linux/i 26 | gem 'fog-libvirt', '0.0.3' if RUBY_PLATFORM =~ /linux/i # https://github.com/pradels/vagrant-libvirt/issues/568 27 | end 28 | 29 | group :plugins do 30 | gem 'vagrant-registration', path: '.' 31 | end 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /MAINTAINERS: -------------------------------------------------------------------------------- 1 | Project/Code Maintainers 2 | ------------------------ 3 | - Josef Strzibny @strzibny 4 | - Langdon White @whitel 5 | - Pavel Valena @pvalena 6 | - Lalatendu Mohanty @LalatenduMohanty 7 | - Hardy Ferentschik @hferentschik 8 | - Budh Ram Gurung @budhrg 9 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | [[vagrant-registration]] 2 | = vagrant-registration 3 | :toc: 4 | :toc-placement!: 5 | 6 | The vagrant-registration plugin for Vagrant allows developers to easily 7 | register their guests for updates on systems with a subscription model 8 | (like Red Hat Enterprise Linux). 9 | 10 | This plugin would run _register_ action on `vagrant up` before any 11 | provisioning and _unregister_ on `vagrant halt` or `vagrant destroy`. 12 | The actions then call the registration capabilities that have to be 13 | provided for the given OS. 14 | 15 | ''' 16 | toc::[] 17 | ''' 18 | 19 | == Installation 20 | 21 | Install vagrant-registration as any other Vagrant plugin: 22 | 23 | [source,shell] 24 | ---- 25 | $ vagrant plugin install vagrant-registration 26 | ---- 27 | 28 | If you are on Fedora, you can install the packaged version of the plugin 29 | by running: 30 | 31 | [source,shell] 32 | ---- 33 | # dnf install vagrant-registration 34 | ---- 35 | 36 | == Usage 37 | 38 | The plugin is designed in a registration-manager agnostic way, which 39 | means, that the plugin itself, depends neither on any OS nor on the way 40 | of registration. The vagrant-registration plugin only calls registration 41 | capabilities for the given guest, passes the configuration options to 42 | them and handles interactive registration. 43 | 44 | That being said, this plugin currently ships only with registration 45 | capability files for RHEL's Subscription Manager and `rhn_register`. 46 | Feel free to submit others. 47 | 48 | To configure the plugin, always include the configuration options 49 | mentioned in this file within the following configuration block in your 50 | Vagrantfile. 51 | 52 | .... 53 | Vagrant.configure('2') do |config| 54 | ... 55 | end 56 | .... 57 | 58 | === General Configuration 59 | 60 | * *skip* skips the registration. If you wish to skip the registration 61 | process altogether, you can do so by setting a `skip` option to `true`: 62 | 63 | [source,ruby] 64 | ---- 65 | config.registration.skip = true 66 | ---- 67 | 68 | * *unregister_on_halt* disables or enables automatic unregistration on 69 | halt (on shut down). By default the plugin unregisters on halt, you can 70 | however change that by setting the option to `false` so that the box 71 | will unregister only on destroy: 72 | 73 | [source,ruby] 74 | ---- 75 | config.registration.unregister_on_halt = false 76 | ---- 77 | 78 | * *manager* selects the registration manager provider. By default the 79 | plugin will use the `subscription_manager` as the registration manager 80 | provider. You can however, change that by setting the option to a 81 | different manager: 82 | 83 | [source,ruby] 84 | ---- 85 | config.registration.manager = 'subscription_manager' 86 | ---- 87 | 88 | === Credential Configuration 89 | 90 | You can set up the credentials as follows: 91 | 92 | [source,ruby] 93 | ---- 94 | Vagrant.configure('2') do |config| 95 | ... 96 | if Vagrant.has_plugin?('vagrant-registration') 97 | config.registration.username = 'foo' 98 | config.registration.password = 'bar' 99 | end 100 | 101 | # Alternatively 102 | if Vagrant.has_plugin?('vagrant-registration') 103 | config.registration.org = 'foo' 104 | config.registration.activationkey = 'bar' 105 | end 106 | ... 107 | end 108 | ---- 109 | 110 | This should go, preferably, into the Vagrantfile in your Vagrant home 111 | directory (defaults to ~/.vagrant.d), to make it available for every 112 | project. It can be later overridden in an individual project's 113 | Vagrantfile if needed. 114 | 115 | If you prefer not to store your username and/or password on your 116 | filesystem, you can optionally configure vagrant-registration plugin to 117 | use environment variables such as: 118 | 119 | [source,ruby] 120 | ---- 121 | Vagrant.configure('2') do |config| 122 | ... 123 | config.registration.username = ENV['SUB_USERNAME'] 124 | config.registration.password = ENV['SUB_PASSWORD'] 125 | ... 126 | end 127 | ---- 128 | 129 | If you do not configure your credentials as outlined above, you will 130 | receive a maximum of 3 prompts for them during the `vagrant up` process. 131 | 132 | Please note that the interactive mode asks you for the preferred 133 | registration pair only for the configured manager. 134 | 135 | === HTTP Proxy Configuration 136 | 137 | HTTP Proxy can be configured via the __proxy__, _proxyUser_ and 138 | _proxyPassword_ configuration options: 139 | 140 | [source,ruby] 141 | ---- 142 | Vagrant.configure('2') do |config| 143 | ... 144 | if Vagrant.has_plugin?('vagrant-registration') 145 | config.registration.proxy = 'mongo:8080' 146 | config.registration.proxyUser = 'flash' 147 | config.registration.proxyPassword = 'zarkov' 148 | end 149 | ... 150 | end 151 | ---- 152 | 153 | As described in the link:#credentials-configuration[credentials 154 | configuration] section, these settings can be placed either into the 155 | Vagrantfile in the Vagrant home directory or provided as environment 156 | variables. 157 | 158 | === subscription-manager Configuration 159 | 160 | The vagrant-registration plugin uses `subscription_manager` as the 161 | default manager. This can also be explicitly configured by setting the 162 | `manager` option to `subscription_manager`: 163 | 164 | [source,ruby] 165 | ---- 166 | Vagrant.configure('2') do |config| 167 | ... 168 | if Vagrant.has_plugin?('vagrant-registration') 169 | config.registration.manager = 'subscription_manager' 170 | end 171 | ... 172 | end 173 | ---- 174 | 175 | In case you choose `subscription_manager` as the manager, you would be 176 | asked for your user credentials, such as the username and password. 177 | 178 | The vagrant-registration plugin supports all the options for the 179 | subscription-manager's register command. You can set any option easily 180 | by setting `config.registration.OPTION_NAME = 'OPTION_VALUE'` in your 181 | Vagrantfile (please see the subscription-manager's documentation for 182 | option description). 183 | 184 | ==== subscription-manager Default Options 185 | 186 | * **--force**: Subscription Manager will fail if you attempt to register 187 | an already registered machine (see the man page for explanation), 188 | therefore vagrant-registration appends the `--force` flag automatically 189 | when subscribing. If you would like to disable this feature, set `force` 190 | option to `false`: 191 | 192 | [source,ruby] 193 | ---- 194 | config.registration.force = false 195 | ---- 196 | 197 | * **--auto-attach**: Vagrant would fail to install packages on 198 | registered RHEL system if the subscription is not attached, therefore 199 | vagrant-registration appends the `--auto-attach` flag automatically when 200 | subscribing. To disable this option, set `auto_attach` option to 201 | `false`: 202 | 203 | [source,ruby] 204 | ---- 205 | config.registration.auto_attach = false 206 | ---- 207 | 208 | Note that the `auto_attach` option is set to false when using 209 | org/activationkey for registration or if pools are specified. 210 | 211 | ==== subscription-manager Options Reference 212 | 213 | [source,ruby] 214 | ---- 215 | # The username to subscribe with (required) 216 | config.registration.username 217 | 218 | # The password of the subscriber (required) 219 | config.registration.password 220 | 221 | # Give the hostname of the subscription service to use (required for Subscription 222 | # Asset Manager, defaults to Customer Portal Subscription Management) 223 | config.registration.serverurl 224 | 225 | # A path to a CA certificate, this file would be copied to /etc/rhsm/ca and 226 | # if the file does not have .pem extension, it will be automatically added 227 | config.registration.ca_cert 228 | 229 | # Give the hostname of the content delivery server to use to receive updates 230 | # (required for Satellite 6) 231 | config.registration.baseurl 232 | 233 | # Give the organization to which to join the system (required, except for 234 | # hosted environments) 235 | config.registration.org 236 | 237 | # Register the system to an environment within an organization (optional) 238 | config.registration.environment 239 | 240 | # Name of the subscribed system (optional, defaults to hostname if unset) 241 | config.registration.name 242 | 243 | # Auto attach suitable subscriptions (optional, auto attach if true, 244 | # defaults to true) 245 | config.registration.auto_attach 246 | 247 | # Attach existing subscriptions as part of the registration process (optional) 248 | config.registration.activationkey 249 | 250 | # Set the service level to use for subscriptions on that machine 251 | # (optional, used only used with the --auto-attach) 252 | config.registration.servicelevel 253 | 254 | # Set the operating system minor release to use for subscriptions for 255 | # the system (optional, used only used with the --auto-attach) 256 | config.registration.release 257 | 258 | # Force the registration (optional, force if true, defaults to true) 259 | config.registration.force 260 | 261 | # Set what type of consumer is being registered (optional, defaults to system) 262 | config.registration.type 263 | 264 | # Skip the registration (optional, skip if true, defaults to false) 265 | config.registration.skip 266 | 267 | # Specify a HTTP proxy to use. This config option if of the format [|:], eg mongo:8080 268 | config.registration.proxy 269 | 270 | # Specify a username to use with an authenticated HTTP proxy 271 | config.registration.proxyUser 272 | 273 | # Specify a password to use with an authenticated HTTP proxy 274 | config.registration.proxyPassword 275 | 276 | # Attach to specified pool(s) (optional) 277 | # 278 | # Example: 279 | # config.registration.pools = [ 'POOL-ID-1', 'POOL-ID-2' ] 280 | config.registration.pools 281 | ---- 282 | 283 | === rhn-register Configuration 284 | 285 | vagrant-registration will use the `rhn_register` manager only if 286 | explicitly configured by setting the `manager` option to `rhn_register`: 287 | 288 | [source,ruby] 289 | ---- 290 | Vagrant.configure('2') do |config| 291 | ... 292 | if Vagrant.has_plugin?('vagrant-registration') 293 | config.registration.manager = 'rhn_register' 294 | end 295 | ... 296 | end 297 | ---- 298 | 299 | In case of a `rhn_register` manager, the preferred registration pair is 300 | the username/password/serverurl combination. 301 | 302 | vagrant-registration supports most of the options of rhnreg_ks's 303 | command. You can set any option easily by setting 304 | `config.registration.OPTION_NAME = 'OPTION_VALUE'` in your Vagrantfile 305 | (please see the `rhnreg_ks`'s documentation for option description). 306 | 307 | `rhn_register` manager reuses the naming of `subscription-manager`'s 308 | command options where possible. 309 | 310 | ==== rhn-register Default Options 311 | 312 | * **--force**: `rhnreg_ks` command will fail if you attempt to register 313 | an already registered machine (see the man page for explanation), 314 | therefore vagrant-registration appends the `--force` flag automatically 315 | when subscribing. If you would like to disable this feature, set `force` 316 | option to `false`: 317 | 318 | [source,ruby] 319 | ---- 320 | config.registration.force = false 321 | ---- 322 | 323 | ==== rhn-register Options Reference 324 | 325 | [source,ruby] 326 | ---- 327 | # The username to register the system with under Spacewalk Server, Red Hat Satellite or 328 | # Red Hat Network Classic. This can be an existing Spacewalk, Red Hat Satellite or 329 | # Red Hat Network Classic username, or a new user‐name. 330 | config.registration.username 331 | 332 | # The password associated with the username specified with the `--username` option. 333 | # This is an unencrypted password. 334 | config.registration.password 335 | 336 | # Give the URL of the subscription service to use (required for registering a 337 | # system with the "Spacewalk Server", "Red Hat Satellite" or "Red Hat Network Classic"). 338 | # The configuration name is mapped to the `--serverUrl` option of rhnreg_ks command. 339 | # 340 | # The serverurl is mandatory and if you do not provide a value, 341 | # you will be prompted for them in the "up process." 342 | config.registration.serverurl 343 | 344 | # A path to a CA certificate file (optional) 345 | # The configuration name is mapped to the `--sslCACert` option of rhnreg_ks command. 346 | # 347 | # The CA certificate file is be uploaded to /usr/share/rhn/ in guest 348 | # and the configuration in `/etc/sysconfig/rhn/up2date` is updated to: 349 | # `sslCACert=/usr/share/rhn/` 350 | # 351 | # As default only the configuration in `/etc/sysconfig/rhn/up2date` is updated 352 | # to point to the CA certificate file that is present on Fedora, CentOS and RHEL: 353 | # `sslCACert=/usr/share/rhn/RHNS-CA-CERT` 354 | config.registration.ca_cert 355 | 356 | # Give the organization to which to join the system (required, except for 357 | # hosted environments) 358 | # The configuration name is mapped to the `--systemorgid` option of rhnreg_ks command. 359 | config.registration.org 360 | 361 | # Name of the subscribed system (optional, defaults to hostname if unset) 362 | # The configuration name is mapped to the `--profilename` option of rhnreg_ks command. 363 | config.registration.name 364 | 365 | # Attach existing subscriptions as part of the registration process (optional) 366 | config.registration.activationkey 367 | 368 | # Subscribe this system to the EUS channel tied to the system's redhat-release (optional) 369 | config.registration.use_eus_channel 370 | 371 | # Do not probe or upload any hardware info (optional) 372 | config.registration.nohardware 373 | 374 | # Do not profile or upload any package info (optional) 375 | config.registration.nopackages 376 | 377 | # Do not upload any virtualization info (optional) 378 | config.registration.novirtinfo 379 | 380 | # Do not start rhnsd after completion (optional) 381 | config.registration.norhnsd 382 | 383 | # Force the registration (optional, force if true, defaults to true) 384 | config.registration.force 385 | 386 | # Skip the registration (optional, skip if true, defaults to false) 387 | config.registration.skip 388 | 389 | # Specify a HTTP proxy to use. This config option if of the format [|:], eg mongo:8080 390 | config.registration.proxy 391 | 392 | # Specify a username to use with an authenticated HTTP proxy 393 | config.registration.proxyUser 394 | 395 | # Specify a password to use with an authenticated HTTP proxy 396 | config.registration.proxyPassword 397 | ---- 398 | 399 | == Development 400 | 401 | The use of https://rvm.io[RVM] is recommended. Verified to work with ruby-2.2.10. 402 | 403 | .... 404 | rvm install 2.2 405 | rvm use 2.2 406 | .... 407 | 408 | To install a development environment, clone the repo and prepare 409 | dependencies by: 410 | 411 | .... 412 | gem install bundler 413 | bundle install 414 | .... 415 | 416 | === Tests 417 | 418 | ==== Minitest 419 | 420 | The source contains a set of 421 | http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html[Minitest] 422 | based unit tests. They can be run via: 423 | 424 | .... 425 | $ bundle exec rake test 426 | .... 427 | 428 | ==== Acceptance tests 429 | 430 | The source also contains a set of https://cucumber.io/[Cucumber] based 431 | acceptance tests. They can be run via: 432 | 433 | .... 434 | $ bundle exec rake features 435 | .... 436 | 437 | The tests assume that the CDK box files are available under 438 | __build/boxes/cdk-.box__. You can either copy the box files 439 | manually or use the _get_cdk_ rake task to download them. 440 | 441 | As per default, only the scenarios for CDK in combination with 442 | VirtualBox are run. You can also run the tests against Libvirt, using 443 | the environment variable __PROVIDER__: 444 | 445 | .... 446 | # Run tests against Libvirt 447 | $ bundle exec rake features PROVIDER=libvirt 448 | 449 | # Run against VirtualBox and Libvirt 450 | $ bundle exec rake features PROVIDER=virtualbox,libvirt 451 | .... 452 | 453 | You can also run a single feature specifying the explicit feature file 454 | to use: 455 | 456 | .... 457 | $ bundle exec rake features FEATURE=features/.feature 458 | .... 459 | 460 | After test execution the acceptance test reports can be found under 461 | __build/features_report.html__. They can also be opened via: 462 | 463 | .... 464 | $ bundle exec rake features:open_report 465 | .... 466 | 467 | == Releasing 468 | 469 | To release a new version of vagrant-registration you will need to do the following: 470 | 471 | *(only contributors of the GitHub repo and owners of the project at RubyGems will have rights to do this)* 472 | 473 | 1. First, bump, commit, and push the version in ~/lib/vagrant-registration/version.rb: 474 | * Follow [Semantic Versioning](http://semver.org/). 475 | 2. Then, create a matching GitHub Release (this will also create a tag): 476 | * Preface the version number with a `v`. 477 | * https://github.com/projectatomic/adb-vagrant-registration/releases 478 | 3. You will then need to build and push the new gem to RubyGems: 479 | * `rake build` 480 | * `gem push pkg/vagrant-registration-1.3.2.gem` 481 | 4. Then, when John Doe runs the following, they will receive the updated vagrant-registration plugin: 482 | * `vagrant plugin update` 483 | * `vagrant plugin update vagrant-registration` 484 | 485 | == Acknowledgements 486 | 487 | The project would like to make sure we thank 488 | https://github.com/purpleidea/[purpleidea], 489 | https://github.com/humaton/[humaton], 490 | https://github.com/strzibny[strzibny], 491 | https://github.com/scollier/[scollier], 492 | https://github.com/puzzle[puzzle], https://github.com/voxik[voxik], 493 | https://github.com/lukaszachy[lukaszachy], 494 | https://github.com/goern[goern], 495 | https://github.com/iconoeugen[iconoeugen] and 496 | https://github.com/pvalena[pvalena] (in no particular order) for their 497 | contributions of ideas, code and testing for this project. 498 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/clean' 3 | require 'rake/testtask' 4 | require 'cucumber/rake/task' 5 | require 'yard' 6 | require 'rubygems/comparator' 7 | require 'launchy' 8 | require 'mechanize' 9 | require 'fileutils' 10 | 11 | CLOBBER.include('pkg') 12 | CLEAN.include('build') 13 | 14 | # Documentation 15 | YARD::Rake::YardocTask.new do |t| 16 | t.files = ['lib/**/*.rb', 'plugins/**/*.rb'] 17 | t.options = [] 18 | t.stats_options = ['--list-undoc'] 19 | end 20 | 21 | task :init do 22 | FileUtils.mkdir_p 'build' 23 | end 24 | 25 | # Default test task 26 | desc 'Run all unit tests' 27 | Rake::TestTask.new do |t| 28 | t.pattern = 'test/**/*_test.rb' 29 | t.libs << 'test' 30 | end 31 | 32 | # Cucumber acceptance test tasks 33 | Cucumber::Rake::Task.new(:features) 34 | task :features => :init 35 | 36 | namespace :features do 37 | desc 'Opens the HTML Cucumber test report' 38 | task :open_report do 39 | Launchy.open('./build/features_report.html') 40 | end 41 | end 42 | 43 | # Compare latest release with current git head 44 | task compare: [:clean, :build] do 45 | git_version = VagrantPlugins::Registration::VERSION 46 | options = {} 47 | options[:output] = 'pkg' 48 | options[:keep_all] = true 49 | comparator = Gem::Comparator.new(options) 50 | comparator.compare_versions('vagrant-registration', ['_', git_version]) 51 | comparator.print_results 52 | end 53 | 54 | desc 'Download CDK Vagrant box using the specified provider (default \'virtualbox\')' 55 | task :get_cdk, [:provider] do |t, args| 56 | provider = args[:provider].nil? ? 'virtualbox' : args[:provider] 57 | agent = Mechanize.new 58 | agent.follow_meta_refresh = true 59 | agent.get(CDK_DOWNLOAD_URL) do |page| 60 | 61 | # Submit first form which is the redirect to login page form 62 | login_page = page.forms.first.submit 63 | 64 | # Submit the login form 65 | after_login = login_page.form_with(:name => 'login_form') do |f| 66 | username_field = f.field_with(:id => 'username') 67 | username_field.value = 'service-manager@mailinator.com' 68 | password_field = f.field_with(:id => 'password') 69 | password_field.value = 'service-manager' 70 | end.click_button 71 | 72 | # There is one more redirect after successful login 73 | download_page = after_login.forms.first.submit 74 | 75 | download_page.links.each do |link| 76 | if link.href =~ /#{Regexp.quote(CDK_BOX_BASE_NAME)}-#{Regexp.quote(provider)}.box/ 77 | download_dir = File.join(File.dirname(__FILE__), 'build', 'boxes') 78 | unless File.directory?(download_dir) 79 | FileUtils.mkdir_p(download_dir) 80 | end 81 | agent.pluggable_parser.default = Mechanize::Download 82 | puts "Downloading #{link.href}" 83 | agent.get(link.href).save(File.join(download_dir, "cdk-#{provider}.box")) 84 | end 85 | end 86 | end 87 | end 88 | task :get_cdk => :init 89 | -------------------------------------------------------------------------------- /features/proxy.feature: -------------------------------------------------------------------------------- 1 | Feature: Booting VM with various proxy settings 2 | 3 | @needs-proxy 4 | Scenario Outline: Test valid proxy configuration 5 | Given provider is 6 | And a file named "Vagrantfile" with: 7 | """ 8 | begin 9 | require 'vagrant-libvirt' 10 | rescue LoadError 11 | # NOOP 12 | end 13 | 14 | Vagrant.configure(2) do |config| 15 | config.vm.box = 'cdk' 16 | config.vm.box_url = 'file://../boxes/cdk-.box' 17 | config.vm.network :private_network, ip: '10.10.10.123' 18 | config.vm.synced_folder '.', '/vagrant', disabled: true 19 | 20 | config.registration.username = 'service-manager@mailinator.com' 21 | config.registration.password = 'service-manager' 22 | config.registration.proxy = '10.10.10.1:8888' 23 | config.registration.proxyUser = 'validUser' 24 | config.registration.proxyPassword = '' 25 | end 26 | """ 27 | 28 | When I run `bundle exec vagrant up --provider ` 29 | Then registration 30 | 31 | Examples: 32 | | provider | password | expectation | 33 | | virtualbox | validPass | should be successful | 34 | | virtualbox | invalidPass | should not be successful | 35 | | libvirt | validPass | should be successful | 36 | | libvirt | invalidPass | should not be successful | 37 | -------------------------------------------------------------------------------- /features/registration.feature: -------------------------------------------------------------------------------- 1 | Feature: Booting VM with various registration settings 2 | 3 | Scenario Outline: Boot VirtualBox with and without vbguest additions plugin 4 | Given provider is virtualbox 5 | And a file named "Vagrantfile" with: 6 | """ 7 | 8 | Vagrant.configure(2) do |config| 9 | config.vm.box = 'cdk' 10 | config.vm.box_url = 'file://../boxes/cdk-virtualbox.box' 11 | config.registration.username = 'service-manager@mailinator.com' 12 | config.registration.password = 'service-manager' 13 | end 14 | """ 15 | 16 | When I successfully run `bundle exec vagrant up --provider virtualbox` 17 | Then vbguest additions be installed 18 | 19 | Examples: 20 | | require | expectation | 21 | | # no require | should not | 22 | | require 'vagrant-vbguest' | should | 23 | 24 | 25 | Scenario Outline: Test invalid registration credentials 26 | Given provider is 27 | And a file named "Vagrantfile" with: 28 | """ 29 | begin 30 | require 'vagrant-libvirt' 31 | rescue LoadError 32 | # NOOP 33 | end 34 | 35 | Vagrant.configure(2) do |config| 36 | config.vm.box = 'cdk' 37 | config.vm.box_url = 'file://../boxes/cdk-.box' 38 | config.registration.username = 'foo' 39 | config.registration.password = 'bar' 40 | config.vm.synced_folder '.', '/vagrant', disabled: true 41 | end 42 | """ 43 | 44 | When I run `bundle exec vagrant up --provider ` 45 | Then startup should fail with invalid credentials error 46 | 47 | Examples: 48 | | provider | 49 | | virtualbox | 50 | | libvirt | 51 | 52 | 53 | Scenario Outline: Test skipping registration 54 | And provider is 55 | And a file named "Vagrantfile" with: 56 | """ 57 | begin 58 | require 'vagrant-libvirt' 59 | rescue LoadError 60 | # NOOP 61 | end 62 | 63 | Vagrant.configure(2) do |config| 64 | config.vm.box = 'cdk' 65 | config.vm.box_url = 'file://../boxes/cdk-.box' 66 | config.registration.skip = true 67 | config.vm.synced_folder '.', '/vagrant', disabled: true 68 | end 69 | """ 70 | 71 | When I run `bundle exec vagrant up --provider ` 72 | Then registration should not be successful 73 | 74 | Examples: 75 | | provider | 76 | | virtualbox | 77 | | libvirt | 78 | 79 | Scenario Outline: Test successful registration 80 | Given provider is 81 | And a file named "Vagrantfile" with: 82 | """ 83 | begin 84 | require 'vagrant-libvirt' 85 | rescue LoadError 86 | # NOOP 87 | end 88 | 89 | Vagrant.configure(2) do |config| 90 | config.vm.box = 'cdk' 91 | config.vm.box_url = 'file://../boxes/cdk-.box' 92 | config.registration.username = 'service-manager@mailinator.com' 93 | config.registration.password = 'service-manager' 94 | config.vm.synced_folder '.', '/vagrant', disabled: true 95 | end 96 | """ 97 | 98 | When I run `bundle exec vagrant up --provider ` 99 | Then registration should be successful 100 | 101 | Examples: 102 | | provider | 103 | | virtualbox | 104 | | libvirt | 105 | -------------------------------------------------------------------------------- /features/step_definitions/proxy_steps.rb: -------------------------------------------------------------------------------- 1 | require 'webrick' 2 | require 'webrick/httpproxy' 3 | require 'stringio' 4 | require 'logger' 5 | 6 | def match_credentials(req, res) 7 | type, credentials = req.header['proxy-authorization'].first.to_s.split(/\s+/, 2) 8 | received_username, received_password = credentials.to_s.unpack("m*")[0].split(":", 2) 9 | unless received_username == 'validUser' && received_password == 'validPass' 10 | res['proxy-authenticate'] = %{Basic realm="testing"} 11 | raise WEBrick::HTTPStatus::ProxyAuthenticationRequired 12 | end 13 | end 14 | 15 | Before('@needs-proxy') do 16 | @log = StringIO.new 17 | logger = Logger.new(@log) 18 | @proxy = WEBrick::HTTPProxyServer.new(:ServerType => Thread, 19 | :Logger => logger, 20 | :AccessLog => [[@log, "[ %m %U -> %s %b"]], 21 | :Port => 8888, 22 | :ProxyAuthProc => method(:match_credentials) 23 | ) 24 | @proxy.start 25 | end 26 | 27 | After('@needs-proxy') do 28 | @proxy.stop 29 | @proxy.shutdown 30 | #puts @log 31 | end 32 | 33 | -------------------------------------------------------------------------------- /features/step_definitions/registration_steps.rb: -------------------------------------------------------------------------------- 1 | Then(/^vbguest additions should( not)? be installed$/) do |negated| 2 | run("vagrant ssh -c \"lsmod | grep -i vbox\"") 3 | 4 | if negated 5 | expect(last_command_started).to have_exit_status(1) 6 | expect(last_command_started).not_to have_output(/vboxguest/) 7 | else 8 | expect(last_command_started).to have_exit_status(0) 9 | expect(last_command_started).to have_output(/vboxguest/) 10 | end 11 | end 12 | 13 | Then(/^startup should fail with invalid credentials error$/) do 14 | expect(last_command_started).to have_exit_status(1) 15 | expect(last_command_started).to have_output(/Invalid username or password./) 16 | end 17 | 18 | -------------------------------------------------------------------------------- /features/support/env.rb: -------------------------------------------------------------------------------- 1 | require 'aruba/cucumber' 2 | require 'komenda' 3 | 4 | ############################################################################### 5 | # Aruba config and Cucumber hooks 6 | ############################################################################### 7 | 8 | Aruba.configure do |config| 9 | config.exit_timeout = 300 10 | config.activate_announcer_on_command_failure = [:stdout, :stderr] 11 | config.working_directory = 'build/aruba' 12 | end 13 | 14 | Before do |scenario| 15 | @scenario_name = scenario.name 16 | ENV['VAGRANT_HOME'] = File.join(File.dirname(__FILE__), '..', '..', 'build', 'vagrant.d') 17 | end 18 | 19 | After do |_scenario| 20 | if File.exist?(File.join(aruba.config.working_directory, 'Vagrantfile')) 21 | Komenda.run('bundle exec vagrant destroy -f', cwd: aruba.config.working_directory, fail_on_fail: true) 22 | if ENV.has_key?('CUCUMBER_RUN_PROVIDER') 23 | # if we have more than one provider we need to wait between scenarios in order to allow for proper cleanup/shutdown 24 | # of virtualization framework 25 | sleep 10 26 | end 27 | end 28 | end 29 | 30 | ############################################################################### 31 | # Some shared step definitions 32 | ############################################################################## 33 | Given /provider is (.*)/ do |current_provider| 34 | requested_provider = ENV.has_key?('PROVIDER') ? ENV['PROVIDER'] : 'virtualbox' 35 | 36 | unless requested_provider.include?(current_provider) 37 | #puts "Skipping scenario '#{@scenario_name}' for provider '#{current_provider}', since this provider is not explicitly enabled via environment variable 'PROVIDER'" 38 | skip_this_scenario 39 | end 40 | end 41 | 42 | Given /box is (.*)/ do |current_box| 43 | requested_box = ENV.has_key?('BOX') ? ENV['BOX'] : 'cdk' 44 | 45 | unless requested_box.include?(current_box) 46 | #puts "Skipping scenario '#{@scenario_name}' for box '#{current_box}', since this box is not explicitly enabled via environment variable 'BOX'" 47 | skip_this_scenario 48 | end 49 | end 50 | 51 | Then(/^stdout from "([^"]*)" should match \/(.*)\/$/) do |cmd, regexp| 52 | aruba.command_monitor.find(Aruba.platform.detect_ruby(cmd)).send(:stdout) =~ /#{regexp}/ 53 | end 54 | 55 | Then(/^registration should( not)? be successful$/) do |negated| 56 | run("vagrant ssh -c \"sudo subscription-manager version\"") 57 | 58 | expect(last_command_started).to have_exit_status(0) 59 | if negated 60 | expect(last_command_started).to have_output(/This system is currently not registered/) 61 | else 62 | expect(last_command_started).to have_output(/Red Hat Subscription Management/) 63 | end 64 | end -------------------------------------------------------------------------------- /lib/vagrant-registration.rb: -------------------------------------------------------------------------------- 1 | require 'pathname' 2 | require 'vagrant-registration/plugin' 3 | 4 | module VagrantPlugins 5 | module Registration 6 | lib_path = Pathname.new(File.expand_path('../vagrant-registration', __FILE__)) 7 | autoload :Action, lib_path.join('action') 8 | 9 | # This returns the path to the source of this plugin. 10 | def self.source_root 11 | @source_root ||= Pathname.new(File.expand_path('../../', __FILE__)) 12 | end 13 | 14 | # Temporally load the extra capability files for Red Hat 15 | load(File.join(source_root, 'plugins/guests/redhat/plugin.rb')) 16 | # Default I18n to load the en locale 17 | I18n.load_path << File.expand_path('locales/en.yml', source_root) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/vagrant-registration/action.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module Registration 3 | module Action 4 | 5 | def self.action_register 6 | Vagrant::Action::Builder.new.tap do |b| 7 | b.use Register 8 | end 9 | end 10 | 11 | def self.action_unregister_on_halt 12 | Vagrant::Action::Builder.new.tap do |b| 13 | b.use UnregisterOnHalt 14 | end 15 | end 16 | 17 | def self.action_unregister_on_destroy 18 | Vagrant::Action::Builder.new.tap do |b| 19 | b.use UnregisterOnDestroy 20 | end 21 | end 22 | 23 | action_root = Pathname.new(File.expand_path('../action', __FILE__)) 24 | autoload :Register, action_root.join('register') 25 | autoload :UnregisterOnHalt, action_root.join('unregister_on_halt') 26 | autoload :UnregisterOnDestroy, action_root.join('unregister_on_destroy') 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/vagrant-registration/action/register.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module Registration 5 | module Action 6 | # This registers the guest if the guest plugin supports it 7 | class Register 8 | MAX_REGISTRATION_ATTEMPTS = 3 9 | 10 | def initialize(app, _) 11 | @app = app 12 | @logger = Log4r::Logger.new('vagrant_registration::action::register') 13 | end 14 | 15 | def call(env) 16 | ui = env[:ui] 17 | # Configuration from Vagrantfile 18 | config = env[:machine].config.registration 19 | machine = env[:machine] 20 | guest = env[:machine].guest 21 | 22 | if should_register?(machine, ui) 23 | ui.info I18n.t('registration.action.register.registration_info') 24 | check_configuration_options(machine, ui) 25 | 26 | if credentials_provided? machine 27 | guest.capability(:registration_register, ui) 28 | else 29 | @logger.debug I18n.t('registration.action.register.no_credentials') 30 | 31 | # Offer to register ATM or skip 32 | register_now = ui.ask I18n.t('registration.action.register.prompt') 33 | process_registration(guest, machine, ui, config) if register_now == 'y' || register_now.empty? 34 | end 35 | end 36 | 37 | @logger.debug(I18n.t('registration.action.register.skip_due_config')) if config.skip 38 | 39 | # Call next middleware in chain 40 | @app.call(env) 41 | end 42 | 43 | private 44 | 45 | # Shall we register the box? 46 | def should_register?(machine, ui) 47 | !machine.config.registration.skip && 48 | capabilities_provided?(machine.guest) && 49 | manager_installed?(machine.guest, ui) && 50 | !machine.guest.capability(:registration_registered?) 51 | end 52 | 53 | # Issues warning if an unsupported option is used and displays 54 | # a list of supported options 55 | def check_configuration_options(machine, ui) 56 | manager = machine.guest.capability(:registration_manager).to_s 57 | available_options = machine.guest.capability(:registration_options) 58 | options = machine.config.registration.conf.each_pair.map { |pair| pair[0] } 59 | 60 | if unsupported_options_provided?(manager, available_options, options, ui) 61 | ui.warn(I18n.t('registration.action.register.options_support_warning', 62 | manager: manager, options: available_options.join(', '))) 63 | end 64 | end 65 | 66 | # Return true if there are any unsupported options 67 | def unsupported_options_provided?(manager, available_options, options, ui) 68 | warned = false 69 | options.each do |option| 70 | unless available_options.include? option 71 | ui.warn(I18n.t('registration.action.register.unsupported_option', 72 | manager: manager, option: option)) 73 | warned = true 74 | end 75 | end 76 | warned 77 | end 78 | 79 | # Check if registration capabilities are available 80 | def capabilities_provided?(guest) 81 | if guest.capability?(:registration_register) && 82 | guest.capability?(:registration_manager_installed) && 83 | guest.capability?(:registration_registered?) 84 | true 85 | else 86 | @logger.debug I18n.t('registration.action.register.skip_missing_guest_capability') 87 | false 88 | end 89 | end 90 | 91 | # Check if selected registration manager is installed 92 | def manager_installed?(guest, ui) 93 | if guest.capability(:registration_manager_installed, ui) 94 | true 95 | else 96 | @logger.debug I18n.t('registration.action.manager_not_found') 97 | false 98 | end 99 | end 100 | 101 | # Fetch required credentials for selected manager 102 | def credentials_required(machine) 103 | if machine.guest.capability?(:registration_credentials) 104 | machine.guest.capability(:registration_credentials) 105 | else 106 | [] 107 | end 108 | end 109 | 110 | # Secret options for selected manager 111 | def secrets(machine) 112 | if machine.guest.capability?(:registration_secrets) 113 | machine.guest.capability(:registration_secrets) 114 | else 115 | [] 116 | end 117 | end 118 | 119 | # Check if required credentials has been provided in Vagrantfile 120 | # 121 | # Checks if at least one of the registration options is able to 122 | # register. 123 | def credentials_provided?(machine) 124 | provided = true 125 | credentials_required(machine).each do |registration_option| 126 | provided = true 127 | registration_option.each do |value| 128 | provided = false unless machine.config.registration.send value 129 | end 130 | break if provided 131 | end 132 | provided ? true : false 133 | end 134 | 135 | # Ask user on required credentials and return them, 136 | # skip options that are provided by Vagrantfile 137 | def register_on_screen(machine, ui) 138 | credentials_required(machine)[0].each do |option| 139 | unless machine.config.registration.send(option) 140 | echo = !(secrets(machine).include? option) 141 | response = ui.ask("#{option}: ", echo: echo) 142 | machine.config.registration.send("#{option}=".to_sym, response) 143 | end 144 | end 145 | machine.config.registration 146 | end 147 | 148 | def process_registration(guest, machine, ui, config) 149 | attempt_count = 1 150 | 151 | MAX_REGISTRATION_ATTEMPTS.times do 152 | config = register_on_screen(machine, ui) 153 | 154 | begin 155 | guest.capability(:registration_register, ui) 156 | ui.info I18n.t('registration.action.register.registration_success') 157 | # break out of loop on successful registration 158 | break 159 | rescue StandardError => e 160 | if attempt_count == MAX_REGISTRATION_ATTEMPTS 161 | ui.error e.message 162 | exit 126 163 | else 164 | # reset registration config 165 | reset_registration_config(machine) 166 | attempt_count += 1 167 | ui.info I18n.t('registration.action.register.registration_retry', 168 | attempt_count: attempt_count, max_attempt: MAX_REGISTRATION_ATTEMPTS) 169 | end 170 | end 171 | end 172 | 173 | config 174 | end 175 | 176 | def reset_registration_config(machine) 177 | credentials_required(machine)[0].each do |option| 178 | machine.config.registration.send("#{option}=".to_sym, nil) 179 | end 180 | end 181 | end 182 | end 183 | end 184 | end 185 | -------------------------------------------------------------------------------- /lib/vagrant-registration/action/unregister_on_destroy.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module Registration 5 | module Action 6 | # This unregisters the guest if the guest has registration capability 7 | class UnregisterOnDestroy 8 | def initialize(app, env) 9 | @app = app 10 | @logger = Log4r::Logger.new('vagrant_registration::action::unregister_on_destroy') 11 | end 12 | 13 | def call(env) 14 | config = env[:machine].config.registration 15 | guest = env[:machine].guest 16 | 17 | if capabilities_provided?(guest) && manager_installed?(guest, env[:ui]) && !config.skip 18 | env[:ui].info I18n.t('registration.action.unregister.unregistration_info') 19 | guest.capability(:registration_unregister) 20 | end 21 | 22 | @logger.debug(I18n.t('registration.action.unregister.skip_due_config')) if config.skip 23 | @app.call(env) 24 | 25 | # Guest might not be available after halting, so log the exception and continue 26 | rescue => e 27 | @logger.info(e) 28 | @logger.debug I18n.t('registration.action.unregister.guest_unavailable') 29 | @app.call(env) 30 | end 31 | 32 | private 33 | 34 | # Check if registration capabilities are available 35 | def capabilities_provided?(guest) 36 | if guest.capability?(:registration_unregister) && guest.capability?(:registration_manager_installed) 37 | true 38 | else 39 | @logger.debug I18n.t('registration.action.unregister.skip_missing_guest_capability') 40 | false 41 | end 42 | end 43 | 44 | # Check if selected registration manager is installed 45 | def manager_installed?(guest, ui) 46 | if guest.capability(:registration_manager_installed, ui) 47 | true 48 | else 49 | @logger.debug I18n.t('registration.action.manager_not_found') 50 | false 51 | end 52 | end 53 | end 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/vagrant-registration/action/unregister_on_halt.rb: -------------------------------------------------------------------------------- 1 | require 'log4r' 2 | 3 | module VagrantPlugins 4 | module Registration 5 | module Action 6 | # This unregisters the guest if the guest has registration capability 7 | class UnregisterOnHalt 8 | def initialize(app, env) 9 | @app = app 10 | @logger = Log4r::Logger.new('vagrant_registration::action::unregister_on_halt') 11 | end 12 | 13 | def call(env) 14 | config = env[:machine].config.registration 15 | guest = env[:machine].guest 16 | 17 | if capabilities_provided?(guest) && manager_installed?(guest, env[:ui]) && !config.skip && config.unregister_on_halt 18 | env[:ui].info I18n.t('registration.action.unregister.unregistration_info') 19 | guest.capability(:registration_unregister) 20 | end 21 | 22 | @logger.debug(I18n.t('registration.action.unregister.skip_due_config')) if config.skip 23 | @logger.debug(I18n.t('registration.action.unregister.skip_on_halt_due_config')) unless config.unregister_on_halt 24 | @app.call(env) 25 | 26 | # Guest might not be available after halting, so log the exception and continue 27 | rescue => e 28 | @logger.info(e) 29 | @logger.debug I18n.t('registration.action.unregister.guest_unavailable') 30 | @app.call(env) 31 | end 32 | 33 | private 34 | 35 | # Check if registration capabilities are available 36 | def capabilities_provided?(guest) 37 | if guest.capability?(:registration_unregister) && guest.capability?(:registration_manager_installed) 38 | true 39 | else 40 | @logger.debug I18n.t('registration.action.unregister.skip_missing_guest_capability') 41 | false 42 | end 43 | end 44 | 45 | # Check if selected registration manager is installed 46 | def manager_installed?(guest, ui) 47 | if guest.capability(:registration_manager_installed, ui) 48 | true 49 | else 50 | @logger.debug I18n.t('registration.action.manager_not_found') 51 | false 52 | end 53 | end 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/vagrant-registration/config.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | require 'ostruct' 3 | 4 | module VagrantPlugins 5 | module Registration 6 | class Config < Vagrant.plugin('2', :config) 7 | attr_reader :conf 8 | 9 | def initialize(region_specific=false) 10 | @conf = UNSET_VALUE 11 | @logger = Log4r::Logger.new('vagrant_registration::config') 12 | end 13 | 14 | def finalize! 15 | get_config 16 | @conf.skip = false unless @conf.skip 17 | # Unregister on halt by default 18 | @conf.unregister_on_halt = true if @conf.unregister_on_halt.nil? 19 | @logger.info I18n.t('registration.config.final_message', conf: @conf.inspect) 20 | end 21 | 22 | def method_missing(method_sym, *arguments, &block) 23 | get_config 24 | command = "@conf.#{method_sym} #{adjust_arguments(arguments)}" 25 | @logger.info I18n.t('registration.config.method_missing_command', command: command) 26 | eval command 27 | end 28 | 29 | private 30 | 31 | # Don't set @conf to OpenStruct in initialize 32 | # to preserve config hierarchy 33 | def get_config 34 | @conf = OpenStruct.new if @conf == UNSET_VALUE 35 | end 36 | 37 | # Serialize strings, nil and boolean values, symbols, arrays and hashes 38 | # to be used within eval() 39 | def adjust_arguments(args) 40 | return '' if args.size < 1 41 | args.inspect[1..-2] 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/vagrant-registration/plugin.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require 'vagrant' 3 | rescue LoadError 4 | raise 'The vagrant-registration plugin must be run within Vagrant.' 5 | end 6 | 7 | # This is a sanity check to make sure no one is attempting to install 8 | # this into an early Vagrant version. 9 | if Vagrant::VERSION < '1.2.0' 10 | fail I18n.t('registration.plugin.compatible_message') 11 | end 12 | 13 | module VagrantPlugins 14 | module Registration 15 | class Plugin < Vagrant.plugin('2') 16 | class << self 17 | # vagrant-vbguest plugin updates GuestAdditions for VirtualBox 18 | # and therefore needs to be run after the box got registered. 19 | # See https://github.com/projectatomic/adb-vagrant-registration/issues/69 20 | # 21 | # vagrant-vbguest hooks before VagrantPlugins::ProviderVirtualBox::Action::CheckGuestAdditions 22 | # (see https://github.com/mitchellh/vagrant/blob/master/plugins/providers/virtualbox/action.rb#L81) 23 | # For registration to occur in time, it has to happen before that. Using WaitForCommunicator 24 | # to be sure - https://github.com/dotless-de/vagrant-vbguest/blob/master/lib/vagrant-vbguest.rb#L53 25 | # 26 | # For vagrant-libvirt WaitTillUp is used 27 | def register(hook) 28 | setup_logging 29 | 30 | registered = false 31 | if virtual_box? 32 | hook.after(VagrantPlugins::ProviderVirtualBox::Action::WaitForCommunicator, 33 | VagrantPlugins::Registration::Action.action_register) 34 | registered = true 35 | end 36 | if libvirt? 37 | hook.after(VagrantPlugins::ProviderLibvirt::Action::WaitTillUp, 38 | VagrantPlugins::Registration::Action.action_register) 39 | registered = true 40 | end 41 | # Best guess for the other providers 42 | unless registered 43 | hook.after(Vagrant::Action::Builtin::WaitForCommunicator, 44 | VagrantPlugins::Registration::Action.action_register) 45 | end 46 | end 47 | 48 | def unregister_on_halt(hook) 49 | setup_logging 50 | hook.prepend(VagrantPlugins::Registration::Action.action_unregister_on_halt) 51 | end 52 | 53 | def unregister_on_destroy(hook) 54 | setup_logging 55 | hook.prepend(VagrantPlugins::Registration::Action.action_unregister_on_destroy) 56 | end 57 | end 58 | 59 | name I18n.t('registration.plugin.name') 60 | description I18n.t('registration.plugin.description') 61 | 62 | action_hook(:registration_register, :machine_action_up, &method(:register)) 63 | action_hook(:registration_register, :machine_action_provision, &method(:register)) 64 | action_hook(:registration_unregister_on_halt, :machine_action_halt, &method(:unregister_on_halt)) 65 | action_hook(:registration_unregister_on_destroy, :machine_action_destroy, &method(:unregister_on_destroy)) 66 | 67 | config(:registration) do 68 | setup_logging 69 | require_relative 'config' 70 | Config 71 | end 72 | 73 | # This sets up our log level to be whatever VAGRANT_LOG is 74 | # for loggers prepended with 'vagrant_registration' 75 | def self.setup_logging 76 | require 'log4r' 77 | level = nil 78 | begin 79 | level = Log4r.const_get(ENV['VAGRANT_LOG'].upcase) 80 | rescue NameError 81 | # This means that the logging constant wasn't found, 82 | # which is fine. We just keep `level` as `nil`. But 83 | # we tell the user. 84 | level = nil 85 | end 86 | # Some constants, such as "true" resolve to booleans, so the 87 | # above error checking doesn't catch it. This will check to make 88 | # sure that the log level is an integer, as Log4r requires. 89 | level = nil unless level.is_a?(Integer) 90 | # Set the logging level on all "vagrant" namespaced 91 | # logs as long as we have a valid level. 92 | if level 93 | logger = Log4r::Logger.new('vagrant_registration') 94 | logger.outputters = Log4r::Outputter.stderr 95 | logger.level = level 96 | logger = nil 97 | end 98 | end 99 | 100 | # Determines if VirtualBox is provider 101 | def self.virtual_box? 102 | defined?(VagrantPlugins::ProviderVirtualBox::Provider) 103 | end 104 | 105 | # Determines if LibVirt is provider 106 | def self.libvirt? 107 | defined?(VagrantPlugins::ProviderLibvirt::Provider) 108 | end 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /lib/vagrant-registration/version.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | # Registration plugin to auto-register guests on `vagrant up` 3 | module Registration 4 | VERSION = '1.3.4' 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /locales/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | registration: 3 | config: 4 | final_message: 'Final registration configuration: %{conf}' 5 | method_missing_command: 'Evaluating registration configuration: %{command}' 6 | plugin: 7 | compatible_message: 'The Vagrant RHEL plugin is only compatible with Vagrant 1.2+.' 8 | name: 'Registration' 9 | description: |- 10 | This plugin adds register and unregister functionality to Vagrant Guests that 11 | support the capability 12 | action: 13 | manager_not_found: 'Registration manager not found on guest' 14 | register: 15 | registration_info: 'Registering box with vagrant-registration...' 16 | no_credentials: 'Credentials for registration not provided' 17 | prompt: 'Would you like to register the system now (default: yes)? [y|n]' 18 | skip_due_config: 'Registration is skipped due to the configuration' 19 | options_support_warning: |- 20 | WARNING: %{manager} supports only the following options: 21 | WARNING: %{options}" 22 | unsupported_option: "WARNING: %{option} option is not supported for %{manager}" 23 | skip_missing_guest_capability: 'Registration is skipped due to the missing guest capability' 24 | registration_retry: |- 25 | Invalid username/password. Try again (%{attempt_count}/%{max_attempt}) 26 | registration_success: 'Registration successful.' 27 | unregister: 28 | unregistration_info: 'Unregistering box with vagrant-registration...' 29 | skip_due_config: 'Unregistration is skipped due to the configuration' 30 | skip_on_halt_due_config: 'Unregistration is skipped on halt due to the configuration' 31 | guest_unavailable: 'Guest is not available, ignore unregistration' 32 | skip_missing_guest_capability: 'Unregistration is skipped due to the missing guest capability' 33 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/registration.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | # Common configuration options for all managers 5 | DEFAULT_CONFIGURATION_OPTIONS = [:manager, :skip, :unregister_on_halt] 6 | 7 | # This provides registration capabilities for vagrant-registration 8 | # 9 | # As we might support more registration options (managers), this 10 | # just calls the capabilities of the selected registration manager 11 | # (from config.registration.manager). 12 | class Registration 13 | # Is the machine already registered? 14 | def self.registration_registered?(machine) 15 | cap = "#{registration_manager(machine)}_registered?".to_sym 16 | if machine.guest.capability?(cap) 17 | machine.guest.capability(cap) 18 | else 19 | false 20 | end 21 | end 22 | 23 | # Register the given machine 24 | def self.registration_register(machine, ui) 25 | cap = "#{registration_manager(machine)}_register".to_sym 26 | if machine.guest.capability?(cap) 27 | machine.guest.capability(cap, ui) 28 | else 29 | false 30 | end 31 | end 32 | 33 | # Unregister the given machine 34 | def self.registration_unregister(machine) 35 | cap = "#{registration_manager(machine)}_unregister".to_sym 36 | if machine.guest.capability?(cap) 37 | machine.guest.capability(cap) 38 | else 39 | false 40 | end 41 | end 42 | 43 | # Check that the machine has the selected registration manager installed 44 | # and warn if the user specifically selected a manager that is not available 45 | def self.registration_manager_installed(machine, ui) 46 | cap = "#{registration_manager(machine)}".to_sym 47 | return machine.guest.capability(cap) if machine.guest.capability?(cap) 48 | if machine.config.registration.manager != '' 49 | ui.error("WARNING: Selected registration manager #{machine.config.registration.manager} is not available, skipping.") 50 | end 51 | false 52 | end 53 | 54 | # Required configuration options of the registration manager 55 | # 56 | # This is array of arrays of all possible registration combinations. 57 | # First one is the default used in interactive mode. 58 | # 59 | # e.g. [[:username, :password]] 60 | def self.registration_credentials(machine) 61 | cap = "#{registration_manager(machine)}_credentials".to_sym 62 | if machine.guest.capability?(cap) 63 | machine.guest.capability(cap) 64 | else 65 | [] 66 | end 67 | end 68 | 69 | # Return all available options for a given registration manager together 70 | # with general options available to any. 71 | def self.registration_options(machine) 72 | cap = "#{registration_manager(machine)}_options".to_sym 73 | if machine.guest.capability?(cap) 74 | DEFAULT_CONFIGURATION_OPTIONS + machine.guest.capability(cap) 75 | else 76 | DEFAULT_CONFIGURATION_OPTIONS 77 | end 78 | end 79 | 80 | # Return secret options for the registration manager 81 | def self.registration_secrets(machine) 82 | cap = "#{registration_manager(machine)}_secrets".to_sym 83 | if machine.guest.capability?(cap) 84 | machine.guest.capability(cap) 85 | else 86 | [] 87 | end 88 | end 89 | 90 | # Return selected registration manager or default 91 | def self.registration_manager(machine) 92 | (machine.config.registration.manager || 'subscription_manager').to_sym 93 | end 94 | end 95 | end 96 | end 97 | end 98 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/rhn_register.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | class RhnRegister 5 | # Test that the machine is already registered 6 | def self.rhn_register_registered?(machine) 7 | true if machine.communicate.sudo('/usr/sbin/rhn_check') 8 | rescue 9 | false 10 | end 11 | 12 | # Test that we have rhn installed 13 | def self.rhn_register(machine) 14 | machine.communicate.test('/usr/sbin/rhn_check --version', sudo: true) && 15 | machine.communicate.test('/usr/sbin/rhnreg_ks --version', sudo: true) 16 | end 17 | 18 | # Register the machine using 'rhnreg_ks' command, config is (Open)Struct 19 | def self.rhn_register_register(machine, ui) 20 | rhn_register_upload_certificate(machine, ui) 21 | rhn_register_server_url(machine, ui) if machine.config.registration.serverurl 22 | command = "rhnreg_ks #{configuration_to_options(machine.config.registration)}" 23 | 24 | # Handle exception to avoid displaying password 25 | begin 26 | error = String.new 27 | machine.communicate.sudo(registration_command(command)) do |type, data| 28 | error += "#{data}" if type == :stderr 29 | end 30 | rescue Vagrant::Errors::VagrantError 31 | raise Vagrant::Errors::VagrantError.new, error.strip 32 | end 33 | end 34 | 35 | # Unregister the machine using 'rhn_unregister.py' resource script 36 | def self.rhn_register_unregister(machine) 37 | machine.communicate.tap do |comm| 38 | tmp = '/tmp/rhn_unregister' 39 | system_id = '/etc/sysconfig/rhn/systemid' 40 | server_url = machine.config.registration.serverurl 41 | # Generate the API URL 42 | server_url = server_url.sub(/XMLRPC$/, 'rpc/api') 43 | comm.sudo("rm -f #{tmp}", error_check: false) 44 | comm.upload(resource('rhn_unregister.py'), tmp) 45 | comm.sudo("python #{tmp} -s #{server_url} -f #{system_id}") 46 | comm.sudo("rm -f #{tmp}") 47 | # Guest still thinks it is a part of RHN network until systemdid file is removed 48 | comm.sudo("rm -f #{system_id}") 49 | end 50 | end 51 | 52 | # Return required configuration options for rhn register 53 | # 54 | # For rhn_register the Server URL is mandatory and must be always 55 | # provided together with the credentials 56 | def self.rhn_register_credentials(machine) 57 | [[:username, :password, :serverurl], [:org, :activationkey, :serverurl]] 58 | end 59 | 60 | # Return all available options for rhn register 61 | def self.rhn_register_options(machine) 62 | [:name, :username, :password, :org, :serverurl, :ca_cert, 63 | :activationkey, :use_eus_channel, :nohardware, :nopackages, 64 | :novirtinfo, :norhnsd, :force, :proxy, :proxyUser, :proxyPassword] 65 | end 66 | 67 | # Return secret options for rhreg_ks 68 | def self.rhn_register_secrets(manager) 69 | [:password] 70 | end 71 | 72 | private 73 | 74 | # Upload provided SSL CA cert to the standard /usr/share/rhn/ path on the guest 75 | # and configure the correct path in `up2date` system configuration 76 | def self.rhn_register_upload_certificate(machine, ui) 77 | # Set as the default CA certificate file that is present on Fedora, CentOS and RHEL 78 | cert_file_name = 'RHNS-CA-CERT' 79 | if machine.config.registration.ca_cert 80 | ui.info("Uploading CA certificate from #{machine.config.registration.ca_cert}...") 81 | if File.exist?(machine.config.registration.ca_cert) 82 | # Make sure the provided CA certificate file will be configured 83 | cert_file_name = File.basename(machine.config.registration.ca_cert) 84 | cert_file_content = File.read(machine.config.registration.ca_cert) 85 | machine.communicate.sudo("echo '#{cert_file_content}' > /usr/share/rhn/#{cert_file_name}") 86 | else 87 | ui.warn("WARNING: Provided CA certificate file #{machine.config.registration.ca_cert} does not exist, skipping") 88 | end 89 | end 90 | # Make sure the correct CA certificate file is always configured 91 | ui.info("Updating CA certificate to /usr/share/rhn/#{cert_file_name}`...") 92 | machine.communicate.sudo("sed -i 's|^sslCACert\s*=.*$|sslCACert=/usr/share/rhn/#{cert_file_name}|g' /etc/sysconfig/rhn/up2date") 93 | end 94 | 95 | # Build registration command that skips registration if the system is registered 96 | def self.registration_command(command) 97 | "cmd=$(#{command}); if [ \"$?\" != \"0\" ]; then echo $cmd | grep 'This system is already registered' || (echo $cmd 1>&2 && exit 1) ; fi" 98 | end 99 | 100 | # Update configuration file '/etc/sysconfig/rhn/up2date' with 101 | # provided server URL 102 | def self.rhn_register_server_url(machine, ui) 103 | ui.info("Update server URL to #{machine.config.registration.serverurl}...") 104 | machine.communicate.sudo("sed -i 's|^serverURL=.*$|serverURL=/usr/share/rhn/#{machine.config.registration.serverurl}|' /etc/sysconfig/rhn/up2date") 105 | end 106 | 107 | # The absolute path to the resource file 108 | def self.resource(name) 109 | File.join(resource_root, name) 110 | end 111 | 112 | # The absolute path to the resource directory 113 | def self.resource_root 114 | File.expand_path('../../../../../resources', __FILE__) 115 | end 116 | 117 | # Build additional rhreg_ks options based on the plugin configuration 118 | def self.configuration_to_options(config) 119 | config.force = true if config.force.nil? 120 | 121 | options = [] 122 | options << "--profilename='#{config.name}'" if config.name 123 | options << "--username='#{config.username}'" if config.username 124 | options << "--password='#{config.password}'" if config.password 125 | options << "--systemorgid='#{config.org}'" if config.org 126 | options << "--serverUrl='#{config.serverurl}'" if config.serverurl 127 | options << "--activationkey='#{config.activationkey}'" if config.activationkey 128 | options << '--use-eus-channel' if config.use_eus_channel 129 | options << '--nohardware' if config.nohardware 130 | options << '--nopackages' if config.nopackages 131 | options << '--novirtinfo' if config.novirtinfo 132 | options << '--norhnsd' if config.norhnsd 133 | options << '--force' if config.force 134 | options << "--proxy='#{config.proxy}'" if config.proxy 135 | options << "--proxyUser='#{config.proxyUser}'" if config.proxyUser 136 | options << "--proxyPassword='#{config.proxyPassword}'" if config.proxyPassword 137 | options.join(' ') 138 | end 139 | end 140 | end 141 | end 142 | end 143 | -------------------------------------------------------------------------------- /plugins/guests/redhat/cap/subscription_manager.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module GuestRedHat 3 | module Cap 4 | class SubscriptionManager 5 | # Test that the machine is already registered 6 | def self.subscription_manager_registered?(machine) 7 | true if machine.communicate.sudo("/usr/sbin/subscription-manager list --consumed --pool-only | grep -E '^[a-f0-9]{32}$'") 8 | rescue 9 | false 10 | end 11 | 12 | # Test that we have subscription-manager installed 13 | def self.subscription_manager(machine) 14 | machine.communicate.test('/usr/sbin/subscription-manager', sudo: true) 15 | end 16 | 17 | # Register the machine using 'register' option, config is (Open)Struct 18 | def self.subscription_manager_register(machine, ui) 19 | subscription_manager_upload_certificate(machine, ui) if machine.config.registration.ca_cert 20 | command = "subscription-manager register #{configuration_to_options(machine.config.registration)}" 21 | 22 | # Handle exception to avoid displaying password 23 | begin 24 | error = String.new 25 | machine.communicate.sudo(registration_command(command)) do |type, data| 26 | error += "#{data}" if type == :stderr 27 | end 28 | rescue Vagrant::Errors::VagrantError 29 | raise Vagrant::Errors::VagrantError.new, error.strip 30 | end 31 | 32 | attach_pools(machine, machine.config.registration.pools) 33 | end 34 | 35 | # Unregister the machine using 'unregister' option 36 | def self.subscription_manager_unregister(machine) 37 | machine.communicate.sudo("subscription-manager unregister #{configuration_to_options_unregister(machine.config.registration)}") 38 | end 39 | 40 | # Return required configuration options for subscription-manager 41 | def self.subscription_manager_credentials(machine) 42 | [[:username, :password], [:org, :activationkey]] 43 | end 44 | 45 | # Return all available options for subscription-manager 46 | # 47 | # ca_cert is not part of 'register' command API, but it's needed 48 | # in conjuntion with serverurl option. 49 | def self.subscription_manager_options(machine) 50 | [:username, :password, :serverurl, :baseurl, :org, :environment, 51 | :name, :auto_attach, :activationkey, :servicelevel, :release, 52 | :force, :type, :ca_cert, :pools, :proxy, :proxyUser, :proxyPassword] 53 | end 54 | 55 | # Return secret options for subscription-manager 56 | def self.subscription_manager_secrets(machine) 57 | [:password] 58 | end 59 | 60 | private 61 | 62 | # Upload provided CA cert to the standard /etc/rhsm/ca path on the guest 63 | # 64 | # Since subscription-manager recognizes only .pem files, we rename those 65 | # files not ending with '.pem' extension. 66 | def self.subscription_manager_upload_certificate(machine, ui) 67 | ui.info("Uploading CA certificate from #{machine.config.registration.ca_cert}...") 68 | if File.exist?(machine.config.registration.ca_cert) 69 | cert_file_content = File.read(machine.config.registration.ca_cert) 70 | cert_file_name = File.basename(machine.config.registration.ca_cert) 71 | cert_file_name = "#{cert_file_name}.pem" unless cert_file_name.end_with? '.pem' 72 | machine.communicate.sudo("echo '#{cert_file_content}' > /etc/rhsm/ca/#{cert_file_name}") 73 | ui.info('Setting repo_ca_cert option in /etc/rhsm/rhsm.conf...') 74 | machine.communicate.sudo("sed -i 's|^repo_ca_cert\s*=.*|repo_ca_cert = /etc/rhsm/ca/#{cert_file_name}|g' /etc/rhsm/rhsm.conf") 75 | else 76 | ui.warn("WARNING: Provided CA certificate file #{machine.config.registration.ca_cert} does not exist, skipping") 77 | end 78 | end 79 | 80 | # Build registration command that skips registration if the system is registered 81 | def self.registration_command(command) 82 | "cmd=$(#{command}); if [ \"$?\" != \"0\" ]; then echo $cmd | grep 'This system is already registered' || (echo $cmd 1>&2 && exit 1) ; fi" 83 | end 84 | 85 | # Build additional subscription-manager options based on plugin configuration 86 | def self.configuration_to_options(config) 87 | config.force = true if config.force.nil? 88 | 89 | # --auto-attach cannot be used in case of org/activationkey registration 90 | # or if pools are specified 91 | if (config.org && config.activationkey) || config.pools 92 | config.auto_attach = false 93 | else 94 | config.auto_attach = true if config.auto_attach.nil? 95 | end 96 | 97 | options = [] 98 | options << "--username='#{config.username}'" if config.username 99 | options << "--password='#{config.password}'" if config.password 100 | options << "--serverurl='#{config.serverurl}'" if config.serverurl 101 | options << "--baseurl='#{config.baseurl}'" if config.baseurl 102 | options << "--org='#{config.org}'" if config.org 103 | options << "--environment='#{config.environment}'" if config.environment 104 | options << "--name='#{config.name}'" if config.name 105 | options << '--auto-attach' if config.auto_attach 106 | options << "--activationkey='#{config.activationkey}'" if config.activationkey 107 | options << "--servicelevel='#{config.servicelevel}'" if config.servicelevel 108 | options << "--release='#{config.release}'" if config.release 109 | options << '--force' if config.force 110 | options << "--type='#{config.type}'" if config.type 111 | options << "--proxy='#{config.proxy}'" if config.proxy 112 | options << "--proxyuser='#{config.proxyUser}'" if config.proxyUser 113 | options << "--proxypassword='#{config.proxyPassword}'" if config.proxyPassword 114 | options.join(' ') 115 | end 116 | 117 | # Build subscription manager options for unregistering the Vagrant guest 118 | def self.configuration_to_options_unregister(config) 119 | options = [] 120 | options << "--proxy='#{config.proxy}'" if config.proxy 121 | options << "--proxyuser='#{config.proxyUser}'" if config.proxyUser 122 | options << "--proxypassword='#{config.proxyPassword}'" if config.proxyPassword 123 | options.join(' ') 124 | end 125 | 126 | # Attach subscription pools 127 | def self.attach_pools(machine, pools) 128 | if pools 129 | command = "subscription-manager attach #{pools_to_options(pools)}" 130 | machine.communicate.sudo(command) 131 | end 132 | end 133 | 134 | # Return pools options for subscription-manager 135 | def self.pools_to_options(pools) 136 | pools = [pools] if pools.kind_of?(String) 137 | pools.map do |pool| 138 | "--pool=#{pool}" 139 | end.join(' ') 140 | end 141 | end 142 | end 143 | end 144 | end 145 | -------------------------------------------------------------------------------- /plugins/guests/redhat/plugin.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant' 2 | 3 | module VagrantPlugins 4 | module GuestRedHat 5 | class Plugin < Vagrant.plugin('2') 6 | guest_capability('redhat', 'registration_registered?') do 7 | require_relative 'cap/registration' 8 | Cap::Registration 9 | end 10 | 11 | guest_capability('redhat', 'registration_register') do 12 | require_relative 'cap/registration' 13 | Cap::Registration 14 | end 15 | 16 | guest_capability('redhat', 'registration_unregister') do 17 | require_relative 'cap/registration' 18 | Cap::Registration 19 | end 20 | 21 | guest_capability('redhat', 'registration_manager_installed') do 22 | require_relative 'cap/registration' 23 | Cap::Registration 24 | end 25 | 26 | guest_capability('redhat', 'registration_credentials') do 27 | require_relative 'cap/registration' 28 | Cap::Registration 29 | end 30 | 31 | guest_capability('redhat', 'registration_options') do 32 | require_relative 'cap/registration' 33 | Cap::Registration 34 | end 35 | 36 | guest_capability('redhat', 'registration_secrets') do 37 | require_relative 'cap/registration' 38 | Cap::Registration 39 | end 40 | 41 | guest_capability('redhat', 'registration_manager') do 42 | require_relative 'cap/registration' 43 | Cap::Registration 44 | end 45 | 46 | guest_capability('redhat', 'subscription_manager') do 47 | require_relative 'cap/subscription_manager' 48 | Cap::SubscriptionManager 49 | end 50 | 51 | guest_capability('redhat', 'subscription_manager_registered?') do 52 | require_relative 'cap/subscription_manager' 53 | Cap::SubscriptionManager 54 | end 55 | 56 | guest_capability('redhat', 'subscription_manager_register') do 57 | require_relative 'cap/subscription_manager' 58 | Cap::SubscriptionManager 59 | end 60 | 61 | guest_capability('redhat', 'subscription_manager_unregister') do 62 | require_relative 'cap/subscription_manager' 63 | Cap::SubscriptionManager 64 | end 65 | 66 | guest_capability('redhat', 'subscription_manager_credentials') do 67 | require_relative 'cap/subscription_manager' 68 | Cap::SubscriptionManager 69 | end 70 | 71 | guest_capability('redhat', 'subscription_manager_options') do 72 | require_relative 'cap/subscription_manager' 73 | Cap::SubscriptionManager 74 | end 75 | 76 | guest_capability('redhat', 'subscription_manager_secrets') do 77 | require_relative 'cap/subscription_manager' 78 | Cap::SubscriptionManager 79 | end 80 | 81 | guest_capability('redhat', 'rhn_register') do 82 | require_relative 'cap/rhn_register' 83 | Cap::RhnRegister 84 | end 85 | 86 | guest_capability('redhat', 'rhn_register_registered?') do 87 | require_relative 'cap/rhn_register' 88 | Cap::RhnRegister 89 | end 90 | 91 | guest_capability('redhat', 'rhn_register_register') do 92 | require_relative 'cap/rhn_register' 93 | Cap::RhnRegister 94 | end 95 | 96 | guest_capability('redhat', 'rhn_register_unregister') do 97 | require_relative 'cap/rhn_register' 98 | Cap::RhnRegister 99 | end 100 | 101 | guest_capability('redhat', 'rhn_register_credentials') do 102 | require_relative 'cap/rhn_register' 103 | Cap::RhnRegister 104 | end 105 | 106 | guest_capability('redhat', 'rhn_register_options') do 107 | require_relative 'cap/rhn_register' 108 | Cap::RhnRegister 109 | end 110 | 111 | guest_capability('redhat', 'rhn_register_secrets') do 112 | require_relative 'cap/rhn_register' 113 | Cap::RhnRegister 114 | end 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /resources/rhn_unregister.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import xmlrpclib 3 | import os.path 4 | import sys 5 | 6 | def main(): 7 | parser = argparse.ArgumentParser(description="Unregister the system from Spacewalk Server, Red Hat Satellite or Red Hat Network Classic.") 8 | parser.add_argument("-s", "--serverurl", dest="server_url", type=str, required=True, 9 | help="Specify a URL to as the server.") 10 | parser.add_argument("-f", "--file", dest="system_id", type=str, default='/etc/sysconfig/rhn/systemid', 11 | help="Specify a path to the RHN systemid file.") 12 | 13 | args = parser.parse_args() 14 | 15 | try: 16 | if not os.path.exists(args.system_id): 17 | print "System is not registered to RHN" 18 | return 1 19 | client = xmlrpclib.Server(args.server_url) 20 | client.system.delete_system(open(args.system_id).read()) 21 | except xmlrpclib.ProtocolError as err: 22 | print "A fault occurred" 23 | print "Fault string: %s" % err 24 | return 1 25 | except xmlrpclib.Fault as err: 26 | print "A fault occurred" 27 | print "Fault code: %d" % err.faultCode 28 | print "Fault string: %s" % err.faultString 29 | return 1 30 | except IOError as err: 31 | print "A fault occurred" 32 | print "Fault string: %s" % err 33 | return 1 34 | except Exception as e: 35 | print "A fault occurred" 36 | print "Fault: %s" % e 37 | return 1 38 | print "Unregister successful" 39 | return 0 40 | 41 | if __name__ == "__main__": 42 | sys.exit(main()) 43 | -------------------------------------------------------------------------------- /test/support/fake_ui.rb: -------------------------------------------------------------------------------- 1 | class FakeUI 2 | def self.info(*args) 3 | end 4 | end 5 | -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | $:.push(File.expand_path('../../plugins', __FILE__)) 2 | $:.push(File.expand_path('../../lib', __FILE__)) 3 | 4 | require 'bundler/setup' 5 | 6 | require 'vagrant-registration' 7 | require 'guests/redhat/cap/subscription_manager' 8 | require 'guests/redhat/cap/rhn_register' 9 | 10 | require 'minitest/autorun' 11 | require 'mocha/mini_test' 12 | 13 | require_relative 'support/fake_ui.rb' 14 | 15 | def fake_environment(options = { enabled: true }) 16 | { machine: fake_machine(options), ui: FakeUI } 17 | end 18 | 19 | class RecordingCommunicator 20 | attr_reader :commands, :responses 21 | 22 | def initialize 23 | @commands = Hash.new([]) 24 | @responses = Hash.new('') 25 | end 26 | 27 | def stub_command(command, response) 28 | responses[command] = response 29 | end 30 | 31 | def sudo(command) 32 | #puts "SUDO: #{command}" 33 | commands[:sudo] << command 34 | responses[command] 35 | end 36 | 37 | def execute(command) 38 | #puts "EXECUTE: #{command}" 39 | commands[:execute] << command 40 | responses[command].split("\n").each do |line| 41 | yield(:stdout, "#{line}\n") 42 | end 43 | end 44 | 45 | def test(command) 46 | commands[:test] << command 47 | true 48 | end 49 | 50 | def ready? 51 | true 52 | end 53 | end 54 | 55 | module Registration 56 | class FakeProvider 57 | def initialize(*args) 58 | end 59 | 60 | def _initialize(*args) 61 | end 62 | 63 | def ssh_info 64 | end 65 | 66 | def state 67 | @state ||= Vagrant::MachineState.new('fake-state', 'fake-state', 'fake-state') 68 | end 69 | end 70 | end 71 | 72 | module Registration 73 | class FakeConfig 74 | def registration 75 | @registration_config ||= VagrantPlugins::Registration::Config.new 76 | end 77 | 78 | def vm 79 | VagrantPlugins::Kernel_V2::VMConfig.new 80 | end 81 | end 82 | end 83 | 84 | def fake_machine(options={}) 85 | env = options.fetch(:env, Vagrant::Environment.new) 86 | machine = Vagrant::Machine.new( 87 | 'fake_machine', 88 | 'fake_provider', 89 | Registration::FakeProvider, 90 | 'provider_config', 91 | {}, # provider_options 92 | env.vagrantfile.config, # config 93 | Pathname('data_dir'), 94 | 'box', 95 | options.fetch(:env, Vagrant::Environment.new), 96 | env.vagrantfile 97 | ) 98 | 99 | machine.instance_variable_set("@communicator", RecordingCommunicator.new) 100 | machine.config.vm.hostname = options.fetch(:hostname, 'somehost.vagrant.test') 101 | machine 102 | end 103 | 104 | module MiniTest 105 | class Spec 106 | alias_method :hush, :capture_io 107 | end 108 | end 109 | 110 | 111 | 112 | 113 | 114 | 115 | -------------------------------------------------------------------------------- /test/vagrant-registration/cap/redhat/rhn_register_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../test_helper.rb' 2 | 3 | describe VagrantPlugins::GuestRedHat::Cap::RhnRegister do 4 | let(:machine) { fake_machine } 5 | 6 | describe 'options' do 7 | it 'supports proxy options' do 8 | supported_options = VagrantPlugins::GuestRedHat::Cap::RhnRegister.rhn_register_options(machine) 9 | supported_options.must_include :proxy 10 | supported_options.must_include :proxyUser 11 | supported_options.must_include :proxyPassword 12 | end 13 | end 14 | 15 | describe 'register' do 16 | it 'calls rhn_register with default options' do 17 | VagrantPlugins::GuestRedHat::Cap::RhnRegister.rhn_register_register(machine, FakeUI) 18 | 19 | assert_equal(2, machine.communicate.commands[:sudo].length, 'there should be only one recorded sudo command') 20 | registration_command = machine.communicate.commands[:sudo][1] 21 | assert_match(/rhnreg_ks/, registration_command, 'rhnreg_ks should have been called') 22 | end 23 | 24 | it 'passes username and password to rhn_register as specified via Vagrant config' do 25 | machine.config.registration.username = 'foo' 26 | machine.config.registration.password = 'bar' 27 | 28 | VagrantPlugins::GuestRedHat::Cap::RhnRegister.rhn_register_register(machine, FakeUI) 29 | 30 | registration_command = machine.communicate.commands[:sudo][1] 31 | assert_match(/--username='foo'/, registration_command, 'the username should have been set') 32 | assert_match(/--password='bar'/, registration_command, 'the password should have been set') 33 | end 34 | end 35 | 36 | it 'passes proxy settings to rhn_register as specified via Vagrant config' do 37 | machine.config.registration.proxy = 'mongo:8080' 38 | machine.config.registration.proxyUser = 'flash' 39 | machine.config.registration.proxyPassword = 'zarkov' 40 | 41 | VagrantPlugins::GuestRedHat::Cap::RhnRegister.rhn_register_register(machine, FakeUI) 42 | 43 | registration_command = machine.communicate.commands[:sudo][1] 44 | assert_match(/--proxy='mongo:8080'/, registration_command, 'the proxy server and port should have been set') 45 | assert_match(/--proxyUser='flash'/, registration_command, 'the proxy username have been set') 46 | assert_match(/--proxyPassword='zarkov'/, registration_command, 'the proxy password should have been set') 47 | end 48 | end 49 | 50 | -------------------------------------------------------------------------------- /test/vagrant-registration/cap/redhat/subscription_manager_test.rb: -------------------------------------------------------------------------------- 1 | require_relative '../../../test_helper.rb' 2 | 3 | describe VagrantPlugins::GuestRedHat::Cap::SubscriptionManager do 4 | let(:machine) { fake_machine } 5 | 6 | describe 'options' do 7 | it 'supports proxy options' do 8 | supported_options = VagrantPlugins::GuestRedHat::Cap::SubscriptionManager.subscription_manager_options(machine) 9 | supported_options.must_include :proxy 10 | supported_options.must_include :proxyUser 11 | supported_options.must_include :proxyPassword 12 | end 13 | end 14 | 15 | describe 'register' do 16 | it 'calls subscription-manager register with default options' do 17 | VagrantPlugins::GuestRedHat::Cap::SubscriptionManager.subscription_manager_register(machine, FakeUI) 18 | 19 | # RecordingCommunicator keeps track of the commands executed 20 | assert_equal(1, machine.communicate.commands[:sudo].length, 'there should be only one recorded sudo command') 21 | registration_command = machine.communicate.commands[:sudo][0] 22 | assert_match(/subscription-manager register/, registration_command, 'subscription-manager register should have been called') 23 | end 24 | 25 | it 'passes username and password to subscription-manager as specified via Vagrant config' do 26 | machine.config.registration.username = 'foo' 27 | machine.config.registration.password = 'bar' 28 | 29 | VagrantPlugins::GuestRedHat::Cap::SubscriptionManager.subscription_manager_register(machine, FakeUI) 30 | 31 | registration_command = machine.communicate.commands[:sudo][0] 32 | assert_match(/--username='foo'/, registration_command, 'the username should have been set') 33 | assert_match(/--password='bar'/, registration_command, 'the password should have been set') 34 | end 35 | end 36 | 37 | it 'passes proxy settings to subscription-manager as specified via Vagrant config' do 38 | machine.config.registration.proxy = 'mongo:8080' 39 | machine.config.registration.proxyUser = 'flash' 40 | machine.config.registration.proxyPassword = 'zarkov' 41 | 42 | VagrantPlugins::GuestRedHat::Cap::SubscriptionManager.subscription_manager_register(machine, FakeUI) 43 | 44 | registration_command = machine.communicate.commands[:sudo][0] 45 | assert_match(/--proxy='mongo:8080'/, registration_command, 'the proxy server and port should have been set') 46 | assert_match(/--proxyuser='flash'/, registration_command, 'the proxy username have been set') 47 | assert_match(/--proxypassword='zarkov'/, registration_command, 'the proxy password should have been set') 48 | end 49 | end 50 | 51 | -------------------------------------------------------------------------------- /vagrant-registration.gemspec: -------------------------------------------------------------------------------- 1 | $LOAD_PATH.unshift File.expand_path('../lib', __FILE__) 2 | require 'vagrant-registration/version' 3 | 4 | Gem::Specification.new do |s| 5 | s.name = 'vagrant-registration' 6 | s.version = VagrantPlugins::Registration::VERSION 7 | s.platform = Gem::Platform::RUBY 8 | s.license = 'GPL-2.0' 9 | s.authors = ['Langdon White', 'Josef Strzibny', 'et al'] 10 | s.email = ['langdon@fedoraproject.org', 'strzibny@strzibny.name'] 11 | s.summary = 'Automatic guest registration for Vagrant' 12 | s.description = 'Enables guests to be registered automatically which is especially useful for RHEL or SLES guests.' 13 | s.homepage = 'https://github.com/projectatomic/adb-vagrant-registration' 14 | s.required_rubygems_version = '>= 1.3.6' 15 | 16 | # Note that the entire gitignore(5) syntax is not supported, specifically 17 | # the '!' syntax, but it should mostly work correctly. 18 | root_path = File.dirname(__FILE__) 19 | all_files = Dir.chdir(root_path) do 20 | Dir.glob('lib/**/{*,.*}') + 21 | Dir.glob('plugins/**/{*,.*}') + 22 | Dir.glob('locales/**/{*,.*}') + 23 | Dir.glob('resources/**/{*,.*}') + 24 | ['Rakefile', 'Gemfile', 'README.adoc', 'CHANGELOG.adoc', 'LICENSE', 'vagrant-registration.gemspec'] 25 | end 26 | all_files.reject! { |file| ['.', '..'].include?(File.basename(file)) } 27 | gitignore_path = File.join(root_path, '.gitignore') 28 | gitignore = File.readlines(gitignore_path) 29 | gitignore.map! { |line| line.chomp.strip } 30 | gitignore.reject! { |line| line.empty? || line =~ /^(#|!)/ } 31 | 32 | unignored_files = all_files.reject do |file| 33 | # Ignore any directories, the gemspec only cares about files 34 | next true if File.directory?(file) 35 | 36 | # Ignore any paths that match anything in the gitignore. We do 37 | # two tests here: 38 | # 39 | # - First, test to see if the entire path matches the gitignore. 40 | # - Second, match if the basename does, this makes it so that things 41 | # like '.DS_Store' will match sub-directories too (same behavior 42 | # as git). 43 | # 44 | gitignore.any? do |ignore| 45 | File.fnmatch(ignore, file, File::FNM_PATHNAME) || 46 | File.fnmatch(ignore, File.basename(file), File::FNM_PATHNAME) 47 | end 48 | end 49 | 50 | s.files = unignored_files 51 | s.executables = unignored_files.map { |f| f[/^bin\/(.*)/, 1] }.compact 52 | s.require_path = 'lib' 53 | end 54 | --------------------------------------------------------------------------------