Rex-1.3.3/0000755000175000017500000000000012572251052012141 5ustar jenkinsjenkinsRex-1.3.3/CONTRIBUTORS0000644000175000017500000000214712572251052014025 0ustar jenkinsjenkins# alphabetical order Alex Mestiashvili alex1line Alexandr Ciornii Anders Ossowicki Andrej Zverev Andrew Beverley Arnold Bechtoldt bollwarm Boris Däppen Brian Manning Cameron Daniel Chris Steigmeier Cuong Manh Le Daniel Baeurer David Golovan Denis Silakov Dmitry Kopytov Dominik Danter Dominik Schulz eduardoj Eivin Giske Skaaren Elmer Quintanilla Eric Johnson Erik Huelsmann fanyeren (范野人) Ferenc Erki Fran Rodriguez Franky Van Liedekerke Gilles Gaudin, for writing a french howto Graham Todd Hiroaki Nakamura Ilya Evseev Jean Charles Passard Jean-Marie Renouard Jeen Lee Jens Berthold John Karr Jon Gentle Jonathan Delgado Joris DE POOTER Jose Luis Martinez Kasim Tuman Keedi Kim Laird Liu Mario Domgoergen Mitch Broadhead Nathan Abu Naveed Massjouni Nicolas Leclercq Niklas Larsson Nikolay Fetisov Nils Domrose okaoka Pavel Timofeev Peter H. Ezetta Peter Manthey Piotr Karbowski Rao Chenlin (Chenryn) RenatoCRON Renee Bäcker Robert Abraham Samuele Tognini Sascha Askani Sascha Guenther Simon Bertrang Stephane Benoit Sven Dowideit Tianon Gravi Tokuhiro Matsuno Tomohiro Hosaka Сергей Романов (complefor) Rex-1.3.3/LICENSE0000644000175000017500000002635312572251052013157 0ustar jenkinsjenkinsThis software is Copyright (c) 2015 by Jan Gehring. This is free software, licensed under: The Apache License, Version 2.0, January 2004 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. Rex-1.3.3/META.yml0000644000175000017500000006665412572251052013433 0ustar jenkinsjenkins--- abstract: 'Remote Execution' author: - 'Jan Gehring ' build_requires: File::Temp: '0' String::Escape: '0' Test::More: '0' Test::Pod: '0' Test::UseAllModules: '0' XML::LibXML: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'Dist::Zilla version 5.032, CPAN::Meta::Converter version 2.142690' license: apache meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Rex provides: Rex: file: lib/Rex.pm version: v1.3.3 Rex::Args: file: lib/Rex/Args.pm version: v1.3.3 Rex::Args::Integer: file: lib/Rex/Args/Integer.pm version: v1.3.3 Rex::Args::Single: file: lib/Rex/Args/Single.pm version: v1.3.3 Rex::Args::String: file: lib/Rex/Args/String.pm version: v1.3.3 Rex::Batch: file: lib/Rex/Batch.pm version: v1.3.3 Rex::Box: file: lib/Rex/Box.pm version: v1.3.3 Rex::Box::Amazon: file: lib/Rex/Box/Amazon.pm version: v1.3.3 Rex::Box::Base: file: lib/Rex/Box/Base.pm version: v1.3.3 Rex::Box::KVM: file: lib/Rex/Box/KVM.pm version: v1.3.3 Rex::Box::VBox: file: lib/Rex/Box/VBox.pm version: v1.3.3 Rex::CLI: file: lib/Rex/CLI.pm version: v1.3.3 Rex::CMDB: file: lib/Rex/CMDB.pm version: v1.3.3 Rex::CMDB::Base: file: lib/Rex/CMDB/Base.pm version: v1.3.3 Rex::CMDB::YAML: file: lib/Rex/CMDB/YAML.pm version: v1.3.3 Rex::Cloud: file: lib/Rex/Cloud.pm version: v1.3.3 Rex::Cloud::Amazon: file: lib/Rex/Cloud/Amazon.pm version: v1.3.3 Rex::Cloud::Base: file: lib/Rex/Cloud/Base.pm version: v1.3.3 Rex::Cloud::Jiffybox: file: lib/Rex/Cloud/Jiffybox.pm version: v1.3.3 Rex::Cloud::OpenStack: file: lib/Rex/Cloud/OpenStack.pm version: v1.3.3 Rex::Commands: file: lib/Rex/Commands.pm version: v1.3.3 Rex::Commands::Augeas: file: lib/Rex/Commands/Augeas.pm version: v1.3.3 Rex::Commands::Box: file: lib/Rex/Commands/Box.pm version: v1.3.3 Rex::Commands::Cloud: file: lib/Rex/Commands/Cloud.pm version: v1.3.3 Rex::Commands::Cron: file: lib/Rex/Commands/Cron.pm version: v1.3.3 Rex::Commands::DB: file: lib/Rex/Commands/DB.pm version: v1.3.3 Rex::Commands::Download: file: lib/Rex/Commands/Download.pm version: v1.3.3 Rex::Commands::File: file: lib/Rex/Commands/File.pm version: v1.3.3 Rex::Commands::Fs: file: lib/Rex/Commands/Fs.pm version: v1.3.3 Rex::Commands::Gather: file: lib/Rex/Commands/Gather.pm version: v1.3.3 Rex::Commands::Host: file: lib/Rex/Commands/Host.pm version: v1.3.3 Rex::Commands::Inventory: file: lib/Rex/Commands/Inventory.pm version: v1.3.3 Rex::Commands::Iptables: file: lib/Rex/Commands/Iptables.pm version: v1.3.3 Rex::Commands::JobControl: file: lib/Rex/Commands/JobControl.pm version: v1.3.3 Rex::Commands::Kernel: file: lib/Rex/Commands/Kernel.pm version: v1.3.3 Rex::Commands::LVM: file: lib/Rex/Commands/LVM.pm version: v1.3.3 Rex::Commands::MD5: file: lib/Rex/Commands/MD5.pm version: v1.3.3 Rex::Commands::Network: file: lib/Rex/Commands/Network.pm version: v1.3.3 Rex::Commands::Notify: file: lib/Rex/Commands/Notify.pm version: v1.3.3 Rex::Commands::Partition: file: lib/Rex/Commands/Partition.pm version: v1.3.3 Rex::Commands::Pkg: file: lib/Rex/Commands/Pkg.pm version: v1.3.3 Rex::Commands::PkgConf: file: lib/Rex/Commands/PkgConf.pm version: v1.3.3 Rex::Commands::Process: file: lib/Rex/Commands/Process.pm version: v1.3.3 Rex::Commands::Rsync: file: lib/Rex/Commands/Rsync.pm version: v1.3.3 Rex::Commands::Run: file: lib/Rex/Commands/Run.pm version: v1.3.3 Rex::Commands::SCM: file: lib/Rex/Commands/SCM.pm version: v1.3.3 Rex::Commands::Service: file: lib/Rex/Commands/Service.pm version: v1.3.3 Rex::Commands::SimpleCheck: file: lib/Rex/Commands/SimpleCheck.pm version: v1.3.3 Rex::Commands::Sync: file: lib/Rex/Commands/Sync.pm version: v1.3.3 Rex::Commands::Sysctl: file: lib/Rex/Commands/Sysctl.pm version: v1.3.3 Rex::Commands::Tail: file: lib/Rex/Commands/Tail.pm version: v1.3.3 Rex::Commands::Upload: file: lib/Rex/Commands/Upload.pm version: v1.3.3 Rex::Commands::User: file: lib/Rex/Commands/User.pm version: v1.3.3 Rex::Commands::Virtualization: file: lib/Rex/Commands/Virtualization.pm version: v1.3.3 Rex::Config: file: lib/Rex/Config.pm version: v1.3.3 Rex::Constants: file: lib/Rex/Constants.pm version: v1.3.3 Rex::Cron: file: lib/Rex/Cron.pm version: v1.3.3 Rex::Cron::Base: file: lib/Rex/Cron/Base.pm version: v1.3.3 Rex::Cron::Linux: file: lib/Rex/Cron/Linux.pm version: v1.3.3 Rex::Cron::SunOS: file: lib/Rex/Cron/SunOS.pm version: v1.3.3 Rex::Exporter: file: lib/Rex/Exporter.pm version: v1.3.3 Rex::FS::File: file: lib/Rex/FS/File.pm version: v1.3.3 Rex::File::Parser::Data: file: lib/Rex/File/Parser/Data.pm version: v1.3.3 Rex::File::Parser::Ini: file: lib/Rex/File/Parser/Ini.pm version: v1.3.3 Rex::Fork::Manager: file: lib/Rex/Fork/Manager.pm version: v1.3.3 Rex::Fork::Task: file: lib/Rex/Fork/Task.pm version: v1.3.3 Rex::Group: file: lib/Rex/Group.pm version: v1.3.3 Rex::Group::Entry::Server: file: lib/Rex/Group/Entry/Server.pm version: v1.3.3 Rex::Group::Lookup::Command: file: lib/Rex/Group/Lookup/Command.pm version: v1.3.3 Rex::Group::Lookup::DBI: file: lib/Rex/Group/Lookup/DBI.pm version: v1.3.3 Rex::Group::Lookup::File: file: lib/Rex/Group/Lookup/File.pm version: v1.3.3 Rex::Group::Lookup::INI: file: lib/Rex/Group/Lookup/INI.pm version: v1.3.3 Rex::Group::Lookup::XML: file: lib/Rex/Group/Lookup/XML.pm version: v1.3.3 Rex::Group::Lookup::YAML: file: lib/Rex/Group/Lookup/YAML.pm version: v1.3.3 Rex::Hardware: file: lib/Rex/Hardware.pm version: v1.3.3 Rex::Hardware::Host: file: lib/Rex/Hardware/Host.pm version: v1.3.3 Rex::Hardware::Kernel: file: lib/Rex/Hardware/Kernel.pm version: v1.3.3 Rex::Hardware::Memory: file: lib/Rex/Hardware/Memory.pm version: v1.3.3 Rex::Hardware::Network: file: lib/Rex/Hardware/Network.pm version: v1.3.3 Rex::Hardware::Network::Darwin: file: lib/Rex/Hardware/Network/Darwin.pm version: v1.3.3 Rex::Hardware::Network::FreeBSD: file: lib/Rex/Hardware/Network/FreeBSD.pm version: v1.3.3 Rex::Hardware::Network::Linux: file: lib/Rex/Hardware/Network/Linux.pm version: v1.3.3 Rex::Hardware::Network::NetBSD: file: lib/Rex/Hardware/Network/NetBSD.pm version: v1.3.3 Rex::Hardware::Network::OpenBSD: file: lib/Rex/Hardware/Network/OpenBSD.pm version: v1.3.3 Rex::Hardware::Network::Solaris: file: lib/Rex/Hardware/Network/Solaris.pm version: v1.3.3 Rex::Hardware::Swap: file: lib/Rex/Hardware/Swap.pm version: v1.3.3 Rex::Hardware::VirtInfo: file: lib/Rex/Hardware/VirtInfo.pm version: v1.3.3 Rex::Helper::Array: file: lib/Rex/Helper/Array.pm version: v1.3.3 Rex::Helper::DBI: file: lib/Rex/Helper/DBI.pm version: v1.3.3 Rex::Helper::Encode: file: lib/Rex/Helper/Encode.pm version: v1.3.3 Rex::Helper::File::Spec: file: lib/Rex/Helper/File/Spec.pm version: v1.3.3 Rex::Helper::File::Stat: file: lib/Rex/Helper/File/Stat.pm version: v1.3.3 Rex::Helper::File::Stat::Unix: file: lib/Rex/Helper/File/Stat/Unix.pm version: v1.3.3 Rex::Helper::File::Stat::Win32: file: lib/Rex/Helper/File/Stat/Win32.pm version: v1.3.3 Rex::Helper::Hash: file: lib/Rex/Helper/Hash.pm version: v1.3.3 Rex::Helper::INI: file: lib/Rex/Helper/INI.pm version: v1.3.3 Rex::Helper::Misc: file: lib/Rex/Helper/Misc.pm version: v1.3.3 Rex::Helper::Path: file: lib/Rex/Helper/Path.pm version: v1.3.3 Rex::Helper::Run: file: lib/Rex/Helper/Run.pm version: v1.3.3 Rex::Helper::SSH2: file: lib/Rex/Helper/SSH2.pm version: v1.3.3 Rex::Helper::SSH2::Expect: file: lib/Rex/Helper/SSH2/Expect.pm version: v1.3.3 Rex::Helper::System: file: lib/Rex/Helper/System.pm version: v1.3.3 Rex::Helper::URI: file: lib/Rex/Helper/URI.pm version: v1.3.3 Rex::Helper::UserAgent: file: lib/Rex/Helper/UserAgent.pm version: v1.3.3 Rex::Hook: file: lib/Rex/Hook.pm version: v1.3.3 Rex::Interface::Cache: file: lib/Rex/Interface/Cache.pm version: v1.3.3 Rex::Interface::Cache::Base: file: lib/Rex/Interface/Cache/Base.pm version: v1.3.3 Rex::Interface::Cache::YAML: file: lib/Rex/Interface/Cache/YAML.pm version: v1.3.3 Rex::Interface::Connection: file: lib/Rex/Interface/Connection.pm version: v1.3.3 Rex::Interface::Connection::Base: file: lib/Rex/Interface/Connection/Base.pm version: v1.3.3 Rex::Interface::Connection::Fake: file: lib/Rex/Interface/Connection/Fake.pm version: v1.3.3 Rex::Interface::Connection::HTTP: file: lib/Rex/Interface/Connection/HTTP.pm version: v1.3.3 Rex::Interface::Connection::HTTPS: file: lib/Rex/Interface/Connection/HTTPS.pm version: v1.3.3 Rex::Interface::Connection::Local: file: lib/Rex/Interface/Connection/Local.pm version: v1.3.3 Rex::Interface::Connection::OpenSSH: file: lib/Rex/Interface/Connection/OpenSSH.pm version: v1.3.3 Rex::Interface::Connection::SSH: file: lib/Rex/Interface/Connection/SSH.pm version: v1.3.3 Rex::Interface::Exec: file: lib/Rex/Interface/Exec.pm version: v1.3.3 Rex::Interface::Exec::Base: file: lib/Rex/Interface/Exec/Base.pm version: v1.3.3 Rex::Interface::Exec::HTTP: file: lib/Rex/Interface/Exec/HTTP.pm version: v1.3.3 Rex::Interface::Exec::Local: file: lib/Rex/Interface/Exec/Local.pm version: v1.3.3 Rex::Interface::Exec::OpenSSH: file: lib/Rex/Interface/Exec/OpenSSH.pm version: v1.3.3 Rex::Interface::Exec::SSH: file: lib/Rex/Interface/Exec/SSH.pm version: v1.3.3 Rex::Interface::Exec::Sudo: file: lib/Rex/Interface/Exec/Sudo.pm version: v1.3.3 Rex::Interface::Executor: file: lib/Rex/Interface/Executor.pm version: v1.3.3 Rex::Interface::Executor::Base: file: lib/Rex/Interface/Executor/Base.pm version: v1.3.3 Rex::Interface::Executor::Default: file: lib/Rex/Interface/Executor/Default.pm version: v1.3.3 Rex::Interface::File: file: lib/Rex/Interface/File.pm version: v1.3.3 Rex::Interface::File::Base: file: lib/Rex/Interface/File/Base.pm version: v1.3.3 Rex::Interface::File::HTTP: file: lib/Rex/Interface/File/HTTP.pm version: v1.3.3 Rex::Interface::File::Local: file: lib/Rex/Interface/File/Local.pm version: v1.3.3 Rex::Interface::File::OpenSSH: file: lib/Rex/Interface/File/OpenSSH.pm version: v1.3.3 Rex::Interface::File::SSH: file: lib/Rex/Interface/File/SSH.pm version: v1.3.3 Rex::Interface::File::Sudo: file: lib/Rex/Interface/File/Sudo.pm version: v1.3.3 Rex::Interface::Fs: file: lib/Rex/Interface/Fs.pm version: v1.3.3 Rex::Interface::Fs::Base: file: lib/Rex/Interface/Fs/Base.pm version: v1.3.3 Rex::Interface::Fs::HTTP: file: lib/Rex/Interface/Fs/HTTP.pm version: v1.3.3 Rex::Interface::Fs::Local: file: lib/Rex/Interface/Fs/Local.pm version: v1.3.3 Rex::Interface::Fs::OpenSSH: file: lib/Rex/Interface/Fs/OpenSSH.pm version: v1.3.3 Rex::Interface::Fs::SSH: file: lib/Rex/Interface/Fs/SSH.pm version: v1.3.3 Rex::Interface::Fs::Sudo: file: lib/Rex/Interface/Fs/Sudo.pm version: v1.3.3 Rex::Interface::Shell: file: lib/Rex/Interface/Shell.pm version: v1.3.3 Rex::Interface::Shell::Ash: file: lib/Rex/Interface/Shell/Ash.pm version: v1.3.3 Rex::Interface::Shell::Base: file: lib/Rex/Interface/Shell/Base.pm version: v1.3.3 Rex::Interface::Shell::Bash: file: lib/Rex/Interface/Shell/Bash.pm version: v1.3.3 Rex::Interface::Shell::Csh: file: lib/Rex/Interface/Shell/Csh.pm version: v1.3.3 Rex::Interface::Shell::Default: file: lib/Rex/Interface/Shell/Default.pm version: v1.3.3 Rex::Interface::Shell::Idrac: file: lib/Rex/Interface/Shell/Idrac.pm version: v1.3.3 Rex::Interface::Shell::Ksh: file: lib/Rex/Interface/Shell/Ksh.pm version: v1.3.3 Rex::Interface::Shell::Sh: file: lib/Rex/Interface/Shell/Sh.pm version: v1.3.3 Rex::Interface::Shell::Tcsh: file: lib/Rex/Interface/Shell/Tcsh.pm version: v1.3.3 Rex::Interface::Shell::Zsh: file: lib/Rex/Interface/Shell/Zsh.pm version: v1.3.3 Rex::Inventory: file: lib/Rex/Inventory.pm version: v1.3.3 Rex::Inventory::Bios: file: lib/Rex/Inventory/Bios.pm version: v1.3.3 Rex::Inventory::DMIDecode: file: lib/Rex/Inventory/DMIDecode.pm version: v1.3.3 Rex::Inventory::DMIDecode::BaseBoard: file: lib/Rex/Inventory/DMIDecode/BaseBoard.pm version: v1.3.3 Rex::Inventory::DMIDecode::Bios: file: lib/Rex/Inventory/DMIDecode/Bios.pm version: v1.3.3 Rex::Inventory::DMIDecode::CPU: file: lib/Rex/Inventory/DMIDecode/CPU.pm version: v1.3.3 Rex::Inventory::DMIDecode::Memory: file: lib/Rex/Inventory/DMIDecode/Memory.pm version: v1.3.3 Rex::Inventory::DMIDecode::MemoryArray: file: lib/Rex/Inventory/DMIDecode/MemoryArray.pm version: v1.3.3 Rex::Inventory::DMIDecode::Section: file: lib/Rex/Inventory/DMIDecode/Section.pm version: v1.3.3 Rex::Inventory::DMIDecode::SystemInformation: file: lib/Rex/Inventory/DMIDecode/SystemInformation.pm version: v1.3.3 Rex::Inventory::HP::ACU: file: lib/Rex/Inventory/HP/ACU.pm version: v1.3.3 Rex::Inventory::Hal: file: lib/Rex/Inventory/Hal.pm version: v1.3.3 Rex::Inventory::Hal::Object: file: lib/Rex/Inventory/Hal/Object.pm version: v1.3.3 Rex::Inventory::Hal::Object::Net: file: lib/Rex/Inventory/Hal/Object/Net.pm version: v1.3.3 Rex::Inventory::Hal::Object::Storage: file: lib/Rex/Inventory/Hal/Object/Storage.pm version: v1.3.3 Rex::Inventory::Hal::Object::Volume: file: lib/Rex/Inventory/Hal/Object/Volume.pm version: v1.3.3 Rex::Inventory::Proc: file: lib/Rex/Inventory/Proc.pm version: v1.3.3 Rex::Inventory::Proc::Cpuinfo: file: lib/Rex/Inventory/Proc/Cpuinfo.pm version: v1.3.3 Rex::Inventory::SMBios: file: lib/Rex/Inventory/SMBios.pm version: v1.3.3 Rex::Inventory::SMBios::BaseBoard: file: lib/Rex/Inventory/SMBios/BaseBoard.pm version: v1.3.3 Rex::Inventory::SMBios::Bios: file: lib/Rex/Inventory/SMBios/Bios.pm version: v1.3.3 Rex::Inventory::SMBios::CPU: file: lib/Rex/Inventory/SMBios/CPU.pm version: v1.3.3 Rex::Inventory::SMBios::Memory: file: lib/Rex/Inventory/SMBios/Memory.pm version: v1.3.3 Rex::Inventory::SMBios::MemoryArray: file: lib/Rex/Inventory/SMBios/MemoryArray.pm version: v1.3.3 Rex::Inventory::SMBios::Section: file: lib/Rex/Inventory/SMBios/Section.pm version: v1.3.3 Rex::Inventory::SMBios::SystemInformation: file: lib/Rex/Inventory/SMBios/SystemInformation.pm version: v1.3.3 Rex::Logger: file: lib/Rex/Logger.pm version: v1.3.3 Rex::Notify: file: lib/Rex/Notify.pm version: v1.3.3 Rex::Output: file: lib/Rex/Output.pm version: v1.3.3 Rex::Output::Base: file: lib/Rex/Output/Base.pm version: v1.3.3 Rex::Output::JUnit: file: lib/Rex/Output/JUnit.pm version: v1.3.3 Rex::Pkg: file: lib/Rex/Pkg.pm version: v1.3.3 Rex::Pkg::ALT: file: lib/Rex/Pkg/ALT.pm version: v1.3.3 Rex::Pkg::Base: file: lib/Rex/Pkg/Base.pm version: v1.3.3 Rex::Pkg::Debian: file: lib/Rex/Pkg/Debian.pm version: v1.3.3 Rex::Pkg::FreeBSD: file: lib/Rex/Pkg/FreeBSD.pm version: v1.3.3 Rex::Pkg::Gentoo: file: lib/Rex/Pkg/Gentoo.pm version: v1.3.3 Rex::Pkg::Mageia: file: lib/Rex/Pkg/Mageia.pm version: v1.3.3 Rex::Pkg::NetBSD: file: lib/Rex/Pkg/NetBSD.pm version: v1.3.3 Rex::Pkg::OpenBSD: file: lib/Rex/Pkg/OpenBSD.pm version: v1.3.3 Rex::Pkg::OpenWrt: file: lib/Rex/Pkg/OpenWrt.pm version: v1.3.3 Rex::Pkg::Redhat: file: lib/Rex/Pkg/Redhat.pm version: v1.3.3 Rex::Pkg::SuSE: file: lib/Rex/Pkg/SuSE.pm version: v1.3.3 Rex::Pkg::SunOS: file: lib/Rex/Pkg/SunOS.pm version: v1.3.3 Rex::Pkg::SunOS::OpenCSW: file: lib/Rex/Pkg/SunOS/OpenCSW.pm version: v1.3.3 Rex::Pkg::SunOS::pkg: file: lib/Rex/Pkg/SunOS/pkg.pm version: v1.3.3 Rex::Pkg::Ubuntu: file: lib/Rex/Pkg/Ubuntu.pm version: v1.3.3 Rex::PkgConf: file: lib/Rex/PkgConf.pm version: v1.3.3 Rex::PkgConf::Base: file: lib/Rex/PkgConf/Base.pm version: v1.3.3 Rex::PkgConf::Debian: file: lib/Rex/PkgConf/Debian.pm version: v1.3.3 Rex::Profiler: file: lib/Rex/Profiler.pm version: v1.3.3 Rex::Report: file: lib/Rex/Report.pm version: v1.3.3 Rex::Report::Base: file: lib/Rex/Report/Base.pm version: v1.3.3 Rex::Report::YAML: file: lib/Rex/Report/YAML.pm version: v1.3.3 Rex::Require: file: lib/Rex/Require.pm version: v1.3.3 Rex::Resource: file: lib/Rex/Resource.pm version: v1.3.3 Rex::Resource::Common: file: lib/Rex/Resource/Common.pm version: v1.3.3 Rex::SCM::Git: file: lib/Rex/SCM/Git.pm version: v1.3.3 Rex::SCM::Subversion: file: lib/Rex/SCM/Subversion.pm version: v1.3.3 Rex::Service: file: lib/Rex/Service.pm version: v1.3.3 Rex::Service::ALT: file: lib/Rex/Service/ALT.pm version: v1.3.3 Rex::Service::ALT::systemd: file: lib/Rex/Service/ALT/systemd.pm version: v1.3.3 Rex::Service::Base: file: lib/Rex/Service/Base.pm version: v1.3.3 Rex::Service::Debian: file: lib/Rex/Service/Debian.pm version: v1.3.3 Rex::Service::Debian::systemd: file: lib/Rex/Service/Debian/systemd.pm version: v1.3.3 Rex::Service::FreeBSD: file: lib/Rex/Service/FreeBSD.pm version: v1.3.3 Rex::Service::Gentoo: file: lib/Rex/Service/Gentoo.pm version: v1.3.3 Rex::Service::Gentoo::systemd: file: lib/Rex/Service/Gentoo/systemd.pm version: v1.3.3 Rex::Service::Mageia: file: lib/Rex/Service/Mageia.pm version: v1.3.3 Rex::Service::Mageia::systemd: file: lib/Rex/Service/Mageia/systemd.pm version: v1.3.3 Rex::Service::NetBSD: file: lib/Rex/Service/NetBSD.pm version: v1.3.3 Rex::Service::OpenBSD: file: lib/Rex/Service/OpenBSD.pm version: v1.3.3 Rex::Service::OpenWrt: file: lib/Rex/Service/OpenWrt.pm version: v1.3.3 Rex::Service::Redhat: file: lib/Rex/Service/Redhat.pm version: v1.3.3 Rex::Service::Redhat::systemd: file: lib/Rex/Service/Redhat/systemd.pm version: v1.3.3 Rex::Service::SuSE: file: lib/Rex/Service/SuSE.pm version: v1.3.3 Rex::Service::SuSE::systemd: file: lib/Rex/Service/SuSE/systemd.pm version: v1.3.3 Rex::Service::SunOS: file: lib/Rex/Service/SunOS.pm version: v1.3.3 Rex::Service::SunOS::svcadm: file: lib/Rex/Service/SunOS/svcadm.pm version: v1.3.3 Rex::Service::Ubuntu: file: lib/Rex/Service/Ubuntu.pm version: v1.3.3 Rex::Shared::Var: file: lib/Rex/Shared/Var.pm version: v1.3.3 Rex::Shared::Var::Array: file: lib/Rex/Shared/Var/Array.pm version: v1.3.3 Rex::Shared::Var::Hash: file: lib/Rex/Shared/Var/Hash.pm version: v1.3.3 Rex::Shared::Var::Scalar: file: lib/Rex/Shared/Var/Scalar.pm version: v1.3.3 Rex::Sudo::File: file: lib/Rex/Sudo/File.pm version: v1.3.3 Rex::Task: file: lib/Rex/Task.pm version: v1.3.3 Rex::TaskList: file: lib/Rex/TaskList.pm version: v1.3.3 Rex::TaskList::Base: file: lib/Rex/TaskList/Base.pm version: v1.3.3 Rex::TaskList::Parallel_ForkManager: file: lib/Rex/TaskList/Parallel_ForkManager.pm version: v1.3.3 Rex::Template: file: lib/Rex/Template.pm version: v1.3.3 Rex::Template::NG: file: lib/Rex/Template/NG.pm version: v1.3.3 Rex::Test: file: lib/Rex/Test.pm version: v1.3.3 Rex::Test::Base: file: lib/Rex/Test/Base.pm version: v1.3.3 Rex::Test::Base::has_content: file: lib/Rex/Test/Base/has_content.pm version: v1.3.3 Rex::Test::Base::has_dir: file: lib/Rex/Test/Base/has_dir.pm version: v1.3.3 Rex::Test::Base::has_file: file: lib/Rex/Test/Base/has_file.pm version: v1.3.3 Rex::Test::Base::has_package: file: lib/Rex/Test/Base/has_package.pm version: v1.3.3 Rex::Test::Base::has_service_running: file: lib/Rex/Test/Base/has_service_running.pm version: v1.3.3 Rex::Test::Base::has_service_stopped: file: lib/Rex/Test/Base/has_service_stopped.pm version: v1.3.3 Rex::Test::Base::has_stat: file: lib/Rex/Test/Base/has_stat.pm version: v1.3.3 Rex::Transaction: file: lib/Rex/Transaction.pm version: v1.3.3 Rex::User: file: lib/Rex/User.pm version: v1.3.3 Rex::User::Base: file: lib/Rex/User/Base.pm version: v1.3.3 Rex::User::FreeBSD: file: lib/Rex/User/FreeBSD.pm version: v1.3.3 Rex::User::Linux: file: lib/Rex/User/Linux.pm version: v1.3.3 Rex::User::NetBSD: file: lib/Rex/User/NetBSD.pm version: v1.3.3 Rex::User::OpenBSD: file: lib/Rex/User/OpenBSD.pm version: v1.3.3 Rex::User::OpenWrt: file: lib/Rex/User/OpenWrt.pm version: v1.3.3 Rex::User::SunOS: file: lib/Rex/User/SunOS.pm version: v1.3.3 Rex::Value: file: lib/Rex/Value.pm version: v1.3.3 Rex::Virtualization: file: lib/Rex/Virtualization.pm version: v1.3.3 Rex::Virtualization::Base: file: lib/Rex/Virtualization/Base.pm version: v1.3.3 Rex::Virtualization::Docker: file: lib/Rex/Virtualization/Docker.pm version: v1.3.3 Rex::Virtualization::Docker::create: file: lib/Rex/Virtualization/Docker/create.pm version: v1.3.3 Rex::Virtualization::Docker::daemon: file: lib/Rex/Virtualization/Docker/daemon.pm version: v1.3.3 Rex::Virtualization::Docker::delete: file: lib/Rex/Virtualization/Docker/delete.pm version: v1.3.3 Rex::Virtualization::Docker::destroy: file: lib/Rex/Virtualization/Docker/destroy.pm version: v1.3.3 Rex::Virtualization::Docker::info: file: lib/Rex/Virtualization/Docker/info.pm version: v1.3.3 Rex::Virtualization::Docker::list: file: lib/Rex/Virtualization/Docker/list.pm version: v1.3.3 Rex::Virtualization::Docker::reboot: file: lib/Rex/Virtualization/Docker/reboot.pm version: v1.3.3 Rex::Virtualization::Docker::shutdown: file: lib/Rex/Virtualization/Docker/shutdown.pm version: v1.3.3 Rex::Virtualization::Docker::start: file: lib/Rex/Virtualization/Docker/start.pm version: v1.3.3 Rex::Virtualization::LibVirt: file: lib/Rex/Virtualization/LibVirt.pm version: v1.3.3 Rex::Virtualization::LibVirt::blklist: file: lib/Rex/Virtualization/LibVirt/blklist.pm version: v1.3.3 Rex::Virtualization::LibVirt::clone: file: lib/Rex/Virtualization/LibVirt/clone.pm version: v1.3.3 Rex::Virtualization::LibVirt::create: file: lib/Rex/Virtualization/LibVirt/create.pm version: v1.3.3 Rex::Virtualization::LibVirt::delete: file: lib/Rex/Virtualization/LibVirt/delete.pm version: v1.3.3 Rex::Virtualization::LibVirt::destroy: file: lib/Rex/Virtualization/LibVirt/destroy.pm version: v1.3.3 Rex::Virtualization::LibVirt::dumpxml: file: lib/Rex/Virtualization/LibVirt/dumpxml.pm version: v1.3.3 Rex::Virtualization::LibVirt::guestinfo: file: lib/Rex/Virtualization/LibVirt/guestinfo.pm version: v1.3.3 Rex::Virtualization::LibVirt::hypervisor: file: lib/Rex/Virtualization/LibVirt/hypervisor.pm version: v1.3.3 Rex::Virtualization::LibVirt::iflist: file: lib/Rex/Virtualization/LibVirt/iflist.pm version: v1.3.3 Rex::Virtualization::LibVirt::import: file: lib/Rex/Virtualization/LibVirt/import.pm version: v1.3.3 Rex::Virtualization::LibVirt::info: file: lib/Rex/Virtualization/LibVirt/info.pm version: v1.3.3 Rex::Virtualization::LibVirt::list: file: lib/Rex/Virtualization/LibVirt/list.pm version: v1.3.3 Rex::Virtualization::LibVirt::option: file: lib/Rex/Virtualization/LibVirt/option.pm version: v1.3.3 Rex::Virtualization::LibVirt::reboot: file: lib/Rex/Virtualization/LibVirt/reboot.pm version: v1.3.3 Rex::Virtualization::LibVirt::shutdown: file: lib/Rex/Virtualization/LibVirt/shutdown.pm version: v1.3.3 Rex::Virtualization::LibVirt::start: file: lib/Rex/Virtualization/LibVirt/start.pm version: v1.3.3 Rex::Virtualization::LibVirt::status: file: lib/Rex/Virtualization/LibVirt/status.pm version: v1.3.3 Rex::Virtualization::LibVirt::vncdisplay: file: lib/Rex/Virtualization/LibVirt/vncdisplay.pm version: v1.3.3 Rex::Virtualization::VBox: file: lib/Rex/Virtualization/VBox.pm version: v1.3.3 Rex::Virtualization::VBox::bridge: file: lib/Rex/Virtualization/VBox/bridge.pm version: v1.3.3 Rex::Virtualization::VBox::create: file: lib/Rex/Virtualization/VBox/create.pm version: v1.3.3 Rex::Virtualization::VBox::delete: file: lib/Rex/Virtualization/VBox/delete.pm version: v1.3.3 Rex::Virtualization::VBox::destroy: file: lib/Rex/Virtualization/VBox/destroy.pm version: v1.3.3 Rex::Virtualization::VBox::forward_port: file: lib/Rex/Virtualization/VBox/forward_port.pm version: v1.3.3 Rex::Virtualization::VBox::guestinfo: file: lib/Rex/Virtualization/VBox/guestinfo.pm version: v1.3.3 Rex::Virtualization::VBox::import: file: lib/Rex/Virtualization/VBox/import.pm version: v1.3.3 Rex::Virtualization::VBox::info: file: lib/Rex/Virtualization/VBox/info.pm version: v1.3.3 Rex::Virtualization::VBox::list: file: lib/Rex/Virtualization/VBox/list.pm version: v1.3.3 Rex::Virtualization::VBox::option: file: lib/Rex/Virtualization/VBox/option.pm version: v1.3.3 Rex::Virtualization::VBox::reboot: file: lib/Rex/Virtualization/VBox/reboot.pm version: v1.3.3 Rex::Virtualization::VBox::share_folder: file: lib/Rex/Virtualization/VBox/share_folder.pm version: v1.3.3 Rex::Virtualization::VBox::shutdown: file: lib/Rex/Virtualization/VBox/shutdown.pm version: v1.3.3 Rex::Virtualization::VBox::start: file: lib/Rex/Virtualization/VBox/start.pm version: v1.3.3 Rex::Virtualization::VBox::status: file: lib/Rex/Virtualization/VBox/status.pm version: v1.3.3 requires: Carp: '0' Cwd: '0' Data::Dumper: '0' Digest::MD5: '0' Exporter: '0' Fcntl: '0' File::Basename: '0' File::Spec: '0' File::Spec::Unix: '0' File::Spec::Win32: '0' FindBin: '0' HTTP::Request: '0' HTTP::Request::Common: '0' Hash::Merge: '0' IO::File: '0' IO::Socket: '0' IO::String: '0' IPC::Open3: '0' JSON::XS: '0' LWP::UserAgent: '0' List::MoreUtils: '0' List::Util: '0' MIME::Base64: '0' POSIX: '0' Sort::Naturally: '0' Storable: '0' Symbol: '0' Term::ReadKey: '0' Test::Builder::Module: '0' Text::Glob: '0' Text::Wrap: '0' Time::HiRes: '0' UNIVERSAL: '0' URI: '0' URI::QueryParam: '0' XML::Simple: '0' YAML: '0' attributes: '0' base: '0' constant: '0' overload: '0' perl: '5.008008' strict: '0' vars: '0' warnings: '0' resources: IRC: irc://irc.freenode.net/rex Twitter: https://twitter.com/RexOps bugtracker: https://github.com/RexOps/Rex/issues homepage: http://www.rexify.org repository: https://github.com/RexOps/Rex.git version: 1.3.3 Rex-1.3.3/ChangeLog0000644000175000017500000015330712572251052013724 0ustar jenkinsjenkins2015-09-04 Ferenc Erki (1.3.3) * Catch another way to manage services on FreeBSD (close #773) - timp87 * Fix generated links for Commands modules (fix #776) - Ferenc Erki * Fix code block output when there's no space before closing tag - Ferenc Erki * Escape curly braces in template content - Ferenc Erki * Force syncing package information on FreeBSD - Ferenc Erki * Take service name and rcvar mapping into account on FreeBSD (close #770) - timp87 * Check if systemctl is functional before using it (fix #753) - Ferenc Erki * Rearrange dist.ini - Ferenc Erki * Fail early on unsupported Windows versions (fix #751) - Ferenc Erki * Warn about missing environment instead of panicking (fix #742) - Ferenc Erki * Document alias of get_operating_system() - Ferenc Erki * Fix perlcritic warnings about modifying list elements - Ferenc Erki * Fix perlcritic warnings about two-argument open - Ferenc Erki * Update auth docs - Ferenc Erki * Fix docs for transaction (fix #686, close #766) - Elmer Quintanilla * Fix ensure option for NetBSD services (close #759) - timp87 * Do not silently fail on update errors (close #758) - Andrew Beverley * Fix ensure option for FreeBSD services (close #752) - timp87 * Enable Rex to manage system services on FreeBSD (#752) - timp87 * Recognize multi-arch packages on Debian (fix #748, close #755) - Erik Huelsmann * Fix Gentoo service detection (fix #747) - Ferenc Erki * force apt-listchanges to not run - Anders Ossowicki * Added doc about using regex for auth - Eivin Giske Skaaren * Fixes #760 timeout for OpenSSH - Eivin Giske Skaaren * Use the correct class for managing forks (fix #743) - Ferenc Erki * Support key files for Debian repositories + add docs (close #736) - John Karr * Don't recreate connection during rethink_connection (fix #694, close #727) - Mitch Broadhead * Pass exception to on_rollback (fix #687, close #732) - Mitch Broadhead * Document hostname expressions support in INI files - Ferenc Erki * Support hostname expressions in INI files (close #713) - okaoka * Document -O CLI option - Ferenc Erki * Revert "Remove unused CLI option" (fix RexOps/rex-jobcontrol#10) - Ferenc Erki * make Fcntl calls os independent - Jan * added a wrapper module for File::Spec - Jan * Fix LEFT_PRECEDENCE typo - Dmitry Kopytov * Add function for checkout of Git tags - Eivin Giske Skaaren 2015-06-17 Ferenc Erki (1.3.2) * Use binmode as a function - Jan * Use raw Rex::Interface::Exec to call can_run - Jan * Remove md5sum usage - Ferenc Erki * Fix for filenames with at sign in them - Ferenc Erki * Add test case for filenames with at sign - Ferenc Erki * Add initial MD5 test - Ferenc Erki * Fix check for environment-specific filenames - Ferenc Erki * Use OS-agnostic perl executable detection - Ferenc Erki * Fix RC version handling - Ferenc Erki * Refactor MD5 checksum calculation (fix #719) - Ferenc Erki * Add missing test names - Ferenc Erki * Only display diagnostic message if something went wrong - Ferenc Erki * Explicitly test for optional dependencies - Ferenc Erki * Fix LEFT_PRECEDENCE typo - Dmitry Kopytov 2015-06-08 (1.3.1) * Cleanup db tests (fix #714) - Ferenc Erki * Update parallelism docs - Ferenc Erki 2015-06-03 (1.3.0) * Fix regex pattern for perl-5.22.0 - Ferenc Erki * Filter changelogger output - Ferenc Erki * Cleanup group command POD - Ferenc Erki * Convert POD directives of methods and DSL functions (fix #685, close #705) - Brian Manning * pass cmdb() arguments to callback - fixed #709 - Jan * allow creation of inherited Rex::Group::Entry::Server objects - fixed #708 - Jan * Reuse VM name as image filename when importing - Ferenc Erki * Recognize CloudLinux as Red Hat clone (close #699) - Dmitry Kopytov * Fix auth test when REX_USER env is present - Dmitry Kopytov * Remove unused CLI option - Ferenc Erki * More helpful/verbose help message (close #698) - Eric Johnson * Cleanup a file used during testing - Ferenc Erki * Cleanup tests with optional dependencies - Ferenc Erki * Use explicit test plans everywhere - Ferenc Erki * Cleanup test imports - Ferenc Erki * Remove tests doing nothing else than use_ok() - Ferenc Erki * Automatically use all modules during testing - Ferenc Erki * Remove redundant hostname evaluation tests - Ferenc Erki * Remove unused Data::Dumper from tests - Ferenc Erki * Add CMDB docs - Ferenc Erki * Don't run into an endless loop: fix for #692 - Jan Gehring * Iptables.pm: add long-form iptables examples to POD - Brian Manning * Iptables.pm: show error from iptables on non-zero exit status - Brian Manning * ignore backfiles from editors - Jan * Log STDERR on errors where auto_die is enabled - Dmitry Kopytov * Set parallelism automatically (fix #491) - Ferenc Erki * added template_ng tests - Jan * fixed a problem when one template object was used twice - Jan * new template engine for 1.3 - Jan * Fix checking of virsh command result upon VM creation - Ferenc Erki * Update clearpart command documentation - Ferenc Erki * Add bios_boot option to GPT initialization - Ferenc Erki * make report filename configurable. don't sleep in test - Jan * Check for CLI argument definedness (fix #668) - Ferenc Erki * this commit fixes #667. this bug was introduced with the fix for #629 - Jan * first detect if uname and md5sum can be run, then use it. fixed #665 - Jan * fix warning if local file is not given. fixed #647 - Jan * Include provided modules in META.yml - Ferenc Erki * added systemd support for debian. fixes #659 - Jan * this prevents the stderr output of perl to get send over the wire. fixes #658 - Jan 2015-05-04 (1.2.1) * first detect if uname and md5sum can be run, then use it. fixed #665 - Jan 2015-05-02 (1.2.0) * Set version to 9999.99.99 if version is not present (e.g. during development) - Jan * Fix Rexfile parsing (fix #629) - Jan * Refactor tasklist output (fix #631, #653) - Eric Johnson * Remove -w from shebang (fix #650) - Eric Johnson * Add tab completion (fix #636, #652) - Eric Johnson * Update modules listed in POD - Brian Manning * Add another Red Hat synonym for RHWS version 3 - Brian Manning * Fix file manipulation when using Net::OpenSSH and sudo (fix #640) - Jan * Check if requested environment is defined (fix #639) - Ferenc Erki * Use normal DSL for internal task - Ferenc Erki * Fix SCM documentation - Ferenc Erki * Sort server names naturally - Ferenc Erki * Sort tasklist output (fix #633) - Ferenc Erki * Add YAML CMDB merging support (fix #499) - Ferenc Erki * Add CMDB merge tests - Ferenc Erki * Update list of contributors - Ferenc Erki * Check number of elements returned by stat - Ferenc Erki * Rex::Commands::Fs::stat() should return a hash or throw an exception. - Mitch Broadhead * Allow single-character tasknames (fix #621) - Ferenc Erki * Fix reporting for umount - Ferenc Erki 2015-03-29 (1.1.0) * Fix dependencies for openssh + pass_auth - Ferenc Erki * prevent faulty debug message - Jan * fixed merge_auth() method for #615 -Jan * Update task tests (fix #614) - Jan * Recognize usable SSH modules separately - Ferenc Erki * Describe platform-specific dependencies - Ferenc Erki * Only check for iDrac signature if there was an output - Ferenc Erki * added a prototype, this will prevent failures like RexOps/Rex#584 - references: RexOps/Rex#608 - Jan * we need to do an explicit return undef. if we only use 'return' and the return of is_file/is_dir is passed to an array, this will not appear in the array. reference: RexOps/Rex#608 - Jan * updated tests to use is() instead of ok(). reference: RexOps/Rex#608 - Jan * changed return code to undef if file/dir not found. fix for RexOps/Rex#608 - Jan * Add initial iDrac shell support - Ferenc Erki * Allow can_run method to accept command to do the check with - Jan * Check if a command can be run before its execution (fix #514) - Ferenc Erki * Refactor can_run - Ferenc Erki * Support can_run command on Windows - Ferenc Erki * Move can_run to Rex::Interface::Exec - Ferenc Erki * Add can_run tests - Ferenc Erki * Create target directory before extracting an archive (fix #600, close #604) - Arnold Bechtoldt * Update POD (close #598) - Ferenc Erki * added a Rex::Logger::masq() function that can masq sensitiv data for logging output. (fix for RexOps/Rex#554) - Jan * added code to make shells pluggable. - RexOps/Rex#602 - Jan * Avoid noisy test output - Ferenc Erki * added support to export resources to main namespace and added more events - Jan * added possibility to use auth(for => task) before a task is created - fixed #402 - Jan * Fix handling of symbolic links (fix #591, close #592) - Jan * this adds a new method to the server objects called group() - Jan * fixed setting of path environment variable - #583 - Jan * Add preferred type option for mount command (fix #469) - Ferenc Erki * Reword has_{dir,file} test outputs - Ferenc Erki * Add has_dir test - Ferenc Erki * Print explicit PASS or FAIL output upon finishing a test suite - Ferenc Erki * Fix has_stat test for non-existing UIDs and GIDs - Ferenc Erki * Allow has_stat test to handle directories (fix #582) - Ferenc Erki * Add diag method for Rex::Test::Base - Ferenc Erki * Ensure proper return values for is_{dir,file} functions (fix #584) - Ferenc Erki * Drop potentially dangerous --force-yes option (fix #559) - Ferenc Erki * Generate docs for Rex::Test (fix #483) - Ferenc Erki 2015-03-08 (1.0.0) * Remove hardcoded connection type (fix #579) - Ferenc Erki * fixed systemd status query - Jan * test output of tmpdir gathering before working with it. - Jan * fixed removing some tmp files - Jan * fixed some warnings for netstat listing if reading an unknown transport layer - Jan * added no_autodie feature flag - Jan * fixed is_file() for files with spaces - Jan * Fix POD - Ferenc Erki * don't redirect stdout 2 times. freebsd don't like it - Jan * added tty feature flag and sorted the flags - Jan * added some defaults for kvm boxes (network) - Jan * fixed autodie bug for is_symlink function - Jan * added reconnect tries to Net::OpenSSH connections - Jan * Allow spaces in Augeas values - Andrew Beverley * Warn if Augeas command fails - Andrew Beverley * fixed a problem if a server group was empty - Jan * dist.ini: Add Twitter and IRC links to metaresources block - Brian Manning * Rex::Commands::MD5: Make Rex use the /sbin/md5 binary on OS X - Brian Manning * Rex::Commands::User: fix typo in POD (user_group -> user_groups) - Brian Manning * Rex::Helper:Run->i_run: check no_path_cleanup before calling get_path - Brian Manning * stop 'profile' before returning from a subroutine. - Andrej Zverev * Speed up connecting to Boxes - Ferenc Erki * allow call of run() command with arrayRef - Jan * fixed sync_up/sync_down with Text::Glob - Jan * fixed authentication, failing if try password auth without mentioning pass_auth directly - Jan * fixed line endings with openssh and pty - Jan * Added possibility to use group() also as a resource function - Jan * added possibility to define task parameters multiple times from cli. - #516 - Jan * fixed windows tests - #514 - Jan * fixed #555 - default for Net::OpenSSH now also spawn a pty. Can be disabled with feature no_tty - Jan * Die if trying to run augeas without augtool installed (close #547) - Andrew Beverley * Skip db tests if there are missing dependencies (fix #548, close #549) - Volker Kroll (vkroll) * Restore perl-5.8.9 compatibility - Ferenc Erki * Add test for minimum perl version required - Ferenc Erki * Be more explicit about required perl version - Ferenc Erki * Stop append_or_amend_line inserting extra blank lines - Andrew Beverley * Add tests for append_or_amend_line - Andrew Beverley * fixed Rex::Box with Net::OpenSSH - Jan * rex/CLI.pm: update docs for Rex options - Brian Manning * CLI.pm: throw error if -T used with task arg, but no matching task found - Brian Manning * fixed #539 - detect primary network address - Jan * Add append_or_amend_line function to File command - Andrew Beverley * Drop Rex::Helper::Glob - Ferenc Erki * Suppress noisy test output - Ferenc Erki * Suppress warning about a variable being used only once - Ferenc Erki * Tidy up all the tests - Ferenc Erki * Use more helpful test functions - Ferenc Erki * use more appropriate functions from Test::More in tests - reneeb * some class inherit cleanup - Jan * Use correct path when using augeas insert - Andrew Beverley * Return correct output from augtool - Andrew Beverley * Fix false positive when using "augeas exists" - Andrew Beverley * Optimise Rex::Commands::Augeas - Andrew Beverley * Add user base class for those calls not supported in all OS - Andrew Beverley * Add password lock/unlock functions (Linux only) - Andrew Beverley * fixed resource end - Jan * Add PkgConf command to configure packages - Andrew Beverley * fixed set_openssh_opt() function to allow multiple options - Jan * fixed #527 - Rex::Output leaks semaphores and shared memory - Jan * improved continous_read option for Net::SSH2 connection mode - Jan * tail now also works with sudo also fixed #530 - Jan * use Net::OpenSSH is now default. don't need feature flag 0.55 - Jan * fixed line based operation with OpenSSH connection mode - Jan * migrated augeas module into Rex core - #532 - Jan * added partial sudo support for rsync command - Jan * fixed #529 - odd number of elements - Jan * fixed #528 -Amazon list_services, doesn't get all ec2 instances - thanks to David Golovan - Jan * fixed an issue that causes the parser to think the rexfile has an error - Jan * start of unit-test for Rex::Commands::DB - Volker Kroll (vkroll) * better fix for #521, don't print all servers by rex -T. Also fixed group authentication. - Jan * patch from twitter/@tekcurmudgeon to allow setting of gpgkey for a repository - Jan * fixed late group lookup - #521 - Jan * if the evaluation of the Rexfile was without syntax errors, but don't return a true value, try to evaluate it manually. so is is not needed to return a true value at the end. - fix for #513 - Jan * fixed path resolution for private_key and public_key when used a ~ (tilde) sign. #517 - Jan * fix rsync with port definition - #520 - Jan * added parse_templates option to sync_up function, so that template parsing can be prevented - #519 - Jan * Rex::FS::File accepts filenames now - reneeb * Add initial version of changelog generator - Ferenc Erki 2015-01-11 Jan Gehring (0.57.0) * allow definition of gpgkey for redhat/yum repositories - #522 - tekcurmudgeon * fixed Group defined after task definition - #521 * fixed rsync will execute failed when use -H 127.0.0.1:2222 - #520 * added new sync_up/down option for sync_up function will replace template variable of *.tpl - #519 * fixed failed authentication when used ~ symbol - #517 * fixed before_task_start() fails with an ambiguous error when your Rexfile does not return a true value - #513 2015-01-06 Jan Gehring (0.56.1) * tasks doesn't return a value when called as a sub (#523) - Jan 2014-12-26 Jan Gehring (0.56.0) * Extend documentation of run() options (#466) - Ferenc Erki * New template engine with better error reporting. - Jan * Only try to run umount if mount point is already mounted - Ferenc Erki * Set changed flag for umount after the command has been run - Ferenc Erki * Fix error when only grow option was given to partition() - Ferenc Erki * Fix regex to find end of partition instead of size - Ferenc Erki * Use kB as unit when determining partition boundaries - Ferenc Erki * Fix missing `strict` and `warnings` pragmas - Ferenc Erki * Add LICENSE section to POD - Ferenc Erki * Replace defined-or operator to restore perl-5.8.0 compatibility - Ferenc Erki * Fix test for Parallel::ForkManager - Ferenc Erki * Fix test for Amazon Cloud Module - Ferenc Erki * Add rex_kvm_agent feature flag - Ferenc Erki * Allow multiple tasks to run with Rex::Test::Base (fix #476) - Robert Abraham * Improve evaluation of hostnames (fix #479, close #480) - Renee Bäcker * Fix POD (close #488) - Brian Manning * Fixed some deprecated docker calls - Jan * Fix mode option for mkdir command - Ferenc Erki * Fixed needs function - Jan * Added before_execute and after_execute task hooks - Jan * Add basic tests for Rex::Logger (close #484) - Renee Bäcker * Clarify/correct documentation (close #486) - Sascha Askani * Check versions of installed packages - Ferenc Erki * Refactor has_package test for simpler version matching - Ferenc Erki * Use OurPkgVersion for automatic module versioning - Ferenc Erki * Add has_stat to Rex::Test - Robert Abraham * Add documentation for has_stat (close #474) - Ferenc Erki * fix for #473 - download root restricted files in sudo mode - Jan * fix for #498 - added autodie feature flag - Jan * fixed local mkdir return code - Jan * fixed path quoting for #512 - Jan * added glob_to_regex function (Text::Glob) - fix for #495 - Jan * use test binary instead of '[ ... ]' for file tests - Jan 2014-11-02 Ferenc Erki (0.55.3) * Fix @INC compilation for Windows - Ferenc Erki 2014-11-01 Ferenc Erki (0.55.2) * Don't return leading ./ on pathes - Ferenc Erki * Make helper_path tests OS-agnostic - Ferenc Erki * Convert ok() tests to is() - Ferenc Erki * Remove unnecessary variable assignment - Ferenc Erki * Update installation instructions - Ferenc Erki * Use ChangeLog file in tests - Ferenc Erki * Fix typo - Ferenc Erki 2014-10-25 Jan Gehring (0.55.1) * status call for services with upstart and systemd may not work properly - #460 - Jan * sudo with -e cli flag doesn't work - #461 - Jan * Cannot pass an argument with the value zero to a task - #463 - Jan * Issue tracker not in META.yml - #464 - Ferenc Erki * Allow specifying which tests to run as a parameter for Test:run #462 - Ferenc Erki 2014-10-19 Ferenc Erki (0.55.0) * vm names in quote. so they can contain spaces - Jan * fallback to arp query if no answer from rex-kvm-agent - #454 - Jan * Print out error messages during Test:run (fix #450) - Ferenc Erki * Clarify error message during image download - Ferenc Erki * Remove explicit setting of VERSION - Ferenc Erki * return 0 if no swap given - #452 - Jan * fixed windows crashing on multiple connects - #448 - Jan * Work when swap in not enabled and values are undefined. FreeBSD only for now. - Graham Todd * possibility to modify Net::OpenSSH constructor - Jan * Revert use Rex::Group (#447) - Ferenc Erki * added late-group lookup, if group is not defined yet. fixed #447 - Jan * Make PkgVersion happy - Ferenc Erki * Fix typo - Ferenc Erki * removed unlink - Jan * Added possibility to query rex-kvm-agent. fixed #436 - Jan * dont throw error with multiple test files - Robert Abraham * Add ROSA systems support - Denis Silakov * fixed get_installed and is_installed functions Rex::Pkg::Gentoo - Robert Abraham * create binary installers from Rexfiles - Jan * Correct ChangeLog - Ferenc Erki * use Net::OpenSSH as default when available - #435 - Jan * removed executable bit - Jan * Added possibility to pack rex with PAR - Jan 2014-10-03 Jan Gehring (0.54.3) * added possibility to clone an jiffybox image - #439 - Peter Manthey * only execute testfiles which end on .t - #434 - Robert Abraham * close last used ssh connection after test - #433 - Robert Abraham * Add error message when attempting to run a non-existing task - FErki * Check if file exists before checking contents - fix #432 - FErki * refactored the behaviour of set() function to do what it is saying. So with feature 0.54 enabled set is always overwriting the existing values. (#425) * Add service_exists for Gentoo - FErki * fixing nested sudo operations. - #423 * added check if service exists - #407 * Handle hostgroup members with leading numeric ranges - FErki * redirect nohup output to /dev/null * fixed return value for flavors function - #406 - exzz * make apt-listchanges non-interactive - #417 - aowi * added path_map function - Erik Huelsmann * don't try to run dmidecode if it is not in PATH - Andrej Zverev * enhanced support for pkgng (FreeBSD) - Andrej Zverev * fixed Rex::Commands::MD5::md5() to obey path settings * Add documentation for run() function. - #440 - Erik Huelsmann 2014-09-13 Jan Gehring (0.53.1) * added Rex::JobControl functions * fixed hanging VBox with CentOS 7 and delayed dhcp ip lease * fixed on_change hook for file() resource when file was removed * added cmdb variables to template with feature flag - #420 * export Rex::Config variables to all template variants - #419 * fixed chkconfig bug for Mageia, Redhat and SuSE - chenryn * added resource() function, to define own resources. 2014-08-30 Jan Gehring (0.52.0) * fixed #381 - file NAME, ensure => 'absent' for a directory * fixed #392 - run conditional options with exec_autodie * added on_change hook for update_system function. fixed #401 * Added support for end_if_matched option to run command * Rex::Output to persist across different processes (forks) * Add floating ip support for openstack provider - #398 * Auto upload ssh key to openstack cloud provider * Implement feature to tie server.ini to specified -E environment (server.$environment.ini). * #409 - added before_task_start and after_task_finished hooks * [#408] - define fallback authentication * [#416] - fixed pkg with ensure => 'ver.si.on' 2014-07-29 Jan Gehring (0.51.2) * Fixed #394 - export of is_symlink function * Fixed #395 - is_file compatibility bug, doesn't detect symlinks anymore * Added "." in the allowed char of lvm create #393 - samuelet * possibility to call tasks as a method (prettier dsl) * load cmdb by default * load ini group module by default, if server.ini exists 2014-07-20 Jan Gehring (0.50.0) * Use stat() output for directory and file tests (fix #391) - FErki * added Paralell::ForkManager as optional component - #295 * fixed Problem with failed conditionals in Rex::Command::Run - #389 * activate exit_status feature by default for non parallel task execution * added proxy_command support - fixed #380 2014-07-12 Jan Gehring (0.49.0) * Added FreeBSD 10 Support for pkgng. #280 2014-07-10 Jan Gehring (0.48.0) * Added CentOS 7 support 2014-07-05 Jan Gehring (0.47.0) * Rex::Test now also working with KVM - FErki * Update default VNC listen address for KVM machines - FErki * added pkgng commands for FreeBSD 10 * A module which allows to read configuration files from an XML file. - nathanIL * Fixed a problem with auth_type try for rsync * Fixed using -G cli switch with a non existing group it will run localy #379 * added Darwin (MacOSX) network module * documentation updates - FErki * Ident task description when running -T - Nathan Abu * use https to communicate with amazon * allow set callback and environment together #374 (run command) - alex1line * added exclude option to sync commands - Cameron Daniel * General tasks before/after sub #353 * shell_path variable is not checked for empty value before use #376 - Ilya Evseev * verbose_run feature flag #375 * Syntax enhancement of "group" command #369 - Jens Berthold * extend service() function, so that it knows how to get a status for a service if the init script doesn't have a status call * Avoid warning if there's nothing to upgrade (update_system) - FErki * Possible precedence issue with control flow operator with perl-5.20.0 - FErki * added Rex::Constants library * don't use shadow file if not present - user module * detect amazon system and use redhat classes * fixed inline templates for modules 2014-05-22 Jan Gehring (0.46.2) * fixed tmp_dir configuration * load Rex::Commands::Box if Rex::Test is loaded, so that set(box => '') work * fixed a problem with Test:run 2014-05-19 Jan Gehring (0.46.1) * fixed a dependency problem * fixed a problem detecting the temporary directory * 'set port' ignored in Rexfile - #366 * update_system / better error message - #367 * set sudo auth for a special server in a group causes endless loops - #368 2014-05-01 Jan Gehring (0.46.0) * Rex::Box, added kvm support - #174 * core: allow passing template content to template command - #345 - reneeb * core/report: refactored report generation. This change break backward compat. because the report format changed. * core: added groups_dbi() function to generate server groups from sql - #346 - Jean-Marie RENOUARD * core: added groups_yaml() function to generate server groups from yaml file - Jean-Marie RENOUARD * core: add support for df on a given mount point - Simon Bertrang * cloud/amazon: fixed a case where amazon returns instance item in an array - Kasim Tuman * core: added authentication to download() function. - #340 * core: refactored tmp dir generation - FErki * cloud: added cloud_volume detach/attach function * cloud/amazon: fixed multiple tags - David Golovan * core: added description to environments - #274 * refactored README.pod to README.md, added build badge - eduardoj * core: extended rexify command to work with git * core/test: Added Rex::Test - Framework to run tests * core: Connect failure reports "Error running task/batch: Wrong username/password or wrong key" - #359 - eduardoj * core/cmdb: path can now have variables / can be extended * core/user: refactored handling of home directory creation. This might break compat. because we are following the system default now. (added create_home option) - #270 - FErki * core: added a special load path for perl libraries, so that we don't mix up perl and rex modules. * core/service: using nohup to work around a bug in Net::SSH2/libssh2 * core: the caching is now enabled by default. this might break backward compat. if you are using chroot() to another system inside a task. * core: added 'no_cache' feature. 2014-04-13 Jan Gehring (0.45.3) * fixed jiffybox endless loop on creating instances. #344 - reneeb 2014-04-12 Jan Gehring (0.45.2) * fixed special mkdir() case on local windows runs. 2014-04-11 Jan Gehring (0.45.1) * no_overwrite option for file() function * ensure 'directory' option for file() function * added notifications * pkg resource (replacement for install function) * allow array for file() function * check if iptables rule already exists * creates option for run() resource * only_if and unless option for run() resrouce * added notification for service() resource * added account() resource (as replacement for create_user) * fixed SCM::Git to work with sudo * update _parse_ip subroutine. be possible to parse ppp0. #328 - Tomohiro Hosaka * support -g to supply group name - #330 - fanyeren * added openstack cloud support - Ferenc Erki * run() resource support customized environments - #316 andrejzverev * can_run() now returns the first command found as string - #193 * read cpu information out of /proc/cpuinfo if dmidecode is not available - #306 * Handles the case where rsync is missing, and that makes Rex wait forever - #331 - Joris DE POOTER * fixed $Rex::Logger::format does not apply. - #335 * fixed download() command on windows - #271 * added cloud_image_list function() * fixed debian system_update - #339 - Niklas Larsson 2014-03-02 Jan Gehring (0.44.6) * fixed wrong expansion of home paths #324 * fixed return code on failed connects is wrong #317 * get as much output from ps(1) as possible #323 - sbertrang 2014-02-25 Jan Gehring (0.44.5) * fixed shell gathering 2014-02-17 Jan Gehring (0.44.4) * fixed manifest file 2014-02-14 Jan Gehring (0.44.3) * do not call sprintf on undefined values to prevent warnings - #312 - sbertrang * add ksh to shells - #310 - sbertrang * only pass actual option strings to prevent ssh crashes - #309 - sbertrang * rexify does not create projects due to missing file error - #318 * sed command changes mode of target file - #314 2014-02-08 Jan Gehring (0.44.2) * fixed sudo_without_sh - #305 * added warning if no perl interpreter was found on the remote system - #302 2014-02-02 Jan Gehring (0.44.1) * fixed detection of openSUSE with lsb-release installed - #297 * use Makefile.PL for tests. fixed #300 * Support for DBI \%attr hashref - #296 - stefb69 * Make quiet mode not mute warnings and errors. - #294 - slashbeast * new cli parameter -qw for quiet with warnings - #294 2014-01-25 Jan Gehring (0.44.0) * docker support (experimental) - #278 - chenryn * format the output of say() - #155 * userdefined columns for ps() command - #175 - dirkcjelli * using tilde (~) sign for directories - #198 - gnouc, krimdomu * SCM::Git, now uses cwd option of run() command, so it works also remote. - #211 - atrodo * Box default pkg update - #217 - endyman * run_batch() command to run batches on demand - #222 - jorisd * Allow "sed" function to work on multiple lines. - #227 - davidolrik, krimdomu * Added bulk_install() method for packages installing - #229 - jorisd * Enable bulk_install for Gentoo and OpenWrt - #231 - ferki * Added some hooks at central points in rex, so that it is possible to control the behaviour of rex in some points. * added on_change hook for sync_up/sync_down - #232 * Rex::Group::Lookup::Command - read hostnames from a command. - #233 - fanyeren * Improve user and group management on OpenWrt - #242 - ferki * Add kernel module (un)loading support for OpenWrt - #243 - ferki * Add service status support for OpenWrt - #246 - ferki * make ssh read buffer configurable (for Net::SSH2 connections) - #247 this will speedup the connection, but may break on older systems! * Add systemd service provider support for Gentoo - #250 - ferki * Add systemd service provider support for Mageia - #282 * feature flag to deactivate path cleanup - #261 * feature flag to parse $HOME/.profile - #262 * Cloud::Amazon Check to make sure it is HASH before key look up - #263 - oneness * autodie feature if run() fail - #265 * added support for tcsh shell - #284 * Fix guestinfo for Gentoo - #236 - ferki * get_host can't find aliases - #239, #240 - jorisd, ferki * rsync get wrong user if using "auth for $task" - #252 * Flag existing feature sudo_without_sh as found - #253 - gittex * Cleaned-Up Data module dependence - #254 * iptables arguments needs quote if they are whitespaced - #257 - jorisd * add Pod encoding marker - #259 - sergeyromanov * "needs" doesn't know how to call tasks from the main Rexfile - #260 * gathering alias network interfaces like eth0:0 - #264 * Cron: Jobs can be duplicated - #269 - jorisd * FreeBSD: store netmask in dotted decimal format - #287 - andrejzverev * Uninitialized value in OpenSSH.pm - #290 - samuelet 2013-10-03 Jan Gehring (0.43.7) * fixed problem with unconfigured network devices * fixed return of complete cmdb * fixed bug with the reporting initialization 2013-09-17 Jan Gehring (0.43.3) * fixed return of string '0' on stdout * fixed loading of report via env variable * fixed manifest 2013-09-17 Jan Gehring (0.43.2) * #234 - Silent yum operations - Chris Steigmeier 2013-09-16 Jan Gehring (0.43.0) * #223 - generating reports of changed things on the remote system (report infrastructure) * #220 - atomic uploads * #219 - df function doesnt parse errors - jorisd * #218 - problems with escaping of special characters, reverted back to old behaviour (pre 0.42) * #215 - input validation for rexify to prevent creation of invalid module names * #214 - yum operations should be silent * #213, #231 - rexify to use proxy settings - Chris Steigmeier * #231 - Another Red Hat Enterprise flavor - Chris Steigmeier * #200 - Refactor OpenWrt user module - Ferenc Erki * #195 - Fix a typo in example code - Boris Däppen * #194 - Prefer ip command over ifconfig - Ferenc Erki * #189 - Zero values in crontab fields - Ferenc Erki * #186 - Turn "eval your Rexfile" into a debug message - Anders Ossowicki * #210 - zypper --no-gpg-checks option * #208 - Cache inventory of servers for faster execution * #206 - sync_up function doesn't work in modules. * #196 - Support port with ranged hostnamed * #180 - support of other shells than bash for the PATH / environment variable - Cuong Manh Le * #177 - if a feature can't be satisfied, die() * #166 - tmp directory now configurable 2013-07-04 Jan Gehring (0.42.4) * fixed an issue with append_if_no_such_line when searching for a string containing a quote. 2013-06-29 Jan Gehring (0.42.3) * #189 fixed zero values in crontab - ferki * fixed ownership problem with sudo mode and file manipulation 2013-06-23 Jan Gehring (0.42.2) * fixed local run of run_with helper command 2013-06-22 Jan Gehring (0.42.1) * #178 - no_ssh option doesn't work with OpenSSH connection * #181 - ssh ports doesn't work with Net::OpenSSH * #182 - addition parameters doesn't work for ini files * #183 - fqdn doesn't work in ini files * #184 - hostname evaluation and additional parameters doesn't work together 2013-06-15 Jan Gehring (0.42.0) * added Net::OpenSSH support - chenryn, jfried * custom user for sudo command * new function: delete_lines_according_to * new feature flag use_server_auth * improved ini file parsing * support for custom server parameters * cwd option for run command * speed improvements: #123, #133, #135, #136, #137, #143 - liedekef * removed blastwave package capabilities from solaris, because blastwave doesn't exists anymore * #129 - removed an unnecessary opendir call - liedekef * #148 - use equery for Rex::Pkg::Gentoo in get_installed, later replaced by #165 - tianon * #149 - updated most of Rsync with server-specific auth - tianon * #159 - don't execute a task if the defined group doesn't contain servers. There is a feature flag to disable this behavior (empty_groups) * #163 - Rex::Pkg::Gentoo: Fix separator character between package name and version * #165 - Rex::Pkg::Gentoo: Replace get_installed checking method 2013-05-03 Jan Gehring (0.41.3) * fixed using -c flag with Rex::Box - #160 * fixed parsing ssh/config file - #158 * get_box() : better error message - #157 * fixed PATH variable for run() with multiple commands - #156 2013-04-19 Jan Gehring (0.41.2) * fixed exit status code for some situations where it fails * fixed rexify --use=module command * fixinig 'unititialized value' output of inspect() function. returning now 'no value'. - #152 * added check if template result is empty. if so - die() - #152 * fixing problem with invalid variable names in templates - #152 2013-03-30 Jan Gehring (0.41.1) * fixed a parsing bug in df output * fixed mount command with persistend option 2013-03-30 Jan Gehring (0.41.0) * Function to get the last output of a command that uses run() #104 * Refactores Cron module, added environment variable support to cron * New sync module * added Hardware::VirtInfo module #119 - Franky Van Liedekerke * new keyword "case" * Refactored net_ssh2_exec() function - Peter H. Ezetta * Refactored local command execution to use IPC::Open3 * Changed the Debian is_installed function to use the more accurate get_installed function. - Samuele Tognini * '-t' option should work with '-e' option. rex -t 2 -H "hostA hostB" -e 'run "sleep 10"; say run "uptime"' should run in parallel. - Tokuhiro Matsuno * Fixed loading of modules in $HOME/.rex/recipes * Don't calculate md5 sums if there is no on_change hook for file() function - Franky Van Liedekerke * Better understandable error messages for authentication - Franky Van Liedekerke * Cloud/Amazon: support multiple security groups - RenatoCRON * Fix Pod about pubkey authentication - Joris * Rex/Gearman: Fixed get_exit_codes use flag * Rex/Boxes: Creation order of VMs can now be defined in YAML file 2013-03-10 Jan Gehring (0.40.4) * fixed get_box() command if task is run on a remote host * fixed sudo without password 2013-03-09 Jan Gehring (0.40.3) * fixed loading of files in lib directory @INC sometime got populated too late 2013-03-02 Jan Gehring (0.40.2) * fixed #117 - encode everything except a-z, 0-9 and _ 2013-02-27 Jan Gehring (0.40.1) * fixed #114 - used only once warnings * fixed #115 - passwordless sudo didn't work 2013-02-23 Jan Gehring (0.40.0) * fixed bug and refactored file path calculation #103 and #102 * added ini style groups #99 - Franky Van Liedekerke * VirtualBox Headless mode #105 * added default environment "default" * basic cmdb via YAML #107 * crypt sudo password * sudo without locales and password #98 - Dominik Schulz * fixed dmidecode on openbsd * export update_system sub - Ferenc Erki * fixing regex which gets name interfaces - Fran Rodriguez 2013-02-07 Jan Gehring (0.39.0) * don't need PERL5LIB env any more, fixed bug #95 * match comments better - Naveed Massjouni * more allowed characters in lvname - Samuele Tognini * new feature flag: exit_status - rex will now return a number higher than 0 if a task execution fails. * new function: is_installed - Daniel Baeurer * optimized lookup_file function - Franky Van Liedekerke * rexify command now allows usage of private module server 2013-01-27 Jan Gehring (0.38.0) * added security groups to amazon cloud - Jonathan Delgado * updated pod documentation - jorisd * fixed a problem with do_task() and lost ssh connections * rexify command now allows usage of local templates * added architecture and apt key to Pkg::Debian - Daniel Baeurer * added updated_system command to update a system * box: added function to list all vms * box: amazon support * box: describe boxes with an YAML file 2013-01-15 Jan Gehring (0.37.1) * fixed template bug in modules 2013-01-05 Jan Gehring (0.37.0) * box module is now plugable * run_task now accepts additional parameters * virtualization module is now plugable * hardware provider now plugable * package provider now plugable * service provider now plugable * fixed zypper ref call for SuSE on unsigned repositories 2012-12-22 Jan Gehring (0.36.0) * added run_task a new function to run tasks on specific hosts * added feature to install perl dependencies via cpanm/cpan with rexify command * get private IP of amazon ec2 instances - jdelgado7 * added possibility to extend cloud api with external modules * spawn a pty to execute commands #80. this fixes the requiretty thing. 2012-12-22 Jan Gehring (0.35.1) * VirtualBox support for virtualization module * new command - Rex::Commands::Box * auth for - supports regular expresions * repository function now supports multiple distributions in one call * Unwrapped double looping over files and regexes and adding $new_line if not present in absence of regexes - Mario Domgoergen * Better handling of $option parameter for 'install' - joris 2012-12-14 Jan Gehring (0.34.2) * fixed login for Rex::connect 2012-11-25 Jan Gehring (0.34.1) * fixed #77. added iptables tests - Dominik Danter * Relax ssh config file parsing - Dominik Schulz 2012-11-02 Jan Gehring (0.34.0) * Use Storable module for shared variables * Enhanced lookup_file function. Comments (#) and empty lines are now skipped. (chenryn) * get_network_devices now detects ppp devices (under linux). (bokutin) * Fixed pkg_info execution on FreeBSD (bokutin) * Set $? to match effective command return value (joris) * If a task is defined multiple times it will now print out a warning. * Fixed mount bug #75 * Fixed Redhat Repo bug #73 * Fixed a bug with profiling and http endpoint 2012-10-04 Jan Gehring (0.33.3) * fixed rename() bug, #67 2012-10-02 Jan Gehring (0.33.2) * fixed windows bug 2012-09-22 Jan Gehring (0.33.1) * speed improvements * profiler class * mounts can now be persisted in /etc/fstab - Laird Liu * the partition command accepts a mount parameter to mount the partition after creation - Laird Liu * new keyword "make" * some usability improvements - Anders Ossowicki * create_user got a new option "no_create_home" * it is now possible to use other template engines. * it is now easier to write independant modules * fixed expire date for create_user * check shell before executing things 2012-08-30 Jan Gehring (0.32.1) * fixed a bug in the transaction module 2012-08-21 Jan Gehring (0.32.0) * made the worker model exchangeable * added a reporting base class * replaced Getops::Std with Rex::Args * added start command to amazon cloud module * fixed stop command in amazon cloud module 2012-08-16 Jan Gehring (0.31.5) * fixed cli parameter bug (-G) * fixed logging bug with %h 2012-08-04 Jan Gehring (0.31.0) * fixed a bug for task with the no_ssh attribute * added http transport layer * added possibility to modify task and server authentication 2012-07-21 Jan Gehring (0.30.1) * fixed a cli parameter bug for custom user authentication * fixed a batch display bug 2012-06-15 Jan Gehring (0.30.0) * rex -T now show the server groups as well * new option "type" for the extract function - Sven Dowideit * Added user_list and user_groups - Jean Charles Passard * fixed the problem with pass_auth and rsync (#30) * Better Error Messages for compile failures in modules * Added support for task specific parallelism * fixed upload and download to work in sudo environments * add mode to extract function * Added the on_change support to the append_if_no_such_line - Samuele Tognini 2012-05-17 Jan Gehring (0.29.0) * Fixed wrong error message in LibVirt/create.pm - Sven Dowideit * Added dumpxml command (LibVirt) - Sven Dowideit * Updated docs - Sven Dowideit * Default listening on all ip's for vnc (LibVirt) - Sven Dowideit * Added more colorized output options - Samuele Tognini * Fixed a logging bug - Samuele Tognini * -Tv command line option output information about requested task - Samuele Tognini * -Tv command line option output information about batches and environments - Samuele Tognini * Updated some error messages output - Samuele Tognini * Added iflist command (LibVirt) - Jean Charles Passard * Added blklist command (LibVirt) - Jean Charles Passard * Added vncdisplay command (LibVirt) - Sven Dowideit * Fixed a bug with hooks and packages #41 - Jan Gehring * Refactored Task Module. Task is now an object - Jan Gehring * Added module to parse cli parameters - Jan Gehring * Added driver_type for kvm disks * fixed a md5 check bug for 'install file =>' * fixed bug #50 (extract function) * if no rexfile is in the current path try to guess the rexfile from the taskname - Sven Dowideit * added experimental feature: shared variables - Jan Gehring 2012-05-08 Jan Gehring (0.28.0) * fixed a bug with relative source file names inside external modules * new parameter -Tv to display more information about tasks * allow additional parameters for rsync * more code refactoring * fixed a bug in the libvirt module (thanks to SvenDowideit for reporting and testing) 2012-05-04 Jan Gehring (0.27.0) * added callback parameter to run command * added logformat function to define custom logging * reworked the output classes for better jenkins integration * code refactoring * added coloriszed output if Term::ANSIColor is available * fixed a bug with older lvm versions * added on_change option to sed command, thanks to Samuele Tognini 2012-04-26 Jan Gehring (0.26.3) * fixed a notification bug in the on_change event of the file function. * fixed a cli parameter bug in the rexify command. 2012-03-28 Jan Gehring (0.26.2) * fixed a cli parameter bug (-G) 2012-03-13 Jan Gehring (0.26.1) * fixed a bug in the libvirt module 2012-02-19 Jan Gehring (0.26.0) * changed license to Apache 2.0 * added sudo compatibility * added support for custom init commands * added rex-agent compatibility * added overmind compatibility * added lvm support to libvirt module * allow package installation with "install $pkg" * added sed function * added chdir parameter to extract function * added include function to include Rex recipes without registering the tasks * Specify the sudo password prompt to avoid different prompts in different locales. thanks to Hiroaki Nakamura * Sync exclude option now takes a string or an array of strings. thanks to Hiroaki Nakamura 2012-02-16 Jan Gehring (0.25.3) * fixed a display bug in rexify --search command * fixed a bug in the libvirt module if it gets executed local * fixed a bug in the service module for ubuntu 2012-02-15 Jan Gehring (0.25.2) * display the correct module name in rexify --search command 2012-02-15 Jan Gehring (0.25.1) * don't use github for recipes query 2012-02-15 Jan Gehring (0.25.0) * added public repository commands to rexify * added patch from JEEN Lee for gpgcheck on yum repositories 2012-02-13 Jan Gehring (0.24.1) * fixed a dependeny bug 2012-02-10 Jan Gehring (0.24.0) * Added patches from Alexandr Ciornii for Makefile.PL and home-directory detection * it is now possible to use Rex as a library * fixed/simplified SCM module * added iptables flush command * added a simple tcp alive test * allow inline templates * cloud_instance returns vm info after create * added cli parameters to before/around hooks * fixed before/around/after hooks for lokal tasks * added lvm create functions 2012-01-14 Jan Gehring (0.23.0) * Redhat Enterprise Linux Support (5/6) * read ssh_config file * rsync now automatically accept keys 2012-01-04 Jan Gehring (0.22.0) * systemd service provider (for redhat and suse) * before, around and after hooks for tasks * curl: Allow connections to SSL sites without certs * don't override db config if no import options given * fixed suse detection bug * user: set crypted passwords * added OpenSuSE 12.1 compatibility * fixed redhat versiond detection * automatically use systemd service class if opensuse >= 12.1 * added fusioninventory-agent output to the inventory module (if available) 2011-10-28 Jan Gehring (0.21.1) * fix for #8 - HOME environment variable on Windows * fix for #5 - hostname evaluation with ips 2011-10-10 Jan Gehring (0.21.0) * fixed running of multiple tasks by do_task * allow multiple groups for a task * every task can have its own auth information * user module: add ssh key * ssh port isn't fix anymore (patch from Jose Luis Martinez) * use generic auth method from Net::SSH2 (patch from Jose Luis Martinez) * add SCM module (Subversion and Git) * file and upload now scans for environment specifiy files first * added a file lookup function to build groups from * fixed windows syslog bug #6, thanks to aero * added -nolog parameter to logging function to disable logging at all * added posibility to evaluate perl code within the -H cli parameter 2011-09-16 Jan Gehring (0.20.0) * added virtualization module (from Sascha Guenther) * added extract function * flattend hardware gather template variables * fixed set_path and get_path * fixed get_random to return not 1 char too much * added set and get commands to set config values 2011-09-01 Jan Gehring (0.19.0) * added JUnit output module * added environment support * load Rex::Commands::Process as default 2011-09-01 Jan Gehring (0.18.1) * fixed a bug registering tasks as functions 2011-09-01 Jan Gehring (0.18) * added network support for Solaris, NetBSD, FreeBSD and OpenBSD * added is_solaris, is_bsd and is_linux function 2011-09-01 Jan Gehring (0.17) * added solaris 11 support * added solaris 10 support * added a caching module * added a clear task function (for rex-swarm) * added a function to get os release * fixed local copy error handling 2011-08-28 Jan Gehring (0.16) * added NetBSD support * added OpenBSD support * fixed a bug in the gentoo pkg management module 2011-08-07 Jan Gehring (0.15) * new function to detect a redhat system (or clone like CentOS, Scientific Linux) * increased timeouts for jiffybox * fixed template bug with $ signs * added support for scientific linux * added support for gentoo 2011-08-07 Jan Gehring (0.14.0) * Extended API to allow passing of arguments to Rex::Task->run * FreeBSD support * Ubuntu support 2011-08-07 Jan Gehring (0.13.0) * cache sftp object - for speed * added function to update package database * added windows support * license changed to GPL3 * added an alias for unlink (rm) * added functions to manage repositories * revised error handling * added jiffybox support, a german cloudservice from domainfactory * fixed template parsing bug (port from 0.12.1) * fixed bug with too long content in file function (port from 0.12.2) 2011-07-23 Jan Gehring (0.12.0) * allow array refs for Pkg::remove * register every task as a sub if not in main package * use lsb_release if available as default to detect operating system/version * added sudo command * allow to manage multiple services at once * added possibility to add and remove services from runlevels * added iptables module for basic iptables commands * added cloud layer and support for amazon ec2 instances 2011-07-26 Jan Gehring (0.11.1) * fixed output of netstat (reported by Thomas Biege) * fixed inclusion of some modules in Run.pm that causes errors under some circumstances (reported by Thomas Biege) 2011-07-22 Jan Gehring (0.11.0) * added lvm module * added lvm to inventory * fixed inventory string * fixed multiplicator for GB and TB * added order key to selects * added support for hpacucli * added centos 6 support 2011-07-17 Jan Gehring (0.10.1) * fixed db disconnect on forks * fixed some typos 2011-07-12 Jan Gehring (0.10.0) * added network module for route, default gateway and netstat * added mount and umount function * added cron module * added more information (basic system information) to the inventor function * added installed_packages function to get all the installed packages 2011-07-03 Jan Gehring (0.9.0) * register tasks as function if possible * add "lib" to INC if exists * added function get_operating_system * added transactions * deprecated "package file =>" * added hal module to access hardware information detected by hal * added dmidecode module to access bios information * added inventory function "inventor" * added ubuntu support (tested with lts 10.04) * added can_run function, to test if a command is present 2011-07-03 Jan Gehring (0.8.1) * fixed mageia detection * fixed bug if dnsdomainname returns no domainname * fixed mkdir bug on setting permissions, caused by a wrong merge 2011-06-26 Jan Gehring (0.8.0) * added mageia support for services and packages * added chown, chgrp and chmod functions * mkdir, added possibility to specify the permission, the user and the group * added function delete_lines_matching * added function append_if_no_such_line * added reload action for services * extended db module to support insert, delete, update 2011-06-25 Jan Gehring (0.7.1) * restored the backward compatibility with perl 5.8.x * suppress warning if no parameter is given * fixed mkdir function 2011-06-23 Jan Gehring (0.7.0) * preload a lot more default modules * added new functions (df, du, cp) * added some aliases (ln, cp, cd, ls) * added process management functions (kill, killall, nice, ps) * splitted out rex-agent and rex-master. 2011-06-19 Jan Gehring (0.6.1) * fixed documentation bugs (thanks to djill) * fixed #68827, rewrote is_readable/is_writable * handle auth failure correctly * mkdir now created directories recursive Rex-1.3.3/dist.ini0000644000175000017500000000201112572251052013577 0ustar jenkinsjenkinsname = Rex version = 1.3.3 release_status = stable author = Jan Gehring license = Apache_2_0 copyright_holder = Jan Gehring [@Filter] -bundle = @Basic -remove = MakeMaker [AutoPrereqs] [MakeMaker::Awesome] header = die 'Unsupported OS' if ( $^O eq 'MSWin32' && scalar((Win32::GetOSVersion())[1]) < 6 ); [ManifestSkip] [MetaProvides::Package] [MetaResources] homepage = http://www.rexify.org bugtracker.web = https://github.com/RexOps/Rex/issues repository.url = https://github.com/RexOps/Rex.git repository.web = https://github.com/RexOps/Rex repository.type = git x_twitter = https://twitter.com/RexOps x_IRC = irc://irc.freenode.net/rex [OSPrereqs / !~MSWin] IO::Pty = 0 Net::OpenSSH = 0 Net::SFTP::Foreign = 0 [OSPrereqs / ~MSWin] Net::SSH2 = 0 [OurPkgVersion] ; [PodCoverageTests] [PodSyntaxTests] [Prereqs] perl = 5.008008 [Prereqs / BuildRequires] Test::Pod = 0 [Test::MinimumVersion] max_target_perl = 5.8.8 [Test::Perl::Critic] critic_config = ../../.perlcriticrc Rex-1.3.3/bin/0000755000175000017500000000000012572251052012711 5ustar jenkinsjenkinsRex-1.3.3/bin/rexify0000755000175000017500000010032012572251052014141 0ustar jenkinsjenkins#!perl # # (c) Jan Gehring # # vim: set ts=3 sw=3 tw=0: # vim: set expandtab: use strict; use warnings; our $VERSION = '1.3.3'; # VERSION $|++; use LWP::UserAgent; use YAML; use Data::Dumper; use Rex::Config; use Rex::Logger; use Rex::Commands::Fs; use Rex::Commands::File; use JSON::XS; use Cwd qw(getcwd); use Carp; use URI; use URI::QueryParam; use File::Spec; use File::Basename; use Rex::Helper::Misc; use Rex::Helper::URI; use HTTP::Request; use HTTP::Request::Common; require Rex; $Rex::Logger::silent = 1; my ($major_minor) = ( $Rex::VERSION =~ m/^(\d*\.\d*)/ ); my $opts = {}; ###### # default server my $SEARCH_SERVER = "http://modules.rexify.org/api/$major_minor/get/recipes"; my $RECIPE_SERVER = "http://modules.rexify.org/api/$major_minor/get/mod/%s"; my $DEPEND_SERVER = "http://modules.rexify.org/api/$major_minor/get/dep/%s"; my $PERL_DEPEND_SERVER = "http://modules.rexify.org/api/$major_minor/get/perldep/%s"; my $AUTH_USER; my $AUTH_PASSWORD; my $AUTH_REALM; Rex::Config->register_config_handler( "module_server", sub { my ($param) = @_; if ( exists $param->{search} ) { $SEARCH_SERVER = $param->{search}; } if ( exists $param->{recipes} ) { $RECIPE_SERVER = $param->{recipes}; } if ( exists $param->{dependencies} ) { $DEPEND_SERVER = $param->{dependencies}; } if ( exists $param->{perl_dependencies} ) { $PERL_DEPEND_SERVER = $param->{perl_dependencies}; } if ( exists $param->{username} ) { $AUTH_USER = $param->{username}; } if ( exists $param->{password} ) { $AUTH_PASSWORD = $param->{password}; } if ( exists $param->{realm} ) { $AUTH_REALM = $param->{realm}; } } ); for ( my $i = 0 ; $i < @ARGV ; $i++ ) { if ( $ARGV[$i] =~ m/^\-\-([a-z0-9\-_]+)=/ ) { my $key = $1; my ( $c_key, $val ) = split( /=/, $ARGV[$i], 2 ); if ( exists $opts->{$key} ) { $opts->{$key} = [ $opts->{$key} ] if ( !ref $opts->{$key} ); push( @{ $opts->{$key} }, $val ); } else { $opts->{$key} = $val || 0; } } elsif ( $ARGV[$i] =~ m/^\-\-([a-z0-9\-_]+)/ ) { my $key = $1; if ( !$ARGV[ $i + 1 ] || $ARGV[ $i + 1 ] =~ m/^\-\-/ ) { $opts->{$key} = 1; } else { if ( exists $opts->{$key} ) { $opts->{$key} = [ $opts->{$key} ] if ( !ref $opts->{$key} ); push( @{ $opts->{$key} }, $ARGV[ ++$i ] ); } else { $opts->{$key} = $ARGV[ ++$i ]; } } } } if ( !$ARGV[0] || join( ",", @ARGV ) =~ m/\-h,|\-\-help,/ || $ARGV[0] eq "--help" ) { print STDERR "Usage: rexify [ []] []\n"; print STDERR "\n"; print STDERR "Options:"; print STDERR "\n"; print STDERR "\t--search=value\t\t\tWill search community recipes\n"; print STDERR "\t--use=recipe\t\t\tWill download community recipe\n"; print STDERR "\t--init=git-url\t\t\tWill download and initialize the given repo\n"; print STDERR "\t--update-from-git\t\tUpdate the cloned repository.\n"; print STDERR "\t--template=template\t\tUse a custom template to create the Rexfile skeleton\n"; print STDERR "\t--create-module\t\t\tCreate a module skeleton.\n"; print STDERR "\t--create-module=Mod::Name\tCreate a module skeleton inside a Rex project.\n"; print STDERR "\t--sudo\t\t\t\tTo use sudo for Perl Module installation.\n"; print STDERR "\t--resolve-deps\t\t\tRead meta.yml and try to resolve project dependencies\n"; print STDERR "\t--no-install-perl-deps\t\tUse this if you don't want that rexify tries to install Perl Modules.\n"; print STDERR "\n"; print STDERR "Custom Templates:\n"; print STDERR " box - Template to use for Rex::Commands::Box projects.\n"; print STDERR "\n"; print STDERR "Application Bundle Commands:\n"; print STDERR "\n"; print STDERR "\t--bundle\tCreate an all-containing redistributable binary application.\n"; print STDERR "\t--task=taskname\tWhich task should be executed. default: setup\n"; print STDERR "\n"; print STDERR "Rex-JobControl Commands:\n"; print STDERR "\n"; print STDERR "\t--upload\tUpload Rexfile to JobControl server.\n"; print STDERR "\t\t--project=\t\tProject where the Rexfile should be registered.\n"; print STDERR "\t\t--name=\t\t\tThe name for the Rexfile.\n"; print STDERR "\t\t--description=''\tA small description for the Rexfile.\n"; print STDERR "\n"; print STDERR "\t--execute\tExecute Job on JobControl server.\n"; print STDERR "\t\t--project=\t\tProject where the Rexfile should be registered.\n"; print STDERR "\t\t--job=\t\t\tThe name of the job to execute.\n"; print STDERR "\t\t--hosts=''\tA comma seperated list of servers.\n"; print STDERR "\n"; print STDERR "General options:"; print STDERR "\n"; print STDERR "\t--server=\t\tThe URL to JobControl server.\n"; print STDERR "\t--username=\t\tThe username to use for login to JobControl server.\n"; print STDERR "\t--password=\t\tThe password for the user.\n"; print STDERR "\n"; exit 1; } sub print_found { my ( $name, $data ) = @_; $name =~ s/\//::/g; $name =~ s/\.pm$//; print "* $name\n"; print " Author : " . $data->{Author} . "\n"; print " Requires : " . join( ", ", @{ $data->{Requires} } ) . "\n" if ( $data->{Requires} ); print " License : " . $data->{License} . "\n" if ( $data->{License} ); print " Description: " . $data->{Description} . "\n"; } sub update_from_git { system "git pull origin"; resolve_deps("meta.yml"); } sub download_recipe_git { my ($url) = @_; $Rex::Logger::silent = 0; my $u = URI->new($url); my $branch = $u->query_param("branch"); my @splitted_path = split /\//, $u->path; $splitted_path[-1] =~ s/\.git$//; $branch ||= "master"; my $path = File::Spec->catdir( File::Spec->rel2abs( File::Spec->curdir() ), $splitted_path[-1] ); my $parent_path = dirname $path; mkdir $parent_path; my $clone_url = $u->scheme . '://' . $u->host . $u->path; Rex::Logger::info("Cloning $clone_url to $path. Using branch: $branch."); system "git clone $url -b $branch '$path'"; chdir $path; resolve_deps("meta.yml"); } sub download_recipe_local_tar_gz { my ($url) = @_; $Rex::Logger::silent = 0; system "tar xzf $url"; my $path = basename($url); $path =~ s/\.tar\.gz$//; chdir $path; resolve_deps("meta.yml"); } # upload rexfile to rex-jobcontrol (the complete directory) sub upload_rexfile { my (%option) = @_; my $tmp_dir = File::Spec->tmpdir; my $tmp_file = File::Spec->catfile( $tmp_dir, basename(getcwd) . ".tar.gz" ); my $login_url = $option{server} . "/login"; my $upload_url = $option{server} . "/project/" . Rex::Helper::URI::encode( $option{project} ) . "/rexfile/new"; Rex::Logger::info("Creating tar.gz file out of this directory."); my $dir = basename( getcwd() ); system "cd .. ; tar czf $tmp_file $dir"; # upload the file my $ua = LWP::UserAgent->new( cookie_jar => {} ); #my $request = HTTP::Request->new(POST 'http://example.com', Content_Type => 'multipart/form-data', Content => [file_0 => ['options2.txt']]); # first login my $res = $ua->post( $login_url, { username => $option{username}, password => $option{password} } ); if ( $res->code != 302 ) { print "Server not found or authentication wrong.\n"; exit 1; } my $up_request = POST( $upload_url, Content_Type => 'form-data', Content => [ rexfile_archive => [$tmp_file], rexfile_name => $option{name}, rexfile_description => $option{description} ] ); my $up_res = $ua->request($up_request); if ( $up_res->code != 302 ) { print "Upload of Rexfile failed.\n"; exit 1; } unlink $tmp_file; } # execute job on Job-Control server sub dispatch_execute_job { my (%option) = @_; my $login_url = $option{server} . "/login"; my $execute_url = $option{server} . "/project/" . Rex::Helper::URI::encode( $option{project} ) . "/job/" . Rex::Helper::URI::encode( $option{job} ) . "/execute"; # execute a job my $ua = LWP::UserAgent->new( cookie_jar => {} ); # first login my $res = $ua->post( $login_url, { username => $option{username}, password => $option{password} } ); if ( $res->code != 302 ) { print "Server not found or authentication wrong.\n"; exit 1; } # then send the execute command my $ex_request = POST( $execute_url, Content => [ sel_server => [ split( /[ ,]/, $option{hosts} ) ], ] ); my $ex_res = $ua->request($ex_request); if ( $ex_res->code != 302 ) { print "Execute of job failed.\n"; exit 1; } } sub download_recipe { my ($name) = @_; if ( $name =~ m/^(https|git):\/\// ) { # seems to be a git link download_recipe_git($name); return; } if ( !-f "Rexfile" ) { print STDERR "This is not a Rex project directory. There is no Rexfile.\n"; exit 1; } if ( !-d "lib" ) { mkdir "lib"; } print "Getting dependencies for $name...\n"; my $deps = decode_json( get( sprintf( $DEPEND_SERVER, $name ) ) ); if ( scalar( @{$deps} ) > 0 ) { print " Found: \n - " . join( "\n - ", @{$deps} ) . "\n"; for my $dep ( @{$deps} ) { download_recipe($dep); } } else { print " None found.\n"; } if ( !exists $opts->{"no-install-perl-deps"} ) { print "Getting perl dependencies for $name...\n"; my $perl_deps = decode_json( get( sprintf( $PERL_DEPEND_SERVER, $name ) ) ); if ( scalar( @{$perl_deps} ) > 0 ) { print " Found: \n - " . join( "\n - ", @{$perl_deps} ) . "\n"; for my $dep ( @{$perl_deps} ) { install_perl_module($dep); } } else { print " None found.\n"; } } print "Downloading $name... "; $name =~ s/::/\//g; my $content = get( sprintf( $RECIPE_SERVER, $name ) ); open( my $fh, ">", "tmp-mod.tar.gz" ) or die($!); binmode $fh; print $fh $content; close($fh); chdir("lib"); system("tar xvzf ../tmp-mod.tar.gz >dl.log 2>&1"); unlink("dl.log"); chdir(".."); unlink("tmp-mod.tar.gz"); print "done.\n"; } sub resolve_deps { my ($file) = @_; $Rex::Logger::silent = 0; $file ||= "meta.yml"; if ( !-f $file ) { return; } my $ref = YAML::LoadFile($file); my ( %deps, %perl_deps ); if ( exists $ref->{Require} ) { if ( ref $ref->{Require} eq "ARRAY" ) { $deps{$_} = $_ for @{ $ref->{Require} }; } else { %deps = %{ $ref->{Require} }; } } if ( exists $ref->{PerlRequire} ) { if ( ref $ref->{PerlRequire} eq "ARRAY" ) { $perl_deps{$_} = $_ for @{ $ref->{PerlRequire} }; } else { %perl_deps = %{ $ref->{PerlRequire} }; } } Rex::Logger::debug("Found dependencies: "); Rex::Logger::debug( Dumper( \%deps ) ); for my $req ( keys %deps ) { if ( ref $deps{$req} ) { if ( exists $deps{$req}->{git} ) { # git dep my $branch = "master"; if ( exists $deps{$req}->{branch} ) { $branch = $deps{$req}->{branch}; } my @path_parts = split /::/, $req; my $path = File::Spec->catdir( File::Spec->rel2abs( File::Spec->curdir() ), "lib", @path_parts ); my $parent_path = dirname $path; if ( !-d $parent_path ) { mkdir $parent_path; } if ( -d $path && !-d "$path/.git" ) { Rex::Logger::info( "$req not under git control. Skipping.", "warn" ); next; } if ( -d "$path/.git" ) { system "rm -rf '$path'"; } Rex::Logger::info("Cloning $deps{$req}->{git}#$branch to $path"); system "git clone $deps{$req}->{git} -b $branch '$path'"; resolve_deps("$path/meta.yml"); } } else { download_recipe($req); } } Rex::Logger::debug("Found perl dependencies: "); Rex::Logger::debug( Dumper( \%perl_deps ) ); for my $req ( keys %perl_deps ) { if ( ref $perl_deps{$req} ) { if ( exists $perl_deps{$req}->{git} ) { # git dep my $branch = "master"; if ( exists $perl_deps{$req}->{branch} ) { $branch = $perl_deps{$req}->{branch}; } my $curdir = getcwd; my $path = File::Spec->catdir( File::Spec->tmpdir, "tmp-build-$$" ); my $lib_path = File::Spec->catdir( File::Spec->rel2abs( File::Spec->curdir() ), "lib", "perl" ); my $parent_path = dirname $lib_path; if ( !-d $parent_path ) { mkdir $parent_path; } Rex::Logger::info("Cloning $perl_deps{$req}->{git}#$branch to $path"); system "git clone $perl_deps{$req}->{git} -b $branch '$path'"; chdir $path; system "cpanm -l '$lib_path' ."; chdir $curdir; system "rm -rf '$path'"; } } else { # we need relative directories, because auf a cpanm bug on windows. my $lib_path = File::Spec->catdir( File::Spec->curdir(), "lib", "perl" ); eval "use $req"; if ($@) { system "cpanm -l '$lib_path' $req"; } } } } sub install_perl_module { my ($mod) = @_; print "Checking $mod: "; eval "use $mod"; if ($@) { print "[failed]\n"; } else { print "[ok]\n"; return; } print "Trying to install $mod... "; my $cmd = "cpanm"; my $out = qx($cmd --help 2>&1); if ( $? != 0 ) { $cmd = "cpan"; $out = qx($cmd -h 2>&1); if ( $? != 0 ) { print "[failed]\n"; print "Can't find cpanm or cpan. Please install $mod manually.\n"; return; } } my $cpanm_opts = ""; if ( exists $opts->{sudo} ) { $cmd = "sudo $cmd"; } $out = qx($cmd $cpanm_opts $mod 2>&1); open( my $log, ">>", "rexify-install.log" ) or die($!); print $log $out; close($log); if ( $? != 0 ) { print "[failed]\n"; print "!! Please install $mod manually. See rexify-install.log for more details.\n"; } else { print "[ok]\n"; } } if ( exists $opts->{bundle} ) { # bundle everything to an application CORE::mkdir("rex.payload"); system "cp -vR * rex.payload/ 2>/dev/null"; system "rm -rf rex.payload/rex.payload"; my $rex = File::Spec->catfile( dirname($0), "rex" ); my $tmp_args_file = File::Spec->catfile( File::Spec->tmpdir(), "pp.args.$$.tmp" ); open( my $fh, ">", $tmp_args_file ) or die($!); print $fh template('@pp.args.tpl'); close($fh); # build the perl and application system "pp \@$tmp_args_file -o rex.payload/rex.bin $rex"; # find libssh2.so and libexpat.so my $arch = qx{uname -m}; chomp $arch; my $elf = "ELF32"; if ( $arch eq "x86_64" ) { $elf = "ELF64"; } CORE::mkdir( File::Spec->catdir( "rex.payload", "lib.bin" ) ); my @libexpat = qx{find /usr/lib /usr/lib32 /usr/lib64 /lib -name 'libexpat.so*' -type f 2>/dev/null}; my @libssh2 = qx{find /usr/lib /usr/lib32 /usr/lib64 /lib -name 'libssh2.so*' -type f 2>/dev/null}; chomp @libexpat; chomp @libssh2; for my $f ( @libexpat, @libssh2 ) { my $elf_class = qx{readelf -h $f | grep Class:}; # only copy architecture specific files # currently no multi arch support if ( $elf_class =~ m/$elf/ ) { system "cp -va $f " . File::Spec->catdir( "rex.payload", "lib.bin" ); } } system "cd rex.payload/lib.bin ; ln -s " . basename( $libssh2[0] ) . " libssh2.so.1"; system "cd rex.payload/lib.bin ; ln -s " . basename( $libexpat[0] ) . " libexpat.so.1"; # create wrapper script. open( my $fh2, ">", "rex.sh" ) or die($!); print $fh2 template( '@bundle.sh.tpl', task => 'setup' ); close($fh2); system "cd rex.payload ; tar czf ../rex.payload.tar.gz *"; system "cat rex.sh rex.payload.tar.gz >rex.selfextract.sbx ; chmod 755 rex.selfextract.sbx"; CORE::unlink($tmp_args_file); CORE::unlink("rex.sh"); system "rm -rf rex.payload"; CORE::unlink("rex.payload.tar.gz"); exit 0; } if ( exists $opts->{upload} && exists $opts->{server} && exists $opts->{username} && exists $opts->{password} && exists $opts->{project} && exists $opts->{name} ) { $opts->{description} ||= ""; upload_rexfile( %{$opts} ); exit 0; } if ( exists $opts->{execute} && exists $opts->{server} && exists $opts->{username} && exists $opts->{password} && exists $opts->{project} && exists $opts->{hosts} && exists $opts->{job} ) { dispatch_execute_job( %{$opts} ); exit 0; } if ( exists $opts->{search} ) { my $search_string = $opts->{search}; # only a search print "Downloading recipes.yml ... "; my $recipes = get($SEARCH_SERVER); print " done.\n"; print "Searching...\n\n"; my $data = Load($recipes); for my $mod ( keys %{$data} ) { if ( $mod =~ qr{$search_string}i ) { print_found( $mod, $data->{$mod} ); next; } if ( $data->{$mod}->{Description} =~ qr{$search_string}i ) { print_found( $mod, $data->{$mod} ); } } exit 0; } if ( exists $opts->{"update-from-git"} ) { update_from_git(); exit 0; } if ( exists $opts->{init} ) { if ( -f $opts->{init} ) { download_recipe_local_tar_gz( $opts->{init} ); } else { download_recipe_git( $opts->{init} ); } exit 0; } if ( exists $opts->{use} && $ARGV[0] =~ /^\-\-use/ ) { if ( $opts->{use} ) { if ( !ref $opts->{use} ) { $opts->{use} = [ $opts->{use} ]; } for my $use_mod ( @{ $opts->{use} } ) { download_recipe($use_mod); } } exit 0; } if ( exists $opts->{"resolve-deps"} && $opts->{"resolve-deps"} ) { resolve_deps("meta.yml"); exit 0; } if ( exists $opts->{"create-module"} ) { my $dir = $ARGV[0]; my $module_name = $dir; if ( $dir !~ m/^[a-zA-Z][a-zA-Z_:0-9]+$/ ) { print "USAGE: $0 Module::Name --create-module\n"; print " Allowed characters: a-z, A-Z, _, 0-9, '::'.\n"; exit 1; } if ( -f "Rexfile" && $opts->{"create-module"} ) { $dir = "lib/$dir"; } if ( $dir =~ m/\-\-create\-module/ ) { print "USAGE: $0 Module::Name --create-module\n"; print " Allowed characters: a-z, A-Z, _, 0-9, '::'.\n"; exit 1; } $dir =~ s/::/\//g; print "Creating module $module_name...\n"; print " mkdir $dir\n"; mkdir $dir, recursive => 1; chdir $dir; print " Creating template file: __module__.pm\n"; file "__module__.pm", content => template( '@module.pm.tpl', dir => $dir, module_name => $module_name ); print " Creating template file: meta.yml\n"; file "meta.yml", content => template( '@meta.yml.tpl', dir => $dir, module_name => $module_name ); print "\n"; print "Your module has been created in $dir.\n"; exit 0; } my $dir = $ARGV[0]; if ( defined $ARGV[1] && $ARGV[1] !~ m/^\-\-/ ) { $dir = $ARGV[1]; } if ( $dir !~ m/^[a-zA-Z][a-zA-Z_:0-9]+$/ ) { print "USAGE: $0 Project::Name\n"; print " Allowed characters: a-z, A-Z, 0-9, _, '::'.\n"; exit 1; } if ( exists $opts->{template} && -f $opts->{template} && $opts->{template} !~ m/^\// ) { my $cwd = getcwd; $opts->{template} = "$cwd/" . $opts->{template}; } elsif ( exists $opts->{template} && $opts->{template} !~ m/^\// ) { $opts->{template} = '@' . $opts->{template}; } unless ( -d $dir ) { print "Created $dir\n"; mkdir($dir); } print "chdir to $dir\n"; chdir($dir); unless ( -d 'lib' ) { mkdir('lib'); } unless ( -f 'lib' . $ARGV[0] . '.pm' ) { open( my $fh, ">", "lib/$ARGV[0].pm" ) or die($!); print $fh template( '@libfile', lib => $ARGV[0] ); close($fh); print STDERR "Created lib/Rex/$ARGV[0].pm\n"; if ( $opts->{template} ) { open( $fh, ">", "Rexfile" ) or die($!); print $fh template( $opts->{template}, lib => $ARGV[0] ); close($fh); } else { open( $fh, ">", "Rexfile" ) or die($!); print $fh template( '@rexfile', lib => $ARGV[0] ); close($fh); } if ( $opts->{use} ) { if ( !ref $opts->{use} ) { $opts->{use} = [ $opts->{use} ]; } for my $use_mod ( @{ $opts->{use} } ) { download_recipe($use_mod); } } print STDERR "Created Rexfile.\n"; print STDERR "Done.\n\nNow edit Rexfile to suite your needs.\n"; print STDERR "You can edit $dir/lib/$ARGV[0].pm to define tasks.\n"; print STDERR "\n\nIf you have any questions or wishes\n\n\tjust join #rex on freenode\n\nor post them here:\n\n\thttps://github.com/RexOps/Rex/issues\n\n"; } else { if ( $opts->{use} ) { if ( !ref $opts->{use} ) { $opts->{use} = [ $opts->{use} ]; } for my $use_mod ( @{ $opts->{use} } ) { download_recipe($use_mod); } } exit; } sub get { my ($url) = @_; my $ua = LWP::UserAgent->new; $ua->env_proxy; if ( $AUTH_USER && $AUTH_PASSWORD ) { my ($netloc) = ( $RECIPE_SERVER =~ m/^https?:\/\/([^\/]+)\// ); unless ( $netloc =~ m/\:\d+$/ ) { if ( $netloc =~ m/^https/ ) { $netloc .= ":443"; } else { $netloc .= ":80"; } } $ua->credentials( $netloc, $AUTH_REALM, $AUTH_USER, $AUTH_PASSWORD ); } my $resp = $ua->get($url); if ( $resp->is_success ) { return $resp->decoded_content; } } __DATA__ @rexfile # enable new Features use Rex -feature => 0.40; # set your username set user => ""; # set your password set password => ""; # enable password authentication set -passauth; # put your server in this group set group => "servers" => "server1", "server2"; # now load every module via ,,require'' require <%= $::lib %>; @end @libfile package <%= $::lib %>; use Rex -base; desc "Get uptime of server"; task "uptime", group => 'servers', sub { say run "uptime"; }; 1; @end @box use strict; use warnings; use Rex -feature => 0.40; use Rex::Commands::Box; set user => ''; set password => ''; set -passauth; # # CALL: # rex init --name=<%= $::lib %> --url=http://box.rexify.org/box/ubuntu-server-12.10-amd64.ova desc "Initialize and start the VM: rex init --name=vmname [--url=http://...]"; task "init", sub { my $param = shift; box { my ($box) = @_; $box->name($param->{name}); # where to download the base image $box->url($param->{url}); # default is nat #$box->network(1 => { # type => "bridged", # bridge => "eth0", #}); # only works with network type = nat # if a key ssh is present, rex will use this to log into the vm # you need this if you run VirtualBox not on your local host. $box->forward_port(ssh => [2222 => 22]); # share a folder from the host system #$box->share_folder("sharename" => "/path/on/host/system"); # define the authentication to the box # if you're downloading one from box.rexify.org this is the default. $box->auth( user => "root", password => "box", ); # if you want to provision the machine, # you can define the tasks to do that $box->setup(qw/install_webserver/); }; }; # # CALL: # rex down --name=<%= $::lib %> desc "Stop the VM: rex down --name=vmname"; task "down", sub { my $param = shift; my $box = Rex::Commands::Box->new(name => $param->{name}); $box->stop; }; task "install_webserver", sub { # update package db update_package_db; # install packages / customize the vm install "apache2"; }; require <%= $::lib %>; @end @module.pm.tpl package <%= $::module_name %>; use Rex -base; task example => sub { my $output = run "uptime"; say $output; }; 1; =pod =head1 NAME $::module_name - {{ SHORT DESCRIPTION }} =head1 DESCRIPTION {{ LONG DESCRIPTION }} =head1 USAGE {{ USAGE DESCRIPTION }} include qw/<%= $::module_name %>/; task yourtask => sub { <%= $::module_name %>::example(); }; =head1 TASKS =over 4 =item example This is an example Task. This task just output's the uptime of the system. =back =cut @end @meta.yml.tpl Name: <%= $::module_name %> Description: {{ DESCRIPTION }} Author: {{ your name }} License: {{ THE LICENSE }} # Only if you have dependencies to other Rex Modules. Require: - Other::Rex::Module - 2nd::Rex::Module @end @pp.args.tpl -M Net::OpenSSH::ShellQuoter::POSIX -M Net::SFTP::Foreign::Backend::Unix -M Sys::Syslog -M Net::OpenSSH -M Net::SFTP::Foreign -M UNIVERSAL -M Rex::Virtualization -M Rex::User::Linux -M Rex::User::FreeBSD -M Rex::User::SunOS -M Rex::User::OpenWrt -M Rex::User::NetBSD -M Rex::User::OpenBSD -M Rex::Virtualization::VBox::delete -M Rex::Virtualization::VBox::list -M Rex::Virtualization::VBox::info -M Rex::Virtualization::VBox::shutdown -M Rex::Virtualization::VBox::reboot -M Rex::Virtualization::VBox::status -M Rex::Virtualization::VBox::import -M Rex::Virtualization::VBox::forward_port -M Rex::Virtualization::VBox::create -M Rex::Virtualization::VBox::bridge -M Rex::Virtualization::VBox::option -M Rex::Virtualization::VBox::start -M Rex::Virtualization::VBox::share_folder -M Rex::Virtualization::VBox::destroy -M Rex::Virtualization::VBox::guestinfo -M Rex::Virtualization::VBox -M Rex::Virtualization::LibVirt -M Rex::Virtualization::Docker -M Rex::Virtualization::LibVirt::delete -M Rex::Virtualization::LibVirt::blklist -M Rex::Virtualization::LibVirt::list -M Rex::Virtualization::LibVirt::info -M Rex::Virtualization::LibVirt::shutdown -M Rex::Virtualization::LibVirt::reboot -M Rex::Virtualization::LibVirt::dumpxml -M Rex::Virtualization::LibVirt::status -M Rex::Virtualization::LibVirt::import -M Rex::Virtualization::LibVirt::create -M Rex::Virtualization::LibVirt::option -M Rex::Virtualization::LibVirt::start -M Rex::Virtualization::LibVirt::vncdisplay -M Rex::Virtualization::LibVirt::clone -M Rex::Virtualization::LibVirt::iflist -M Rex::Virtualization::LibVirt::destroy -M Rex::Virtualization::LibVirt::hypervisor -M Rex::Virtualization::LibVirt::guestinfo -M Rex::Virtualization::Base -M Rex::Virtualization::Docker::delete -M Rex::Virtualization::Docker::list -M Rex::Virtualization::Docker::daemon -M Rex::Virtualization::Docker::info -M Rex::Virtualization::Docker::shutdown -M Rex::Virtualization::Docker::reboot -M Rex::Virtualization::Docker::create -M Rex::Virtualization::Docker::start -M Rex::Virtualization::Docker::destroy -M Rex::Shared::Var::Scalar -M Rex::Shared::Var::Array -M Rex::Shared::Var::Hash -M Rex::Shared::Var -M Rex::Hardware -M Rex::Args::Single -M Rex::Args::Integer -M Rex::Args::String -M Rex::Inventory::DMIDecode -M Rex::Inventory::Proc::Cpuinfo -M Rex::Inventory::SMBios::SystemInformation -M Rex::Inventory::SMBios::CPU -M Rex::Inventory::SMBios::Memory -M Rex::Inventory::SMBios::BaseBoard -M Rex::Inventory::SMBios::Section -M Rex::Inventory::SMBios::MemoryArray -M Rex::Inventory::SMBios::Bios -M Rex::Inventory::Hal -M Rex::Inventory::SMBios -M Rex::Inventory::Bios -M Rex::Inventory::HP::ACU -M Rex::Inventory::Hal::Object::Net -M Rex::Inventory::Hal::Object::Storage -M Rex::Inventory::Hal::Object::Volume -M Rex::Inventory::Hal::Object -M Rex::Inventory::DMIDecode::SystemInformation -M Rex::Inventory::DMIDecode::CPU -M Rex::Inventory::DMIDecode::Memory -M Rex::Inventory::DMIDecode::BaseBoard -M Rex::Inventory::DMIDecode::Section -M Rex::Inventory::DMIDecode::MemoryArray -M Rex::Inventory::DMIDecode::Bios -M Rex::Inventory::Proc -M Rex::File::Parser::Data -M Rex::File::Parser::Ini -M Rex::Notify -M Rex::Logger -M Rex::Commands -M Rex::Hook -M Rex::Exporter -M Rex::Box::VBox -M Rex::Box::Amazon -M Rex::Box::Base -M Rex::Box::KVM -M Rex::Output::JUnit -M Rex::Output::Base -M Rex::Report::YAML -M Rex::Report::Base -M Rex::Inventory -M Rex::FS::File -M Rex::Output -M Rex::Cron -M Rex::Batch -M Rex::CMDB -M Rex::TaskList -M Rex::Pkg::SuSE -M Rex::Pkg::Debian -M Rex::Pkg::Ubuntu -M Rex::Pkg::Gentoo -M Rex::Pkg::FreeBSD -M Rex::Pkg::SunOS -M Rex::Pkg::OpenWrt -M Rex::Pkg::Redhat -M Rex::Pkg::NetBSD -M Rex::Pkg::Base -M Rex::Pkg::ALT -M Rex::Pkg::Mageia -M Rex::Pkg::OpenBSD -M Rex::Pkg::SunOS::pkg -M Rex::Pkg::SunOS::OpenCSW -M Rex::Template -M Rex::Profiler -M Rex::User -M Rex::Box -M Rex::Resource::Common -M Rex::Cloud -M Rex::SCM::Subversion -M Rex::SCM::Git -M Rex::Report -M Rex::Value -M Rex::Group -M Rex::CMDB::YAML -M Rex::CMDB::Base -M Rex::Group::Entry::Server -M Rex::Group::Lookup::Command -M Rex::Group::Lookup::File -M Rex::Group::Lookup::DBI -M Rex::Group::Lookup::YAML -M Rex::Group::Lookup::XML -M Rex::Group::Lookup::INI -M Rex::Task -M Rex::Resource -M Rex::Interface::Fs::Sudo -M Rex::Interface::Fs::HTTP -M Rex::Interface::Fs::Local -M Rex::Interface::Fs::Base -M Rex::Interface::Fs::SSH -M Rex::Interface::Fs::OpenSSH -M Rex::Interface::File::Sudo -M Rex::Interface::File::HTTP -M Rex::Interface::File::Local -M Rex::Interface::File::Base -M Rex::Interface::File::SSH -M Rex::Interface::File::OpenSSH -M Rex::Interface::Cache::YAML -M Rex::Interface::Cache::Base -M Rex::Interface::Connection::Fake -M Rex::Interface::Connection::HTTP -M Rex::Interface::Connection::Local -M Rex::Interface::Connection::HTTPS -M Rex::Interface::Connection::Base -M Rex::Interface::Connection::SSH -M Rex::Interface::Connection::OpenSSH -M Rex::Interface::File -M Rex::Interface::Connection -M Rex::Interface::Executor -M Rex::Interface::Shell -M Rex::Interface::Exec::Sudo -M Rex::Interface::Exec::HTTP -M Rex::Interface::Exec::Local -M Rex::Interface::Exec::Base -M Rex::Interface::Exec::SSH -M Rex::Interface::Exec::OpenSSH -M Rex::Interface::Executor::Default -M Rex::Interface::Executor::Base -M Rex::Interface::Exec -M Rex::Interface::Fs -M Rex::Interface::Shell::Ksh -M Rex::Interface::Shell::Zsh -M Rex::Interface::Shell::Ash -M Rex::Interface::Shell::Default -M Rex::Interface::Shell::Sh -M Rex::Interface::Shell::Bash -M Rex::Interface::Shell::Tcsh -M Rex::Interface::Shell::Base -M Rex::Interface::Shell::Csh -M Rex::Interface::Cache -M Rex::Fork::Task -M Rex::Fork::Manager -M Rex::CLI -M Rex::Test::Base -M Rex::Test::Base::has_content -M Rex::Test::Base::has_file -M Rex::Test::Base::has_package -M Rex::Test::Base::has_service_stopped -M Rex::Test::Base::has_service_running -M Rex::Constants -M Rex::Hardware::Memory -M Rex::Hardware::Network -M Rex::Hardware::VirtInfo -M Rex::Hardware::Swap -M Rex::Hardware::Kernel -M Rex::Hardware::Host -M Rex::Hardware::Network::Linux -M Rex::Hardware::Network::FreeBSD -M Rex::Hardware::Network::Solaris -M Rex::Hardware::Network::NetBSD -M Rex::Hardware::Network::OpenBSD -M Rex::Hardware::Network::Darwin -M Rex::Cloud::Amazon -M Rex::Cloud::Base -M Rex::Cloud::Jiffybox -M Rex::Cloud::OpenStack -M Rex::Transaction -M Rex::Commands::LVM -M Rex::Commands::Virtualization -M Rex::Commands::Sysctl -M Rex::Commands::SimpleCheck -M Rex::Commands::Rsync -M Rex::Commands::Notify -M Rex::Commands::Tail -M Rex::Commands::Inventory -M Rex::Commands::Cron -M Rex::Commands::DB -M Rex::Commands::File -M Rex::Commands::Gather -M Rex::Commands::Network -M Rex::Commands::User -M Rex::Commands::Box -M Rex::Commands::Upload -M Rex::Commands::JobControl -M Rex::Commands::Cloud -M Rex::Commands::Run -M Rex::Commands::Download -M Rex::Commands::Process -M Rex::Commands::Sync -M Rex::Commands::Kernel -M Rex::Commands::MD5 -M Rex::Commands::Iptables -M Rex::Commands::Partition -M Rex::Commands::Service -M Rex::Commands::Pkg -M Rex::Commands::Fs -M Rex::Commands::Host -M Rex::Commands::SCM -M Rex::Service -M Rex::Pkg -M Rex::Cron::Linux -M Rex::Cron::SunOS -M Rex::Cron::Base -M Rex::Config -M Rex::Helper::System -M Rex::Helper::Run -M Rex::Helper::SSH2 -M Rex::Helper::DBI -M Rex::Helper::Encode -M Rex::Helper::Array -M Rex::Helper::INI -M Rex::Helper::Misc -M Rex::Helper::SSH2::Expect -M Rex::Helper::UserAgent -M Rex::Helper::Hash -M Rex::Helper::URI -M Rex::Helper::Path -M Rex::TaskList::Parallel_ForkManager -M Rex::TaskList::Base -M Rex::Require -M Rex::Args -M Rex::Sudo::File -M Rex::Test -M Rex::Service::SuSE -M Rex::Service::Debian -M Rex::Service::ALT::systemd -M Rex::Service::Gentoo::systemd -M Rex::Service::Mageia::systemd -M Rex::Service::Ubuntu -M Rex::Service::Gentoo -M Rex::Service::FreeBSD -M Rex::Service::SunOS -M Rex::Service::Redhat::systemd -M Rex::Service::OpenWrt -M Rex::Service::Redhat -M Rex::Service::NetBSD -M Rex::Service::Base -M Rex::Service::ALT -M Rex::Service::Mageia -M Rex::Service::OpenBSD -M Rex::Service::SunOS::svcadm -M Rex::Service::SuSE::systemd -M Rex -M Net::SSH2 @end @bundle.sh.tpl #!/bin/bash echo "" echo "Self Extracting Rex Installer" echo "" export TMPDIR=`mktemp -d /tmp/rex.bundle.XXXXXX` ARCHIVE=`awk '/^__ARCHIVE_BELOW__/ {print NR + 1; exit 0; }' $0` echo -n "Extracting archive... " echo tail -n+$ARCHIVE $0 | tar xz -C $TMPDIR if [ "$?" != "0" ]; then echo "failed." exit 1 fi echo "done." CDIR=`pwd` cd $TMPDIR export LD_LIBRARY_PATH=`pwd`/lib.bin:$LD_LIBRARY_PATH ./rex.bin -f `pwd`/Rexfile $* cd $CDIR rm -rf $TMPDIR exit 0 __ARCHIVE_BELOW__ @end Rex-1.3.3/bin/rex0000755000175000017500000001015712572251052013441 0ustar jenkinsjenkins#!perl # # (c) Jan Gehring # # vim: set ts=3 sw=3 tw=0: # vim: set expandtab: use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::CLI; my $rex = Rex::CLI->new; $rex->__run__; __END__ =pod =head1 NAME (R)?ex - (Remote)? Execution =head1 DESCRIPTION Rex is a tool to ease the execution of commands on multiple remote servers. You can define small tasks, chain tasks to batches, link them with servers or server groups, and execute them easily in your terminal. =head2 Command line options =over 4 =item -b Run batch =item -e Run the give code fragment =item -E Execute task on the given environment =item -H Execute task on these hosts =item -z Execute task on hosts from this command's output =item -G|-g Execute task on these group =item -u Username for the ssh connection =item -p Password for the ssh connection =item -P Private Keyfile for the ssh connection =item -K Public Keyfile for the ssh connection =item -T List all known tasks. =item -Tm List all known tasks in "machine readable" format =item -Ty List all known tasks in YAML format =item -Tv List all known tasks with all information =item -f Use this file instead of Rexfile =item -h Display this help =item -m Monochrome output. No colors =item -M Load Module instead of Rexfile =item -s Use sudo for every command =item -S Password for sudo =item -v Display (R)?ex Version =item -F Force. Don't regard lock file =item -d Debug =item -dd More Debug (includes Profiling Output) =item -o Create a compatible output for the given module =item -C Turn cache OFF =item -c Turn cache ON =item -q Quiet mode. No Logging output =item -qw Quiet mode. Only output warnings and errors =item -Q Really quiet. Output nothing. =item -t Number of threads to use ('parallelism' parameter) =back =head2 Rexfile If you run I it will read the file I in the current working directory. A Rexfile consists of 3 major parts. =head3 Authentication and Configuration In that part you define the user and password you want to use to log into your servers. You can even define timeouts or the paralellism of task execution. =head4 Simple Authentication B user ""; B password ""; B pass_auth; =head4 Key Authentication B private_key "/path/to/your/private/key.file"; B public_key "/path/to/your/public/key.file"; =head4 Define Logging B logging to_file => "rex.log"; B logging to_syslog => "local0"; =head4 Other Configuration parameters B timeout 10; B parallelism 2; =head3 Group your servers Rex gives you the possibility to B. One way is to do it in code within the Rexfile. Another is to use a I file in the same directory as the Rexfile. =head4 Code in the Rexfile Rex gives you the possibility to B. So you don't need to type every servername multiple times. group "frontends" => "frontend01", "frontend02", "frontend03", "frontend04"; You can even B in the servernames: group "frontends" => "frontend[01..04]"; =head4 Using server.ini The same group definition can be stored in a I file: [frontends] frontend[01..04] =head3 Your tasks B desc "This is a long description of a task"; B task "shortname", group => "frontends", sub { run "uptime"; }; B task "shortname", "frontend01", "frontend02", "frontend03", "frontend04", sub { run "uptime"; }; B task "shortname", "frontend[01..04]", sub { run "uptime"; }; =cut Rex-1.3.3/MANIFEST0000644000175000017500000002405112572251052013274 0ustar jenkinsjenkins# This file was automatically generated by Dist::Zilla::Plugin::Manifest v5.032. CONTRIBUTORS ChangeLog LICENSE MANIFEST META.yml Makefile.PL README bin/rex bin/rexify dist.ini lib/Rex.pm lib/Rex/Args.pm lib/Rex/Args/Integer.pm lib/Rex/Args/Single.pm lib/Rex/Args/String.pm lib/Rex/Batch.pm lib/Rex/Box.pm lib/Rex/Box/Amazon.pm lib/Rex/Box/Base.pm lib/Rex/Box/KVM.pm lib/Rex/Box/VBox.pm lib/Rex/CLI.pm lib/Rex/CMDB.pm lib/Rex/CMDB/Base.pm lib/Rex/CMDB/YAML.pm lib/Rex/Cloud.pm lib/Rex/Cloud/Amazon.pm lib/Rex/Cloud/Base.pm lib/Rex/Cloud/Jiffybox.pm lib/Rex/Cloud/OpenStack.pm lib/Rex/Commands.pm lib/Rex/Commands/Augeas.pm lib/Rex/Commands/Box.pm lib/Rex/Commands/Cloud.pm lib/Rex/Commands/Cron.pm lib/Rex/Commands/DB.pm lib/Rex/Commands/Download.pm lib/Rex/Commands/File.pm lib/Rex/Commands/Fs.pm lib/Rex/Commands/Gather.pm lib/Rex/Commands/Host.pm lib/Rex/Commands/Inventory.pm lib/Rex/Commands/Iptables.pm lib/Rex/Commands/JobControl.pm lib/Rex/Commands/Kernel.pm lib/Rex/Commands/LVM.pm lib/Rex/Commands/MD5.pm lib/Rex/Commands/Network.pm lib/Rex/Commands/Notify.pm lib/Rex/Commands/Partition.pm lib/Rex/Commands/Pkg.pm lib/Rex/Commands/PkgConf.pm lib/Rex/Commands/Process.pm lib/Rex/Commands/Rsync.pm lib/Rex/Commands/Run.pm lib/Rex/Commands/SCM.pm lib/Rex/Commands/Service.pm lib/Rex/Commands/SimpleCheck.pm lib/Rex/Commands/Sync.pm lib/Rex/Commands/Sysctl.pm lib/Rex/Commands/Tail.pm lib/Rex/Commands/Upload.pm lib/Rex/Commands/User.pm lib/Rex/Commands/Virtualization.pm lib/Rex/Commands/templates/append_if_no_such_line.tpl.pl lib/Rex/Config.pm lib/Rex/Constants.pm lib/Rex/Cron.pm lib/Rex/Cron/Base.pm lib/Rex/Cron/Linux.pm lib/Rex/Cron/SunOS.pm lib/Rex/Exporter.pm lib/Rex/FS/File.pm lib/Rex/File/Parser/Data.pm lib/Rex/File/Parser/Ini.pm lib/Rex/Fork/Manager.pm lib/Rex/Fork/Task.pm lib/Rex/Group.pm lib/Rex/Group/Entry/Server.pm lib/Rex/Group/Lookup/Command.pm lib/Rex/Group/Lookup/DBI.pm lib/Rex/Group/Lookup/File.pm lib/Rex/Group/Lookup/INI.pm lib/Rex/Group/Lookup/XML.pm lib/Rex/Group/Lookup/YAML.pm lib/Rex/Hardware.pm lib/Rex/Hardware/Host.pm lib/Rex/Hardware/Kernel.pm lib/Rex/Hardware/Memory.pm lib/Rex/Hardware/Network.pm lib/Rex/Hardware/Network/Darwin.pm lib/Rex/Hardware/Network/FreeBSD.pm lib/Rex/Hardware/Network/Linux.pm lib/Rex/Hardware/Network/NetBSD.pm lib/Rex/Hardware/Network/OpenBSD.pm lib/Rex/Hardware/Network/Solaris.pm lib/Rex/Hardware/Swap.pm lib/Rex/Hardware/VirtInfo.pm lib/Rex/Helper/Array.pm lib/Rex/Helper/DBI.pm lib/Rex/Helper/Encode.pm lib/Rex/Helper/File/Spec.pm lib/Rex/Helper/File/Stat.pm lib/Rex/Helper/File/Stat/Unix.pm lib/Rex/Helper/File/Stat/Win32.pm lib/Rex/Helper/Hash.pm lib/Rex/Helper/INI.pm lib/Rex/Helper/Misc.pm lib/Rex/Helper/Path.pm lib/Rex/Helper/Run.pm lib/Rex/Helper/SSH2.pm lib/Rex/Helper/SSH2/Expect.pm lib/Rex/Helper/System.pm lib/Rex/Helper/URI.pm lib/Rex/Helper/UserAgent.pm lib/Rex/Hook.pm lib/Rex/Interface/Cache.pm lib/Rex/Interface/Cache/Base.pm lib/Rex/Interface/Cache/YAML.pm lib/Rex/Interface/Connection.pm lib/Rex/Interface/Connection/Base.pm lib/Rex/Interface/Connection/Fake.pm lib/Rex/Interface/Connection/HTTP.pm lib/Rex/Interface/Connection/HTTPS.pm lib/Rex/Interface/Connection/Local.pm lib/Rex/Interface/Connection/OpenSSH.pm lib/Rex/Interface/Connection/SSH.pm lib/Rex/Interface/Exec.pm lib/Rex/Interface/Exec/Base.pm lib/Rex/Interface/Exec/HTTP.pm lib/Rex/Interface/Exec/Local.pm lib/Rex/Interface/Exec/OpenSSH.pm lib/Rex/Interface/Exec/SSH.pm lib/Rex/Interface/Exec/Sudo.pm lib/Rex/Interface/Executor.pm lib/Rex/Interface/Executor/Base.pm lib/Rex/Interface/Executor/Default.pm lib/Rex/Interface/File.pm lib/Rex/Interface/File/Base.pm lib/Rex/Interface/File/HTTP.pm lib/Rex/Interface/File/Local.pm lib/Rex/Interface/File/OpenSSH.pm lib/Rex/Interface/File/SSH.pm lib/Rex/Interface/File/Sudo.pm lib/Rex/Interface/Fs.pm lib/Rex/Interface/Fs/Base.pm lib/Rex/Interface/Fs/HTTP.pm lib/Rex/Interface/Fs/Local.pm lib/Rex/Interface/Fs/OpenSSH.pm lib/Rex/Interface/Fs/SSH.pm lib/Rex/Interface/Fs/Sudo.pm lib/Rex/Interface/Shell.pm lib/Rex/Interface/Shell/Ash.pm lib/Rex/Interface/Shell/Base.pm lib/Rex/Interface/Shell/Bash.pm lib/Rex/Interface/Shell/Csh.pm lib/Rex/Interface/Shell/Default.pm lib/Rex/Interface/Shell/Idrac.pm lib/Rex/Interface/Shell/Ksh.pm lib/Rex/Interface/Shell/Sh.pm lib/Rex/Interface/Shell/Tcsh.pm lib/Rex/Interface/Shell/Zsh.pm lib/Rex/Inventory.pm lib/Rex/Inventory/Bios.pm lib/Rex/Inventory/DMIDecode.pm lib/Rex/Inventory/DMIDecode/BaseBoard.pm lib/Rex/Inventory/DMIDecode/Bios.pm lib/Rex/Inventory/DMIDecode/CPU.pm lib/Rex/Inventory/DMIDecode/Memory.pm lib/Rex/Inventory/DMIDecode/MemoryArray.pm lib/Rex/Inventory/DMIDecode/Section.pm lib/Rex/Inventory/DMIDecode/SystemInformation.pm lib/Rex/Inventory/HP/ACU.pm lib/Rex/Inventory/Hal.pm lib/Rex/Inventory/Hal/Object.pm lib/Rex/Inventory/Hal/Object/Net.pm lib/Rex/Inventory/Hal/Object/Storage.pm lib/Rex/Inventory/Hal/Object/Volume.pm lib/Rex/Inventory/Proc.pm lib/Rex/Inventory/Proc/Cpuinfo.pm lib/Rex/Inventory/SMBios.pm lib/Rex/Inventory/SMBios/BaseBoard.pm lib/Rex/Inventory/SMBios/Bios.pm lib/Rex/Inventory/SMBios/CPU.pm lib/Rex/Inventory/SMBios/Memory.pm lib/Rex/Inventory/SMBios/MemoryArray.pm lib/Rex/Inventory/SMBios/Section.pm lib/Rex/Inventory/SMBios/SystemInformation.pm lib/Rex/Logger.pm lib/Rex/Notify.pm lib/Rex/Output.pm lib/Rex/Output/Base.pm lib/Rex/Output/JUnit.pm lib/Rex/Pkg.pm lib/Rex/Pkg/ALT.pm lib/Rex/Pkg/Base.pm lib/Rex/Pkg/Debian.pm lib/Rex/Pkg/FreeBSD.pm lib/Rex/Pkg/Gentoo.pm lib/Rex/Pkg/Mageia.pm lib/Rex/Pkg/NetBSD.pm lib/Rex/Pkg/OpenBSD.pm lib/Rex/Pkg/OpenWrt.pm lib/Rex/Pkg/Redhat.pm lib/Rex/Pkg/SuSE.pm lib/Rex/Pkg/SunOS.pm lib/Rex/Pkg/SunOS/OpenCSW.pm lib/Rex/Pkg/SunOS/pkg.pm lib/Rex/Pkg/Ubuntu.pm lib/Rex/PkgConf.pm lib/Rex/PkgConf/Base.pm lib/Rex/PkgConf/Debian.pm lib/Rex/Profiler.pm lib/Rex/Report.pm lib/Rex/Report/Base.pm lib/Rex/Report/YAML.pm lib/Rex/Require.pm lib/Rex/Resource.pm lib/Rex/Resource/Common.pm lib/Rex/SCM/Git.pm lib/Rex/SCM/Subversion.pm lib/Rex/Service.pm lib/Rex/Service/ALT.pm lib/Rex/Service/ALT/systemd.pm lib/Rex/Service/Base.pm lib/Rex/Service/Debian.pm lib/Rex/Service/Debian/systemd.pm lib/Rex/Service/FreeBSD.pm lib/Rex/Service/Gentoo.pm lib/Rex/Service/Gentoo/systemd.pm lib/Rex/Service/Mageia.pm lib/Rex/Service/Mageia/systemd.pm lib/Rex/Service/NetBSD.pm lib/Rex/Service/OpenBSD.pm lib/Rex/Service/OpenWrt.pm lib/Rex/Service/Redhat.pm lib/Rex/Service/Redhat/systemd.pm lib/Rex/Service/SuSE.pm lib/Rex/Service/SuSE/systemd.pm lib/Rex/Service/SunOS.pm lib/Rex/Service/SunOS/svcadm.pm lib/Rex/Service/Ubuntu.pm lib/Rex/Shared/Var.pm lib/Rex/Shared/Var/Array.pm lib/Rex/Shared/Var/Hash.pm lib/Rex/Shared/Var/Scalar.pm lib/Rex/Sudo/File.pm lib/Rex/Task.pm lib/Rex/TaskList.pm lib/Rex/TaskList/Base.pm lib/Rex/TaskList/Parallel_ForkManager.pm lib/Rex/Template.pm lib/Rex/Template/NG.pm lib/Rex/Test.pm lib/Rex/Test/Base.pm lib/Rex/Test/Base/has_content.pm lib/Rex/Test/Base/has_dir.pm lib/Rex/Test/Base/has_file.pm lib/Rex/Test/Base/has_package.pm lib/Rex/Test/Base/has_service_running.pm lib/Rex/Test/Base/has_service_stopped.pm lib/Rex/Test/Base/has_stat.pm lib/Rex/Transaction.pm lib/Rex/User.pm lib/Rex/User/Base.pm lib/Rex/User/FreeBSD.pm lib/Rex/User/Linux.pm lib/Rex/User/NetBSD.pm lib/Rex/User/OpenBSD.pm lib/Rex/User/OpenWrt.pm lib/Rex/User/SunOS.pm lib/Rex/Value.pm lib/Rex/Virtualization.pm lib/Rex/Virtualization/Base.pm lib/Rex/Virtualization/Docker.pm lib/Rex/Virtualization/Docker/create.pm lib/Rex/Virtualization/Docker/daemon.pm lib/Rex/Virtualization/Docker/delete.pm lib/Rex/Virtualization/Docker/destroy.pm lib/Rex/Virtualization/Docker/info.pm lib/Rex/Virtualization/Docker/list.pm lib/Rex/Virtualization/Docker/reboot.pm lib/Rex/Virtualization/Docker/shutdown.pm lib/Rex/Virtualization/Docker/start.pm lib/Rex/Virtualization/LibVirt.pm lib/Rex/Virtualization/LibVirt/blklist.pm lib/Rex/Virtualization/LibVirt/clone.pm lib/Rex/Virtualization/LibVirt/create.pm lib/Rex/Virtualization/LibVirt/delete.pm lib/Rex/Virtualization/LibVirt/destroy.pm lib/Rex/Virtualization/LibVirt/dumpxml.pm lib/Rex/Virtualization/LibVirt/guestinfo.pm lib/Rex/Virtualization/LibVirt/hypervisor.pm lib/Rex/Virtualization/LibVirt/iflist.pm lib/Rex/Virtualization/LibVirt/import.pm lib/Rex/Virtualization/LibVirt/info.pm lib/Rex/Virtualization/LibVirt/list.pm lib/Rex/Virtualization/LibVirt/option.pm lib/Rex/Virtualization/LibVirt/reboot.pm lib/Rex/Virtualization/LibVirt/shutdown.pm lib/Rex/Virtualization/LibVirt/start.pm lib/Rex/Virtualization/LibVirt/status.pm lib/Rex/Virtualization/LibVirt/vncdisplay.pm lib/Rex/Virtualization/VBox.pm lib/Rex/Virtualization/VBox/bridge.pm lib/Rex/Virtualization/VBox/create.pm lib/Rex/Virtualization/VBox/delete.pm lib/Rex/Virtualization/VBox/destroy.pm lib/Rex/Virtualization/VBox/forward_port.pm lib/Rex/Virtualization/VBox/guestinfo.pm lib/Rex/Virtualization/VBox/import.pm lib/Rex/Virtualization/VBox/info.pm lib/Rex/Virtualization/VBox/list.pm lib/Rex/Virtualization/VBox/option.pm lib/Rex/Virtualization/VBox/reboot.pm lib/Rex/Virtualization/VBox/share_folder.pm lib/Rex/Virtualization/VBox/shutdown.pm lib/Rex/Virtualization/VBox/start.pm lib/Rex/Virtualization/VBox/status.pm t/0.31.t t/0.54.t t/01.t t/args.t t/auth.t t/author-critic.t t/base.t t/base_virt.t t/can_run.t t/case.t t/cmdb.t t/cmdb/default.yml t/cmdb/default/default.yml t/cmdb/default/foo.yml t/cmdb/foo.yml t/commands.t t/commands/evaluate_hostnames.t t/commands/file/test.tpl t/commands_file_template.t t/config-ssh.t t/config.t t/cron.ex t/cron.t t/db.t t/df.out1 t/df.out2 t/df.t t/dmi.fbsd.out t/dmi.linux.out t/dmi.obsd.out t/dmi.t t/env.t t/file.t t/fs.t t/fs_files.t t/group.t t/helper_hash.t t/helper_path.t t/host.t t/hosts.ex t/hosts.ex2 t/ifconfig.out1 t/ifconfig.out2 t/ifconfig.out3 t/ifconfig.out4 t/ifconfig.out5 t/ifconfig.out6 t/ifconfig.out7 t/ini.t t/interface_fs_local.t t/ip.out1 t/ip.out2 t/ip.out3 t/ip.out_centos7 t/ip.out_centos7_alias t/ip.out_issue_539 t/iptables.t t/issue_539.t t/last_command_output.t t/logger.t t/md5.t t/md5test.bin t/needs.t t/net_interface_centos7.t t/network_linux.t t/no_tty.t t/package.t t/path.t t/release-minimum-version.t t/release-pod-syntax.t t/report.t t/shared.t t/ssh_config.1 t/task.t t/task_hosts.t t/template.t t/template_ng.t t/test.ini t/test.xml t/url_encode.t t/virtualization.t t/xml.t Rex-1.3.3/t/0000755000175000017500000000000012572251052012404 5ustar jenkinsjenkinsRex-1.3.3/t/env.t0000644000175000017500000000035712572251052013366 0ustar jenkinsjenkinsuse Test::More tests => 1; use Rex::Commands::Run; $::QUIET = 1; SKIP: { skip 'Do not run tests on Windows', 1 if $^O =~ m/^MSWin/; my $s = run( "printenv REX", env => { 'REX' => 'XER' } ); like( $s, qr/XER/, "run with env" ); } Rex-1.3.3/t/ip.out_issue_5390000644000175000017500000000115112572251052015353 0ustar jenkinsjenkins1: lo: mtu 16436 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 08:00:27:4b:b8:48 brd ff:ff:ff:ff:ff:ff inet 192.168.178.81/24 brd 192.168.178.255 scope global eth0 inet 192.168.99.37/24 brd 192.168.99.255 scope global secondary eth0 inet6 fe80::a00:27ff:fe4b:b848/64 scope link valid_lft forever preferred_lft forever Rex-1.3.3/t/0.31.t0000644000175000017500000001270512572251052013157 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 139; use Rex -feature => '0.31'; delete $ENV{REX_USER}; user("root3"); password("pass3"); private_key("priv.key3"); public_key("pub.key3"); key_auth(); no warnings; is( Rex::TaskList->create()->is_default_auth(), 0, "default auth off" ); use warnings; group( "foo", "server1", "server2", "server3" ); group( "bar", "serv[01..10]" ); my @servers = Rex::Group->get_group("foo"); is( $servers[0], "server1", "get_group" ); is( $servers[2], "server3", "get_group" ); @servers = Rex::Group->get_group("bar"); @servers = $servers[0]->get_servers; is( $servers[0], "serv01", "get_group with evaluation" ); is( $servers[5], "serv06", "get_group with evaluation" ); task( "authtest1", group => "foo", sub { } ); task( "authtest2", group => "bar", sub { } ); task( "authtest3", "srv001", sub { } ); task( "authtest4", group => "latebar", sub { } ); group( "latebar", "server[01..03]" ); my $task = Rex::TaskList->create()->get_task("authtest3"); my @all_server = @{ $task->server }; for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "root3", "merge_auth - user" ); is( $auth->{password}, "pass3", "merge_auth - pass" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv" ); is( $auth->{auth_type}, "key", "merge_auth - auth" ); } pass_auth(); for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "root3", "merge_auth - user" ); is( $auth->{password}, "pass3", "merge_auth - pass" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv" ); is( $auth->{auth_type}, "pass", "merge_auth - auth" ); } auth( for => "bar", user => "jan", password => "foo" ); auth( for => "latebar", user => "jan", password => "foo" ); $task = Rex::TaskList->create()->get_task("authtest1"); @all_server = @{ $task->server }; for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "root3", "merge_auth - user" ); is( $auth->{password}, "pass3", "merge_auth - pass" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv" ); } $task = Rex::TaskList->create()->get_task("authtest2"); @all_server = @{ $task->server }; for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "jan", "merge_auth - user" ); is( $auth->{password}, "foo", "merge_auth - pass" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv" ); is( $auth->{auth_type}, "try", "merge_auth - auth_type" ); ok( !$auth->{sudo}, "merge_auth - sudo" ); } $task = Rex::TaskList->create()->get_task("authtest4"); @all_server = @{ $task->server }; for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "jan", "merge_auth - user - lategroup" ); is( $auth->{password}, "foo", "merge_auth - pass - lategroup" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub - lategroup" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv - lategroup" ); is( $auth->{auth_type}, "try", "merge_auth - auth_type - lategroup" ); ok( !$auth->{sudo}, "merge_auth - sudo - lategroup" ); } auth( for => "authtest1", user => "deploy", password => "baz", private_key => FALSE(), public_key => FALSE(), sudo => TRUE() ); $task = Rex::TaskList->create()->get_task("authtest1"); @all_server = @{ $task->server }; for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "deploy", "merge_auth - user" ); is( $auth->{password}, "baz", "merge_auth - pass" ); is( $auth->{public_key}, FALSE(), "merge_auth - pub" ); is( $auth->{private_key}, FALSE(), "merge_auth - priv" ); is( $auth->{auth_type}, "pass", "merge_auth - auth_type" ); is( $auth->{sudo}, TRUE(), "merge_auth - sudo" ); } set( "key1", "val1" ); is( get("key1"), "val1", "got value of key1" ); set( "key1", "val2" ); is( get("key1"), "val2", "got new value of key1" ); set( "key2", [qw/one two three/] ); is( get("key2")->[0], "one", "got value of first item in key2" ); is( get("key2")->[1], "two", "got value of 2nd item in key2" ); is( get("key2")->[2], "three", "got value of 3rd item in key2" ); set( "key2", [qw/four five/] ); is( get("key2")->[0], "one", "got value of first item in key2" ); is( get("key2")->[1], "two", "got value of 2nd item in key2" ); is( get("key2")->[2], "three", "got value of 3rd item in key2" ); is( get("key2")->[3], "four", "got value of NEW first item in key2" ); is( get("key2")->[4], "five", "got value of NEW 2nd item in key2" ); set( "key3", { name => 'foo', surname => 'bar' } ); is( get("key3")->{name}, "foo", "got value of name parameter in key3" ); is( get("key3")->{surname}, "bar", "got value of surname parameter in key3" ); set( "key3", { x1 => 'x', x2 => 'xx' } ); is( get("key3")->{name}, "foo", "got value of name parameter in key3" ); is( get("key3")->{surname}, "bar", "got value of surname parameter in key3" ); is( get("key3")->{x1}, "x", "got value of NEW name parameter x1 in key3" ); is( get("key3")->{x2}, "xx", "got value of NEW name parameter x2 in key3" ); Rex-1.3.3/t/cmdb.t0000644000175000017500000000464312572251052013505 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 13; use Rex::CMDB; use Rex::Commands; use Rex::Commands::File; set( cmdb => { type => "YAML", path => "t/cmdb", } ); my $ntp = get( cmdb( "ntp", "foo" ) ); ok( $ntp->[0] eq "ntp1" && $ntp->[1] eq "ntp2", "got something from default.yml" ); my $name = get( cmdb( "name", "foo" ) ); is( $name, "foo", "got name from foo.yml" ); my $dns = get( cmdb( "dns", "foo" ) ); ok( $dns->[0] eq "1.1.1.1" && $dns->[1] eq "2.2.2.2", "got dns from env/default.yml" ); my $vhost = get( cmdb( "vhost", "foo" ) ); ok( $vhost->{name} eq "foohost" && $vhost->{doc_root} eq "/var/www", "got vhost from env/foo.yml" ); $ntp = undef; $ntp = get( cmdb("ntp") ); ok( $ntp->[0] eq "ntp1" && $ntp->[1] eq "ntp2", "got something from default.yml" ); $dns = undef; $dns = get( cmdb("dns") ); ok( $dns->[0] eq "1.1.1.1" && $dns->[1] eq "2.2.2.2", "got dns from env/default.yml" ); my $all = get( cmdb( undef, "foo" ) ); is( $all->{ntp}->[0], "ntp1", "got ntp1 from cmdb - all request" ); is( $all->{dns}->[1], "2.2.2.2", "got dns2 from cmdb - all request" ); is( $all->{vhost}->{name}, "foohost", "got vhost name from cmdb - all request" ); is( $all->{name}, "foo", "got name from cmdb - all request" ); Rex::Config->set_register_cmdb_template(1); my $content = 'Hello this is <%= $::name %>'; is( template( \$content, __no_sys_info__ => 1 ), "Hello this is defaultname", "get keys from CMDB" ); is( template( \$content, { name => "baz", __no_sys_info__ => 1 } ), "Hello this is baz", "overwrite keys from CMDB" ); set( cmdb => { type => "YAML", path => "t/cmdb", merge_behavior => 'LEFT_PRECEDENT', } ); my $foo_all = get( cmdb( undef, "foo" ) ); is_deeply( $foo_all, { 'ntp' => [ 'ntp1', 'ntp2' ], 'newntp' => [ 'ntpdefaultfoo01', 'ntpdefaultfoo02', 'ntp1', 'ntp2' ], 'dns' => [ '1.1.1.1', '2.2.2.2' ], 'vhost' => { 'name' => 'foohost', 'doc_root' => '/var/www' }, 'name' => 'foo', 'vhost2' => { 'name' => 'vhost2foo', 'doc_root' => '/var/www' }, 'users' => { 'root' => { 'password' => 'proot', 'id' => '0' }, 'user02' => { 'password' => 'puser02', 'id' => '600' }, 'user01' => { 'password' => 'puser01', 'id' => '500' } } }, "DeepMerge CMDB" ); Rex-1.3.3/t/no_tty.t0000644000175000017500000000077312572251052014114 0ustar jenkinsjenkinsuse Test::More tests => 3; use Rex::Commands::Run; use Rex::Config; $::QUIET = 1; SKIP: { skip 'don\'t know how to test this right on windows', 3 if $^O =~ m/^MSWin/; Rex::Config->set_no_tty(0); my $s = run("ls -l /jllkjlkj"); like( $s, qr/No such file/, "with tty" ); Rex::Config->set_no_tty(1); $s = run("ls -l /jllkjlkj"); unlike( $s, qr/No such file/, "with no tty" ); Rex::Config->set_no_tty(0); $s = run("ls -l /jllkjlkj"); like( $s, qr/No such file/, "again with tty" ); } Rex-1.3.3/t/ifconfig.out70000644000175000017500000000067312572251052015016 0ustar jenkinsjenkinsppp0 Link encap:Point-to-Point Protocol inet addr:123.117.251.17 P-t-P:234.165.249.179 Mask:255.255.255.255 UP POINTOPOINT RUNNING NOARP MULTICAST MTU:1454 Metric:1 RX packets:4143329786 errors:0 dropped:0 overruns:0 frame:0 TX packets:754829057 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:3 RX bytes:1171440390 (1.0 GiB) TX bytes:121847007 (116.2 MiB) Rex-1.3.3/t/db.t0000644000175000017500000000523712572251052013165 0ustar jenkinsjenkinsuse strict; use warnings; BEGIN { use Test::More; use Data::Dumper; eval "use DBI; 1" or plan skip_all => "Could not load DBI module"; eval "use Rex::Commands::DB; 1" or plan skip_all => "Could not load Rex::Commands::DB module: $@"; eval "use Test::mysqld; 1" or plan skip_all => "Could not load Test::mysqld module"; } my $dbh; my $mysqld = Test::mysqld->new( my_cnf => { 'skip-networking' => '', # no TCP socket } ) or do { no warnings 'once'; plan skip_all => $Test::mysqld::errstr; }; plan tests => 38; SKIP: { $dbh = DBI->connect( $mysqld->dsn( dbname => 'test' ), ); Rex::Commands::DB->import( { dsn => $mysqld->dsn( dbname => 'test' ) } ); _test_select(); _test_insert(); _test_delete(); _test_update(); _test_batch(); } sub _test_select { _initalize_db(); my @data = db( 'select' => { fields => '*', from => 'mytest', where => 'id=2' } ); is( $data[0]->{mykey}, "second", "correct value for id 2" ); @data = db( 'select' => { fields => '*', from => 'mytest', where => 'id=5' } ); is( $data[0], undef, "no data" ) or diag Dumper \@data; _cleanup_db(); } sub _test_insert { _initalize_db(); ok( db( insert => 'mytest', { id => 5, mykey => 'fifth' } ), "INSERT" ); my @data = db( 'select' => { fields => '*', from => 'mytest', where => 'id=5' } ); is( $data[0]->{mykey}, "fifth", "inserted fifths value" ); _cleanup_db(); } sub _test_delete { _initalize_db(); ok( db( delete => 'mytest', { where => 'id = 1' } ), "deleted" ); my @data = db( 'select' => { fields => '*', from => 'mytest', where => 'id=1' } ); is( $data[0], undef, "no data returned delete ok" ); _cleanup_db(); } sub _test_update { _initalize_db(); ok( db( 'update', 'mytest' => { set => { mykey => 'new value' }, where => "id=2" } ), "updated" ); my @data = db( 'select' => { fields => '*', from => 'mytest', where => 'id=2' } ); is( $data[0]->{mykey}, "new value", "correct updated value for id 2" ); _cleanup_db(); } sub _test_batch { TODO: { _initalize_db(); _cleanup_db(); } } sub _cleanup_db { ok( $dbh->do('DROP TABLE mytest'), "table mytest deleted" ); } sub _initalize_db { ok( $dbh->do('CREATE TABLE mytest (id INT primary key, mykey varchar(64))'), "table mytest created" ); ok( $dbh->do('INSERT INTO mytest VALUES(1, "first")'), "First INSERT" ); ok( $dbh->do('INSERT INTO mytest VALUES(2, "second")'), "Second INSERT" ); ok( $dbh->do('INSERT INTO mytest VALUES(3, "third")'), "Third INSERT" ); ok( $dbh->do('INSERT INTO mytest VALUES(4, "fourth")'), "Fourth INSERT" ); } Rex-1.3.3/t/ifconfig.out20000644000175000017500000000066412572251052015011 0ustar jenkinsjenkinsvif1.0 Link encap:Ethernet HWaddr fe:ff:ff:ff:ff:ff inet6 addr: fe80::fcff:ffff:feff:ffff/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:426013098 errors:0 dropped:0 overruns:0 frame:0 TX packets:407288230 errors:0 dropped:12 overruns:0 carrier:0 collisions:0 txqueuelen:32 RX bytes:519084830261 (483.4 GiB) TX bytes:172943515025 (161.0 GiB) Rex-1.3.3/t/issue_539.t0000644000175000017500000000276312572251052014331 0ustar jenkinsjenkinsuse Test::More tests => 16; use Rex::Hardware::Network::Linux; use Rex::Helper::Hash; my @in = eval { local (@ARGV) = ("t/ip.out_issue_539"); <>; }; my $info = Rex::Hardware::Network::Linux::_parse_ip(@in); is( $info->{eth0}->{broadcast}, "192.168.178.255", "eth0 primary / broadcast" ); is( $info->{eth0}->{ip}, "192.168.178.81", "eth0 primary / ip" ); is( $info->{eth0}->{netmask}, "255.255.255.0", "eth0 primary / netmask" ); is( $info->{eth0}->{mac}, "08:00:27:4b:b8:48", "eth0 primary / mac" ); is( $info->{eth0_1}->{broadcast}, "192.168.99.255", "eth0 secondary / broadcast" ); is( $info->{eth0_1}->{ip}, "192.168.99.37", "eth0 secondary / ip" ); is( $info->{eth0_1}->{netmask}, "255.255.255.0", "eth0 secondary / netmask" ); is( $info->{eth0_1}->{mac}, "08:00:27:4b:b8:48", "eth0 secondary / mac" ); my $f = {}; hash_flatten( $info, $f, "_" ); is( $f->{eth0_mac}, "08:00:27:4b:b8:48", "eth0 primary / flatten / mac" ); is( $f->{eth0_ip}, "192.168.178.81", "eth0 primary / flatten / ip" ); is( $f->{eth0_netmask}, "255.255.255.0", "eth0 primary / flatten / netmask" ); is( $f->{eth0_broadcast}, "192.168.178.255", "eth0 primary / flatten / broadcast" ); is( $f->{eth0_1_mac}, "08:00:27:4b:b8:48", "eth0 secondary / flatten / mac" ); is( $f->{eth0_1_ip}, "192.168.99.37", "eth0 secondary / flatten / ip" ); is( $f->{eth0_1_netmask}, "255.255.255.0", "eth0 secondary / flatten / netmask" ); is( $f->{eth0_1_broadcast}, "192.168.99.255", "eth0 secondary / flatten / broadcast" ); Rex-1.3.3/t/dmi.fbsd.out0000644000175000017500000001270212572251052014625 0ustar jenkinsjenkins# dmidecode 2.10 SMBIOS 2.3 present. 20 structures occupying 896 bytes. Table at 0x000F6120. Handle 0x0000, DMI type 0, 20 bytes BIOS Information Vendor: Parallels Software International Inc. Version: 6.0.12094.676533 Release Date: 10/26/2007 Address: 0xF0000 Runtime Size: 64 kB ROM Size: 64 kB Characteristics: ISA is supported PCI is supported PNP is supported APM is supported VLB is supported Boot from CD is supported 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported Handle 0x0001, DMI type 1, 25 bytes System Information Manufacturer: Parallels Software International Inc. Product Name: Parallels Virtual Platform Version: None Serial Number: Parallels-16 BE 64 A3 DA 80 4A 1F B9 12 1A 49 1C 47 6A DA UUID: 16BE64A3-DA80-4A1F-B912-1A491C476ADA Wake-up Type: Power Switch Handle 0x0002, DMI type 2, 8 bytes Base Board Information Manufacturer: Parallels Software International Inc. Product Name: Parallels Virtual Platform Version: None Serial Number: None Handle 0x0003, DMI type 3, 18 bytes Chassis Information Manufacturer: Parallels Software International Inc. Type: Unknown Lock: Not Present Version: Serial Number: Asset Tag: Boot-up State: Safe Power Supply State: Safe Thermal State: Safe Security Status: None OEM Information: 0x00000000 Handle 0x0004, DMI type 4, 35 bytes Processor Information Socket Designation: CPU Socket #0 Type: Central Processor Family: Unknown Manufacturer: GenuineIntel ID: E5 06 01 00 FF FB EB BF Version: Not Specified Voltage: 3.3 V External Clock: 466 MHz Max Speed: 2800 MHz Current Speed: 2800 MHz Status: Populated, Enabled Upgrade: Other L1 Cache Handle: Not Provided L2 Cache Handle: Not Provided L3 Cache Handle: Not Provided Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0005, DMI type 9, 13 bytes System Slot Information Designation: ISA slot 1 Type: 16-bit ISA Current Usage: Unknown Length: Unknown Characteristics: 3.3 V is provided Handle 0x0006, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 1 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 1 Characteristics: 3.3 V is provided Handle 0x0007, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 2 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 2 Characteristics: 3.3 V is provided Handle 0x0008, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 3 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 3 Characteristics: 3.3 V is provided Handle 0x0009, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 4 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 4 Characteristics: 3.3 V is provided Handle 0x000A, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 5 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 5 Characteristics: 3.3 V is provided Handle 0x000B, DMI type 10, 8 bytes On Board Device 1 Information Type: Video Status: Disabled Description: Parallels Video Adapter On Board Device 2 Information Type: Sound Status: Disabled Description: Parallels Sound Adapter Handle 0x000C, DMI type 16, 15 bytes Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: None Maximum Capacity: 8 GB Error Information Handle: Not Provided Number Of Devices: 4 Handle 0x000D, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: 512 MB Form Factor: DIMM Set: None Locator: DIMM #0 Bank Locator: BANK #0 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x000E, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #1 Bank Locator: BANK #1 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x000F, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #2 Bank Locator: BANK #2 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0010, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #3 Bank Locator: BANK #3 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0011, DMI type 19, 15 bytes Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0001FFFFFFF Range Size: 512 MB Physical Array Handle: 0x000C Partition Width: 0 Handle 0x0012, DMI type 32, 20 bytes System Boot Information Status: No errors detected Handle 0x0013, DMI type 127, 4 bytes End Of Table Rex-1.3.3/t/interface_fs_local.t0000644000175000017500000000112712572251052016374 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 7; use Rex::Interface::Fs; my $fs = Rex::Interface::Fs->create("Local"); ok( $fs, "created fs interface object" ); my @files = $fs->ls("."); ok( grep { /^ChangeLog$/ } @files, "found ChangeLog" ); is( $fs->is_file("ChangeLog"), 1, "ChangeLog is a file" ); is( $fs->is_dir("."), 1, ". is a directory" ); $fs->mkdir("foo"); is( $fs->is_dir("foo"), 1, "mkdir" ); $fs->rmdir("foo"); is( $fs->is_dir("foo"), undef, "rmdir" ); is( $fs->stat("some_file_that_does_not_exist"), undef, "stat should return undef for non-existent files" ); Rex-1.3.3/t/helper_hash.t0000644000175000017500000000201712572251052015053 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 6; use Rex::Helper::Hash; my %h = ( name => "FooBar", age => 99, data => { foo => "bar", blah => "fasel", more => { a => "eins", b => "zwei", c => "drei", d => { germany => "Berlin", france => "Paris", }, }, emails => [ 'm@m.m', 'a@a.a', { n1 => "nested_1", n2 => "nested_2", }, [ 'eins', 'zwei', 'drei', ], ], }, blub => [qw/eins zwei drei/], ); my $nh = {}; hash_flatten( \%h, $nh, "_" ); is( $nh->{"age"}, 99, "testing flattened hash" ); is( $nh->{"data_more_d_france"}, "Paris", "testing flattened hash - nested" ); is( $nh->{"blub_0"}, "eins", "testing flattened array" ); is( $nh->{"data_emails_0"}, 'm@m.m', "testing flattened array - nested" ); is( $nh->{"data_emails_1"}, 'a@a.a', "testing flattened array - nested (2)" ); is( $nh->{"data_emails_2_n1"}, 'nested_1', "testing flattened hash nested in array" ); Rex-1.3.3/t/hosts.ex20000644000175000017500000000026212572251052014164 0ustar jenkinsjenkins127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 1.2.3.4 rexify.org Rex-1.3.3/t/ip.out10000644000175000017500000000030612572251052013625 0ustar jenkinsjenkins2: wlp2s0: mtu 1500 qdisc mq state UP qlen 1000 link/ether aa:bb:cc:dd:ee:ff brd ff:ff:ff:ff:ff:ff inet 10.20.30.40/24 brd 10.20.30.255 scope global wlp2s0 Rex-1.3.3/t/needs.t0000644000175000017500000000231212572251052013665 0ustar jenkinsjenkinspackage MyTest; use strict; use warnings; $::QUIET = 1; use Rex::Commands; desc("MyTest - Test1"); task( "test1", sub { open( my $fh, ">", "test1.txt" ); close($fh); } ); desc("MyTest - Test2"); task( "test2", sub { open( my $fh, ">", "test2.txt" ); close($fh); } ); 1; package main; use Test::More tests => 3; use Rex::Commands; desc("Test"); task( "test", sub { needs MyTest; if ( -f "test1.txt" && -f "test2.txt" ) { unlink("test1.txt"); unlink("test2.txt"); return 1; } is( 1, -1 ); } ); desc("Test 2"); task( "test2", sub { needs MyTest "test2"; if ( -f "test2.txt" ) { unlink("test2.txt"); return 1; } is( 1, -1 ); } ); desc("Test 3"); task( "test3", sub { needs("test4"); if ( -f "test4.txt" ) { unlink("test4.txt"); return 1; } is( 1, -1 ); } ); desc("Test 4"); task( "test4", sub { open( my $fh, ">", "test4.txt" ); close($fh); } ); ok( Rex::TaskList->create()->run("test"), "testing needs" ); ok( Rex::TaskList->create()->run("test2"), "testing needs" ); ok( Rex::TaskList->create()->run("test3"), "testing needs - local namespace" ); 1; Rex-1.3.3/t/release-pod-syntax.t0000644000175000017500000000045612572251052016322 0ustar jenkinsjenkins#!perl BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } # This file was automatically generated by Dist::Zilla::Plugin::PodSyntaxTests. use Test::More; use Test::Pod 1.41; all_pod_files_ok(); Rex-1.3.3/t/ip.out_centos70000644000175000017500000000136312572251052015212 0ustar jenkinsjenkins1: lo: mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 00:1c:42:fe:5a:b5 brd ff:ff:ff:ff:ff:ff inet 10.211.55.171/24 brd 10.211.55.255 scope global dynamic eth0 valid_lft 1783sec preferred_lft 1783sec inet6 fec0::fea9:21c:42ff:fefe:5ab5/64 scope site dynamic valid_lft 2591627sec preferred_lft 2591627sec inet6 fe80::21c:42ff:fefe:5ab5/64 scope link valid_lft forever preferred_lft forever Rex-1.3.3/t/report.t0000644000175000017500000000272012572251052014105 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 3; use YAML; use Rex::Commands; use Rex::Commands::File; use Rex::Commands::Fs; use Rex::Report::YAML; { no warnings 'once'; $::QUIET = 1; } if ( $^O =~ m/^MSWin/ ) { system("rd /Q /S tmp\\report"); } else { system("rm -rf tmp/report"); } my $report = Rex::Report->create; isa_ok( $report, "Rex::Report::Base", "created report class" ); mkdir "tmp"; Rex::Report->destroy; report( -on => "YAML" ); set( report_path => "tmp/report" ); my $report_num = 1; Rex::Report::YAML->set_report_name( sub { return $report_num; } ); task( "test", sub { file( "test_report.txt", content => "this is a test" ); } ); Rex::TaskList->create()->get_task("test")->run(""); my @files = list_files("tmp/report/_local_"); my $content = eval { local ( @ARGV, $/ ) = ("tmp/report/_local_/$files[0]"); <>; }; my $ref = Load($content); is( $ref->{'file[test_report.txt]'}->{changed}, 1, "a new file was created." ); $report_num += 1; Rex::TaskList->create()->get_task("test")->run(""); @files = sort { $a =~ s/\.yml//; $b =~ s/\.yml//; $a <=> $b } list_files("tmp/report/_local_/"); $content = eval { local ( @ARGV, $/ ) = ("tmp/report/_local_/$files[1].yml"); <>; }; $ref = Load($content); is( $ref->{'file[test_report.txt]'}->{changed}, 0, "the file was not changed" ); unlink "test_report.txt"; if ( $^O =~ m/^MSWin/ ) { system("rd /Q /S tmp\\report"); } else { system("rm -rf tmp/report"); } Rex-1.3.3/t/config.t0000644000175000017500000000220512572251052014035 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 9; use Rex::Config; Rex::Config->set( "test", "foobar" ); is( Rex::Config->get("test"), "foobar", "setting scalars" ); Rex::Config->set( "test_a", [qw/one two three/] ); is( Rex::Config->get("test_a")->[1], "two", "setting arrayRef" ); is_deeply( Rex::Config->get('test_a'), [qw/one two three/], "compare complete arrayRef", ); Rex::Config->set( "test_a", [qw/four/] ); ok( Rex::Config->get("test_a")->[-1] eq "four" && Rex::Config->get("test_a")->[0] eq "one", "adding more to arrayRef" ); is_deeply( Rex::Config->get('test_a'), [qw/one two three four/], "compare complete arrayRef", ); Rex::Config->set( "test_h", { name => "john" } ); is( Rex::Config->get("test_h")->{"name"}, "john", "setting hashRef" ); is_deeply( Rex::Config->get('test_h'), { name => 'john' }, 'check test_h' ); Rex::Config->set( "test_h", { surname => "doe" } ); ok( Rex::Config->get("test_h")->{"surname"} eq "doe" && Rex::Config->get("test_h")->{"name"} eq "john", "adding more to hashRef" ); is_deeply( Rex::Config->get('test_h'), { name => 'john', surname => 'doe' }, 'check test_h' ); 1; Rex-1.3.3/t/commands.t0000644000175000017500000000407612572251052014401 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 18; use Rex::Commands; delete $ENV{REX_USER}; user("test"); is( Rex::Config->get_user, "test", "setting user" ); password("test"); is( Rex::Config->get_password, "test", "setting password" ); sudo_password("test"); is( Rex::Config->get_sudo_password, "test", "setting password" ); timeout(5); is( Rex::Config->get_timeout, 5, "setting timeout" ); max_connect_retries(5); is( Rex::Config->get_max_connect_fails, 5, "setting max connect retries" ); is( length( get_random( 5, 'a' .. 'z' ) ), 5, "get random string" ); public_key("/tmp/pub.key"); is( Rex::Config->get_public_key, "/tmp/pub.key", "set public key" ); private_key("/tmp/priv.key"); is( Rex::Config->get_private_key, "/tmp/priv.key", "set private key" ); pass_auth(); ok( Rex::Config->get_password_auth, "password auth" ); parallelism(5); is( Rex::Config->get_parallelism, 5, "set parallelism" ); parallelism(1); path( "/bin", "/sbin" ); is_deeply( [ Rex::Config->get_path ], [qw!/bin /sbin!], "set path" ); set( "foo", "bar" ); is( get("foo"), "bar", "set/get" ); my @ret = Rex::Commands::evaluate_hostname("test[01..04]"); is_deeply( \@ret, [qw/test01 test02 test03 test04/], "evaluate hostname" ); @ret = Rex::Commands::evaluate_hostname("test[01..04].rexify.org"); is_deeply( \@ret, [qw/test01.rexify.org test02.rexify.org test03.rexify.org test04.rexify.org/], "evaluate hostname / with domain" ); @ret = Rex::Commands::evaluate_hostname("test[1..4]"); is_deeply( \@ret, [qw/test1 test2 test3 test4/], "evaluate hostname without zeros" ); @ret = Rex::Commands::evaluate_hostname("test[1..4].rexify.org"); is_deeply( \@ret, [qw/test1.rexify.org test2.rexify.org test3.rexify.org test4.rexify.org/], "evaluate hostname with domainname / without zero" ); @ret = Rex::Commands::evaluate_hostname("10.5.9.[8..11]"); is_deeply( \@ret, [qw/10.5.9.8 10.5.9.9 10.5.9.10 10.5.9.11/], "evaluate ip" ); @ret = Rex::Commands::evaluate_hostname("[1..3].host.domain"); is_deeply( \@ret, [qw/1.host.domain 2.host.domain 3.host.domain/], "evaluate leading range" ); Rex-1.3.3/t/cmdb/0000755000175000017500000000000012572251052013311 5ustar jenkinsjenkinsRex-1.3.3/t/cmdb/default/0000755000175000017500000000000012572251052014735 5ustar jenkinsjenkinsRex-1.3.3/t/cmdb/default/foo.yml0000644000175000017500000000017012572251052016241 0ustar jenkinsjenkinsvhost: name: foohost doc_root: /var/www vhost2: name: vhost2foo newntp: - ntpdefaultfoo01 - ntpdefaultfoo02 Rex-1.3.3/t/cmdb/default/default.yml0000644000175000017500000000025712572251052017110 0ustar jenkinsjenkinsdns: - 1.1.1.1 - 2.2.2.2 vhost2: name: defaulthost doc_root: /var/www users: user01: id: 500 password: puser01 user02: id: 600 password: puser02 Rex-1.3.3/t/cmdb/foo.yml0000644000175000017500000000001212572251052014610 0ustar jenkinsjenkinsname: foo Rex-1.3.3/t/cmdb/default.yml0000644000175000017500000000016212572251052015457 0ustar jenkinsjenkinsntp: - ntp1 - ntp2 name: defaultname newntp: - ntp1 - ntp2 users: root: id: 0 password: proot Rex-1.3.3/t/df.out10000644000175000017500000000043612572251052013612 0ustar jenkinsjenkinsFilesystem 1K-blocks Used Available Use% Mounted on /dev/mapper/vg_c6test0232-lv_root 18102140 1693244 15489344 10% / tmpfs 255160 0 255160 0% /dev/shm /dev/sda1 495844 67557 402687 15% /boot Rex-1.3.3/t/last_command_output.t0000644000175000017500000000052012572251052016647 0ustar jenkinsjenkinsuse Test::More tests => 3; use Rex::Commands; use Rex::Commands::Run; $::QUIET = 1; my $command = ( $^O =~ /MSWin/ ) ? 'dir' : 'ls -l'; run($command); my $s = last_command_output(); like( $s, qr/ChangeLog/ms ); $command .= ' t'; run($command); $s = last_command_output(); unlike( $s, qr/ChangeLog/ms ); like( $s, qr/auth\.t/ms ); Rex-1.3.3/t/task_hosts.t0000644000175000017500000000106012572251052014750 0ustar jenkinsjenkinspackage main; use Test::More tests => 2; use Rex::Commands; desc("Test"); task( "test", "server01", "server02", sub { } ); desc("Test 2"); task( "test2", "fe[01..10]", sub { } ); desc("Test 3"); task( "test3", "fe06", "server02", sub { } ); my @tasks = Rex::TaskList->create()->get_tasks_for("server01"); is_deeply( \@tasks, ["test"], "tasks has one element: 'test'" ); @tasks = Rex::TaskList->create()->get_tasks_for("fe06"); is_deeply( \@tasks, [ "test2", "test3" ], "tasks has two elements: 'test2' and 'test3'" ); Rex-1.3.3/t/test.ini0000644000175000017500000000060212572251052014062 0ustar jenkinsjenkins; my group file [frontends] fe01 fe02 fe03 fe04 fe05 # the backends [backends] be01 be02 ;be03 be04 [db] db[01..02] [cassandra] [01..02]-cassandra [voldemort] [111..133/11]-voldemort [kiokudb] [1,3,7,01]-kiokudb [riak] [1..3,5,9..21/3]-riak [redis] @backends redis01 redis02 [memcache < redis] memcache01 memcache02 user=root password=foob4r sudo=true services=apache,memcache Rex-1.3.3/t/virtualization.t0000644000175000017500000000102412572251052015652 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 3; use Rex::Commands; Rex::Commands::set( virtualization => "LibVirt" ); is( Rex::Config->get("virtualization"), "LibVirt", "set virtualization handler" ); Rex::Commands::set( virtualization => { "type" => "LibVirt", "connect" => "qemu:///system", } ); is( Rex::Config->get("virtualization")->{type}, "LibVirt", "Virtualization type with connection URI" ); is( Rex::Config->get("virtualization")->{connect}, "qemu:///system", "Virtualization URI with connection URI" ); Rex-1.3.3/t/host.t0000644000175000017500000000174512572251052013555 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 10; use Rex::Commands::Host; my @content = eval { local (@ARGV) = ("t/hosts.ex"); <>; }; my @ret = Rex::Commands::Host::_parse_hosts(@content); is( $ret[0]->{host}, "localhost", "got localhost" ); is( $ret[0]->{ip}, "127.0.0.1", "got 127.0.0.1" ); @ret = get_host( "mango", @content ); is( $ret[0]->{ip}, "192.168.2.23", "got 192.168.2.23 by alias" ); is( $ret[0]->{host}, "mango.rexify.org", "got mango.rexify.org by alias" ); @content = eval { local (@ARGV) = ("t/hosts.ex2"); <>; }; @ret = Rex::Commands::Host::_parse_hosts(@content); is( $ret[0]->{host}, "localhost", "got localhost" ); is( $ret[0]->{ip}, "127.0.0.1", "got 127.0.0.1" ); is( $ret[2]->{host}, "rexify.org", "got rexify.org" ); is( $ret[2]->{ip}, "1.2.3.4", "got 1.2.3.4" ); @ret = get_host( "rexify.org", @content ); is( $ret[0]->{ip}, "1.2.3.4", "got 1.2.3.4 from get_host" ); is( $ret[0]->{host}, "rexify.org", "got rexify.org from get_host" ); Rex-1.3.3/t/args.t0000644000175000017500000000331112572251052013523 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 13; use Rex::Args; push( @ARGV, qw(-h -g test1 -g test2 -T -dv -u user -p pass -t 5 foo --name=thename --num=5) ); Rex::Args->import( C => {}, c => {}, q => {}, Q => {}, F => {}, T => {}, h => {}, v => {}, d => {}, s => {}, S => { type => "string" }, E => { type => "string" }, o => { type => "string" }, f => { type => "string" }, M => { type => "string" }, b => { type => "string" }, e => { type => "string" }, H => { type => "string" }, u => { type => "string" }, p => { type => "string" }, P => { type => "string" }, K => { type => "string" }, G => { type => "string" }, g => { type => "string" }, t => { type => "integer" }, ); my %opts = Rex::Args->getopts; my $groups = $opts{g}; is_deeply( $groups, [qw/test1 test2/], "Got array for groups" ); ok( exists $opts{h} && $opts{h}, "single parameter" ); ok( exists $opts{T} && $opts{T}, "single parameter (2)" ); ok( exists $opts{d} && $opts{d}, "single parameter (3) (multiple)" ); ok( exists $opts{v} && $opts{v}, "single parameter (4) (multiple)" ); ok( exists $opts{u} && $opts{u} eq "user", "parameter with option (1) / string" ); ok( exists $opts{p} && $opts{p} eq "pass", "parameter with option (2) / string" ); ok( exists $opts{t} && $opts{t} == 5, "parameter with option (3) / integer" ); is( $ARGV[0], "foo", "got the taskname" ); my %params = Rex::Args->get; is( $ARGV[1], "--name=thename", "got the whole parameter (1)" ); is( $ARGV[2], "--num=5", "got the whole parameter (2)" ); ok( exists $params{name} && $params{name} eq "thename", "got task parameter (1)" ); ok( exists $params{num} && $params{num} == 5, "got task parameter (2)" ); Rex-1.3.3/t/net_interface_centos7.t0000644000175000017500000000130212572251052017035 0ustar jenkinsjenkinsuse Test::More tests => 6; use Rex::Hardware::Network::Linux; my @in = eval { local (@ARGV) = ("t/ip.out_centos7"); <>; }; my $info = Rex::Hardware::Network::Linux::_parse_ip(@in); is( $info->{lo}->{netmask}, '255.0.0.0', 'loopback netmask' ); is( $info->{lo}->{ip}, '127.0.0.1', 'loopback ip' ); is( $info->{eth0}->{ip}, '10.211.55.171', 'eth0 ip' ); is( $info->{eth0}->{netmask}, '255.255.255.0', 'eth0 netmask' ); is( $info->{eth0}->{broadcast}, '10.211.55.255', 'eth0 broadcast' ); is( $info->{eth0}->{mac}, '00:1c:42:fe:5a:b5', 'eth0 mac' ); @in = eval { local (@ARGV) = ("t/ip.out_centos7_alias"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ip(@in); 1; Rex-1.3.3/t/01.t0000644000175000017500000000061312572251052013011 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 3; use Rex::Commands; desc("Test"); task( "test", sub { return "test"; } ); is( 1, Rex::TaskList->create()->is_task("test"), "is_task" ); is( "Test", Rex::TaskList->create()->get_desc("test"), "get test task description" ); is( "test", Rex::TaskList->create()->get_task("test")->run(""), "run test task" ); 1; Rex-1.3.3/t/shared.t0000644000175000017500000000151312572251052014037 0ustar jenkinsjenkinsuse strict; use warnings; BEGIN { use Test::More tests => 8; use Rex::Shared::Var; share(qw($scalar @array %hash)); } $scalar = "scalar"; is( $scalar, "scalar", "scalar test" ); @array = qw(one two three four); is( join( "-", @array ), "one-two-three-four", "array test" ); push( @array, "five" ); is( $array[-1], "five", "array push" ); %hash = ( name => "joe", surename => "doe", multi => { key1 => "foo", arr1 => [qw/bar baz/], } ); is( $hash{name}, "joe", "hash test, key 1" ); is( $hash{surename}, "doe", "hash test, key 2" ); is( $hash{multi}->{key1}, "foo", "multidimension, key1" ); is( $hash{multi}->{arr1}->[0], "bar", "multidimension, arr1 - key0" ); is( $hash{multi}->{arr1}->[1], "baz", "multidimension, arr1 - key1" ); unlink("vars.db"); unlink("vars.db.lock"); Rex-1.3.3/t/ssh_config.10000644000175000017500000000007712572251052014614 0ustar jenkinsjenkinsHost * StrictHostKeyChecking no UserKnownHostsFile=/dev/null Rex-1.3.3/t/hosts.ex0000644000175000017500000000025512572251052014104 0ustar jenkinsjenkins# Host Database # 127.0.0.1 localhost 255.255.255.255 broadcasthost ::1 localhost 192.168.2.23 mango.rexify.org mango 192.168.2.222 syrr.rexify.org syrr Rex-1.3.3/t/cron.t0000644000175000017500000005346512572251052013547 0ustar jenkinsjenkinsuse Test::More; $^O =~ m/^MSWin/ ? plan tests => 83 : plan tests => 286; use Rex::Cron::Base; my @lines = eval { local (@ARGV) = ("t/cron.ex"); <>; }; chomp @lines; my $c = Rex::Cron::Base->new; $c->parse_cron(@lines); my @cron = $c->list; is( $cron[0]->{type}, "comment", "first line is a comment" ); is( $cron[1]->{type}, "comment", "second line is comment" ); is( $cron[1]->{line}, "# Shell variable for cron", "got the line content #2" ); is( $cron[2]->{type}, "env", "3rd line is a env variable" ); is( $cron[2]->{name}, "SHELL", "name is SHELL" ); is( $cron[2]->{value}, "/bin/bash", "value is /bin/bash" ); is( $cron[3]->{type}, "comment", "another comment" ); is( $cron[4]->{type}, "env", "another env - path" ); is( $cron[4]->{name}, "PATH", "path env" ); is( $cron[4]->{value}, "/usr/local/bin:/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/bin/X11", "path env value" ); is( $cron[5]->{type}, "env", "myvar env" ); is( $cron[5]->{name}, "MYVAR", "myvar env got name" ); is( $cron[5]->{value}, '"foo=bar"', "myvar env got value" ); is( $cron[6]->{type}, "comment", "yet another comment" ); is( $cron[7]->{type}, "comment", "yet another line comment" ); is( $cron[8]->{type}, "job", "the first job" ); is( $cron[8]->{cron}->{minute}, 5, "the first job / min" ); is( $cron[8]->{cron}->{hour}, "9-20", "the first job / hour" ); is( $cron[8]->{cron}->{day_of_month}, "*", "the first job / day" ); is( $cron[8]->{cron}->{month}, "*", "the first job / month" ); is( $cron[8]->{cron}->{day_of_week}, "*", "the first job / day_of_month of week" ); is( $cron[8]->{cron}->{command}, "/home/username/script/script1.sh > /dev/null", "the first job / cmd" ); is( $cron[9]->{type}, "job", "the 2nd job" ); is( $cron[9]->{cron}->{minute}, "*/10", "the 2nd job / min" ); is( $cron[9]->{cron}->{hour}, "*", "the 2nd job / hour" ); is( $cron[9]->{cron}->{day_of_month}, "*", "the 2nd job / day" ); is( $cron[9]->{cron}->{month}, "*", "the 2nd job / month" ); is( $cron[9]->{cron}->{day_of_week}, "*", "the 2nd job / day_of_month of week" ); is( $cron[9]->{cron}->{command}, "/usr/bin/script2.sh > /dev/null 2>&1", "the 2nd job / cmd" ); is( $cron[10]->{type}, "job", "the 3rd job" ); is( $cron[10]->{cron}->{minute}, "59", "the 3rd job / min" ); is( $cron[10]->{cron}->{hour}, "23", "the 3rd job / hour" ); is( $cron[10]->{cron}->{day_of_month}, "*", "the 3rd job / day" ); is( $cron[10]->{cron}->{month}, "*", "the 3rd job / month" ); is( $cron[10]->{cron}->{day_of_week}, "0,4", "the 3rd job / day_of_month of week" ); is( $cron[10]->{cron}->{command}, "cp /pfad/zu/datei /pfad/zur/kopie", "the 3rd job / cmd" ); is( $cron[11]->{type}, "job", "the 4th job" ); is( $cron[11]->{cron}->{minute}, "*", "the 4th job / min" ); is( $cron[11]->{cron}->{hour}, "*", "the 4th job / hour" ); is( $cron[11]->{cron}->{day_of_month}, "*", "the 4th job / day" ); is( $cron[11]->{cron}->{month}, "*", "the 4th job / month" ); is( $cron[11]->{cron}->{day_of_week}, "*", "the 4th job / day_of_month of week" ); like( $cron[11]->{cron}->{command}, qr/DISPLAY=:0 LANG=de_DE.UTF-8 zenity --info --text/i, "the 4th job / cmd" ); is( $cron[12]->{type}, "job", "the 5th job" ); is( $cron[12]->{cron}->{minute}, "0", "the 5th job / min" ); is( $cron[12]->{cron}->{hour}, "0", "the 5th job / hour" ); is( $cron[12]->{cron}->{day_of_month}, "*", "the 5th job / day" ); is( $cron[12]->{cron}->{month}, "*", "the 5th job / month" ); is( $cron[12]->{cron}->{day_of_week}, "*", "the 5th job / day_of_month of week" ); is( $cron[12]->{cron}->{command}, "backup", "the 5th job / cmd" ); is( $cron[13]->{type}, "comment", "last line is comment" ); $c->add( minute => "1", hour => "2", day_of_month => "3", month => "4", day_of_week => "5", command => "ls", ); $c->add( command => "foo", ); $c->add( hour => "5,6,7", month => "*/2", command => "bar", ); $c->add( minute => "0", hour => "0", day_of_week => "0", ); @cron = $c->list; is( $cron[14]->{type}, "job", "the 6th job" ); is( $cron[14]->{cron}->{minute}, "1", "the 6th job / min" ); is( $cron[14]->{cron}->{hour}, "2", "the 6th job / hour" ); is( $cron[14]->{cron}->{day_of_month}, "3", "the 6th job / day" ); is( $cron[14]->{cron}->{month}, "4", "the 6th job / month" ); is( $cron[14]->{cron}->{day_of_week}, "5", "the 6th job / day_of_month of week" ); is( $cron[14]->{cron}->{command}, "ls", "the 6th job / cmd" ); is( $cron[14]->{line}, "1 2 3 4 5 ls", "the 6th job / cron line" ); is( $cron[15]->{type}, "job", "the 7th job" ); is( $cron[15]->{cron}->{minute}, "*", "the 7th job / min" ); is( $cron[15]->{cron}->{hour}, "*", "the 7th job / hour" ); is( $cron[15]->{cron}->{day_of_month}, "*", "the 7th job / day" ); is( $cron[15]->{cron}->{month}, "*", "the 7th job / month" ); is( $cron[15]->{cron}->{day_of_week}, "*", "the 7th job / day_of_month of week" ); is( $cron[15]->{cron}->{command}, "foo", "the 7th job / cmd" ); is( $cron[15]->{line}, "* * * * * foo", "the 7th job / cron line" ); is( $cron[16]->{type}, "job", "the 8th job" ); is( $cron[16]->{cron}->{minute}, "*", "the 8th job / min" ); is( $cron[16]->{cron}->{hour}, "5,6,7", "the 8th job / hour" ); is( $cron[16]->{cron}->{day_of_month}, "*", "the 8th job / day" ); is( $cron[16]->{cron}->{month}, "*/2", "the 8th job / month" ); is( $cron[16]->{cron}->{day_of_week}, "*", "the 8th job / day_of_month of week" ); is( $cron[16]->{cron}->{command}, "bar", "the 8th job / cmd" ); is( $cron[16]->{line}, "* 5,6,7 * */2 * bar", "the 8th job / cron line" ); is( $cron[17]->{type}, "job", "the 9th job" ); is( $cron[17]->{cron}->{minute}, "0", "the 9th job / min" ); is( $cron[17]->{cron}->{hour}, "0", "the 9th job / hour" ); is( $cron[17]->{cron}->{day_of_month}, "*", "the 9th job / day" ); is( $cron[17]->{cron}->{month}, "*", "the 9th job / month" ); is( $cron[17]->{cron}->{day_of_week}, "0", "the 9th job / day_of_month of week" ); is( $cron[17]->{cron}->{command}, "false", "the 9th job / cmd" ); is( $cron[17]->{line}, "0 0 * * 0 false", "the 9th job / cron line" ); unless ( $^O =~ m/^MSWin/ ) { # # Write new entries and test again # my $file = $c->write_cron(); @lines = undef; @lines = eval { local (@ARGV) = ($file); <>; }; chomp @lines; unlink $file; $c = Rex::Cron::Base->new; $c->parse_cron(@lines); @cron = $c->list; is( $cron[0]->{type}, "comment", "first line is a comment" ); is( $cron[1]->{type}, "comment", "second line is comment" ); is( $cron[1]->{line}, "# Shell variable for cron", "got the line content #2" ); is( $cron[2]->{type}, "env", "3rd line is a env variable" ); is( $cron[2]->{name}, "SHELL", "name is SHELL" ); is( $cron[2]->{value}, "/bin/bash", "value is /bin/bash" ); is( $cron[3]->{type}, "comment", "another comment" ); is( $cron[4]->{type}, "env", "another env - path" ); is( $cron[4]->{name}, "PATH", "path env" ); is( $cron[4]->{value}, "/usr/local/bin:/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/bin/X11", "path env value" ); is( $cron[5]->{type}, "env", "myvar env" ); is( $cron[5]->{name}, "MYVAR", "myvar env got name" ); is( $cron[5]->{value}, '"foo=bar"', "myvar env got value" ); is( $cron[6]->{type}, "comment", "yet another comment" ); is( $cron[7]->{type}, "comment", "yet another line comment" ); is( $cron[8]->{type}, "job", "the first job" ); is( $cron[8]->{cron}->{minute}, 5, "the first job / min" ); is( $cron[8]->{cron}->{hour}, "9-20", "the first job / hour" ); is( $cron[8]->{cron}->{day_of_month}, "*", "the first job / day" ); is( $cron[8]->{cron}->{month}, "*", "the first job / month" ); is( $cron[8]->{cron}->{day_of_week}, "*", "the first job / day_of_month of week" ); is( $cron[8]->{cron}->{command}, "/home/username/script/script1.sh > /dev/null", "the first job / cmd" ); is( $cron[9]->{type}, "job", "the 2nd job" ); is( $cron[9]->{cron}->{minute}, "*/10", "the 2nd job / min" ); is( $cron[9]->{cron}->{hour}, "*", "the 2nd job / hour" ); is( $cron[9]->{cron}->{day_of_month}, "*", "the 2nd job / day" ); is( $cron[9]->{cron}->{month}, "*", "the 2nd job / month" ); is( $cron[9]->{cron}->{day_of_week}, "*", "the 2nd job / day_of_month of week" ); is( $cron[9]->{cron}->{command}, "/usr/bin/script2.sh > /dev/null 2>&1", "the 2nd job / cmd" ); is( $cron[10]->{type}, "job", "the 3rd job" ); is( $cron[10]->{cron}->{minute}, "59", "the 3rd job / min" ); is( $cron[10]->{cron}->{hour}, "23", "the 3rd job / hour" ); is( $cron[10]->{cron}->{day_of_month}, "*", "the 3rd job / day" ); is( $cron[10]->{cron}->{month}, "*", "the 3rd job / month" ); is( $cron[10]->{cron}->{day_of_week}, "0,4", "the 3rd job / day_of_month of week" ); is( $cron[10]->{cron}->{command}, "cp /pfad/zu/datei /pfad/zur/kopie", "the 3rd job / cmd" ); is( $cron[11]->{type}, "job", "the 4th job" ); is( $cron[11]->{cron}->{minute}, "*", "the 4th job / min" ); is( $cron[11]->{cron}->{hour}, "*", "the 4th job / hour" ); is( $cron[11]->{cron}->{day_of_month}, "*", "the 4th job / day" ); is( $cron[11]->{cron}->{month}, "*", "the 4th job / month" ); is( $cron[11]->{cron}->{day_of_week}, "*", "the 4th job / day_of_month of week" ); is( $cron[11]->{cron}->{command}, 'DISPLAY=:0 LANG=de_DE.UTF-8 zenity --info --text "Beispiel für das Starten eines Programmes mit GUI"', "the 4th job / cmd" ); is( $cron[12]->{type}, "job", "the 5th job" ); is( $cron[12]->{cron}->{minute}, "0", "the 5th job / min" ); is( $cron[12]->{cron}->{hour}, "0", "the 5th job / hour" ); is( $cron[12]->{cron}->{day_of_month}, "*", "the 5th job / day" ); is( $cron[12]->{cron}->{month}, "*", "the 5th job / month" ); is( $cron[12]->{cron}->{day_of_week}, "*", "the 5th job / day_of_month of week" ); is( $cron[12]->{cron}->{command}, "backup", "the 5th job / cmd" ); is( $cron[13]->{type}, "comment", "last line is comment" ); is( $cron[14]->{type}, "job", "the 6th job" ); is( $cron[14]->{cron}->{minute}, "1", "the 6th job / min" ); is( $cron[14]->{cron}->{hour}, "2", "the 6th job / hour" ); is( $cron[14]->{cron}->{day_of_month}, "3", "the 6th job / day" ); is( $cron[14]->{cron}->{month}, "4", "the 6th job / month" ); is( $cron[14]->{cron}->{day_of_week}, "5", "the 6th job / day_of_month of week" ); is( $cron[14]->{cron}->{command}, "ls", "the 6th job / cmd" ); is( $cron[14]->{line}, "1 2 3 4 5 ls", "the 6th job / cron line" ); is( $cron[15]->{type}, "job", "the 7th job" ); is( $cron[15]->{cron}->{minute}, "*", "the 7th job / min" ); is( $cron[15]->{cron}->{hour}, "*", "the 7th job / hour" ); is( $cron[15]->{cron}->{day_of_month}, "*", "the 7th job / day" ); is( $cron[15]->{cron}->{month}, "*", "the 7th job / month" ); is( $cron[15]->{cron}->{day_of_week}, "*", "the 7th job / day_of_month of week" ); is( $cron[15]->{cron}->{command}, "foo", "the 7th job / cmd" ); is( $cron[15]->{line}, "* * * * * foo", "the 7th job / cron line" ); is( $cron[16]->{type}, "job", "the 8th job" ); is( $cron[16]->{cron}->{minute}, "*", "the 8th job / min" ); is( $cron[16]->{cron}->{hour}, "5,6,7", "the 8th job / hour" ); is( $cron[16]->{cron}->{day_of_month}, "*", "the 8th job / day" ); is( $cron[16]->{cron}->{month}, "*/2", "the 8th job / month" ); is( $cron[16]->{cron}->{day_of_week}, "*", "the 8th job / day_of_month of week" ); is( $cron[16]->{cron}->{command}, "bar", "the 8th job / cmd" ); is( $cron[16]->{line}, "* 5,6,7 * */2 * bar", "the 8th job / cron line" ); is( $cron[17]->{type}, "job", "the 9th job" ); is( $cron[17]->{cron}->{minute}, "0", "the 9th job / min" ); is( $cron[17]->{cron}->{hour}, "0", "the 9th job / hour" ); is( $cron[17]->{cron}->{day_of_month}, "*", "the 9th job / day" ); is( $cron[17]->{cron}->{month}, "*", "the 9th job / month" ); is( $cron[17]->{cron}->{day_of_week}, "0", "the 9th job / day_of_month of week" ); is( $cron[17]->{cron}->{command}, "false", "the 9th job / cmd" ); is( $cron[17]->{line}, "0 0 * * 0 false", "the 9th job / cron line" ); # # Delete 2 entries # $c->delete(14); $c->delete(9); @cron = $c->list; is( $cron[0]->{type}, "comment", "first line is a comment" ); is( $cron[1]->{type}, "comment", "second line is comment" ); is( $cron[1]->{line}, "# Shell variable for cron", "got the line content #2" ); is( $cron[2]->{type}, "env", "3rd line is a env variable" ); is( $cron[2]->{name}, "SHELL", "name is SHELL" ); is( $cron[2]->{value}, "/bin/bash", "value is /bin/bash" ); is( $cron[3]->{type}, "comment", "another comment" ); is( $cron[4]->{type}, "env", "another env - path" ); is( $cron[4]->{name}, "PATH", "path env" ); is( $cron[4]->{value}, "/usr/local/bin:/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/bin/X11", "path env value" ); is( $cron[5]->{type}, "env", "myvar env" ); is( $cron[5]->{name}, "MYVAR", "myvar env got name" ); is( $cron[5]->{value}, '"foo=bar"', "myvar env got value" ); is( $cron[6]->{type}, "comment", "yet another comment" ); is( $cron[7]->{type}, "comment", "yet another line comment" ); is( $cron[8]->{type}, "job", "the first job" ); is( $cron[8]->{cron}->{minute}, 5, "the first job / min" ); is( $cron[8]->{cron}->{hour}, "9-20", "the first job / hour" ); is( $cron[8]->{cron}->{day_of_month}, "*", "the first job / day" ); is( $cron[8]->{cron}->{month}, "*", "the first job / month" ); is( $cron[8]->{cron}->{day_of_week}, "*", "the first job / day_of_month of week" ); is( $cron[8]->{cron}->{command}, "/home/username/script/script1.sh > /dev/null", "the first job / cmd" ); is( $cron[9]->{type}, "job", "the 3rd job" ); is( $cron[9]->{cron}->{minute}, "59", "the 3rd job / min" ); is( $cron[9]->{cron}->{hour}, "23", "the 3rd job / hour" ); is( $cron[9]->{cron}->{day_of_month}, "*", "the 3rd job / day" ); is( $cron[9]->{cron}->{month}, "*", "the 3rd job / month" ); is( $cron[9]->{cron}->{day_of_week}, "0,4", "the 3rd job / day_of_month of week" ); is( $cron[9]->{cron}->{command}, "cp /pfad/zu/datei /pfad/zur/kopie", "the 3rd job / cmd" ); is( $cron[10]->{type}, "job", "the 4th job" ); is( $cron[10]->{cron}->{minute}, "*", "the 4th job / min" ); is( $cron[10]->{cron}->{hour}, "*", "the 4th job / hour" ); is( $cron[10]->{cron}->{day_of_month}, "*", "the 4th job / day" ); is( $cron[10]->{cron}->{month}, "*", "the 4th job / month" ); is( $cron[10]->{cron}->{day_of_week}, "*", "the 4th job / day_of_month of week" ); is( $cron[10]->{cron}->{command}, 'DISPLAY=:0 LANG=de_DE.UTF-8 zenity --info --text "Beispiel für das Starten eines Programmes mit GUI"', "the 4th job / cmd" ); is( $cron[11]->{type}, "job", "the 5th job" ); is( $cron[11]->{cron}->{minute}, "0", "the 5th job / min" ); is( $cron[11]->{cron}->{hour}, "0", "the 5th job / hour" ); is( $cron[11]->{cron}->{day_of_month}, "*", "the 5th job / day" ); is( $cron[11]->{cron}->{month}, "*", "the 5th job / month" ); is( $cron[11]->{cron}->{day_of_week}, "*", "the 5th job / day_of_month of week" ); is( $cron[11]->{cron}->{command}, "backup", "the 5th job / cmd" ); is( $cron[12]->{type}, "comment", "last line is comment" ); is( $cron[13]->{type}, "job", "the 7th job" ); is( $cron[13]->{cron}->{minute}, "*", "the 7th job / min" ); is( $cron[13]->{cron}->{hour}, "*", "the 7th job / hour" ); is( $cron[13]->{cron}->{day_of_month}, "*", "the 7th job / day" ); is( $cron[13]->{cron}->{month}, "*", "the 7th job / month" ); is( $cron[13]->{cron}->{day_of_week}, "*", "the 7th job / day_of_month of week" ); is( $cron[13]->{cron}->{command}, "foo", "the 7th job / cmd" ); is( $cron[13]->{line}, "* * * * * foo", "the 7th job / cron line" ); is( $cron[14]->{type}, "job", "the 8th job" ); is( $cron[14]->{cron}->{minute}, "*", "the 8th job / min" ); is( $cron[14]->{cron}->{hour}, "5,6,7", "the 8th job / hour" ); is( $cron[14]->{cron}->{day_of_month}, "*", "the 8th job / day" ); is( $cron[14]->{cron}->{month}, "*/2", "the 8th job / month" ); is( $cron[14]->{cron}->{day_of_week}, "*", "the 8th job / day_of_month of week" ); is( $cron[14]->{cron}->{command}, "bar", "the 8th job / cmd" ); is( $cron[14]->{line}, "* 5,6,7 * */2 * bar", "the 8th job / cron line" ); is( $cron[15]->{type}, "job", "the 9th job" ); is( $cron[15]->{cron}->{minute}, "0", "the 9th job / min" ); is( $cron[15]->{cron}->{hour}, "0", "the 9th job / hour" ); is( $cron[15]->{cron}->{day_of_month}, "*", "the 9th job / day" ); is( $cron[15]->{cron}->{month}, "*", "the 9th job / month" ); is( $cron[15]->{cron}->{day_of_week}, "0", "the 9th job / day_of_month of week" ); is( $cron[15]->{cron}->{command}, "false", "the 9th job / cmd" ); is( $cron[15]->{line}, "0 0 * * 0 false", "the 9th job / cron line" ); $c->add_env( "FOOVAR" => "FOOVAL", ); $c->add_env( "BARVAR" => "BARVAL", ); @cron = $c->list; is( $cron[0]->{type}, "env", "1st line is now env" ); is( $cron[0]->{name}, "BARVAR", "1st line / name" ); is( $cron[0]->{value}, "BARVAL", "1st line / value" ); is( $cron[0]->{line}, 'BARVAR="BARVAL"', "1st line / value" ); is( $cron[1]->{type}, "env", "2nd line is now env" ); is( $cron[1]->{name}, "FOOVAR", "2nd line / name" ); is( $cron[1]->{value}, "FOOVAL", "2nd line / value" ); is( $cron[1]->{line}, 'FOOVAR="FOOVAL"', "2nd line / value" ); @cron = $c->list_jobs; is( $cron[0]->{minute}, 5, "the first job / min" ); is( $cron[0]->{hour}, "9-20", "the first job / hour" ); is( $cron[0]->{day_of_month}, "*", "the first job / day" ); is( $cron[0]->{month}, "*", "the first job / month" ); is( $cron[0]->{day_of_week}, "*", "the first job / day_of_month of week" ); is( $cron[0]->{command}, "/home/username/script/script1.sh > /dev/null", "the first job / cmd" ); is( $cron[1]->{minute}, "59", "the second job / min" ); is( $cron[1]->{hour}, "23", "the second job / hour" ); is( $cron[1]->{day_of_month}, "*", "the second job / day" ); is( $cron[1]->{month}, "*", "the second job / month" ); is( $cron[1]->{day_of_week}, "0,4", "the second job / day_of_month of week" ); is( $cron[1]->{command}, "cp /pfad/zu/datei /pfad/zur/kopie", "the second job / cmd" ); is( $cron[2]->{minute}, "*", "the third job / min" ); is( $cron[2]->{hour}, "*", "the third job / hour" ); is( $cron[2]->{day_of_month}, "*", "the third job / day" ); is( $cron[2]->{month}, "*", "the third job / month" ); is( $cron[2]->{day_of_week}, "*", "the third job / day_of_month of week" ); is( $cron[2]->{command}, 'DISPLAY=:0 LANG=de_DE.UTF-8 zenity --info --text "Beispiel für das Starten eines Programmes mit GUI"', "the third job / cmd" ); $c->delete_job(1); $c->delete_job(0); @cron = $c->list; is( $cron[0]->{type}, "env", "1st line is now env" ); is( $cron[0]->{name}, "BARVAR", "1st line / name" ); is( $cron[0]->{value}, "BARVAL", "1st line / value" ); is( $cron[0]->{line}, 'BARVAR="BARVAL"', "1st line / value" ); is( $cron[1]->{type}, "env", "2nd line is now env" ); is( $cron[1]->{name}, "FOOVAR", "2nd line / name" ); is( $cron[1]->{value}, "FOOVAL", "2nd line / value" ); is( $cron[1]->{line}, 'FOOVAR="FOOVAL"', "2nd line / value" ); @cron = $c->list_jobs; is( $cron[0]->{minute}, "*", "the third job / min" ); is( $cron[0]->{hour}, "*", "the third job / hour" ); is( $cron[0]->{day_of_month}, "*", "the third job / day" ); is( $cron[0]->{month}, "*", "the third job / month" ); is( $cron[0]->{day_of_week}, "*", "the third job / day_of_month of week" ); is( $cron[0]->{command}, 'DISPLAY=:0 LANG=de_DE.UTF-8 zenity --info --text "Beispiel für das Starten eines Programmes mit GUI"', "the third job / cmd" ); @cron = $c->list_envs; is( $cron[0]->{name}, "BARVAR", "1st env name" ); is( $cron[0]->{value}, "BARVAL", "1st env name" ); is( $cron[0]->{line}, 'BARVAR="BARVAL"', "1st env name" ); is( $cron[1]->{name}, "FOOVAR", "2nd env name" ); is( $cron[1]->{value}, "FOOVAL", "2nd env name" ); is( $cron[1]->{line}, 'FOOVAR="FOOVAL"', "2nd env name" ); is( $cron[2]->{name}, "SHELL", "3rd env name" ); is( $cron[2]->{value}, "/bin/bash", "3rd env name" ); is( $cron[2]->{line}, 'SHELL=/bin/bash', "3rd env name" ); $c->delete_env(1); $c->delete_env(0); @cron = $c->list_envs; is( $cron[0]->{name}, "SHELL", "3rd env name" ); is( $cron[0]->{value}, "/bin/bash", "3rd env name" ); is( $cron[0]->{line}, 'SHELL=/bin/bash', "3rd env name" ); } Rex-1.3.3/t/df.t0000644000175000017500000000555512572251052013174 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 36; use Rex::Commands::Fs; my @lines = eval { local (@ARGV) = ("t/df.out2"); <>; }; my $df = Rex::Commands::Fs::_parse_df(@lines); ok( exists $df->{tmpfs}, "found tmpfs" ); is( $df->{tmpfs}->{used_perc}, '0%', "tmpfs percent usage" ); is( $df->{tmpfs}->{free}, 255160, "tmpfs free" ); is( $df->{tmpfs}->{mounted_on}, "/dev/shm", "tmpfs mounted_on" ); is( $df->{tmpfs}->{used}, 0, "tmpfs used" ); is( $df->{tmpfs}->{size}, 255160, "tmpfs size" ); ok( exists $df->{"/dev/sda1"}, "found /dev/sda1" ); is( $df->{"/dev/sda1"}->{used_perc}, '15%', "/dev/sda1 percent usage" ); is( $df->{"/dev/sda1"}->{free}, 402687, "/dev/sda1 free" ); is( $df->{"/dev/sda1"}->{mounted_on}, "/boot", "/dev/sda1 mounted_on" ); is( $df->{"/dev/sda1"}->{used}, 67557, "/dev/sda1 used" ); is( $df->{"/dev/sda1"}->{size}, 495844, "/dev/sda1 size" ); ok( exists $df->{"/dev/sda2"}, "found /dev/sda2" ); is( $df->{"/dev/sda2"}->{used_perc}, '10%', "/dev/sda2 percent usage" ); is( $df->{"/dev/sda2"}->{free}, 15489344, "/dev/sda2 free" ); is( $df->{"/dev/sda2"}->{mounted_on}, "/", "/dev/sda2 mounted_on" ); is( $df->{"/dev/sda2"}->{used}, 1693244, "/dev/sda2 used" ); is( $df->{"/dev/sda2"}->{size}, 18102140, "/dev/sda2 size" ); @lines = (); $df = {}; @lines = eval { local (@ARGV) = ("t/df.out1"); <>; }; $df = Rex::Commands::Fs::_parse_df(@lines); ok( exists $df->{tmpfs}, "found tmpfs" ); is( $df->{tmpfs}->{used_perc}, '0%', "tmpfs percent usage" ); is( $df->{tmpfs}->{free}, 255160, "tmpfs free" ); is( $df->{tmpfs}->{mounted_on}, "/dev/shm", "tmpfs mounted_on" ); is( $df->{tmpfs}->{used}, 0, "tmpfs used" ); is( $df->{tmpfs}->{size}, 255160, "tmpfs size" ); ok( exists $df->{"/dev/sda1"}, "found /dev/sda1" ); is( $df->{"/dev/sda1"}->{used_perc}, '15%', "/dev/sda1 percent usage" ); is( $df->{"/dev/sda1"}->{free}, 402687, "/dev/sda1 free" ); is( $df->{"/dev/sda1"}->{mounted_on}, "/boot", "/dev/sda1 mounted_on" ); is( $df->{"/dev/sda1"}->{used}, 67557, "/dev/sda1 used" ); is( $df->{"/dev/sda1"}->{size}, 495844, "/dev/sda1 size" ); ok( exists $df->{"/dev/mapper/vg_c6test0232-lv_root"}, "found /dev/mapper/vg_c6test0232-lv_root" ); is( $df->{"/dev/mapper/vg_c6test0232-lv_root"}->{used_perc}, '10%', "/dev/mapper/vg_c6test0232-lv_root percent usage" ); is( $df->{"/dev/mapper/vg_c6test0232-lv_root"}->{free}, 15489344, "/dev/mapper/vg_c6test0232-lv_root free" ); is( $df->{"/dev/mapper/vg_c6test0232-lv_root"}->{mounted_on}, "/", "/dev/mapper/vg_c6test0232-lv_root mounted_on" ); is( $df->{"/dev/mapper/vg_c6test0232-lv_root"}->{used}, 1693244, "/dev/mapper/vg_c6test0232-lv_root used" ); is( $df->{"/dev/mapper/vg_c6test0232-lv_root"}->{size}, 18102140, "/dev/mapper/vg_c6test0232-lv_root size" ); Rex-1.3.3/t/0.54.t0000644000175000017500000000226712572251052013166 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 13; use Rex -feature => '0.54'; set( "key1", "val1" ); is( get("key1"), "val1", "got value of key1" ); set( "key1", "val2" ); is( get("key1"), "val2", "got new value of key1" ); set( "key2", [qw/one two three/] ); is( get("key2")->[0], "one", "got value of first item in key2" ); is( get("key2")->[1], "two", "got value of 2nd item in key2" ); is( get("key2")->[2], "three", "got value of 3rd item in key2" ); set( "key2", [qw/four five/] ); is( get("key2")->[0], "four", "got value of NEW first item in key2" ); is( get("key2")->[1], "five", "got value of NEW 2nd item in key2" ); set( "key3", { name => 'foo', surname => 'bar' } ); is( get("key3")->{name}, "foo", "got value of name parameter in key3" ); is( get("key3")->{surname}, "bar", "got value of surname parameter in key3" ); set( "key3", { x1 => 'x', x2 => 'xx' } ); is( get("key3")->{x1}, "x", "got value of NEW name parameter x1 in key3" ); is( get("key3")->{x2}, "xx", "got value of NEW name parameter x2 in key3" ); ok( !exists get("key3")->{name}, "name parameter doesn't exists anymore" ); ok( !exists get("key3")->{surname}, "surname parameter doesn't exists anymore" ); Rex-1.3.3/t/template_ng.t0000644000175000017500000000544412572251052015077 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 20; use Rex::Template::NG; use Rex::Config; my $t = Rex::Template::NG->new; my $content = 'one two three'; is( $t->parse( $content, {} ), "one two three", "just text" ); $content = '{ 1 }'; my $content_ok = '{ 1 }'; is( $t->parse( $content, {} ), $content_ok, "curly braces" ); $content = 'Hello this is <%= $::name %>'; is( $t->parse( $content, { name => "foo" } ), "Hello this is foo", "simple variable" ); $content = 'Hello this is <%=$::name%>'; is( $t->parse( $content, { name => "bar" } ), "Hello this is bar", "simple variable - no spaces around tag" ); $content = '<% if($::logged_in) { %> Logged in! <% } else { %> Logged out! <% } %>'; $content_ok = " Logged in! "; is( $t->parse( $content, { logged_in => 1 } ), $content_ok, "if condition" ); $content = 'Hello this is <%= $::name %>'; is( Rex::Config->get_template_function()->( $content, { name => "baz" } ), "Hello this is baz", "get template function" ); is( $t->parse( $content, name => "bar" ), "Hello this is bar", "simple variable without hashRef" ); $Rex::Template::BE_LOCAL = 1; $Rex::Template::BE_LOCAL = 1; $content = 'Hello this is <%= $foo %>'; is( $t->parse( $content, { foo => "baz" } ), "Hello this is baz", "local vars" ); $content = '<%= join(",", @{ $arr }) %>'; is( $t->parse( $content, { arr => [qw/one two three/] } ), "one,two,three", "local var with array" ); # # old variable style # $content = 'one two three'; is( $t->parse( $content, {} ), "one two three", "just text" ); $content = 'Hello this is <%= $::name %>'; is( $t->parse( $content, { name => "foo" } ), "Hello this is foo", "simple variable" ); $content = '<% if($::logged_in) { %> Logged in! <% } else { %> Logged out! <% } %>'; $content_ok = " Logged in! "; is( $t->parse( $content, { logged_in => 1 } ), $content_ok, "if condition" ); $content = 'Hello this is <%= $::name %>'; is( Rex::Config->get_template_function()->( $content, { name => "baz" } ), "Hello this is baz", "get template function" ); is( $t->parse( $content, name => "bar" ), "Hello this is bar", "simple variable without hashRef" ); $content = 'Hello this is <%= $::foo %> <%= $::veth1_0_ip %>'; is( $t->parse( $content, { foo => "baz", "veth1.0_ip" => "10.1.2.3" } ), "Hello this is baz 10.1.2.3", "template with invalid key name" ); my $v = { "foo" => { val => "val1", name => "foo" }, "foo_bar" => { val => "val2", name => "foo_bar" }, "k-ey" => { val => "val3", name => "k_ey" }, "veth0.1" => { val => "val4", name => "veth0_1" }, "2nd\\key" => { val => "val5", name => "2nd_key" }, }; for my $key ( keys %{$v} ) { my $var_name = Rex::Template::_normalize_var_name($key); is( $var_name, $v->{$key}->{name}, "$var_name is equal to " . $v->{$key}->{name} ); } Rex-1.3.3/t/author-critic.t0000644000175000017500000000070212572251052015345 0ustar jenkinsjenkins#!perl BEGIN { unless ($ENV{AUTHOR_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for testing by the author'); } } use strict; use warnings; use Test::More; use English qw(-no_match_vars); eval "use Test::Perl::Critic"; plan skip_all => 'Test::Perl::Critic required to criticise code' if $@; Test::Perl::Critic->import( -profile => "../../.perlcriticrc" ) if -e "../../.perlcriticrc"; all_critic_ok(); Rex-1.3.3/t/ini.t0000644000175000017500000000705212572251052013354 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 34; SKIP: { eval { require String::Escape }; skip 'Missing String::Escape for INI file support.', 34 if $@; require Rex::Group::Lookup::INI; Rex::Group::Lookup::INI->import; use Rex::Group; use Rex::Commands; no warnings 'once'; $::QUIET = 1; groups_file("t/test.ini"); my %groups = Rex::Group->get_groups; is( scalar( @{ $groups{frontends} } ), 5, "frontends 5 servers" ); is( scalar( @{ $groups{backends} } ), 3, "backends 3 servers" ); ok( grep { $_ eq "fe01" } @{ $groups{frontends} }, "got fe01" ); ok( grep { $_ eq "fe02" } @{ $groups{frontends} }, "got fe02" ); ok( grep { $_ eq "fe03" } @{ $groups{frontends} }, "got fe03" ); ok( grep { $_ eq "fe04" } @{ $groups{frontends} }, "got fe04" ); ok( grep { $_ eq "fe05" } @{ $groups{frontends} }, "got fe05" ); ok( grep { $_ eq "be01" } @{ $groups{backends} }, "got be01" ); ok( grep { $_ eq "be02" } @{ $groups{backends} }, "got be02" ); ok( grep { $_ eq "be04" } @{ $groups{backends} }, "got be04" ); ok( grep { $_ eq "db[01..02]" } @{ $groups{db} }, "got db[01..02]" ); ok( grep { $_ eq "[01..02]-cassandra" } @{ $groups{cassandra} }, "got [01..02]-cassandra]" ); ok( grep { $_ eq "[111..133/11]-voldemort" } @{ $groups{voldemort} }, "got [111..133/11]-voldemort" ); ok( grep { $_ eq "[1,3,7,01]-kiokudb" } @{ $groups{kiokudb} }, "got [1,3,7,01]-kiokudb" ); ok( grep { $_ eq "[1..3,5,9..21/3]-riak" } @{ $groups{riak} }, "got [1..3,5,9..21/3]-riak" ); ok( grep { $_ eq "redis01" } @{ $groups{redis} }, "got redis01" ); ok( grep { $_ eq "redis02" } @{ $groups{redis} }, "got redis02" ); ok( grep { $_ eq "be01" } @{ $groups{redis} }, "got be01 in redis" ); ok( grep { $_ eq "be02" } @{ $groups{redis} }, "got be01 in redis" ); ok( grep { $_ eq "be04" } @{ $groups{redis} }, "got be01 in redis" ); ok( grep { $_ eq "redis01" } @{ $groups{memcache} }, "got redis01 in memcache" ); ok( grep { $_ eq "redis02" } @{ $groups{memcache} }, "got redis02 in memcache" ); ok( grep { $_ eq "be01" } @{ $groups{memcache} }, "got be01 in redis in memcache" ); ok( grep { $_ eq "be02" } @{ $groups{memcache} }, "got be01 in redis in memcache" ); ok( grep { $_ eq "be04" } @{ $groups{memcache} }, "got be01 in redis in memcache" ); ok( grep { $_ eq "memcache01" } @{ $groups{memcache} }, "got memcache01" ); ok( grep { $_ eq "memcache02" } @{ $groups{memcache} }, "got memcache02" ); delete $ENV{REX_USER}; user("krimdomu"); password("foo"); pass_auth(); my ($server) = grep { $_ eq "memcache02" } @{ $groups{memcache} }; no_ssh( task( "mytask", $server, sub { is( connection()->server->option("services"), "apache,memcache", "got services inside task" ); } ) ); my $task = Rex::TaskList->create()->get_task("mytask"); my $auth = $task->merge_auth($server); is( $auth->{user}, "krimdomu", "got krimdomu user for memcache02" ); is( $auth->{password}, "foo", "got foo password for memcache02" ); Rex::Config->set_use_server_auth(1); $auth = $task->merge_auth($server); is( $auth->{user}, "root", "got root user for memcache02" ); is( $auth->{password}, "foob4r", "got foob4r password for memcache02" ); ok( $auth->{sudo}, "got sudo for memcache02" ); is( $server->option("services"), "apache,memcache", "got services of server" ); # don't fork the task Rex::TaskList->create()->set_in_transaction(1); Rex::Commands::do_task("mytask"); Rex::TaskList->create()->set_in_transaction(0); } Rex-1.3.3/t/ip.out_centos7_alias0000644000175000017500000000133112572251052016356 0ustar jenkinsjenkins1: lo: mtu 65536 qdisc noqueue state UNKNOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: eth0: mtu 1500 qdisc pfifo_fast state UP qlen 1000 link/ether 52:54:00:f4:0d:74 brd ff:ff:ff:ff:ff:ff inet 192.168.112.198/24 brd 192.168.112.255 scope global dynamic eth0 valid_lft 3466sec preferred_lft 3466sec inet 1.2.3.4/32 scope global eth0:1 valid_lft forever preferred_lft forever inet6 fe80::5054:ff:fef4:d74/64 scope link valid_lft forever preferred_lft forever Rex-1.3.3/t/config-ssh.t0000644000175000017500000000405112572251052014631 0ustar jenkinsjenkinsuse strict; use warnings; use File::Temp; use Test::More tests => 21; use Rex::Config; my $ssh_cfg1 = < 1 ); ok( open( my $FH1, '>', $tempdir . '/cfg1' ), 'Opened cfg1' ); print $FH1 $ssh_cfg1; ok( close($FH1), 'Closed cfg1' ); %Rex::Config::SSH_CONFIG_FOR = (); Rex::Config::read_ssh_config_file( $tempdir . '/cfg1' ); my $c = \%Rex::Config::SSH_CONFIG_FOR; is( $c->{'web'}->{'user'}, 'root' ); isnt( $c->{'web'}->{'user'}, 'root ' ); is( $c->{'web'}->{'hostname'}, '192.168.1.1' ); is( $c->{'frontend1'}->{'user'}, 'bogey' ); is( $c->{'frontend1'}->{'hostname'}, 'fe80::1' ); is( $c->{'frontend1'}->{'port'}, 35221 ); ok( open( my $FH2, '>', $tempdir . '/cfg2' ), 'Opened cfg2' ); print $FH2 $ssh_cfg2; ok( close($FH2), 'Closed cfg2' ); %Rex::Config::SSH_CONFIG_FOR = (); Rex::Config::read_ssh_config_file( $tempdir . '/cfg2' ); is( $c->{'frontend2'}->{'user'}, '123' ); is( $c->{'frontend2'}->{'hostname'}, 'this.is.a.domain.tld' ); is( $c->{'frontend2'}->{'port'}, 1005 ); is( $c->{'some'}->{'port'}, '3306' ); is( $c->{'other'}->{'port'}, '3306' ); is( $c->{'hosts'}->{'port'}, '3306' ); my @lines = eval { local (@ARGV) = ("t/ssh_config.1"); <>; }; my %data = Rex::Config::_parse_ssh_config(@lines); ok( exists $data{"*"}, "Host * exists" ); ok( exists $data{"*"}->{stricthostkeychecking}, "Host * / StrictHostKeyChecking exists" ); ok( $data{"*"}->{stricthostkeychecking} eq "no", "Host * / StrictHostKeyChecking and contains 'no'" ); ok( exists $data{"*"}->{userknownhostsfile}, "Host * / UserKnownHostsFile exists" ); ok( $data{"*"}->{userknownhostsfile} eq "/dev/null", "Host * / UserKnownHostsFile and contains '/dev/null'" ); 1; Rex-1.3.3/t/url_encode.t0000644000175000017500000000066412572251052014716 0ustar jenkinsjenkinsuse Test::More tests => 1; use Rex::Helper::Encode; my $input = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#+~*`´!\"§\$%&/()=?\\|<>,.-_'^°"; my $output = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789%23%2B%7E%2A%60%C2%B4%21%22%C2%A7%24%25%26%2F%28%29%3D%3F%5C%7C%3C%3E%2C%2E%2D_%27%5E%C2%B0"; is( Rex::Helper::Encode::url_encode($input), $output, "encode everything except a-z0-9_" ); Rex-1.3.3/t/iptables.t0000644000175000017500000000540212572251052014375 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 32; use Rex::Commands::Iptables; my @iptables_list_1 = ( "# Generated by iptables-save v1.4.12 on Fri Nov 16 22:20:13 2012", "*nat", ":PREROUTING ACCEPT [831648:47063372]", ":INPUT ACCEPT [71162:4082850]", ":OUTPUT ACCEPT [159345:9708626]", ":POSTROUTING ACCEPT [263463:17336449]", "-A PREROUTING -d 1.2.3.4/32 -p tcp -m tcp --dport 25 -j DNAT --to-destination 4.3.2.1:25", "COMMIT", "*foo", "-A syn_flood -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -m limit --limit 25/sec --limit-burst 50 -j RETURN", ); my $rules = Rex::Commands::Iptables::_iptables_list(@iptables_list_1); ok( exists $rules->{nat}, "found nat tables" ); is( $rules->{nat}->[0]->[0], "A", "first is append" ); is( $rules->{nat}->[0]->[1], "PREROUTING", "append to prerouting" ); is( $rules->{nat}->[0]->[2], "d", "should be destination" ); is( $rules->{nat}->[0]->[3], "1.2.3.4/32", "to destination 1.2.3.4" ); is( $rules->{nat}->[0]->[4], "p", "should be proto" ); is( $rules->{nat}->[0]->[5], "tcp", "tcp" ); is( $rules->{nat}->[0]->[6], "m", "in module" ); is( $rules->{nat}->[0]->[7], "tcp", "tcp" ); is( $rules->{nat}->[0]->[8], "dport", "should be destination port" ); is( $rules->{nat}->[0]->[9], "25", "dport 25" ); is( $rules->{nat}->[0]->[10], "j", "jump to" ); is( $rules->{nat}->[0]->[11], "DNAT", "dnating" ); is( $rules->{nat}->[0]->[12], "to-destination", "should be forwarded to destination" ); is( $rules->{nat}->[0]->[13], "4.3.2.1:25", "4.3.2.1:25" ); ok( exists $rules->{foo}, "found foo table" ); is( $rules->{foo}->[0]->[0], "A", "frist is append" ); is( $rules->{foo}->[0]->[1], "syn_flood", "append to sys_flood" ); is( $rules->{foo}->[0]->[2], "p", "should use protocol" ); is( $rules->{foo}->[0]->[3], "tcp", "proto tcp" ); is( $rules->{foo}->[0]->[4], "m", "in module" ); is( $rules->{foo}->[0]->[5], "tcp", "tcp module" ); is( $rules->{foo}->[0]->[6], "tcp-flags", "should match tcp flags" ); is( $rules->{foo}->[0]->[7], "FIN,SYN,RST,ACK SYN", "only these flags" ); is( $rules->{foo}->[0]->[8], "m", "should use module" ); is( $rules->{foo}->[0]->[9], "limit", "limit module" ); is( $rules->{foo}->[0]->[10], "limit", "limit the bandwidth" ); is( $rules->{foo}->[0]->[11], "25/sec", "to 25 req per second" ); is( $rules->{foo}->[0]->[12], "limit-burst", "use burst" ); is( $rules->{foo}->[0]->[13], "50", "up to 50" ); is( $rules->{foo}->[0]->[14], "j", "jump to" ); is( $rules->{foo}->[0]->[15], "RETURN", "RETURN" ); Rex-1.3.3/t/ifconfig.out40000644000175000017500000000075712572251052015016 0ustar jenkinsjenkinswlan0 Link encap:Ethernet HWaddr 8c:a9:82:b0:82:04 inet addr:10.50.20.173 Bcast:10.50.255.255 Mask:255.255.0.0 inet6 addr: fe80::8ea9:82ff:feb0:8204/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:183505 errors:0 dropped:0 overruns:0 frame:0 TX packets:76048 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:227762379 (227.7 MB) TX bytes:11297856 (11.2 MB) Rex-1.3.3/t/logger.t0000644000175000017500000000345312572251052014055 0ustar jenkinsjenkins#!/usr/bin/env perl use strict; use warnings; use Test::More tests => 8; use Rex::Helper::Path; no warnings 'once'; $::QUIET = 1; my $logfile = Rex::Helper::Path::get_tmp_file(); # log to a file ok( !-e $logfile, 'Logfile does not exist' ); Rex::Config->set_log_filename($logfile); $Rex::Logger::format = '%l - %s'; { # only info messages are logged Rex::Logger::debug('debug1'); Rex::Logger::info('info1'); my $logcheck = qq~INFO - info1\n~; my $content = _get_log(); is( $content, $logcheck, "only info messages are logged" ); } { $Rex::Logger::silent = 1; Rex::Logger::debug('debug1'); Rex::Logger::info('info1'); my $logcheck = qq~INFO - info1\n~; my $content = _get_log(); is( $content, $logcheck, "no logging added while silent" ); } { $Rex::Logger::silent = 0; $Rex::Logger::debug = 1; Rex::Logger::debug('debug1'); Rex::Logger::info('info2'); my $logcheck = qq~INFO - info1 DEBUG - debug1 INFO - info2 ~; my $content = _get_log(); is( $content, $logcheck, "all messages are logged" ); } { $Rex::Logger::format = '%D - %l - %s'; my $date_regex = '\d{4}-\d{2}-\d{2} (?:\d+:){2}\d+'; Rex::Logger::debug('debug2'); Rex::Logger::info('info3'); my $logcheck = qq~INFO - info1 DEBUG - debug1 INFO - info2 $date_regex - DEBUG - debug2 $date_regex - INFO - info3 ~; my $content = _get_log(); like( $content, qr/$logcheck/, "all messages are logged - with date" ); } Rex::Logger->shutdown; ok( -e $logfile, 'Logfile still available' ); unlink $logfile; ok( !-e $logfile, 'Logfile unlinked' ); my $masq_s = Rex::Logger::masq( "This is a password: %s", "pass" ); is( $masq_s, "This is a password: **********", "Log-Masquerading" ); sub _get_log { local $/; open my $fh, '<', $logfile or die $!; my $loglines = <$fh>; close $fh; return $loglines; } Rex-1.3.3/t/md5.t0000644000175000017500000000034612572251052013261 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 1; use Rex::Commands::MD5; my $test_file = Rex::Helper::File::Spec->catfile( 't', 'md5test.bin' ); is( md5($test_file), '93b885adfe0da089cdf634904fd59f71', 'MD5 checksum OK' ); Rex-1.3.3/t/base_virt.t0000644000175000017500000000056112572251052014551 0ustar jenkinsjenkinsuse Test::More tests => 2; use Rex::Virtualization; my $vm_obj = Rex::Virtualization->create("VBox"); ok( ref($vm_obj) eq "Rex::Virtualization::VBox", "created vm object with param" ); Rex::Config->set( virtualization => "LibVirt" ); $vm_obj = Rex::Virtualization->create(); ok( ref($vm_obj) eq "Rex::Virtualization::LibVirt", "created vm object with config" ); Rex-1.3.3/t/dmi.obsd.out0000644000175000017500000001270212572251052014636 0ustar jenkinsjenkins# dmidecode 2.10 SMBIOS 2.3 present. 20 structures occupying 896 bytes. Table at 0x000F6120. Handle 0x0000, DMI type 0, 20 bytes BIOS Information Vendor: Parallels Software International Inc. Version: 6.0.12094.676533 Release Date: 10/26/2007 Address: 0xF0000 Runtime Size: 64 kB ROM Size: 64 kB Characteristics: ISA is supported PCI is supported PNP is supported APM is supported VLB is supported Boot from CD is supported 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported Handle 0x0001, DMI type 1, 25 bytes System Information Manufacturer: Parallels Software International Inc. Product Name: Parallels Virtual Platform Version: None Serial Number: Parallels-A2 00 64 F5 C3 9B 49 34 9E B7 F5 4D 34 B7 E2 40 UUID: A20064F5-C39B-4934-9EB7-F54D34B7E240 Wake-up Type: Power Switch Handle 0x0002, DMI type 2, 8 bytes Base Board Information Manufacturer: Parallels Software International Inc. Product Name: Parallels Virtual Platform Version: None Serial Number: None Handle 0x0003, DMI type 3, 18 bytes Chassis Information Manufacturer: Parallels Software International Inc. Type: Unknown Lock: Not Present Version: Serial Number: Asset Tag: Boot-up State: Safe Power Supply State: Safe Thermal State: Safe Security Status: None OEM Information: 0x00000000 Handle 0x0004, DMI type 4, 35 bytes Processor Information Socket Designation: CPU Socket #0 Type: Central Processor Family: Unknown Manufacturer: GenuineIntel ID: E5 06 01 00 FF FB EB BF Version: Not Specified Voltage: 3.3 V External Clock: 466 MHz Max Speed: 2800 MHz Current Speed: 2800 MHz Status: Populated, Enabled Upgrade: Other L1 Cache Handle: Not Provided L2 Cache Handle: Not Provided L3 Cache Handle: Not Provided Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0005, DMI type 9, 13 bytes System Slot Information Designation: ISA slot 1 Type: 16-bit ISA Current Usage: Unknown Length: Unknown Characteristics: 3.3 V is provided Handle 0x0006, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 1 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 1 Characteristics: 3.3 V is provided Handle 0x0007, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 2 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 2 Characteristics: 3.3 V is provided Handle 0x0008, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 3 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 3 Characteristics: 3.3 V is provided Handle 0x0009, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 4 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 4 Characteristics: 3.3 V is provided Handle 0x000A, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 5 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 5 Characteristics: 3.3 V is provided Handle 0x000B, DMI type 10, 8 bytes On Board Device 1 Information Type: Video Status: Disabled Description: Parallels Video Adapter On Board Device 2 Information Type: Sound Status: Disabled Description: Parallels Sound Adapter Handle 0x000C, DMI type 16, 15 bytes Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: None Maximum Capacity: 8 GB Error Information Handle: Not Provided Number Of Devices: 4 Handle 0x000D, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: 512 MB Form Factor: DIMM Set: None Locator: DIMM #0 Bank Locator: BANK #0 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x000E, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #1 Bank Locator: BANK #1 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x000F, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #2 Bank Locator: BANK #2 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0010, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #3 Bank Locator: BANK #3 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0011, DMI type 19, 15 bytes Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0001FFFFFFF Range Size: 512 MB Physical Array Handle: 0x000C Partition Width: 0 Handle 0x0012, DMI type 32, 20 bytes System Boot Information Status: No errors detected Handle 0x0013, DMI type 127, 4 bytes End Of Table Rex-1.3.3/t/group.t0000644000175000017500000000341712572251052013732 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 95; use Rex -feature => '0.31'; delete $ENV{REX_USER}; user("root3"); password("pass3"); private_key("priv.key3"); public_key("pub.key3"); no warnings; $::FORCE_SERVER = "server1 foo[01..10]"; use warnings; group( "forcetest1", "bla1", "blah2", "bla1" ); task( "tasktest3", "group", "forcetest1", sub { } ); my @servers = Rex::Group->get_group("forcetest1"); is( $servers[0], "bla1", "forceserver - 1" ); ok( !defined $servers[2], "group - servername uniq" ); my $task = Rex::TaskList->create()->get_task("tasktest3"); my @all_server = @{ $task->server }; is( $all_server[0], "server1", "forceserver - task - 0" ); is( $all_server[1], "foo01", "forceserver - task - 1" ); is( $all_server[5], "foo05", "forceserver - task - 5" ); is( $all_server[10], "foo10", "forceserver - task - 10" ); for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "root3", "merge_auth - user" ); is( $auth->{password}, "pass3", "merge_auth - pass" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv" ); } auth( for => "tasktest3", user => "jan", password => "foo" ); for my $server (@all_server) { my $auth = $task->merge_auth($server); is( $auth->{user}, "jan", "merge_auth - user" ); is( $auth->{password}, "foo", "merge_auth - pass" ); is( $auth->{public_key}, "pub.key3", "merge_auth - pub" ); is( $auth->{private_key}, "priv.key3", "merge_auth - priv" ); } group( "duplicated_by_list", "s[1..3,2..4]" ); my @cleaned_servers = Rex::Group->get_group("duplicated_by_list"); is_deeply [ $cleaned_servers[0]->get_servers ], [ qw/ s1 s2 s3 s4 / ], "duplicated_by_list"; Rex-1.3.3/t/base.t0000644000175000017500000000121312572251052013500 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More; use Test::UseAllModules; BEGIN { all_uses_ok except => qw( Rex::Cloud::Amazon Rex::Commands::DB Rex::Commands::Rsync Rex::Group::Lookup::DBI Rex::Group::Lookup::INI Rex::Group::Lookup::XML Rex::Helper::DBI Rex::Helper::INI Rex::Interface::Connection::OpenSSH Rex::Interface::Connection::SSH Rex::Interface::Exec::OpenSSH Rex::Interface::Exec::SSH Rex::Interface::File::OpenSSH Rex::Interface::File::SSH Rex::Interface::Fs::OpenSSH Rex::Interface::Fs::SSH Rex::Output Rex::Output::JUnit Rex::TaskList::Parallel_ForkManager ); } Rex-1.3.3/t/case.t0000644000175000017500000000203012572251052013477 0ustar jenkinsjenkinsuse Test::More tests => 7; use Rex::Commands; my $test = "Debian"; my $var = case $test, { Debian => "foo", default => "bar", }; is( $var, "foo", "string equality" ); $var = case $test, { qr{debian}i => "baz", default => "this is bad", }; is( $var, "baz", "regexp match" ); $var = case $test, { debian => "some", default => "this is good", }; is( $var, "this is good", "return default" ); $var = case $test, { debian => "tata", }; ok( !$var, "var is undef" ); $var = case $test, { Debian => sub { return "this is debian"; }, default => sub { return "default"; } }; is( $var, "this is debian", "use a sub - string match" ); $var = undef; $var = case $test, { qr{debian}i => sub { return "this is debian"; }, default => sub { return "default"; } }; is( $var, "this is debian", "use a sub - regexp match" ); $var = undef; $var = case $test, { debian => sub { return "this is debian"; }, default => sub { return "default"; } }; is( $var, "default", "use a sub - return default" ); Rex-1.3.3/t/helper_path.t0000644000175000017500000000373512572251052015074 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 8; use File::Basename; use Cwd 'getcwd'; use Rex::Helper::Path; my $rexfile = "Rexfile"; my $file = Rex::Helper::File::Spec->join( "files", "foo.txt" ); my $path = Rex::Helper::Path::get_file_path( $file, "main", $rexfile ); my $expected = $file; is( $path, $expected, "got file path if called from Rexfile" ); my $cwd = getcwd; $file = Rex::Helper::File::Spec->join( $cwd, "ChangeLog" ); $path = Rex::Helper::Path::get_file_path( $file, "main", $rexfile ); $expected = $file; is( $path, $file, "got file path if called from Rexfile - absolute path" ); $rexfile = Rex::Helper::File::Spec->join( "this", "is", "Rexfile" ); $file = Rex::Helper::File::Spec->join( "files", "foo.txt" ); $path = Rex::Helper::Path::get_file_path( $file, "main", $rexfile ); $expected = Rex::Helper::File::Spec->join( "this", "is", "files", "foo.txt" ); is( $path, $expected, "got file path if called Rexfile from other directory" ); $rexfile = Rex::Helper::File::Spec->join( Rex::Helper::File::Spec->rootdir(), "this", "is", "Rexfile" ); $file = Rex::Helper::File::Spec->join( "files", "foo.txt" ); $path = Rex::Helper::Path::get_file_path( $file, "main", $rexfile ); $expected = Rex::Helper::File::Spec->join( Rex::Helper::File::Spec->rootdir(), "this", "is", "files", "foo.txt" ); is( $path, $expected, "got file path if called Rexfile from other directory (absolute)" ); my $module_path = Rex::Helper::File::Spec->join( "lib", "File", "Foo", "__module__.pm" ); $path = Rex::Helper::Path::get_file_path( $file, "File::Foo", $module_path ); $expected = Rex::Helper::File::Spec->join( "lib", "File", "Foo", "files", "foo.txt" ); is( $path, $expected, "got file path for File::Foo module" ); $path = Rex::Helper::Path::get_tmp_file(); my ( $filename, $directory, $suffix ) = fileparse( $path, '.tmp' ); ok( defined $filename, 'Got temp filename' ); is( $suffix, '.tmp', 'Got filename with .tmp suffix' ); ok( defined $directory, 'Got temp directory' ); Rex-1.3.3/t/ifconfig.out60000644000175000017500000000251412572251052015011 0ustar jenkinsjenkinseth0: flags=4163 mtu 1500 inet 192.168.112.182 netmask 255.255.255.0 broadcast 192.168.112.255 inet6 fe80::5054:ff:fe37:a8e1 prefixlen 64 scopeid 0x20 ether 52:54:00:37:a8:e1 txqueuelen 1000 (Ethernet) RX packets 18300 bytes 94489008 (90.1 MiB) RX errors 0 dropped 3 overruns 0 frame 0 TX packets 14582 bytes 1308678 (1.2 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 eth0:1: flags=4163 mtu 1500 inet 1.2.3.4 netmask 255.255.0.0 broadcast 1.2.255.255 inet6 fe80::5054:ff:fe37:a8e1 prefixlen 64 scopeid 0x20 ether 52:54:00:37:a8:e1 txqueuelen 1000 (Ethernet) RX packets 18300 bytes 94489008 (90.1 MiB) RX errors 0 dropped 3 overruns 0 frame 0 TX packets 14582 bytes 1308678 (1.2 MiB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 lo: flags=73 mtu 65536 inet 127.0.0.1 netmask 255.0.0.0 inet6 ::1 prefixlen 128 scopeid 0x10 loop txqueuelen 0 (Lokale Schleife) RX packets 0 bytes 0 (0.0 B) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 0 bytes 0 (0.0 B) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 Rex-1.3.3/t/auth.t0000644000175000017500000000667612572251052013551 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 48; use Rex::Commands; use Rex::Group; { no warnings 'once'; $::QUIET = 1; } group( "srvgr1", "srv1" ); group( "srvgr2", "srv2", "srv3" ); delete $ENV{REX_USER}; user("root1"); password("pass1"); private_key("priv.key1"); public_key("pub.key1"); task( "testa1", sub { } ); user("root2"); password("pass2"); private_key("priv.key2"); public_key("pub.key2"); auth( for => "srvgr1", user => "foouser", password => "foopass", private_key => "foo.priv", public_key => "foo.pub" ); task( "testb1", group => "srvgr1", sub { } ); task( "testb2", group => "srvgr2", sub { } ); task( "testb3", group => [ "srvgr1", "srvgr2" ], sub { } ); task( "testa2", sub { } ); user("root3"); password("pass3"); private_key("priv.key3"); public_key("pub.key3"); task( "testa3", sub { } ); my $auth = Rex::TaskList->create()->get_task("testa1")->{auth}; is( $auth->{user}, "root1" ); is( $auth->{password}, "pass1" ); is( $auth->{private_key}, "priv.key1" ); is( $auth->{public_key}, "pub.key1" ); $auth = Rex::TaskList->create()->get_task("testa2")->{auth}; is( $auth->{user}, "root2" ); is( $auth->{password}, "pass2" ); is( $auth->{private_key}, "priv.key2" ); is( $auth->{public_key}, "pub.key2" ); $auth = Rex::TaskList->create()->get_task("testa3")->{auth}; is( $auth->{user}, "root3" ); is( $auth->{password}, "pass3" ); is( $auth->{private_key}, "priv.key3" ); is( $auth->{public_key}, "pub.key3" ); my $task_b1 = Rex::TaskList->create()->get_task("testb1"); $auth = $task_b1->{auth}; is( $auth->{user}, "root2" ); is( $auth->{password}, "pass2" ); is( $auth->{private_key}, "priv.key2" ); is( $auth->{public_key}, "pub.key2" ); my $servers = $task_b1->server; for my $server ( @{$servers} ) { $auth = $task_b1->merge_auth($server); is( $auth->{user}, "root2" ); is( $auth->{password}, "pass2" ); is( $auth->{private_key}, "priv.key2" ); is( $auth->{public_key}, "pub.key2" ); } my $task_b2 = Rex::TaskList->create()->get_task("testb2"); $servers = $task_b2->server; for my $server ( @{$servers} ) { $auth = $task_b2->merge_auth($server); is( $auth->{user}, "root2" ); is( $auth->{password}, "pass2" ); is( $auth->{private_key}, "priv.key2" ); is( $auth->{public_key}, "pub.key2" ); } my $task_b3 = Rex::TaskList->create()->get_task("testb3"); $servers = $task_b3->server; for my $server ( @{$servers} ) { $auth = $task_b3->merge_auth($server); is( $auth->{user}, "root2" ); is( $auth->{password}, "pass2" ); is( $auth->{private_key}, "priv.key2" ); is( $auth->{public_key}, "pub.key2" ); } auth( for => "testa4", user => "baruser", password => "barpass", private_key => "testa4.priv", public_key => "testa4.pub" ); task( "testa4", sub { } ); $auth = Rex::TaskList->create()->get_task("testa4")->{auth}; is( $auth->{user}, "baruser" ); is( $auth->{password}, "barpass" ); is( $auth->{private_key}, "testa4.priv" ); is( $auth->{public_key}, "testa4.pub" ); $ENV{REX_USER} = "root5"; user("toor5"); password("pass5"); private_key("testa5.priv"); public_key("testa5.pub"); task( "testa5", sub { } ); $auth = Rex::TaskList->create()->get_task("testa5")->{auth}; is( $auth->{user}, "root5" ); is( $auth->{password}, "pass5" ); is( $auth->{private_key}, "testa5.priv" ); is( $auth->{public_key}, "testa5.pub" ); Rex-1.3.3/t/network_linux.t0000644000175000017500000001004212572251052015476 0ustar jenkinsjenkinsuse Test::More tests => 44; use Rex::Hardware::Network::Linux; use Rex::Helper::Hash; my @in = eval { local (@ARGV) = ("t/ifconfig.out1"); <>; }; my $info = Rex::Hardware::Network::Linux::_parse_ifconfig(@in); is( $info->{eth0}->{broadcast}, "10.18.1.255", "ex1 / broadcast" ); is( $info->{eth0}->{ip}, "10.18.1.107", "ex1 / ip" ); is( $info->{eth0}->{netmask}, "255.255.255.0", "ex1 / netmask" ); is( $info->{eth0}->{mac}, "00:16:3e:7f:fc:3a", "ex1 / mac" ); my $f = {}; hash_flatten( $info, $f, "_" ); is( $f->{eth0_mac}, "00:16:3e:7f:fc:3a", "ex1 / flatten / mac" ); is( $f->{eth0_ip}, "10.18.1.107", "ex1 / flatten / ip" ); is( $f->{eth0_netmask}, "255.255.255.0", "ex1 / flatten / netmask" ); is( $f->{eth0_broadcast}, "10.18.1.255", "ex1 / flatten / broadcast" ); @in = eval { local (@ARGV) = ("t/ifconfig.out2"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ifconfig(@in); ok( !$info->{"vif1.0"}->{broadcast}, "ex2 / broadcast" ); ok( !$info->{"vif1.0"}->{ip}, "ex2 / ip" ); ok( !$info->{"vif1.0"}->{netmask}, "ex2 / netmask" ); is( $info->{"vif1.0"}->{mac}, "fe:ff:ff:ff:ff:ff", "ex2 / mac" ); $f = {}; hash_flatten( $info, $f, "_" ); is( $f->{"vif1_0_mac"}, "fe:ff:ff:ff:ff:ff", "ex2 / flatten / mac" ); ok( !$f->{"vif1_0_ip"}, "ex2 / flatten / ip" ); ok( !$f->{"vif1_0_netmask"}, "ex2 / flatten / netmask" ); ok( !$f->{"vif1_0_broadcast"}, "ex2 / flatten / broadcast" ); @in = eval { local (@ARGV) = ("t/ip.out1"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ip(@in); is( $info->{wlp2s0}->{ip}, "10.20.30.40", "ip / ip" ); is( $info->{wlp2s0}->{netmask}, "255.255.255.0", "ip / netmask" ); is( $info->{wlp2s0}->{broadcast}, "10.20.30.255", "ip / broadcast" ); is( $info->{wlp2s0}->{mac}, "aa:bb:cc:dd:ee:ff", "ip / mac" ); $f = {}; hash_flatten( $info, $f, "_" ); is( $f->{"wlp2s0_mac"}, "aa:bb:cc:dd:ee:ff", "ip / flatten / mac" ); is( $f->{"wlp2s0_ip"}, "10.20.30.40", "ip / flatten / ip" ); is( $f->{"wlp2s0_netmask"}, "255.255.255.0", "ip / flatten / netmask" ); is( $f->{"wlp2s0_broadcast"}, "10.20.30.255", "ip / flatten / broadcast" ); $info = {}; @in = eval { local (@ARGV) = ("t/ip.out2"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ip(@in); is( $info->{eth1}->{ip}, "", "ip / ip" ); is( $info->{eth1}->{netmask}, "", "ip / netmask" ); is( $info->{eth1}->{broadcast}, "", "ip / broadcast" ); is( $info->{eth1}->{mac}, "00:1c:42:73:ad:3c", "ip / mac" ); @in = eval { local (@ARGV) = ("t/ifconfig.out6"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ifconfig(@in); is( $info->{eth0}->{broadcast}, "192.168.112.255", "(fc19) eth0 / broadcast" ); is( $info->{eth0}->{ip}, "192.168.112.182", "(fc19) eth0 / ip" ); is( $info->{eth0}->{netmask}, "255.255.255.0", "(fc19) eth0 / netmask" ); is( $info->{eth0}->{mac}, "52:54:00:37:a8:e1", "(fc19) eth0 / mac" ); is( $info->{"eth0:1"}->{broadcast}, "1.2.255.255", "(fc19) eth0:1 / broadcast" ); is( $info->{"eth0:1"}->{ip}, "1.2.3.4", "(fc19) eth0:1 / ip" ); is( $info->{"eth0:1"}->{netmask}, "255.255.0.0", "(fc19) eth0:1 / netmask" ); is( $info->{"eth0:1"}->{mac}, "52:54:00:37:a8:e1", "(fc19) eth0:1 / mac" ); @in = eval { local (@ARGV) = ("t/ifconfig.out7"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ifconfig(@in); is( $info->{ppp0}->{ip}, "123.117.251.17", "ppp0 / ip" ); is( $info->{ppp0}->{netmask}, "255.255.255.255", "ppp0 / netmask" ); is( $info->{ppp0}->{broadcast}, "", "ppp0 / broadcast" ); is( $info->{ppp0}->{mac}, "", "ppp0 / mac" ); @in = eval { local (@ARGV) = ("t/ip.out3"); <>; }; $info = Rex::Hardware::Network::Linux::_parse_ip(@in); is( $info->{ppp0}->{ip}, "123.117.251.17", "ppp0 / ip" ); is( $info->{ppp0}->{netmask}, "255.255.255.255", "ppp0 / netmask" ); is( $info->{ppp0}->{broadcast}, "", "ppp0 / broadcast" ); is( $info->{ppp0}->{mac}, "", "ppp0 / mac" ); Rex-1.3.3/t/can_run.t0000644000175000017500000000154012572251052014216 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 4; use Rex::Commands::Run; { my $command_to_check = $^O =~ /^MSWin/ ? 'where' : 'which'; my $result = can_run($command_to_check); ok( $result, 'Found checker command' ); } { my $command_to_check = "I'm pretty sure this command doesn't exist anywhere"; my $result = can_run($command_to_check); ok( !$result, 'Non-existing command not found' ); } { my @commands_to_check = $^O =~ /^MSWin/ ? 'where' : 'which'; push @commands_to_check, 'non-existing command'; my $result = can_run(@commands_to_check); ok( $result, 'Multiple commands - existing first' ); } { my @commands_to_check = $^O =~ /^MSWin/ ? 'where' : 'which'; unshift @commands_to_check, 'non-existing command'; my $result = can_run(@commands_to_check); ok( $result, 'Multiple commands - non-existing first' ); } Rex-1.3.3/t/fs_files.t0000644000175000017500000000602212572251052014363 0ustar jenkinsjenkins#!/usr/bin/env perl use strict; use warnings; use Test::More tests => 13; use Rex::Helper::Path; use Rex::Commands::File; my @lines = ( "first line", "second line", "test" ); my $filename = Rex::Helper::Path::get_tmp_file(); file( $filename, content => join "\n", @lines ); ok -e $filename, 'file was created'; { # standard Rex::FS::File usage - read file my $fh = Rex::Interface::File->create('Local'); $fh->open( '<', $filename ); my $file_object = Rex::FS::File->new( fh => $fh ); isa_ok $file_object, 'Rex::FS::File', 'new with fh was successful'; my @read_lines = $file_object->read_all; is_deeply \@read_lines, \@lines, 'read lines from fh'; } { # standard Rex::FS::File usage - write file my $fh = Rex::Interface::File->create('Local'); $fh->open( '>', $filename ); my $file_object = Rex::FS::File->new( fh => $fh ); isa_ok $file_object, 'Rex::FS::File', 'new with fh (write mode) was successful'; $file_object->write(qw/this is a test/); $file_object->close; my $read_fh = Rex::Interface::File->create('Local'); $read_fh->open( '<', $filename ); my $read_object = Rex::FS::File->new( fh => $read_fh ); my @read_lines = $read_object->read_all; is_deeply \@read_lines, [qw/this is a test/], 'read lines from fh'; } { # new Rex::FS::File usage - read file file( $filename, content => join "\n", @lines ); my $file_object = Rex::FS::File->new( filename => $filename ); isa_ok $file_object, 'Rex::FS::File', 'new with filename was successful'; my @read_lines = $file_object->read_all; is_deeply \@read_lines, \@lines, 'read lines from filename'; } { # new Rex::FS::File usage - write file my $file_object = Rex::FS::File->new( filename => $filename, mode => '>' ); isa_ok $file_object, 'Rex::FS::File', 'new with filename with mode ">" was successful'; $file_object->write(qw/this is a test/); $file_object->close; my $read_fh = Rex::Interface::File->create('Local'); $read_fh->open( '<', $filename ); my $read_object = Rex::FS::File->new( fh => $read_fh ); my @read_lines = $read_object->read_all; is_deeply \@read_lines, [qw/this is a test/], 'read lines from fh'; } { # new Rex::FS::File usage - read file - explicit read mode file( $filename, content => join "\n", @lines ); my $file_object = Rex::FS::File->new( filename => $filename, mode => '<' ); isa_ok $file_object, 'Rex::FS::File', 'new with filename and explicit read mode was successful'; my @read_lines = $file_object->read_all; is_deeply \@read_lines, \@lines, 'read lines from filename (explicit read mode)'; } { # new Rex::FS::File usage - write file - mode "w" my $file_object = Rex::FS::File->new( filename => $filename, mode => 'w' ); isa_ok $file_object, 'Rex::FS::File', 'new with filename with mode "w" was successful'; $file_object->write(qw/this is a test/); $file_object->close; my $read_object = Rex::FS::File->new( filename => $filename, mode => 'r' ); my @read_lines = $read_object->read_all; is_deeply \@read_lines, [qw/this is a test/], 'read lines from fh'; } Rex-1.3.3/t/release-minimum-version.t0000644000175000017500000000052412572251052017346 0ustar jenkinsjenkins#!perl BEGIN { unless ($ENV{RELEASE_TESTING}) { require Test::More; Test::More::plan(skip_all => 'these tests are for release candidate testing'); } } use Test::More; eval "use Test::MinimumVersion"; plan skip_all => "Test::MinimumVersion required for testing minimum versions" if $@; all_minimum_version_ok( qq{5.8.8} ); Rex-1.3.3/t/dmi.t0000644000175000017500000001052412572251052013344 0ustar jenkinsjenkinsuse Test::More tests => 30; use Rex::Inventory::DMIDecode; my @lines = eval { local (@ARGV) = ("t/dmi.linux.out"); <>; }; my $dmi = Rex::Inventory::DMIDecode->new( lines => \@lines ); isa_ok( $dmi, "Rex::Inventory::DMIDecode", "dmi object" ); my $bb = $dmi->get_base_board; my $bios = $dmi->get_bios; my @cpus = $dmi->get_cpus; my @mems = $dmi->get_memory_modules; my @mema = $dmi->get_memory_arrays; my $sysinfo = $dmi->get_system_information; is( $bb->get_product_name, "Parallels Virtual Platform", "get base board product name" ); is( $bios->get_vendor, "Parallels Software International Inc.", "get bios vendor" ); like( $bios->get_version, qr/\d\.0\./, "get bios version" ); is( $bios->get_release_date, "10/26/2007" ); ok( $cpus[0]->get_max_speed eq "2800 MHz" || $cpus[0]->get_max_speed eq "30000 MHz" || $cpus[0]->get_max_speed eq "2800MHz", "cpu get max speed" ); ok( $mems[0]->get_size eq "512 MB" || $mems[0]->get_size eq "1073741824 bytes", "memory size" ); ok( $mema[0]->get_maximum_capacity eq "8 GB" || $mema[0]->get_maximum_capacity eq "256 GB" || $mema[0]->get_maximum_capacity eq "8589934592 bytes", "memory array max capacity" ); is( $sysinfo->get_manufacturer, "Parallels Software International Inc.", "system information manucafturer" ); is( $sysinfo->get_product_name, "Parallels Virtual Platform", "system information product name" ); @lines = undef; $dmi = undef; $bb = undef; $bios = undef; @cpus = undef; @mems = undef; @mema = undef; $sysinfo = undef; @lines = eval { local (@ARGV) = ("t/dmi.obsd.out"); <>; }; $dmi = Rex::Inventory::DMIDecode->new( lines => \@lines ); isa_ok( $dmi, "Rex::Inventory::DMIDecode", "dmi object (obsd)" ); $bb = $dmi->get_base_board; $bios = $dmi->get_bios; @cpus = $dmi->get_cpus; @mems = $dmi->get_memory_modules; @mema = $dmi->get_memory_arrays; $sysinfo = $dmi->get_system_information; is( $bb->get_product_name, "Parallels Virtual Platform", "get base board product name" ); is( $bios->get_vendor, "Parallels Software International Inc.", "get bios vendor" ); like( $bios->get_version, qr/\d\.0\./, "get bios version" ); is( $bios->get_release_date, "10/26/2007" ); ok( $cpus[0]->get_max_speed eq "2800 MHz" || $cpus[0]->get_max_speed eq "30000 MHz" || $cpus[0]->get_max_speed eq "2800MHz", "cpu get max speed" ); ok( $mems[0]->get_size eq "512 MB" || $mems[0]->get_size eq "1073741824 bytes", "memory size" ); ok( $mema[0]->get_maximum_capacity eq "8 GB" || $mema[0]->get_maximum_capacity eq "256 GB" || $mema[0]->get_maximum_capacity eq "8589934592 bytes", "memory array max capacity" ); is( $sysinfo->get_manufacturer, "Parallels Software International Inc.", "system information manucafturer" ); is( $sysinfo->get_product_name, "Parallels Virtual Platform", "system information product name" ); @lines = undef; $dmi = undef; $bb = undef; $bios = undef; @cpus = undef; @mems = undef; @mema = undef; $sysinfo = undef; @lines = eval { local (@ARGV) = ("t/dmi.fbsd.out"); <>; }; $dmi = Rex::Inventory::DMIDecode->new( lines => \@lines ); isa_ok( $dmi, "Rex::Inventory::DMIDecode", "dmi object (fbsd)" ); $bb = $dmi->get_base_board; $bios = $dmi->get_bios; @cpus = $dmi->get_cpus; @mems = $dmi->get_memory_modules; @mema = $dmi->get_memory_arrays; $sysinfo = $dmi->get_system_information; is( $bb->get_product_name, "Parallels Virtual Platform", "get base board product name" ); is( $bios->get_vendor, "Parallels Software International Inc.", "get bios vendor" ); like( $bios->get_version, qr/\d\.0\./, "get bios version" ); is( $bios->get_release_date, "10/26/2007" ); ok( $cpus[0]->get_max_speed eq "2800 MHz" || $cpus[0]->get_max_speed eq "30000 MHz" || $cpus[0]->get_max_speed eq "2800MHz", "cpu get max speed" ); ok( $mems[0]->get_size eq "512 MB" || $mems[0]->get_size eq "1073741824 bytes", "memory size" ); ok( $mema[0]->get_maximum_capacity eq "8 GB" || $mema[0]->get_maximum_capacity eq "256 GB" || $mema[0]->get_maximum_capacity eq "8589934592 bytes", "memory array max capacity" ); is( $sysinfo->get_manufacturer, "Parallels Software International Inc.", "system information manucafturer" ); is( $sysinfo->get_product_name, "Parallels Virtual Platform", "system information product name" ); Rex-1.3.3/t/ifconfig.out30000644000175000017500000000056512572251052015012 0ustar jenkinsjenkinseth0 Link encap:Ethernet HWaddr 00:21:cc:5f:7c:6c UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) Interrupt:20 Memory:f3900000-f3920000 Rex-1.3.3/t/ifconfig.out50000644000175000017500000000100012572251052014775 0ustar jenkinsjenkinseth1 Link encap:Ethernet HWaddr 00:50:56:86:48:E6 inet addr:10.64.82.10 Bcast:10.64.82.31 Mask:255.255.255.224 inet6 addr: fe80::250:56ff:fe86:48e6/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1723537000 errors:0 dropped:0 overruns:0 frame:0 TX packets:1490804633 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:1276409391132 (1.1 TiB) TX bytes:1122763800358 (1.0 TiB) Rex-1.3.3/t/xml.t0000644000175000017500000000302712572251052013373 0ustar jenkinsjenkinsuse Test::More tests => 6; use FindBin qw($Bin); SKIP: { eval { require XML::LibXML }; skip 'Missing XML::LibXML for XML file support.', 6 if $@; require Rex::Group::Lookup::XML; Rex::Group::Lookup::XML->import; use Rex::Group; use Rex::Commands; no warnings 'once'; $::QUIET = 1; groups_xml("$Bin/test.xml"); my %groups = Rex::Group->get_groups; # stringification needed for is_deeply string comparison my @application_server = map { "$_" } @{ $groups{application} }; is( scalar( @{ $groups{application} } ), 2, "2 application servers" ); is_deeply( [ sort @application_server ], [qw/machine01 machine02/], "got machine02,machine01" ); is( scalar( @{ $groups{profiler} } ), 2, "2 profiler servers 2" ); my ($server1) = grep { m/\bmachine07\b/ } @{ $groups{profiler} }; my ($server2) = grep { m/\bmachine01\b/ } @{ $groups{application} }; Rex::TaskList->create()->set_in_transaction(1); no_ssh( task( "xml_task1", $server1, sub { is( connection()->server->option("services"), "nginx,docker", "got services inside task" ); } ) ); Rex::Commands::do_task("xml_task1"); no_ssh( task( "xml_task2", $server2, sub { is( connection()->server->get_user(), 'root', "$server2 user is 'root'" ); is( connection()->server->get_password(), 'foob4r', "$server2 password is 'foob4r'" ); } ) ); Rex::Commands::do_task("xml_task2"); Rex::TaskList->create()->set_in_transaction(0); } Rex-1.3.3/t/ip.out30000644000175000017500000000023212572251052013625 0ustar jenkinsjenkins4: ppp0: mtu 1454 qdisc pfifo_fast qlen 3 link/ppp inet 123.117.251.17 peer 234.165.249.179/32 scope global ppp0 Rex-1.3.3/t/path.t0000644000175000017500000000074012572251052013526 0ustar jenkinsjenkinsuse Test::More tests => 3; use Rex::Helper::Path; my $path = Rex::Helper::Path::resolv_path( "/home/foo/bar/baz", 1 ); is( $path, "/home/foo/bar/baz", "local test absolute path" ); SKIP: { skip 'No home directory tests for Windows.', 2 if $^O =~ m/^MSWin/; $path = Rex::Helper::Path::resolv_path( "~/bar/baz", 1 ); like( $path, qr{^/}, "expanded \$HOME" ); $path = Rex::Helper::Path::resolv_path("~/bar/baz"); like( $path, qr{^/}, "expanded \$HOME - no local" ); } Rex-1.3.3/t/ifconfig.out10000644000175000017500000000076112572251052015006 0ustar jenkinsjenkinseth0 Link encap:Ethernet HWaddr 00:16:3e:7f:fc:3a inet addr:10.18.1.107 Bcast:10.18.1.255 Mask:255.255.255.0 inet6 addr: fe80::216:3eff:fe7f:fc3a/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:7581854 errors:0 dropped:0 overruns:0 frame:0 TX packets:6074960 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:725754206 (725.7 MB) TX bytes:1594218416 (1.5 GB) Rex-1.3.3/t/cron.ex0000644000175000017500000000130012572251052013675 0ustar jenkinsjenkins#----------------------------------------------------------------- # Shell variable for cron SHELL=/bin/bash # PATH variable for cron PATH=/usr/local/bin:/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin:/usr/bin/X11 MYVAR="foo=bar" #M S T M W Befehl #----------------------------------------------------------------- 5 9-20 * * * /home/username/script/script1.sh > /dev/null */10 * * * * /usr/bin/script2.sh > /dev/null 2>&1 59 23 * * 0,4 cp /pfad/zu/datei /pfad/zur/kopie * * * * * DISPLAY=:0 LANG=de_DE.UTF-8 zenity --info --text "Beispiel für das Starten eines Programmes mit GUI" 0 0 * * * backup #----------------------------------------------------------------- Rex-1.3.3/t/fs.t0000644000175000017500000000044212572251052013201 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 1; use Rex::Commands::Fs; my $fake_file = "file_that_does_not_exist"; eval { Rex::Commands::Fs::stat($fake_file); }; my $err = $@; like( $err, qr/^Can't stat $fake_file/, "Trying to stat a non-existent file throws an exception" ); Rex-1.3.3/t/commands_file_template.t0000644000175000017500000000175112572251052017270 0ustar jenkinsjenkins#!/usr/bin/perl use strict; use warnings; use Test::More tests => 4; use File::Basename; use Rex::Commands::File; my $basename = basename __FILE__; { # templates from file my $tpl = Rex::Helper::File::Spec->catfile( dirname(__FILE__), 'commands', 'file', 'test.tpl', ); my $content = template $tpl, basename => $basename; is $content, $basename . "\n", "template from file"; } { # test templates from __DATA__ my $content = template '@second.tpl', basename => $basename; is $content, $basename . "\n", "second template from __DATA__"; my $name = 'Rex'; my $content_first = template '@first.tpl', name => { test => $name }; is $content_first, $name . "\n", "first template from __DATA__"; } { # passing template content my $content = template \'<%= $basename %>', basename => $basename; is $content, $basename, "passing template content"; } __DATA__ @first.tpl <%= $name->{test} %> @end @second.tpl <%= $basename %> @end Rex-1.3.3/t/task.t0000644000175000017500000000715512572251052013543 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More; my %have_mods = ( 'Net::SSH2' => 1, 'Net::OpenSSH' => 1, ); for my $m ( keys %have_mods ) { my $have_mod = 1; eval "use $m;"; if ($@) { $have_mods{$m} = 0; } } unless ( $have_mods{'Net::SSH2'} or $have_mods{'Net::OpenSSH'} ) { plan skip_all => 'SSH module not found. You need Net::SSH2 or Net::OpenSSH to connect to servers via SSH.'; } else { plan tests => 33; } use Rex::Task; use Rex::Commands; { no warnings 'once'; $::QUIET = 1; } my $t1 = Rex::Task->new( name => "foo" ); isa_ok( $t1, "Rex::Task", "create teask object" ); is( $t1->get_connection_type, "Local", "get connection type for local" ); is( $t1->is_local, 1, "is task local" ); is( $t1->is_remote, 0, "is task not remote" ); $t1->set_server("192.168.1.1"); is( $t1->server->[0], "192.168.1.1", "get/set server" ); is( $t1->is_local, 0, "is task not local" ); $t1->set_desc("Description"); is( $t1->desc, "Description", "get/set description" ); is( $t1->get_connection_type, ( $have_mods{"Net::OpenSSH"} ? "OpenSSH" : "SSH" ), "get connection type for ssh" ); is( $t1->want_connect, 1, "want a connection?" ); $t1->modify( "no_ssh", 1 ); is( $t1->want_connect, 0, "want no connection?" ); is( $t1->get_connection_type, "Fake", "get connection type for fake" ); $t1->modify( "no_ssh", 0 ); is( $t1->want_connect, 1, "want a connection?" ); is( $t1->get_connection_type, ( $have_mods{"Net::OpenSSH"} ? "OpenSSH" : "SSH" ), "get connection type for ssh" ); Rex::Config->set( "connection" => "SSH" ); is( $t1->get_connection_type, "SSH", "get connection type for ssh" ); Rex::Config->set( "connection" => "OpenSSH" ); is( $t1->get_connection_type, "OpenSSH", "get connection type for ssh" ); $t1->set_user("root"); is( $t1->user, "root", "get/set the user" ); $t1->set_password("f00b4r"); is( $t1->password, "f00b4r", "get/set the password" ); is( $t1->name, "foo", "get task name" ); $t1->set_auth( "user", "foo" ); is( $t1->user, "foo", "set auth user" ); $t1->set_auth( "password", "baz" ); is( $t1->password, "baz", "set auth password" ); my $test_var = 0; $t1->set_code( sub { $test_var = connection()->server; } ); ok( !$t1->connection->is_connected, "connection currently not established" ); $t1->modify( "no_ssh", 1 ); $t1->connect("localtest"); ok( $t1->connection->is_connected, "connection established" ); $t1->run("localtest"); is( $test_var, "localtest", "task run" ); $t1->disconnect(); my $before_hook = 0; $t1->delete_server; is( $t1->is_remote, 0, "task is no more remote" ); is( $t1->is_local, 1, "task is now local" ); $t1->modify( before => sub { my $server = shift; my $server_ref = shift; $before_hook = 1; $$server_ref = "local02"; } ); my $server = $t1->current_server; $t1->run_hook( \$server, "before" ); is( $before_hook, 1, "run before hook" ); is( $t1->is_remote, 1, "task is now remote" ); is( $t1->is_local, 0, "task is no more local" ); $t1->modify( before => sub { my $server = shift; my $server_ref = shift; $before_hook = 2; $$server_ref = ""; } ); $server = $t1->current_server; $t1->run_hook( \$server, "before" ); is( $before_hook, 2, "run before hook - right direction" ); is( $t1->is_remote, 0, "task is no not remote" ); is( $t1->is_local, 1, "task is now local" ); task( "ret_test1", sub { return "string"; } ); task( "ret_test2", sub { return ( "e1", "e2" ); } ); my $s = ret_test1(); is( $s, "string", "task successfully returned a string" ); my @l = ret_test2(); is_deeply( \@l, [ "e1", "e2" ], "task successfully returned a list" ); Rex-1.3.3/t/dmi.linux.out0000644000175000017500000001270212572251052015046 0ustar jenkinsjenkins# dmidecode 2.11 SMBIOS 2.3 present. 20 structures occupying 896 bytes. Table at 0x000F6120. Handle 0x0000, DMI type 0, 20 bytes BIOS Information Vendor: Parallels Software International Inc. Version: 7.0.15107.796624 Release Date: 10/26/2007 Address: 0xF0000 Runtime Size: 64 kB ROM Size: 64 kB Characteristics: ISA is supported PCI is supported PNP is supported APM is supported VLB is supported Boot from CD is supported 8042 keyboard services are supported (int 9h) Serial services are supported (int 14h) Printer services are supported (int 17h) CGA/mono video services are supported (int 10h) ACPI is supported Handle 0x0001, DMI type 1, 25 bytes System Information Manufacturer: Parallels Software International Inc. Product Name: Parallels Virtual Platform Version: None Serial Number: Parallels-EB 27 9A D5 DE 07 40 9E 9D AB F9 C0 3E 8D 49 DE UUID: EB279AD5-DE07-409E-9DAB-F9C03E8D49DE Wake-up Type: Power Switch Handle 0x0002, DMI type 2, 8 bytes Base Board Information Manufacturer: Parallels Software International Inc. Product Name: Parallels Virtual Platform Version: None Serial Number: None Handle 0x0003, DMI type 3, 18 bytes Chassis Information Manufacturer: Parallels Software International Inc. Type: Unknown Lock: Not Present Version: Serial Number: Asset Tag: Boot-up State: Safe Power Supply State: Safe Thermal State: Safe Security Status: None OEM Information: 0x00000000 Handle 0x0004, DMI type 4, 35 bytes Processor Information Socket Designation: CPU Socket #0 Type: Central Processor Family: Unknown Manufacturer: GenuineIntel ID: E5 06 01 00 FF FB EB BF Version: Not Specified Voltage: 3.3 V External Clock: 466 MHz Max Speed: 2800 MHz Current Speed: 2800 MHz Status: Populated, Enabled Upgrade: Other L1 Cache Handle: Not Provided L2 Cache Handle: Not Provided L3 Cache Handle: Not Provided Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0005, DMI type 9, 13 bytes System Slot Information Designation: ISA slot 1 Type: 16-bit ISA Current Usage: Unknown Length: Unknown Characteristics: 3.3 V is provided Handle 0x0006, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 1 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 1 Characteristics: 3.3 V is provided Handle 0x0007, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 2 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 2 Characteristics: 3.3 V is provided Handle 0x0008, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 3 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 3 Characteristics: 3.3 V is provided Handle 0x0009, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 4 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 4 Characteristics: 3.3 V is provided Handle 0x000A, DMI type 9, 13 bytes System Slot Information Designation: PCI slot 5 Type: 32-bit PCI Current Usage: Unknown Length: Unknown ID: 5 Characteristics: 3.3 V is provided Handle 0x000B, DMI type 10, 8 bytes On Board Device 1 Information Type: Video Status: Disabled Description: Parallels Video Adapter On Board Device 2 Information Type: Sound Status: Disabled Description: Parallels Sound Adapter Handle 0x000C, DMI type 16, 15 bytes Physical Memory Array Location: System Board Or Motherboard Use: System Memory Error Correction Type: None Maximum Capacity: 8 GB Error Information Handle: Not Provided Number Of Devices: 4 Handle 0x000D, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: 512 MB Form Factor: DIMM Set: None Locator: DIMM #0 Bank Locator: BANK #0 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x000E, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #1 Bank Locator: BANK #1 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x000F, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #2 Bank Locator: BANK #2 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0010, DMI type 17, 27 bytes Memory Device Array Handle: 0x000C Error Information Handle: Not Provided Total Width: 32 bits Data Width: 32 bits Size: No Module Installed Form Factor: DIMM Set: None Locator: DIMM #3 Bank Locator: BANK #3 Type: DRAM Type Detail: EDO Speed: 667 MHz Manufacturer: Not Specified Serial Number: Not Specified Asset Tag: Not Specified Part Number: Not Specified Handle 0x0011, DMI type 19, 15 bytes Memory Array Mapped Address Starting Address: 0x00000000000 Ending Address: 0x0001FFFFFFF Range Size: 512 MB Physical Array Handle: 0x000C Partition Width: 2 Handle 0x0012, DMI type 32, 20 bytes System Boot Information Status: No errors detected Handle 0x0013, DMI type 127, 4 bytes End Of Table Rex-1.3.3/t/df.out20000644000175000017500000000037412572251052013614 0ustar jenkinsjenkinsFilesystem 1K-blocks Used Available Use% Mounted on /dev/sda2 18102140 1693244 15489344 10% / tmpfs 255160 0 255160 0% /dev/shm /dev/sda1 495844 67557 402687 15% /boot Rex-1.3.3/t/ip.out20000644000175000017500000000017712572251052013634 0ustar jenkinsjenkins3: eth1: mtu 1500 qdisc noop state DOWN qlen 1000 link/ether 00:1c:42:73:ad:3c brd ff:ff:ff:ff:ff:ff Rex-1.3.3/t/test.xml0000644000175000017500000000200212572251052014077 0ustar jenkinsjenkins Rex-1.3.3/t/commands/0000755000175000017500000000000012572251052014205 5ustar jenkinsjenkinsRex-1.3.3/t/commands/evaluate_hostnames.t0000644000175000017500000000315312572251052020263 0ustar jenkinsjenkins#!/usr/bin/env perl use strict; use warnings; use Test::More tests => 9; use Rex::Commands; my %tests = ( 'server1.domain.com' => [qw/server1.domain.com/], 'server[9..10].domain.com' => [ qw/ server9.domain.com server10.domain.com / ], 'server[6..10/2].domain.com' => [ qw/ server6.domain.com server8.domain.com server10.domain.com / ], 'server[6,8,10].domain.com' => [ qw/ server6.domain.com server8.domain.com server10.domain.com / ], 'server[4..6,8,10..12].domain.com' => [ qw/ server4.domain.com server5.domain.com server6.domain.com server8.domain.com server10.domain.com server11.domain.com server12.domain.com / ], 'server[4..6,8,10..16/2].domain.com' => [ qw/ server4.domain.com server5.domain.com server6.domain.com server8.domain.com server10.domain.com server12.domain.com server14.domain.com server16.domain.com / ], 'server[1..3,2..4].domain.com' => [ qw/ server1.domain.com server2.domain.com server3.domain.com server2.domain.com server3.domain.com server4.domain.com / ], 'server[01..03].domain.com' => [ qw/ server01.domain.com server02.domain.com server03.domain.com / ], 'server[09..11/2].domain.com' => [ qw/ server09.domain.com server11.domain.com / ], ); for my $test ( sort keys %tests ) { my @result = Rex::Commands::evaluate_hostname($test); is_deeply \@result, $tests{$test}, $test; } Rex-1.3.3/t/commands/file/0000755000175000017500000000000012572251052015124 5ustar jenkinsjenkinsRex-1.3.3/t/commands/file/test.tpl0000644000175000017500000000002112572251052016615 0ustar jenkinsjenkins<%= $basename %> Rex-1.3.3/t/file.t0000644000175000017500000002035212572251052013512 0ustar jenkinsjenkinsuse strict; use warnings; use Cwd 'getcwd'; my $cwd = getcwd; use Test::More tests => 55; use Rex::Commands::File; use Rex::Commands::Fs; use Rex::Commands::Gather; use Rex::Commands::Run; Rex::Config->set( foo => "bar" ); if ( $ENV{rex_LOCALTEST} ) { Rex::Config->set_executor_for( perl => "/Users/jan/perl5/perlbrew/perls/perl-5.14.2/bin/perl" ); } my $tmp_dir = "/tmp"; if ( $^O =~ m/^MSWin/ ) { $tmp_dir = $ENV{TMP}; } my $filename = "$cwd/test-$$.txt"; file( $filename, content => "blah blah\nfoo bar" ); my $c = cat($filename); ok( $c, "cat" ); like( $c, qr/blah/, "file with content (1)" ); like( $c, qr/bar/, "file with content (2)" ); Rex::Commands::Fs::unlink($filename); is( is_file($filename), undef, "file removed" ); file( $filename, content => "blah blah\nbaaazzzz", mode => 777 ); my %stats = Rex::Commands::Fs::stat($filename); if ( is_windows() && !can_run('chmod') ) { is( $stats{mode}, "0666", "windows without chmod" ); } else { is( $stats{mode}, "0777", "fs chmod ok" ); } my $changed = 0; my $content = cat($filename); unlike( $content, qr/change/ms, "found change" ); append_if_no_such_line( $filename, "change", qr{change}, on_change => sub { $changed = 1; } ); $content = cat($filename); like( $content, qr/change/ms, "found change" ); is( $changed, 1, "something was changed in the file" ); append_if_no_such_line( $filename, line => "dream-breaker", regexp => qr{^dream-breaker$} ); $content = cat($filename); like( $content, qr/dream\-breaker/ms, "found dream-breaker" ); append_if_no_such_line( $filename, line => "#include /etc/sudoers.d/*.conf", regexp => qr{^#include /etc/sudoers.d/\*.conf$}, ); $content = cat($filename); like( $content, qr{#include /etc/sudoers\.d/\*\.conf}ms, "found sudoers entry" ); append_if_no_such_line( $filename, line => 'silly with "quotes"' ); $content = cat($filename); like( $content, qr/silly with "quotes"/ms, "found entry with quotes" ); append_if_no_such_line( $filename, line => "#include /etc/sudoers.d/*.conf" ); my @content = split( /\n/, cat($filename) ); isnt( $content[-1], "#include /etc/sudoers.d/*.conf", "last entry is not #include ..." ); append_if_no_such_line( $filename, 'KEY="VAL"' ); $content = cat($filename); like( $content, qr/KEY="VAL"/ms, "found KEY=VAL" ); append_if_no_such_line( $filename, "change", qr{change}, on_change => sub { $changed = 0; } ); is( $changed, 1, "nothing was changed in the file" ); append_if_no_such_line( $filename, "change", on_change => sub { $changed = 0; } ); is( $changed, 1, "nothing was changed in the file without regexp" ); $content = cat($filename); unlike( $content, qr/foobar/ms, "not found foobar" ); append_if_no_such_line( $filename, line => "foobar", ); $content = cat($filename); like( $content, qr/foobar/ms, "found foobar" ); append_if_no_such_line( $filename, line => "bazzada", regexp => qr{^foobar}, ); $content = cat($filename); unlike( $content, qr/bazzada/ms, "not found bazzada" ); append_if_no_such_line( $filename, line => "tacktack", regexp => qr{blah blah}ms, ); $content = cat($filename); unlike( $content, qr/tacktack/ms, "not found tacktack" ); append_if_no_such_line( $filename, line => "nothing there", regexp => [ qr{blah blah}ms, qr{tzuhgjbn}ms ], ); $content = cat($filename); unlike( $content, qr/nothing there/ms, "not found nothing there" ); append_if_no_such_line( $filename, line => "this is there", regexp => [ qr{qaywsx}ms, qr{tzuhgjbn}ms ], ); $content = cat($filename); like( $content, qr/this is there/ms, "found this is there" ); append_if_no_such_line( $filename, line => "bazzada", regexp => qr{^bazzada}, ); $content = cat($filename); like( $content, qr/bazzada/ms, "found bazzada (2)" ); append_or_amend_line( $filename, line => 'silly more "quotes"', regexp => qr{^silly with "quotes"}, ); $content = cat($filename); like( $content, qr/silly more "quotes"/m, "found silly more quotes" ); unlike( $content, qr/silly with "quotes"/m, "silly with quotes no longer exists" ); append_or_amend_line( $filename, line => "dream-maker", regexp => qr{^dream\-}, ); $content = cat($filename); like( $content, qr/^dream\-maker$/m, "found dream-maker" ); unlike( $content, qr/^dream\-breaker$/m, "dream-breaker no longer exists" ); append_or_amend_line( $filename, line => "dream2-maker", regexp => qr{^dream2\-}, ); $content = cat($filename); like( $content, qr/^dream2\-maker$/m, "found dream2-maker" ); like( $content, qr/^dream\-maker$/m, "dream-maker still exists" ); append_or_amend_line( $filename, line => "dream3-maker", regexp => qr{^dream2\-}, ); $content = cat($filename); like( $content, qr/^dream3\-maker$/m, "found dream3-maker" ); unlike( $content, qr/^dream2\-maker$/m, "dream2-maker no longer exists" ); like( $content, qr/^dream\-maker$/m, "dream-maker still exists" ); unlike( $content, qr/^$/m, "no extra blank lines inserted" ); file "file with space-$$.txt", content => "file with space\n"; is( is_file("file with space-$$.txt"), 1, "file with space exists" ); $c = ""; $c = cat "file with space-$$.txt"; like( $c, qr/file with space/m, "found content of file with space" ); Rex::Commands::Fs::unlink("file with space-$$.txt"); is( is_file("file with space-$$.txt"), undef, "file with space removed" ); file "file_with_\@-$$.txt", content => "file with at sign\n"; is( is_file("file_with_\@-$$.txt"), 1, "file with at sign exists" ); $c = ""; $c = cat "file_with_\@-$$.txt"; like( $c, qr/file with at sign/m, "found content of file with at sign" ); Rex::Commands::Fs::unlink("file_with_\@-$$.txt"); is( is_file("file_with_\@-$$.txt"), undef, "file with at sign removed" ); Rex::Commands::Fs::unlink($filename); is( is_file($filename), undef, "test.txt removed" ); $filename = "$tmp_dir/test-sed-$$.txt"; file $filename, content => "this is a sed test file\nthese are just some lines\n0505\n0606\n0707\n'foo'\n/etc/passwd\n\"baz\"\n{klonk}\nfoo bar\n\\.-~'[a-z]\$ foo {1} /with/some/slashes \%\&()?\n|.-\\~'[a-z]\$ bar {2} /with/more/slashes \%\&()?\n"; sed qr/fo{2} bar/, "baz bar", $filename; $content = cat $filename; like( $content, qr/baz bar/, "sed replaced foo bar" ); sed qr/^\\\.\-\~'\[a\-z\]\$ foo \{1\} \/with\/some\/slashes/, "got replaced", $filename; $content = cat $filename; like( $content, qr/got replaced/, "sed replaced strange chars" ); sed qr/^\|\.\-\\\~'\[a\-z\]\$ BAR \{2\} \/with\/more\/slashes/i, "got another replace", $filename; $content = cat $filename; like( $content, qr/got another replace/, "sed replaced strange chars" ); my @lines = split( /\n/, $content ); like( $lines[-1], qr/^got another replace/, "last line was successfully replaced" ); like( $lines[-2], qr/^got replaced/, "second last line was successfully replaced" ); like( $lines[-4], qr/^\{klonk\}/, "fourth last line untouched" ); sed qr{0606}, "6666", $filename; $content = cat $filename; like( $content, qr/6666/, "sed replaced 0606" ); sed qr{'foo'}, "'bar'", $filename; $content = cat $filename; like( $content, qr/'bar'/, "sed replaced 'foo'" ); sed qr{/etc/passwd}, "/etc/shadow", $filename; $content = cat $filename; like( $content, qr/\/etc\/shadow/, "sed replaced /etc/passwd" ); sed qr{"baz"}, '"boooooz"', $filename; $content = cat $filename; like( $content, qr/"boooooz"/, "sed replaced baz" ); sed qr/{klonk}/, '{plonk}', $filename; $content = cat $filename; like( $content, qr/{plonk}/, "sed replaced {klonk}" ); sed qr/{klonk}/, '{plonk}', $filename; $content = cat $filename; like( $content, qr/{plonk}/, "sed replaced {klonk}" ); unlink $filename; file "$tmp_dir/multiline-$$.txt", content => "this is\na test.\n"; sed qr/is\sa test/msi, "no one\nknows!", "$tmp_dir/multiline-$$.txt", multiline => 1; $content = cat "$tmp_dir/multiline-$$.txt"; is( $content, "this no one\nknows!.\n", "multiline replacement" ); unlink "$tmp_dir/multiline-$$.txt"; file "$tmp_dir/test.d-$$", ensure => "directory"; ok( -d "$tmp_dir/test.d-$$", "created directory with file()" ); rmdir "$tmp_dir/test.d-$$"; $content = 'Hello this is <%= $::foo %>'; is( template( \$content, __no_sys_info__ => 1 ), "Hello this is bar", "get keys from Rex::Config" ); is( template( \$content, { foo => "baz", __no_sys_info__ => 1 } ), "Hello this is baz", "overwrite keys from Rex::Config" ); Rex-1.3.3/t/package.t0000644000175000017500000000163612572251052014172 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 4; use Rex::Pkg::Base; my $pkg = Rex::Pkg::Base->new; my @plist1 = ( { name => 'vim', version => '1.0' }, { name => 'mc', version => '2.0' }, { name => 'rex', version => '0.51.0' }, ); my @plist2 = ( { name => 'vim', version => '1.0' }, { name => 'rex', version => '0.52.0' }, { name => 'libssh2-1', version => '0.32.1' }, ); my @mods = $pkg->diff_package_list( \@plist1, \@plist2 ); my $found_vim = grep { $_->{name} eq "vim" } @mods; is( $found_vim, 0, "vim was not modified" ); my ($found_rex) = grep { $_->{name} eq "rex" } @mods; is( $found_rex->{action}, "updated", "rex was updated" ); my ($found_libssh2) = grep { $_->{name} eq "libssh2-1" } @mods; is( $found_libssh2->{action}, "installed", "libssh2-1 was installed" ); my ($found_mc) = grep { $_->{name} eq "mc" } @mods; is( $found_mc->{action}, "removed", "mc was removed" ); 1; Rex-1.3.3/t/md5test.bin0000644000175000017500000000000112572251052014452 0ustar jenkinsjenkinsRex-1.3.3/t/template.t0000644000175000017500000000500112572251052014400 0ustar jenkinsjenkinsuse strict; use warnings; use Test::More tests => 18; use Rex::Template; my $t = Rex::Template->new; my $content = 'one two three'; is( $t->parse( $content, {} ), "one two three", "just text" ); $content = 'Hello this is <%= $::name %>'; is( $t->parse( $content, { name => "foo" } ), "Hello this is foo", "simple variable" ); $content = '<% if($::logged_in) { %> Logged in! <% } else { %> Logged out! <% } %>'; my $content_ok = " Logged in! "; is( $t->parse( $content, { logged_in => 1 } ), $content_ok, "if condition" ); $content = 'Hello this is <%= $::name %>'; is( Rex::Config->get_template_function()->( $content, { name => "baz" } ), "Hello this is baz", "get template function" ); is( $t->parse( $content, name => "bar" ), "Hello this is bar", "simple variable without hashRef" ); $Rex::Template::BE_LOCAL = 1; $Rex::Template::BE_LOCAL = 1; $content = 'Hello this is <%= $foo %>'; is( $t->parse( $content, { foo => "baz" } ), "Hello this is baz", "local vars" ); $content = '<%= join(",", @{ $arr }) %>'; is( $t->parse( $content, { arr => [qw/one two three/] } ), "one,two,three", "local var with array" ); # # old variable style # $content = 'one two three'; is( $t->parse( $content, {} ), "one two three", "just text" ); $content = 'Hello this is <%= $::name %>'; is( $t->parse( $content, { name => "foo" } ), "Hello this is foo", "simple variable" ); $content = '<% if($::logged_in) { %> Logged in! <% } else { %> Logged out! <% } %>'; $content_ok = " Logged in! "; is( $t->parse( $content, { logged_in => 1 } ), $content_ok, "if condition" ); $content = 'Hello this is <%= $::name %>'; is( Rex::Config->get_template_function()->( $content, { name => "baz" } ), "Hello this is baz", "get template function" ); is( $t->parse( $content, name => "bar" ), "Hello this is bar", "simple variable without hashRef" ); $content = 'Hello this is <%= $::foo %> <%= $::veth1_0_ip %>'; is( $t->parse( $content, { foo => "baz", "veth1.0_ip" => "10.1.2.3" } ), "Hello this is baz 10.1.2.3", "template with invalid key name" ); my $v = { "foo" => { val => "val1", name => "foo" }, "foo_bar" => { val => "val2", name => "foo_bar" }, "k-ey" => { val => "val3", name => "k_ey" }, "veth0.1" => { val => "val4", name => "veth0_1" }, "2nd\\key" => { val => "val5", name => "2nd_key" }, }; for my $key ( keys %{$v} ) { my $var_name = Rex::Template::_normalize_var_name($key); is( $var_name, $v->{$key}->{name}, "$var_name is equal to " . $v->{$key}->{name} ); } Rex-1.3.3/lib/0000755000175000017500000000000012572251052012707 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/0000755000175000017500000000000012572251052013445 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Args/0000755000175000017500000000000012572251052014341 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Args/Integer.pm0000644000175000017500000000060612572251052016276 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Args::Integer; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; sub get { my ( $class, $name ) = @_; my $arg = shift @ARGV; if ( $arg =~ m/^\d+$/ ) { return $arg; } Rex::Logger::debug("Invalid argument for $name"); return; } 1; Rex-1.3.3/lib/Rex/Args/String.pm0000644000175000017500000000042012572251052016141 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Args::String; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub get { my ( $class, $name ) = @_; my $arg = shift @ARGV; return $arg; } 1; Rex-1.3.3/lib/Rex/Args/Single.pm0000644000175000017500000000032412572251052016117 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Args::Single; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub get { return 1; } 1; Rex-1.3.3/lib/Rex/User/0000755000175000017500000000000012572251052014363 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/User/NetBSD.pm0000644000175000017500000001040012572251052015773 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::NetBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Run; use Rex::Commands::MD5; use Rex::Helper::Run; use Rex::Commands::Fs; use Rex::User::Linux; use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Interface::Exec; use Rex::Helper::Path; use base qw(Rex::User::Linux); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub create_user { my ( $self, $user, $data ) = @_; my $cmd; my $uid = $self->get_uid($user); my $should_create_home; my $old_pw_md5 = md5("/etc/passwd"); if ( $data->{'create_home'} || $data->{'create-home'} ) { $should_create_home = 1; } elsif ( $data->{'no_create_home'} || $data->{'no-create-home'} ) { $should_create_home = 0; } elsif ( ( exists $data->{'no_create_home'} && $data->{'no_create_home'} == 0 ) || ( exists $data->{'no-create-home'} && $data->{'no-create-home'} == 0 ) ) { $should_create_home = 1; } if ( !defined $uid ) { Rex::Logger::debug("User $user does not exists. Creating it now."); $cmd = "useradd "; if ( exists $data->{system} ) { $cmd .= " -r"; } } else { Rex::Logger::debug("User $user already exists. Updating..."); $cmd = "usermod "; } if ( exists $data->{uid} ) { $cmd .= " -u " . $data->{uid}; } if ( exists $data->{home} ) { $cmd .= " -d " . $data->{home}; } if ( $should_create_home && !defined $uid ) { #useradd mode $cmd .= " -m "; } if ( exists $data->{shell} ) { $cmd .= " -s " . $data->{shell}; } if ( exists $data->{comment} ) { $cmd .= " -c '" . $data->{comment} . "'"; } if ( exists $data->{expire} ) { $cmd .= " -e '" . $data->{expire} . "'"; } if ( exists $data->{groups} ) { my @groups = @{ $data->{groups} }; my $pri_group = shift @groups; $cmd .= " -g $pri_group"; if (@groups) { $cmd .= " -G " . join( ",", @groups ); } } my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write("$cmd $user\nexit \$?\n"); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? == 0 ) { Rex::Logger::debug("User $user created/updated."); } else { Rex::Logger::info( "Error creating/updating user $user", "warn" ); die("Error creating/updating user $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); if ( exists $data->{password} ) { Rex::Logger::debug("Changing password of $user."); $rnd_file = get_tmp_file; $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "usermod -p \$(pwhash '" . $data->{password} . "') $user\nexit \$?\n" ); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error setting password for $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); } if ( exists $data->{crypt_password} ) { Rex::Logger::debug("Setting encrypted password of $user"); $rnd_file = get_tmp_file; $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "usermod -p '" . $data->{crypt_password} . "' $user\nexit \$?\n" ); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error setting password for $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); } my $new_pw_md5 = md5("/etc/passwd"); if ( $new_pw_md5 eq $old_pw_md5 ) { return { changed => 0, ret => $self->get_uid($user), }; } else { return { changed => 1, ret => $self->get_uid($user), }, ; } } sub rm_user { my ( $self, $user, $data ) = @_; Rex::Logger::debug("Removing user $user"); my %user_info = $self->get_user($user); my $cmd = "userdel"; if ( exists $data->{delete_home} ) { $cmd .= " -r"; } i_run $cmd . " " . $user; if ( exists $data->{delete_home} && is_dir( $user_info{home} ) ) { Rex::Logger::debug( "userdel doesn't deleted home. removing it now by hand..."); rmdir $user_info{home}; } if ( $? != 0 ) { die("Error deleting user $user"); } } 1; Rex-1.3.3/lib/Rex/User/SunOS.pm0000644000175000017500000000750212572251052015734 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::SunOS; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::Fs; use Rex::Commands::File; use Rex::User::OpenBSD; use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Interface::Exec; use Rex::Helper::Path; use base qw(Rex::User::OpenBSD); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub create_user { my ( $self, $user, $data ) = @_; my $cmd; my $uid = $self->get_uid($user); my $should_create_home; if ( $data->{'create_home'} || $data->{'create-home'} ) { $should_create_home = 1; } elsif ( $data->{'no_create_home'} || $data->{'no-create-home'} ) { $should_create_home = 0; } elsif ( ( exists $data->{'no_create_home'} && $data->{'no_create_home'} == 0 ) || ( exists $data->{'no-create-home'} && $data->{'no-create-home'} == 0 ) ) { $should_create_home = 1; } if ( !defined $uid ) { Rex::Logger::debug("User $user does not exists. Creating it now."); $cmd = "useradd "; if ( exists $data->{system} ) { $cmd .= " -r"; } } else { Rex::Logger::debug("User $user already exists. Updating..."); $cmd = "usermod "; } if ( exists $data->{uid} ) { $cmd .= " -u " . $data->{uid}; } if ( exists $data->{home} ) { $cmd .= " -d " . $data->{home}; } if ( $should_create_home && !defined $uid ) { #useradd mode $cmd .= " -m "; } if ( exists $data->{shell} ) { $cmd .= " -s " . $data->{shell}; } if ( exists $data->{comment} ) { $cmd .= " -c '" . $data->{comment} . "'"; } if ( exists $data->{expire} ) { $cmd .= " -e '" . $data->{expire} . "'"; } if ( exists $data->{groups} ) { my @groups = @{ $data->{groups} }; my $pri_group = shift @groups; $cmd .= " -g $pri_group"; if (@groups) { $cmd .= " -G " . join( ",", @groups ); } } my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write("$cmd $user\nexit \$?\n"); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? == 0 ) { Rex::Logger::debug("User $user created/updated."); } else { Rex::Logger::info( "Error creating/updating user $user", "warn" ); die("Error creating/updating user $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); if ( exists $data->{password} ) { my $expect_path; if ( can_run("/usr/local/bin/expect") ) { $expect_path = "/usr/local/bin/expect"; } elsif ( can_run("/usr/bin/expect") ) { $expect_path = "/usr/bin/expect"; } if ($expect_path) { my $chpasswd_file = get_tmp_file; my $fh = file_write $chpasswd_file; $fh->write( qq~#!$expect_path -- # Input: username password set USER [lindex \$argv 0] set PASS [lindex \$argv 1] if { \$USER == "" || \$PASS == "" } { puts "Usage: /tmp/chpasswd username password\n" exit 1 } spawn passwd \$USER expect "assword:" send "\$PASS\r" expect "assword:" send "\$PASS\r" expect eof ~ ); $fh->close; $rnd_file = get_tmp_file; $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "$chpasswd_file $user '" . $data->{"password"} . "'\nexit \$?\n" ); $fh->close; chmod 700, $chpasswd_file; i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error changing user's password."); } rm $chpasswd_file; rm $rnd_file; } else { die( "No expect found in /usr/local/bin or /usr/bin. Can't set user password." ); } } return { changed => 0, ret => $self->get_uid($user), }; } 1; Rex-1.3.3/lib/Rex/User/Linux.pm0000644000175000017500000002477612572251052016040 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::Linux; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; require Rex::Commands; use Rex::Commands::Run; use Rex::Commands::MD5; use Rex::Helper::Run; use Rex::Helper::Encode; use Rex::Commands::Fs; use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Interface::Exec; use Rex::Helper::Path; use JSON::XS; use Rex::User::Base; use base qw(Rex::User::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub create_user { my ( $self, $user, $data ) = @_; my $cmd; my $uid = $self->get_uid($user); my $run_cmd = 0; my $should_create_home; # if any home creation intent has been defined, # don't follow the default home creation policy my $use_default_home_policy = ( defined $data->{'create_home'} || defined $data->{'create-home'} || defined $data->{'no_create_home'} || defined $data->{'no-create-home'} ) ? 0 : 1; if ( !$use_default_home_policy ) { if ( $data->{'create_home'} || $data->{'create-home'} ) { $should_create_home = 1; } elsif ( $data->{'no_create_home'} || $data->{'no-create-home'} ) { $should_create_home = 0; } elsif ( ( exists $data->{'no_create_home'} && $data->{'no_create_home'} == 0 ) || ( exists $data->{'no-create-home'} && $data->{'no-create-home'} == 0 ) ) { $should_create_home = 1; } } if ( !defined $uid ) { Rex::Logger::debug("User $user does not exists. Creating it now."); $cmd = "/usr/sbin/useradd "; if ( exists $data->{system} ) { $cmd .= " -r"; } $run_cmd = 1; } else { # only the user should be there, no modifications. # so just return if ( !defined $data ) { return { changed => 0, uid => $uid, }; } Rex::Logger::debug("User $user already exists. Updating..."); if ( exists $data->{uid} && $data->{uid} == $uid ) { delete $data->{uid}; } $cmd = "/usr/sbin/usermod "; } if ( exists $data->{non_uniq} ) { $cmd .= " -o "; $run_cmd = 1; } if ( exists $data->{uid} ) { $cmd .= " --uid " . $data->{uid}; $run_cmd = 1; } if ( exists $data->{home} ) { $run_cmd = 1; $cmd .= " -d " . $data->{home}; # don't create home directory in useradd mode if it already exists $should_create_home = 0 if ( !defined $uid && is_dir( $data->{home} ) ); } if ( !$use_default_home_policy ) { if ( !defined $uid ) { #useradd mode if ($should_create_home) { $cmd .= " -m "; } else { $cmd .= " -M "; } } else { #usermod mode $cmd .= " -m " if ( exists $data->{home} ); } } if ( exists $data->{shell} ) { $run_cmd = 1; $cmd .= " --shell " . $data->{shell}; } if ( exists $data->{comment} ) { $run_cmd = 1; $cmd .= " --comment '" . $data->{comment} . "'"; } if ( exists $data->{expire} ) { $run_cmd = 1; $cmd .= " --expiredate '" . $data->{expire} . "'"; } if ( exists $data->{groups} ) { $run_cmd = 1; my @groups = @{ $data->{groups} }; my $pri_group = shift @groups; $cmd .= " --gid $pri_group"; if (@groups) { $cmd .= " --groups " . join( ",", @groups ); } } my $old_pw_md5 = md5("/etc/passwd"); my $old_sh_md5 = ""; eval { $old_sh_md5 = md5("/etc/shadow"); }; # only run the cmd if needed if ($run_cmd) { my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write("rm \$0\n$cmd $user\nexit \$?\n"); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? == 0 ) { Rex::Logger::debug("User $user created/updated."); } else { Rex::Logger::info( "Error creating/updating user $user", "warn" ); die("Error creating/updating user $user"); } } if ( exists $data->{password} ) { my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "rm \$0\n/bin/echo -e '" . $data->{password} . "\\n" . $data->{password} . "' | /usr/bin/passwd $user\nexit \$?\n" ); $fh->close; Rex::Logger::debug("Changing password of $user."); i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error setting password for $user"); } } if ( exists $data->{crypt_password} && $data->{crypt_password} ) { my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "rm \$0\nusermod -p '" . $data->{crypt_password} . "' $user\nexit \$?\n" ); $fh->close; Rex::Logger::debug("Setting encrypted password of $user"); i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error setting password for $user"); } } my $new_pw_md5 = md5("/etc/passwd"); my $new_sh_md5 = ""; eval { $new_sh_md5 = md5("/etc/shadow"); }; if ( $new_pw_md5 eq $old_pw_md5 && $new_sh_md5 eq $old_sh_md5 ) { return { changed => 0, ret => $self->get_uid($user), }; } else { return { changed => 1, ret => $self->get_uid($user), }, ; } } sub rm_user { my ( $self, $user, $data ) = @_; Rex::Logger::debug("Removing user $user"); my $cmd = "/usr/sbin/userdel"; if ( exists $data->{delete_home} ) { $cmd .= " --remove"; } if ( exists $data->{force} ) { $cmd .= " --force"; } i_run $cmd . " " . $user; if ( $? != 0 ) { die("Error deleting user $user"); } } sub get_uid { my ( $self, $user ) = @_; my %data = $self->get_user($user); return $data{uid}; } sub user_groups { my ( $self, $user ) = @_; Rex::Logger::debug("Getting group membership of $user"); my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; my $script = q| unlink $0; $exe = "/usr/bin/groups"; if(! -x $exe) { $exe = "/bin/groups"; } print to_json([ map {chomp; $_ =~ s/^[^:]*:\s*(.*)\s*$/$1/; split / /, $_} qx{$exe $ARGV[0]} ]); |; $fh->open( ">", $rnd_file ); $fh->write($script); $fh->write( func_to_json() ); $fh->close; my $data_str = i_run "perl $rnd_file $user"; if ( $? != 0 ) { die("Error getting group list"); } my $data = decode_json($data_str); my $wantarray = wantarray(); if ( defined $wantarray && !$wantarray ) { # arrayref return $data; } return @{$data}; } sub user_list { my $self = shift; Rex::Logger::debug("Getting user list"); my $rnd_file = get_tmp_file; my $script = q| unlink $0; print to_json([ map {chomp; $_ =~ s/^([^:]*):.*$/$1/; $_} qx{/usr/bin/getent passwd} ]); |; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write($script); $fh->write( func_to_json() ); $fh->close; my $data_str = i_run "perl $rnd_file"; if ( $? != 0 ) { die("Error getting user list"); } my $data = decode_json($data_str); return @$data; } sub get_user { my ( $self, $user ) = @_; Rex::Logger::debug("Getting information for $user"); my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; my $script = q| unlink $0; print to_json([ getpwnam($ARGV[0]) ]); |; $fh->open( ">", $rnd_file ); $fh->write($script); $fh->write( func_to_json() ); $fh->close; my $data_str = i_run "perl $rnd_file $user"; if ( $? != 0 ) { die("Error getting user information for $user"); } my $data = decode_json($data_str); return ( name => $data->[0], password => $data->[1], uid => $data->[2], gid => $data->[3], comment => $data->[5], home => $data->[7], shell => $data->[8], expire => exists $data->[9] ? $data->[9] : 0, ); } sub lock_password { my ( $self, $user ) = @_; # Is the password already locked? my $result = i_run "passwd --status $user"; die "Unexpected result from passwd: $result" unless $result =~ /^$user\s+(L|NP|P)\s+/; if ( $1 eq 'L' ) { # Already locked return { changed => 0 }; } else { my $ret = i_run "passwd --lock $user"; if ( $? != 0 ) { die("Error locking account $user: $ret"); } return { changed => 1, ret => $ret, }; } } sub unlock_password { my ( $self, $user ) = @_; # Is the password already unlocked? my $result = i_run "passwd --status $user"; die "Unexpected result from passwd: $result" unless $result =~ /^$user\s+(L|NP|P)\s+/; if ( $1 eq 'P' ) { # Already unlocked return { changed => 0 }; } else { # Capture error string on failure (eg. account has no password) my ( $ret, $err ) = i_run "passwd --unlock $user", sub { @_ }; if ( $? != 0 ) { die("Error unlocking account $user: $err"); } return { changed => 1, ret => $ret, }; } } sub create_group { my ( $self, $group, $data ) = @_; my $cmd; my $gid = $self->get_gid($group); if ( !defined $gid ) { Rex::Logger::debug("Creating new group $group"); $cmd = "/usr/sbin/groupadd "; } elsif ( exists $data->{gid} && $data->{gid} == $gid ) { if ( Rex::Config->get_do_reporting ) { return { changed => 0, ret => $gid, }; } return $gid; } else { if ( !defined $data ) { if ( Rex::Config->get_do_reporting ) { return { changed => 0, ret => $gid, }; } return $gid; } Rex::Logger::debug("Group $group already exists. Updating..."); $cmd = "/usr/sbin/groupmod "; } if ( exists $data->{gid} ) { $cmd .= " -g " . $data->{gid}; $gid = undef; } i_run $cmd . " " . $group; if ( $? != 0 ) { die("Error creating/modifying group $group"); } if ( defined $gid ) { return $gid; } return $self->get_gid($group); } sub get_gid { my ( $self, $group ) = @_; my %data = $self->get_group($group); return $data{gid}; } sub get_group { my ( $self, $group ) = @_; Rex::Logger::debug("Getting information for $group"); my @data = split( " ", "" . i_run("perl -le 'print join(\" \", getgrnam(\$ARGV[0]));' '$group'"), 4 ); if ( $? != 0 ) { die("Error getting group information"); } return ( name => $data[0], password => $data[1], gid => $data[2], members => $data[3], ); } sub rm_group { my ( $self, $group ) = @_; i_run "/usr/sbin/groupdel $group"; if ( $? != 0 ) { die("Error deleting group $group"); } } 1; Rex-1.3.3/lib/Rex/User/FreeBSD.pm0000644000175000017500000001467412572251052016147 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::FreeBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Run; use Rex::Commands::MD5; use Rex::Helper::Run; use Rex::Helper::Encode; use Rex::Commands::Fs; use Rex::Commands::File; use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Interface::Exec; use Rex::User::Linux; use Rex::Helper::Path; use JSON::XS; use base qw(Rex::User::Linux); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub create_user { my ( $self, $user, $data ) = @_; my $cmd; my $uid = $self->get_uid($user); my $should_create_home; my $old_pw_md5 = md5("/etc/passwd"); if ( $data->{'create_home'} || $data->{'create-home'} ) { $should_create_home = 1; } elsif ( $data->{'no_create_home'} || $data->{'no-create-home'} ) { $should_create_home = 0; } elsif ( ( exists $data->{'no_create_home'} && $data->{'no_create_home'} == 0 ) || ( exists $data->{'no-create-home'} && $data->{'no-create-home'} == 0 ) ) { $should_create_home = 1; } if ( !defined $uid ) { Rex::Logger::debug("User $user does not exists. Creating it now."); $cmd = "pw useradd "; } else { Rex::Logger::debug("User $user already exists. Updating..."); $cmd = "pw usermod "; } if ( $data->{"uid"} ) { $cmd .= " -u " . $data->{"uid"}; } if ( $data->{"home"} ) { $cmd .= " -d " . $data->{"home"}; } if ( $should_create_home && !defined $uid ) { #useradd mode $cmd .= " -m "; } if ( exists $data->{shell} ) { $cmd .= " -s " . $data->{shell}; } if ( $data->{"comment"} ) { $cmd .= " -c \"" . $data->{"comment"} . "\" "; } if ( $data->{"expire"} ) { $cmd .= " -e " . $data->{"expire"}; } if ( $data->{"groups"} ) { my @groups = @{ $data->{groups} }; $cmd .= " -g " . $groups[0]; $cmd .= " -G " . join( ",", @groups ); } my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write("$cmd -n $user\nexit \$?\n"); $fh->close; i_run "/bin/sh $rnd_file"; my $retval = $?; Rex::Interface::Fs->create()->unlink($rnd_file); if ( $retval == 0 ) { Rex::Logger::debug("User $user created/updated."); } else { Rex::Logger::info( "Error creating/updating user $user", "warn" ); die("Error creating/updating user $user"); } if ( exists $data->{password} ) { Rex::Logger::debug("Changing password of $user."); $rnd_file = get_tmp_file; $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "echo '" . $data->{password} . "' | pw usermod $user -h 0\nexit \$?\n" ); $fh->close; i_run "/bin/sh $rnd_file"; my $pw_retval = $?; Rex::Interface::Fs->create()->unlink($rnd_file); if ( $pw_retval != 0 ) { die("Error setting password for $user"); } } my $new_pw_md5 = md5("/etc/passwd"); if ( $new_pw_md5 eq $old_pw_md5 ) { return { changed => 0, ret => $self->get_uid($user), }; } else { return { changed => 1, ret => $self->get_uid($user), }, ; } } sub rm_user { my ( $self, $user, $data ) = @_; Rex::Logger::debug("Removing user $user"); my $cmd = "pw userdel"; if ( exists $data->{delete_home} ) { $cmd .= " -r "; } i_run $cmd . " -n " . $user; if ( $? != 0 ) { die("Error deleting user $user"); } } sub get_uid { my ( $self, $user ) = @_; my %data = $self->get_user($user); return $data{uid}; } sub get_user { my ( $self, $user ) = @_; Rex::Logger::debug("Getting information for $user"); my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; my $script = q| unlink $0; print to_json([ getpwnam($ARGV[0]) ]); |; $fh->open( ">", $rnd_file ); $fh->write($script); $fh->write( func_to_json() ); $fh->close; my $data_str = i_run "perl $rnd_file $user"; if ( $? != 0 ) { die("Error getting user information for $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); my $data = decode_json($data_str); return ( name => $data->[0], password => $data->[1], uid => $data->[2], gid => $data->[3], comment => $data->[5], home => $data->[7], shell => $data->[8], expire => exists $data->[9] ? $data->[9] : 0, ); } sub create_group { my ( $self, $group, $data ) = @_; my $cmd; if ( !defined $self->get_gid($group) ) { Rex::Logger::debug("Creating new group $group"); $cmd = "pw groupadd "; if ( exists $data->{gid} ) { $cmd .= " -g " . $data->{gid}; } i_run $cmd . " -n " . $group; if ( $? != 0 ) { die("Error creating/modifying group $group"); } } else { Rex::Logger::debug("Group $group already exists. Updating..."); # updating with pw groupmod doesn't work good in freebsd 10 # so we directly edit the /etc/group file #$cmd = "pw groupmod "; if ( exists $data->{gid} ) { eval { my @content = split( /\n/, cat("/etc/group") ); my $gid = $data->{gid}; for (@content) { s/^$group:([^:]+):(\d+):/$group:$1:$gid:/; } my $fh = file_write("/etc/group"); $fh->write( join( "\n", @content ) ); $fh->close; 1; } or do { die("Error creating/modifying group $group"); }; } } return $self->get_gid($group); } sub get_gid { my ( $self, $group ) = @_; my %data = $self->get_group($group); return $data{gid}; } sub get_group { my ( $self, $group ) = @_; Rex::Logger::debug("Getting information for $group"); my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; my $script = q| unlink $0; print to_json([ getgrnam($ARGV[0]) ]); |; $fh->open( ">", $rnd_file ); $fh->write($script); $fh->write( func_to_json() ); $fh->close; my $data_str = i_run "perl $rnd_file $group"; if ( $? != 0 ) { die("Error getting group information"); } Rex::Interface::Fs->create()->unlink($rnd_file); my $data = decode_json($data_str); return ( name => $data->[0], password => $data->[1], gid => $data->[2], members => $data->[3], ); } sub rm_group { my ( $self, $group ) = @_; i_run "pw groupdel $group"; if ( $? != 0 ) { die("Error deleting group $group"); } } 1; Rex-1.3.3/lib/Rex/User/Base.pm0000644000175000017500000000113212572251052015570 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub lock_password { # Overridden in those classes that implement it die "lock_password is not available on this operating system"; } sub unlock_password { # Overridden in those classes that implement it die "unlock_password is not available on this operating system"; } 1; Rex-1.3.3/lib/Rex/User/OpenBSD.pm0000644000175000017500000000742012572251052016156 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::OpenBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Run; use Rex::Commands::MD5; use Rex::Helper::Run; use Rex::Commands::Fs; use Rex::User::NetBSD; use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Interface::Exec; use Rex::Helper::Path; use base qw(Rex::User::NetBSD); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub create_user { my ( $self, $user, $data ) = @_; my $cmd; my $old_pw_md5 = md5("/etc/passwd"); my $uid = $self->get_uid($user); my $should_create_home; if ( $data->{'create_home'} || $data->{'create-home'} ) { $should_create_home = 1; } elsif ( $data->{'no_create_home'} || $data->{'no-create-home'} ) { $should_create_home = 0; } elsif ( ( exists $data->{'no_create_home'} && $data->{'no_create_home'} == 0 ) || ( exists $data->{'no-create-home'} && $data->{'no-create-home'} == 0 ) ) { $should_create_home = 1; } if ( !defined $uid ) { Rex::Logger::debug("User $user does not exists. Creating it now."); $cmd = "useradd "; if ( exists $data->{system} ) { $cmd .= " -r"; } } else { Rex::Logger::debug("User $user already exists. Updating..."); $cmd = "usermod "; } if ( exists $data->{uid} ) { $cmd .= " -u " . $data->{uid}; } if ( exists $data->{home} ) { $cmd .= " -d " . $data->{home}; } if ( $should_create_home && !defined $uid ) { #useradd mode $cmd .= " -m "; } if ( exists $data->{shell} ) { $cmd .= " -s " . $data->{shell}; } if ( exists $data->{comment} ) { $cmd .= " -c '" . $data->{comment} . "'"; } if ( exists $data->{expire} ) { $cmd .= " -e '" . $data->{expire} . "'"; } if ( exists $data->{groups} ) { my @groups = @{ $data->{groups} }; my $pri_group = shift @groups; $cmd .= " -g $pri_group"; if (@groups) { $cmd .= " -G " . join( ",", @groups ); } } my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write("$cmd $user\nexit \$?\n"); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? == 0 ) { Rex::Logger::debug("User $user created/updated."); } else { Rex::Logger::info( "Error creating/updating user $user", "warn" ); die("Error creating/updating user $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); if ( exists $data->{password} ) { Rex::Logger::debug("Changing password of $user."); $rnd_file = get_tmp_file; $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "usermod -p \$(encrypt -b 6 '" . $data->{password} . "') $user\nexit \$?\n" ); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error setting password for $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); } if ( exists $data->{crypt_password} ) { Rex::Logger::debug("Setting encrypted password of $user"); $rnd_file = get_tmp_file; $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write( "usermod -p '" . $data->{crypt_password} . "' $user\nexit \$?\n" ); $fh->close; i_run "/bin/sh $rnd_file"; if ( $? != 0 ) { die("Error setting password for $user"); } Rex::Interface::Fs->create()->unlink($rnd_file); } my $new_pw_md5 = md5("/etc/passwd"); if ( $new_pw_md5 eq $old_pw_md5 ) { return { changed => 0, ret => $self->get_uid($user), }; } else { return { changed => 1, ret => $self->get_uid($user), }, ; } } 1; Rex-1.3.3/lib/Rex/User/OpenWrt.pm0000644000175000017500000000316512572251052016324 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User::OpenWrt; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; require Rex::Commands; use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::Fs; use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Interface::Exec; use Rex::Helper::Path; use Rex::User::Linux; use base qw(Rex::User::Linux); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub get_user { my ( $self, $user ) = @_; Rex::Logger::debug("Getting information for $user"); my $o_data = i_run "perl -e 'print join(\";\", getpwnam(\"$user\"))'"; chomp $o_data; my @data = split( /;/, $o_data ); return ( name => $data[0], password => $data[1], uid => $data[2], gid => $data[3], comment => $data[6], home => $data[7], shell => $data[8], ); } sub user_groups { my ( $self, $user ) = @_; Rex::Logger::debug("Getting group membership of $user"); my $data_str = i_run "/usr/bin/id -Gn $user"; if ( $? != 0 ) { die("Error getting group list"); } my $wantarray = wantarray(); if ( defined $wantarray && !$wantarray ) { # arrayref return [ split( / /, $data_str ) ]; } return split( / /, $data_str ); } sub user_list { my $self = shift; Rex::Logger::debug("Getting user list"); my $data_str = i_run "cut -d':' -f1 /etc/passwd"; if ( $? != 0 ) { die("Error getting user list"); } return split( /\n/, $data_str ); } 1; Rex-1.3.3/lib/Rex/Test/0000755000175000017500000000000012572251052014364 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Test/Base/0000755000175000017500000000000012572251052015236 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Test/Base/has_service_stopped.pm0000644000175000017500000000104712572251052021627 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_service_stopped; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $service ) = @_; $self->ok( service( $service, "status" ) == 0, "Service $service stopped." ); } 1; Rex-1.3.3/lib/Rex/Test/Base/has_file.pm0000644000175000017500000000077512572251052017357 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_file; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $file ) = @_; $self->ok( is_file($file), "Found $file file." ); } 1; Rex-1.3.3/lib/Rex/Test/Base/has_package.pm0000644000175000017500000000147212572251052020026 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_package; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $package, $version ) = @_; my $pkg = Rex::Pkg->get; if ( $pkg->is_installed( $package, { version => $version } ) ) { $self->ok( 1, "Found package $package" . ( $version ? " at version $version" : "" ) ); return 1; } else { $self->ok( 0, "Found package $package" . ( $version ? " at version $version" : "" ) ); return 0; } } 1; Rex-1.3.3/lib/Rex/Test/Base/has_content.pm0000644000175000017500000000121512572251052020100 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_content; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $file, $test ) = @_; return $self->ok( 0, "has_content: $file not found" ) unless is_file($file); my $content = cat $file; $self->ok( ( $content =~ $test ) >= 1, "Content of $file contain $test." ); } 1; Rex-1.3.3/lib/Rex/Test/Base/has_stat.pm0000644000175000017500000000237112572251052017405 0ustar jenkinsjenkins# # (c) Robert Abraham # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_stat; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); use Rex::Commands::Fs; use Rex::Commands::User; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $path, $stats ) = @_; my %stat; eval { %stat = stat $path; }; if ($@) { $self->ok( 0, "has_stat: cannot stat $path." ); $self->diag($@); return; } if ( defined( $stats->{'owner'} ) ) { my $uid = get_uid( $stats->{'owner'} ); my $result = defined $uid ? $uid == $stat{'uid'} : 0; $self->ok( $result, "Owner of $path is $stats->{'owner'}" ); $self->diag("has_stat: get_uid failed for $stats->{'owner'}.") unless defined $uid; } if ( defined( $stats->{'group'} ) ) { my $gid = get_gid( $stats->{'group'} ); my $result = defined $gid ? $gid == $stat{'gid'} : 0; $self->ok( $result, "Group of $path is $stats->{'group'}" ); $self->diag("has_stat: get_gid failed for $stats->{'group'}.") unless defined $gid; } } 1; Rex-1.3.3/lib/Rex/Test/Base/has_service_running.pm0000644000175000017500000000104712572251052021631 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_service_running; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $service ) = @_; $self->ok( service( $service, "status" ) == 1, "Service $service running." ); } 1; Rex-1.3.3/lib/Rex/Test/Base/has_dir.pm0000644000175000017500000000101412572251052017201 0ustar jenkinsjenkins# # (c) Ferenc Erki , adjust GmbH # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test::Base::has_dir; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex -base; use base qw(Rex::Test::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); return $self; } sub run_test { my ( $self, $path ) = @_; $self->ok( is_dir($path), "Found $path directory." ); } 1; Rex-1.3.3/lib/Rex/Test/Base.pm0000644000175000017500000001050212572251052015572 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Test::Base - Basic Test Module =head1 DESCRIPTION This is a basic test module to test your code with the help of local VMs. You can place your tests in the "t" directory. =head1 EXAMPLE use Rex::Test::Base; use Data::Dumper; use Rex -base; test { my $t = shift; $t->name("ubuntu test"); $t->base_vm("http://box.rexify.org/box/ubuntu-server-12.10-amd64.ova"); $t->vm_auth(user => "root", password => "box"); $t->run_task("setup"); $t->has_package("vim"); $t->has_package("ntp"); $t->has_package("unzip"); $t->has_file("/etc/ntp.conf"); $t->has_service_running("ntp"); $t->has_content("/etc/passwd", qr{root:x:0:}ms); run "ls -l"; $t->ok($? == 0, "ls -l returns success."); $t->finish; }; 1; # last line =head1 METHODS =cut package Rex::Test::Base; use strict; use warnings; use base 'Test::Builder::Module'; our $VERSION = '1.3.3'; # VERSION require Rex::Commands; use Rex::Commands::Box; use Data::Dumper; use Carp; require Exporter; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(test); =head2 new(name => $test_name) Constructor if used in OO mode. my $test = Rex::Test::Base->new(name => "test_name"); =cut sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); my ( $pkg, $file ) = caller(0); $self->{name} ||= $file; $self->{redirect_port} = 2222; return $self; } =head2 name($name) The name of the test. A VM called $name will be created for each test. If the VM already exists, Rex will try to reuse it. =cut sub name { my ( $self, $name ) = @_; $self->{name} = $name; } =head2 vm_auth(%auth) Authentication options for the VM. It accepts the same parameters as Cauth()>. =cut sub vm_auth { my ( $self, %auth ) = @_; $self->{auth} = \%auth; } =head2 base_vm($vm) The URL to a base image to be used for the test VM. =cut sub base_vm { my ( $self, $vm ) = @_; $self->{vm} = $vm; } sub test(&) { my $code = shift; my $test = __PACKAGE__->new; $code->($test); } =head2 redirect_port($port) Redirect local $port to the VM's SSH port (default: 2222). =cut sub redirect_port { my ( $self, $port ) = @_; $self->{redirect_port} = $port; } =head2 run_task($task) The task to run on the test VM. You can run multiple tasks by passing an array reference. =cut sub run_task { my ( $self, $task ) = @_; my $box; box { $box = shift; $box->name( $self->{name} ); $box->url( $self->{vm} ); $box->network( 1 => { type => "nat", } ); $box->forward_port( ssh => [ $self->{redirect_port}, 22 ] ); $box->auth( %{ $self->{auth} } ); if ( ref $task eq 'ARRAY' ) { $box->setup(@$task); } else { $box->setup($task); } }; $self->{box} = $box; # connect to the machine Rex::connect( server => $box->ip, %{ $self->{auth} }, ); } sub ok($;$) { my ( $self, $test, $msg ) = @_; my $tb = Rex::Test::Base->builder; $tb->ok( $test, $msg ); } sub diag { my ( $self, $msg ) = @_; my $tb = Rex::Test::Base->builder; $tb->diag($msg); } sub finish { my $tb = Rex::Test::Base->builder; $tb->done_testing(); $tb->is_passing() ? print "PASS\n" : print "FAIL\n"; $tb->reset(); Rex::pop_connection(); } =head1 TEST METHODS =head2 has_content($file, $regexp) Test if the content of $file matches against $regexp. =head2 has_dir($path) Test if $path is present and is a directory. =head2 has_file($file) Test if $file is present. =head2 has_package($package, $version) Test if $package is installed, optionally at $version. =head2 has_service_running($service) Test if $service is running. =head2 has_service_stopped($service) Test if $service is stopped. =head2 has_stat($file, $stat) Test if $file has properties described in hash reference $stat. List of supported checks: =over 4 =item group =item owner =back =cut our $AUTOLOAD; sub AUTOLOAD { my $self = shift or return; ( my $method = $AUTOLOAD ) =~ s{.*::}{}; if ( $method eq "DESTROY" ) { return; } my $pkg = __PACKAGE__ . "::$method"; eval "use $pkg"; if ($@) { confess "Error loading $pkg. No such test method."; } my $p = $pkg->new; $p->run_test(@_); } 1; Rex-1.3.3/lib/Rex/Pkg/0000755000175000017500000000000012572251052014166 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Pkg/ALT.pm0000644000175000017500000000334612572251052015152 0ustar jenkinsjenkins# # Work with ALT Linux APT-RPM package management system # package Rex::Pkg::ALT; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Commands::Fs; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => '/usr/bin/apt-get -y install %s', install_version => '/usr/bin/apt-get -y install %s-%s', remove => '/usr/bin/apt-get -y remove %s', update_package_db => '/usr/bin/apt-get update', }; return $self; } sub get_installed { my ($self) = @_; my @lines = i_run '/usr/bin/rpm -qa --nodigest --qf "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}\n"'; my @pkg; for my $line (@lines) { if ( $line =~ m/^([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s(.*)$/ ) { push( @pkg, { name => $1, epoch => $2, version => $3, release => $4, arch => $5, } ); } } return @pkg; } sub add_repository { my ( $self, %data ) = @_; my $name = $data{"name"}; my $sign = $data{"sign_key"} || ""; my @arch = split( /, */, $data{"arch"} ); my $fh = file_write "/etc/apt/sources.list.d/$name.list"; $fh->write("# This file is managed by Rex\n"); foreach (@arch) { $fh->write( "rpm " . ( $sign ? "[" . $sign . "] " : "" ) . $data{"url"} . " " . $_ . " " . $data{"repository"} . "\n" ); } $fh->close; } sub rm_repository { my ( $self, $name ) = @_; unlink "/etc/apt/sources.list.d/$name.list"; } 1; Rex-1.3.3/lib/Rex/Pkg/Gentoo.pm0000644000175000017500000000622112572251052015760 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::Gentoo; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => 'emerge %s', install_version => 'emerge =%s-%s', update_system => 'emerge --update --deep --with-bdeps=y --newuse world', remove => 'emerge -C %s', update_package_db => 'emerge --sync', }; return $self; } sub bulk_install { my ( $self, $packages_aref, $option ) = @_; delete $option->{version}; # makes no sense to specify the same version for several packages $self->update( "@{$packages_aref}", $option ); return 1; } sub is_installed { my ( $self, $pkg, $option ) = @_; my $version = $option->{version}; $self->{short} = 0; Rex::Logger::debug( "Checking if $pkg" . ( $version ? "-$version" : "" ) . " is installed" ); my @pkg_info = grep { $_->{name} eq $pkg } $self->get_installed(); @pkg_info = grep { $_->{version} eq $version } @pkg_info if defined $version; unless (@pkg_info) { Rex::Logger::debug( "Couldn't find package by category/packagename, trying with packagename only" ); $self->{short} = 1; @pkg_info = grep { $_->{name} eq $pkg } $self->get_installed(); @pkg_info = grep { $_->{version} eq $version } @pkg_info if defined $version; } unless (@pkg_info) { Rex::Logger::debug( "$pkg" . ( $version ? "-$version" : "" ) . " is NOT installed." ); return 0; } Rex::Logger::debug( "$pkg" . ( $version ? "-$version" : "" ) . " is installed." ); return 1; } sub get_installed { my ($self) = @_; my $cut_cmd; if ( $self->{short} ) { $cut_cmd = "cut -d '/' -f6-"; } else { $cut_cmd = "cut -d '/' -f5-"; } # ,,stolen'' from epm my $pkgregex = '(.+?)' . # name '-(\d+(?:\.\d+)*\w*)' . # version, eg 1.23.4a '((?:(?:_alpha|_beta|_pre|_rc)\d*)?)' . # special suffix '((?:-r\d+)?)$'; # revision, eg r12 my @ret; for my $line ( i_run("ls -d /var/db/pkg/*/* | $cut_cmd") ) { my $r = qr{$pkgregex}; my ( $name, $version, $suffix, $revision ) = ( $line =~ $r ); push( @ret, { name => $name, version => $version, suffix => $suffix, release => $revision, } ); } return @ret; } sub add_repository { my ( $self, %data ) = @_; my $name = $data{"name"}; if ( can_run("layman") ) { i_run "layman -a $name"; } else { Rex::Logger::debug("You have to install layman, git and subversion."); die("Please install layman, git and subversion"); } } sub rm_repository { my ( $self, $name ) = @_; if ( can_run("layman") ) { i_run "layman -d $name"; } else { Rex::Logger::debug("You have to install layman, git and subversion."); die("Please install layman, git and subversion"); } } 1; Rex-1.3.3/lib/Rex/Pkg/Debian.pm0000644000175000017500000001003612572251052015706 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::Debian; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Commands::Fs; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => 'APT_LISTCHANGES_FRONTEND=none DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::=--force-confold -y install %s', install_version => 'APT_LISTCHANGES_FRONTEND=none DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::=--force-confold -y install %s=%s', update_system => 'APT_LISTCHANGES_FRONTEND=none DEBIAN_FRONTEND=noninteractive apt-get -y -qq upgrade', remove => 'apt-get -y remove %s', purge => 'dpkg --purge %s', update_package_db => 'apt-get -y update', }; return $self; } sub bulk_install { my ( $self, $packages_aref, $option ) = @_; delete $option->{version}; # makes no sense to specify the same version for several packages $self->update( "@{$packages_aref}", $option ); return 1; } sub get_installed { my ( $self, $pkg ) = @_; my @pkgs; my $dpkg_cmd = 'dpkg-query -W --showformat "\${Status} \${Package}|\${Version}|\${Architecture}\n"'; if ($pkg) { $dpkg_cmd .= " " . $pkg; } my @lines = i_run $dpkg_cmd; for my $line (@lines) { if ( $line =~ m/^install ok installed ([^\|]+)\|([^\|]+)\|(.*)$/ ) { push( @pkgs, { name => $1, version => $2, architecture => $3, } ); } } return @pkgs; } sub diff_package_list { my ( $self, $list1, $list2 ) = @_; my @old_installed = @{$list1}; my @new_installed = @{$list2}; my @modifications; # getting modifications of old packages OLD_PKG: for my $old_pkg (@old_installed) { NEW_PKG: for my $new_pkg (@new_installed) { if ( $old_pkg->{name} eq $new_pkg->{name} && $old_pkg->{architecture} eq $new_pkg->{architecture} ) { # flag the package as found in new package list, # to find removed and new ones. $old_pkg->{found} = 1; $new_pkg->{found} = 1; if ( $old_pkg->{version} ne $new_pkg->{version} ) { push @modifications, { %{$new_pkg}, action => 'updated' }; } next OLD_PKG; } } } # getting removed old packages push @modifications, map { $_->{action} = 'removed'; $_ } grep { !exists $_->{found} } @old_installed; # getting new packages push @modifications, map { $_->{action} = 'installed'; $_ } grep { !exists $_->{found} } @new_installed; map { delete $_->{found} } @modifications; return @modifications; } sub add_repository { my ( $self, %data ) = @_; my $name = $data{"name"}; my $fh = file_write "/etc/apt/sources.list.d/$name.list"; $fh->write("# This file is managed by Rex\n"); if ( exists $data{"arch"} ) { $fh->write( "deb [arch=" . $data{"arch"} . "] " . $data{"url"} . " " . $data{"distro"} . " " . $data{"repository"} . "\n" ); } else { $fh->write( "deb " . $data{"url"} . " " . $data{"distro"} . " " . $data{"repository"} . "\n" ); } if ( exists $data{"source"} && $data{"source"} ) { $fh->write( "deb-src " . $data{"url"} . " " . $data{"distro"} . " " . $data{"repository"} . "\n" ); } $fh->close; if ( exists $data{"key_url"} ) { i_run "wget -O - " . $data{"key_url"} . " | apt-key add -"; } if ( exists $data{"key_file"} ) { i_run "apt-key add $data{'key_file'}"; } if ( exists $data{"key_id"} && $data{"key_server"} ) { i_run "apt-key adv --keyserver " . $data{"key_server"} . " --recv-keys " . $data{"key_id"}; } } sub rm_repository { my ( $self, $name ) = @_; unlink "/etc/apt/sources.list.d/$name.list"; } 1; Rex-1.3.3/lib/Rex/Pkg/Ubuntu.pm0000644000175000017500000000067312572251052016014 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::Ubuntu; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Pkg::Debian; use Rex::Commands::Run; use Rex::Commands::File; use base qw(Rex::Pkg::Debian); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Pkg/NetBSD.pm0000644000175000017500000000237012572251052015605 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::NetBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => '. /etc/profile; /usr/sbin/pkg_add %s', install_version => '. /etc/profile; /usr/sbin/pkg_add %s-%s', remove => '/usr/sbin/pkg_delete %s', }; return $self; } sub remove { my ( $self, $pkg ) = @_; my ($pkg_found) = grep { $_->{"name"} eq "$pkg" } $self->get_installed(); my $pkg_version = $pkg_found->{"version"}; return $self->SUPER::remove("$pkg-$pkg_version"); } sub get_installed { my ($self) = @_; my @lines = i_run "/usr/sbin/pkg_info"; my @pkg; for my $line (@lines) { my ( $pkg_name_v, $descr ) = split( /\s/, $line, 2 ); my ( $pkg_name, $pkg_version ) = ( $pkg_name_v =~ m/^(.*)-(.*?)$/ ); push( @pkg, { name => $pkg_name, version => $pkg_version, } ); } return @pkg; } 1; Rex-1.3.3/lib/Rex/Pkg/SunOS.pm0000644000175000017500000000452312572251052015537 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::SunOS; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = {}; return $self; } sub update { my ( $self, $pkg, $option ) = @_; my $version = $option->{'version'} || ''; Rex::Logger::debug("Version option not supported."); Rex::Logger::debug("Installing $pkg / $version"); my $cmd = "pkgadd "; if ( !exists $option->{"source"} ) { die("You have to specify the source."); } $cmd .= " -a " . $option->{"adminfile"} if ( $option->{"adminfile"} ); $cmd .= " -r " . $option->{"responsefile"} if ( $option->{"responsefile"} ); $cmd .= " -d " . $option->{"source"}; $cmd .= " -n " . $pkg; my $f = i_run($cmd); unless ( $? == 0 ) { Rex::Logger::info( "Error installing $pkg.", "warn" ); Rex::Logger::debug($f); die("Error installing $pkg"); } Rex::Logger::debug("$pkg successfully installed."); return 1; } sub remove { my ( $self, $pkg, $option ) = @_; Rex::Logger::debug("Removing $pkg"); my $cmd = "pkgrm -n "; $cmd .= " -a " . $option->{"adminfile"} if ( $option->{"adminfile"} ); my $f = i_run( $cmd . " $pkg" ); unless ( $? == 0 ) { Rex::Logger::info( "Error removing $pkg.", "warn" ); Rex::Logger::debug($f); die("Error removing $pkg"); } Rex::Logger::debug("$pkg successfully removed."); return 1; } sub get_installed { my ($self) = @_; my @lines = i_run "pkginfo -l"; my ( @pkg, %current ); for my $line (@lines) { if ( $line =~ m/^$/ ) { push( @pkg, {%current} ); next; } if ( $line =~ m/PKGINST:\s+([^\s]+)/ ) { $current{"name"} = $1; next; } if ( $line =~ m/VERSION:\s+([^\s]+)/ ) { my ( $version, $rev ) = split( /,/, $1 ); $current{"version"} = $version; $rev =~ s/^REV=// if ($rev); $current{"revision"} = $rev; next; } if ( $line =~ m/STATUS:\s+(.*?)$/ ) { $current{"status"} = ( $1 eq "completely installed" ? "installed" : $1 ); next; } } return @pkg; } 1; Rex-1.3.3/lib/Rex/Pkg/SuSE.pm0000644000175000017500000000371612572251052015352 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::SuSE; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => 'zypper -n install %s', install_version => 'zypper -n install $pkg-%s', update_system => 'zypper -n up', remove => 'zypper -n remove %s', update_package_db => 'zypper --no-gpg-checks -n ref -fd', }; return $self; } sub bulk_install { my ( $self, $packages_aref, $option ) = @_; delete $option->{version}; # makes no sense to specify the same version for several packages $self->update( "@{$packages_aref}", $option ); return 1; } sub get_installed { my ($self) = @_; my @lines = i_run 'rpm -qa --nosignature --nodigest --qf "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}\n"'; my @pkg; for my $line (@lines) { if ( $line =~ m/^([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s(.*)$/ ) { push( @pkg, { name => $1, epoch => $2, version => $3, release => $4, arch => $5, } ); } } return @pkg; } sub add_repository { my ( $self, %data ) = @_; i_run "zypper addrepo -f -n " . $data{"name"} . " " . $data{"url"} . " " . $data{"name"}; if ( $? == 4 ) { if ( Rex::Config->get_do_reporting ) { return { changed => 0 }; } } if ( $? != 0 ) { die( "Error adding repository " . $data{name} ); } } sub rm_repository { my ( $self, $name ) = @_; i_run "zypper removerepo $name"; if ( $? != 0 ) { die("Error removing repository $name"); } if ( Rex::Config->get_do_reporting ) { return { changed => 1 }; } } 1; Rex-1.3.3/lib/Rex/Pkg/FreeBSD.pm0000644000175000017500000000461312572251052015742 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::FreeBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); # Check if pkg is actually bootstraped (installed and activated) i_run "pkg -N"; if ( $? != 0 ) { i_run "pkg bootstrap", env => { 'ASSUME_ALWAYS_YES' => 'true' }; } $self->{commands} = { install => 'pkg install -q -y %s', install_version => 'pkg install -q -y %s', remove => 'pkg remove -q -y %s', query => 'pkg info', update_package_db => 'pkg update -q -f', # pkg can't update system yet, only packages update_system => 'pkg upgrade -q -y', }; return $self; } sub bulk_install { my ( $self, $packages_aref, $option ) = @_; # makes no sense to specify the same version for several packages delete $option->{version}; $self->update( "@{$packages_aref}", $option ); return 1; } sub remove { my ( $self, $pkg ) = @_; my ($pkg_found) = grep { $_->{"name"} eq "$pkg" } $self->get_installed(); my $pkg_version = $pkg_found->{"version"}; return $self->SUPER::remove("$pkg-$pkg_version"); } sub is_installed { my ( $self, $pkg, $option ) = @_; my $version = $option->{version}; Rex::Logger::debug( "Checking if $pkg" . ( $version ? "-$version" : "" ) . " is installed" ); # pkg info -e allow get quick answer about is pkg installed or not. my $command = $self->{commands}->{query} . " -e $pkg" . ( $version ? "-$version" : "" ); i_run $command; if ( $? != 0 ) { Rex::Logger::debug( "$pkg" . ( $version ? "-$version" : "" ) . " is NOT installed." ); return 0; } Rex::Logger::debug( "$pkg" . ( $version ? "-$version" : "" ) . " is installed." ); return 1; } sub get_installed { my ($self) = @_; my @lines = i_run $self->{commands}->{query}; my @pkg; for my $line (@lines) { my ( $pkg_name_v, $descr ) = split( /\s/, $line, 2 ); my ( $pkg_name, $pkg_version ) = ( $pkg_name_v =~ m/^(.*)-(.*?)$/ ); push( @pkg, { name => $pkg_name, version => $pkg_version, } ); } return @pkg; } 1; Rex-1.3.3/lib/Rex/Pkg/Base.pm0000644000175000017500000001143712572251052015404 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::Base; use strict; use warnings; use Rex::Helper::Run; use Rex::Interface::Exec; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub is_installed { my ( $self, $pkg, $option ) = @_; my $version = $option->{version}; Rex::Logger::debug( "Checking if $pkg" . ( $version ? "-$version" : "" ) . " is installed" ); my @pkg_info = grep { $_->{name} eq $pkg } $self->get_installed(); @pkg_info = grep { $_->{version} eq $version } @pkg_info if defined $version; unless (@pkg_info) { Rex::Logger::debug( "$pkg" . ( $version ? "-$version" : "" ) . " is NOT installed." ); return 0; } Rex::Logger::debug( "$pkg" . ( $version ? "-$version" : "" ) . " is installed." ); return 1; } sub install { my ( $self, $pkg, $option ) = @_; if ( $self->is_installed( $pkg, $option ) ) { Rex::Logger::info("$pkg is already installed"); return 1; } $self->update( $pkg, $option ); return 1; } sub update { my ( $self, $pkg, $option ) = @_; my $version = $option->{'version'} || ''; Rex::Logger::debug( "Installing $pkg" . ( $version ? "-$version" : "" ) ); my $cmd = sprintf $self->{commands}->{install}, $pkg; if ( exists $option->{version} ) { $cmd = sprintf $self->{commands}->{install_version}, $pkg, $option->{version}; } my $f = i_run $cmd; unless ( $? == 0 ) { Rex::Logger::info( "Error installing $pkg.", "warn" ); Rex::Logger::debug($f); die("Error installing $pkg"); } Rex::Logger::debug("$pkg successfully installed."); return 1; } sub update_system { my ($self) = @_; if ( !exists $self->{commands}->{update_system} ) { Rex::Logger::debug("Not supported under this OS"); return; } my $cmd = $self->{commands}->{update_system}; my $f = i_run $cmd; unless ( $? == 0 ) { Rex::Logger::info( "Error updating system.", "warn" ); Rex::Logger::debug($f); die("Error updating system"); } Rex::Logger::debug("System successfully updated."); return 1; } sub remove { my ( $self, $pkg ) = @_; Rex::Logger::debug("Removing $pkg"); my $cmd = sprintf $self->{commands}->{remove}, $pkg; my $f = i_run $cmd; unless ( $? == 0 ) { Rex::Logger::info( "Error removing $pkg.", "warn" ); Rex::Logger::debug($f); die("Error removing $pkg"); } Rex::Logger::debug("$pkg successfully removed."); return 1; } sub purge { my ( $self, $pkg ) = @_; return 1 if ( !exists $self->{commands}->{purge} ); Rex::Logger::debug("Purging $pkg"); my $cmd = sprintf $self->{commands}->{purge}, $pkg; my $f = i_run $cmd; unless ( $? == 0 ) { Rex::Logger::info( "Error purging $pkg.", "warn" ); Rex::Logger::debug($f); die("Error purging $pkg"); } Rex::Logger::debug("$pkg successfully purged."); return 1; } sub update_pkg_db { my ($self) = @_; if ( !exists $self->{commands}->{update_package_db} ) { Rex::Logger::debug("Not supported under this OS"); return; } my $cmd = $self->{commands}->{update_package_db}; i_run $cmd; if ( $? != 0 ) { die("Error updating package database"); } } sub bulk_install { Rex::Logger::info( "Installing bulk packages not supported on this platform. Falling back to one by one method", "warn" ); my ( $self, $packages_aref, $option ) = @_; for my $pkg_to_install ( @{$packages_aref} ) { $self->install( $pkg_to_install, $option ); } return 1; } sub add_repository { my ( $self, %data ) = @_; Rex::Logger::debug("Not supported under this OS"); } sub rm_repository { my ( $self, $name ) = @_; Rex::Logger::debug("Not supported under this OS"); } sub diff_package_list { my ( $self, $list1, $list2 ) = @_; my @old_installed = @{$list1}; my @new_installed = @{$list2}; my @modifications; # getting modifications of old packages OLD_PKG: for my $old_pkg (@old_installed) { NEW_PKG: for my $new_pkg (@new_installed) { if ( $old_pkg->{name} eq $new_pkg->{name} ) { # flag the package as found in new package list, # to find removed and new ones. $old_pkg->{found} = 1; $new_pkg->{found} = 1; if ( $old_pkg->{version} ne $new_pkg->{version} ) { push @modifications, { %{$new_pkg}, action => 'updated' }; } next OLD_PKG; } } } # getting removed old packages push @modifications, map { $_->{action} = 'removed'; $_ } grep { !exists $_->{found} } @old_installed; # getting new packages push @modifications, map { $_->{action} = 'installed'; $_ } grep { !exists $_->{found} } @new_installed; map { delete $_->{found} } @modifications; return @modifications; } 1; Rex-1.3.3/lib/Rex/Pkg/OpenBSD.pm0000644000175000017500000000067412572251052015765 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::OpenBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Commands::File; use Rex::Pkg::NetBSD; use base qw(Rex::Pkg::NetBSD); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Pkg/SunOS/0000755000175000017500000000000012572251052015175 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Pkg/SunOS/pkg.pm0000644000175000017500000000223412572251052016315 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::SunOS::pkg; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::SunOS; use base qw(Rex::Pkg::SunOS); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => 'pkg install -q --accept %s', install_version => 'pkg install -q --accept %s', remove => 'pkg uninstall -r -q %s', update_package_db => 'pkg refresh', }; return $self; } sub get_installed { my ($self) = @_; my @lines = i_run "pkg info -l"; my @pkg; my ( $version, $name ); for my $line (@lines) { if ( $line =~ m/^$/ ) { push( @pkg, { name => $name, version => $version, } ); next; } if ( $line =~ m/Name: .*\/(.*?)$/ ) { $name = $1; next; } if ( $line =~ m/Version: (.*)$/ ) { $version = $1; next; } } return @pkg; } 1; Rex-1.3.3/lib/Rex/Pkg/SunOS/OpenCSW.pm0000644000175000017500000000142312572251052017011 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::SunOS::OpenCSW; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::SunOS; use base qw(Rex::Pkg::SunOS); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => $self->_pkgutil() . ' --yes -i %s', install_version => $self->_pkgutil() . ' --yes -i %s', remove => $self->_pkgutil() . ' --yes -r %s', update_package_db => $self->_pkgutil() . " -U", }; return $self; } sub _pkgutil { return "/opt/csw/bin/pkgutil"; } 1; Rex-1.3.3/lib/Rex/Pkg/OpenWrt.pm0000644000175000017500000000362012572251052016123 0ustar jenkinsjenkins# OpenWrt.pm # # Copyright 2013 Ferenc Erki # # OpenWrt package management module for (R)?ex # based on Rex::Pkg::Debian package Rex::Pkg::OpenWrt; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => 'opkg install %s', install_version => 'opkg install %s', remove => 'opkg remove %s', update_package_db => 'opkg update', }; return $self; } sub bulk_install { my ( $self, $packages_aref, $option ) = @_; delete $option->{version}; # makes no sense to specify the same version for several packages $self->update( "@{$packages_aref}", $option ); return 1; } sub update_system { my ($self) = @_; my @pkgs; my @lines = i_run("opkg list-upgradable"); for my $line (@lines) { if ( $line =~ m/^(.*) - .* - .*$/ ) { push( @pkgs, $1 ); } } my $packages_to_upgrade = join( " ", @pkgs ); i_run( "opkg upgrade " . $packages_to_upgrade ); } sub get_installed { my ( $self, $pkg ) = @_; my @pkgs; my $opkg_cmd = 'opkg list-installed'; if ($pkg) { $opkg_cmd .= ' | grep "^' . $pkg . ' "'; } my @lines = i_run $opkg_cmd; for my $line (@lines) { if ( $line =~ m/^(.*) - (.*)$/ ) { push( @pkgs, { name => $1, version => $2, } ); } } return @pkgs; } sub add_repository { my ( $self, %data ) = @_; append_if_no_such_line "/etc/opkg.conf", "src/gz " . $data{"name"} . " " . $data{"url"}, $data{"name"}, $data{"url"}; } sub rm_repository { my ( $self, $name ) = @_; delete_lines_matching "/etc/opkg.conf" => "src/gz " . $name . " "; } 1; Rex-1.3.3/lib/Rex/Pkg/Redhat.pm0000644000175000017500000000452312572251052015737 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::Redhat; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Commands::Fs; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => $self->_yum('-y install %s'), install_version => $self->_yum('-y install %s-%s'), update_system => $self->_yum("-y upgrade"), remove => $self->_yum('-y erase %s'), update_package_db => $self->_yum("clean all") . " ; " . $self->_yum("makecache"), }; return $self; } sub bulk_install { my ( $self, $packages_aref, $option ) = @_; delete $option->{version}; # makes no sense to specify the same version for several packages $self->update( "@{$packages_aref}", $option ); return 1; } sub get_installed { my ($self) = @_; my @lines = i_run 'rpm -qa --nosignature --nodigest --qf "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}\n"'; my @pkg; for my $line (@lines) { if ( $line =~ m/^([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s(.*)$/ ) { push( @pkg, { name => $1, epoch => $2, version => $3, release => $4, arch => $5, } ); } } return @pkg; } sub add_repository { my ( $self, %data ) = @_; my $name = $data{"name"}; my $desc = $data{"description"} || $data{"name"}; my $fh = file_write "/etc/yum.repos.d/$name.repo"; $fh->write("# This file is managed by Rex\n"); $fh->write("[$name]\n"); $fh->write("name=$desc\n"); $fh->write( "baseurl=" . $data{"url"} . "\n" ); $fh->write("enabled=1\n"); $fh->write( "gpgkey=" . $data{"gpgkey"} . "\n" ) if defined $data{"gpgkey"}; $fh->write( "gpgcheck=" . $data{"gpgcheck"} . "\n" ) if defined $data{"gpgcheck"}; $fh->close; } sub rm_repository { my ( $self, $name ) = @_; unlink "/etc/yum.repos.d/$name.repo"; } sub _yum { my ( $self, @cmd ) = @_; my $str; if ($Rex::Logger::debug) { $str = join( ' ', "yum ", @cmd ); } else { $str = join( ' ', "yum -q ", @cmd ); } return $str; } 1; Rex-1.3.3/lib/Rex/Pkg/Mageia.pm0000644000175000017500000000302612572251052015710 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Pkg::Mageia; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Pkg::Base; use base qw(Rex::Pkg::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { install => 'urpmi --auto --quiet %s', install_version => 'urpmi --auto --quiet %s', update_system => 'urpmi --auto --quiet --auto-update', remove => 'urpme --auto %s', update_package_db => 'urpmi.update -a', }; return $self; } sub get_installed { my ($self) = @_; my @lines = i_run 'rpm -qa --nosignature --nodigest --qf "%{NAME} %|EPOCH?{%{EPOCH}}:{0}| %{VERSION} %{RELEASE} %{ARCH}\n"'; my @pkg; for my $line (@lines) { if ( $line =~ m/^([^\s]+)\s([^\s]+)\s([^\s]+)\s([^\s]+)\s(.*)$/ ) { push( @pkg, { name => $1, epoch => $2, version => $3, release => $4, arch => $5, } ); } } return @pkg; } sub add_repository { my ( $self, %data ) = @_; my $name = $data{"name"}; i_run "urpmi.addmedia $name " . $data{"url"}; if ( $? != 0 ) { die("Error adding repository $name"); } } sub rm_repository { my ( $self, $name ) = @_; i_run "urpmi.removemedia $name"; if ( $? != 0 ) { die("Error removing repository $name"); } } 1; Rex-1.3.3/lib/Rex/Require.pm0000644000175000017500000000222412572251052015417 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Require; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Carp; require Rex::Logger; # some code borrowed from: UNIVERSAL::require (neilb) BEGIN { require UNIVERSAL; } my $module_name_rx = qr/[A-Z_a-z][0-9A-Z_a-z]*(?:::[0-9A-Z_a-z]+)*/; sub UNIVERSAL::require { my ( $module, %option ) = @_; $option{level} ||= 0; my ( $caller_package, $caller_file, $caller_line ) = caller( $option{level} ); my $file = $module . ".pm"; $file =~ s/::/\//g; # check if module is already loaded. return eval { 1 } if $INC{$file}; my $ret = eval "CORE::require(\$file)"; if ( !$ret ) { confess $@; } return $ret; } sub UNIVERSAL::use { my ( $module, @imports ) = @_; $module->require( level => 1 ); my ( $caller_package, $caller_file, $caller_line ) = caller(0); eval "package $caller_package;\n\$module->import(\@imports);\n1;"; if ($@) { confess $@; } return 1; } sub UNIVERSAL::is_loadable { my ($module) = @_; eval { $module->require; 1; }; if ($@) { return 0; } return 1; } 1; Rex-1.3.3/lib/Rex/Cloud.pm0000644000175000017500000000177612572251052015064 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Cloud; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); use Rex::Logger; @EXPORT = qw(get_cloud_service); my %CLOUD_SERVICE; sub register_cloud_service { my ( $class, $service_name, $service_class ) = @_; $CLOUD_SERVICE{"\L$service_name"} = $service_class; return 1; } sub register_cloud_provider { my $class = shift; $class->register_cloud_service(@_); } sub get_cloud_service { my ($service) = @_; if ( exists $CLOUD_SERVICE{"\L$service"} ) { eval "use " . $CLOUD_SERVICE{"\L$service"}; my $mod = $CLOUD_SERVICE{"\L$service"}; return $mod->new; } else { eval "use Rex::Cloud::$service"; if ($@) { Rex::Logger::info("Cloud Service $service not supported."); Rex::Logger::info($@); return 0; } my $mod = "Rex::Cloud::$service"; return $mod->new; } } 1; Rex-1.3.3/lib/Rex/Constants.pm0000644000175000017500000000101512572251052015754 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=3 sw=3 tw=0: # vim: set expandtab: package Rex::Constants; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Rex::Exporter; use base qw(Rex::Exporter); use vars qw(@EXPORT); @EXPORT = qw(present absent latest running started stopped); sub present { return "present"; } sub absent { return "absent"; } sub latest { return "latest"; } sub running { return "running"; } sub started { return "started"; } sub stopped { return "stopped"; } 1; Rex-1.3.3/lib/Rex/Template/0000755000175000017500000000000012572251052015220 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Template/NG.pm0000644000175000017500000001663312572251052016073 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Template::NG; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->_init(); return $self; } sub _init { my ($self) = @_; $self->{__output__} = ""; $self->{__code__} = ""; $self->{__raw_data__} = ""; } sub parse { my $self = shift; my $c = shift; my %in_vars; $self->_init(); if ( ref $_[0] eq "HASH" ) { %in_vars = %{ +shift }; } else { %in_vars = @_; } my %vars; for my $key ( keys %in_vars ) { my $new_key = $key; $new_key =~ s/[^a-zA-Z0-9_]/_/gms; $vars{$new_key} = $in_vars{$key}; } # some backward compat. to old template module. $c =~ s/\$::([a-zA-Z0-9_]+)/_replace_var($1, \%vars)/egms; my $code = ""; my $var_data = ' return sub { my ( $self, '; my @code_values; for my $var ( keys %vars ) { $var_data .= '$' . $var . ", \n"; push( @code_values, $vars{$var} ); } $var_data .= '$this_is_really_nothing) = @_;'; $var_data .= "\n"; $code = $var_data; $code .= $self->_parse($c); $code .= "\n}"; my $idx_c = 1; for my $l ( split( /\n/, $code ) ) { $idx_c++; $l ||= ""; Rex::Logger::debug("$idx_c. $l"); } $self->{__code__} = $code; $self->{__raw_data__} = $c; no warnings; my $tpl_code = eval($code); use warnings; if ($@) { my $error = $@; my ($error_line) = ( $error =~ m/line (\d+)[\.,]/ ); my @code_lines = split( /\n/, $code ); my @raw_lines = split( /\n/, $c ); my $idx = $error_line - 5; for my $l ( @code_lines[ $error_line - 5 .. $error_line + 5 ] ) { $idx++; $l ||= ""; Rex::Logger::debug("$idx. $l"); } my $template_line = 0; my $add_to_error_line = -1; # search the error line Rex::Logger::debug("Template-Error-Line: $error_line"); for ( my $bi = $error_line - 1 ; $bi >= 0 ; $bi-- ) { if ( $code_lines[$bi] =~ m/^# LINE: (\d+)$/ ) { $template_line = $1 + $add_to_error_line; last; } $add_to_error_line++; } if ( !$template_line ) { die "Uncatchable error in template: $error ($error_line)"; } my $start_part = $template_line - 5; $start_part = 0 if $start_part <= 0; my $end_part = $template_line + 5; $end_part = scalar @raw_lines if $end_part > scalar @raw_lines; my $idx_t = $start_part; for my $l ( @raw_lines[ $start_part .. $end_part ] ) { $idx_t++; $l ||= ""; Rex::Logger::info("$idx_t. $l"); } my $tpl_error = $error; $tpl_error =~ s/at \(eval \d+\) line \d+/at template line $template_line/; if ( $error =~ m/Global symbol "([^"]+)" requires explicit package name/ ) { $tpl_error = "Unknown variable name $1 in code line: ,,$raw_lines[$template_line-1]'' line: $template_line.\nOriginal Error:\n$error\n"; } # internal parsing error, maybe runaway line without ";" elsif ( $raw_lines[ $template_line - 2 ] =~ m/^%/ && $raw_lines[ $template_line - 2 ] !~ m/[;{("']/ ) { Rex::Logger::debug( "Template Error in compiled line: $code_lines[$error_line-1]"); Rex::Logger::info( "Template Error somewhere around: $raw_lines[$template_line-2]", "error" ); my $template_line_ = $template_line - 1; $tpl_error = "Maybe missing <<;, {, (, \" or '>> in code line: ,,$raw_lines[$template_line-2]'' line $template_line_.\nOriginal Error:\n$error\n"; } else { $tpl_error = "Failed parsing template. Unkown error near $template_line.\nOriginal Error:\n$error\n"; } die $tpl_error; } $tpl_code->( $self, @code_values ); return $self->{__output__}; } sub __out { my ( $self, $str ) = @_; $self->{__output__} .= $str; } sub _parse { my ( $self, $c ) = @_; my $parsed = ""; my @chars = split( //, $c ); my $begin_line = 0; my $code_line = 0; my $code_block = 0; my $code_block_output = 0; my $current_char_idx = -1; my $line_count = 1; my $string_open = 0; my $skip_next = 0; my $skip_next_newline = 0; for my $curr_char (@chars) { $current_char_idx++; if ($skip_next) { $skip_next = 0; next; } my $prev_char = $chars[ $current_char_idx - 1 ] || ""; my $next_char = $chars[ $current_char_idx + 1 ] || ""; if ( $skip_next_newline && $curr_char eq "\n" ) { $skip_next_newline = 0; $curr_char = ""; } if ( $curr_char eq "\n" && $prev_char ne "\n" ) { # count lines, for error messages $line_count++; $parsed .= $curr_char; if ($string_open) { $parsed .= "});\n"; } # reset vars $code_line = 0; $string_open = 0; next; } if ( $curr_char eq "\n" && $prev_char eq "\n" ) { $parsed .= "\$self->__out(q{\n});\n"; $line_count++; next; } if ( $curr_char eq "-" && $next_char eq "%" && ( $prev_char eq " " || $prev_char eq "\n" ) && $chars[ $current_char_idx + 2 ] eq ">" ) { # skip "-" of -%> sequence $skip_next_newline = 1; next; } # catch code line # % some code if ( !$code_block && ( $prev_char eq "\n" || $current_char_idx == 0 ) # first line or new line && $curr_char eq "%" && $next_char eq " " # code block, and no % char escape sequence ) { $code_line = 1; $parsed .= "\n# LINE: $line_count\n"; next; } # catch '<% ' ... if ( $prev_char eq "<" && $curr_char eq "%" && ( $next_char eq " " || $next_char eq "\n" ) ) { $code_block = 1; if ($string_open) { $parsed .= "});\n"; $string_open = 0; } $parsed .= "\n# LINE: $line_count\n"; next; } # catch ' %>' if ( $code_block && ( ( $code_block_output || $prev_char eq " " ) || $prev_char eq "\n" || $prev_char eq "-" ) && $curr_char eq "%" && $next_char eq ">" ) { $code_block = 0; if ($code_block_output) { $parsed .= ");\n"; $code_block_output = 0; } $string_open = 1; $parsed .= "\n\$self->__out(q{"; next; } # catch '<%=' if ( $prev_char eq "<" && $curr_char eq "%" && $next_char eq "=" ) { $code_block = 1; $code_block_output = 1; if ($string_open) { $parsed .= "});\n"; } $parsed .= "\n# LINE: $line_count\n"; $parsed .= "\$self->__out("; $skip_next = 1; next; } if ( $code_line || $code_block ) { $parsed .= $curr_char; next; } if ( !$string_open ) { $string_open = 1; $parsed .= '$self->__out(q{'; } # don't catch opening < if ( $curr_char eq "<" && $next_char eq "%" ) { next; } # don't catch closing > if ( $curr_char eq ">" && $prev_char eq "%" ) { next; } # escaping of % sign if ( $curr_char eq "%" && $prev_char eq "%" ) { next; } $parsed .= $curr_char =~ m/[{}]/ ? "\\$curr_char" : $curr_char; } if ($string_open) { $parsed .= "});\n"; } return $parsed; } sub _replace_var { my ( $var, $t_vars ) = @_; if ( exists $t_vars->{$var} ) { return '$' . $var; } else { return '$::' . $var; } } 1; Rex-1.3.3/lib/Rex/CMDB/0000755000175000017500000000000012572251052014152 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/CMDB/YAML.pm0000644000175000017500000000514112572251052015253 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::CMDB::YAML; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use base qw(Rex::CMDB::Base); use Rex::Commands -no => [qw/get/]; use Rex::Logger; use YAML; use Data::Dumper; use Hash::Merge qw/merge/; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; $self->{merger} = Hash::Merge->new(); if ( !defined $self->{merge_behavior} ) { $self->{merger}->specify_behavior( { SCALAR => { SCALAR => sub { $_[0] }, ARRAY => sub { $_[0] }, HASH => sub { $_[0] }, }, ARRAY => { SCALAR => sub { $_[0] }, ARRAY => sub { $_[0] }, HASH => sub { $_[0] }, }, HASH => { SCALAR => sub { $_[0] }, ARRAY => sub { $_[0] }, HASH => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) }, }, }, 'REX_DEFAULT', ); # first found value always wins $self->{merger}->set_behavior('REX_DEFAULT'); } else { if ( ref $self->{merge_behavior} eq 'HASH' ) { $self->{merger} ->specify_behavior( $self->{merge_behavior}, 'USER_DEFINED' ); $self->{merger}->set_behavior('USER_DEFINED'); } else { $self->{merger}->set_behavior( $self->{merge_behavior} ); } } bless( $self, $proto ); return $self; } sub get { my ( $self, $item, $server ) = @_; # first open $server.yml # second open $environment/$server.yml # third open $environment/default.yml # forth open default.yml my (@files); if ( !ref $self->{path} ) { my $env = environment; my $yaml_path = $self->{path}; @files = ( "$yaml_path/$env/$server.yml", "$yaml_path/$env/default.yml", "$yaml_path/$server.yml", "$yaml_path/default.yml" ); } elsif ( ref $self->{path} eq "CODE" ) { @files = $self->{path}->( $self, $item, $server ); } elsif ( ref $self->{path} eq "ARRAY" ) { @files = @{ $self->{path} }; } @files = map { $self->_parse_path($_) } @files; my $all = {}; Rex::Logger::debug( Dumper( \@files ) ); for my $file (@files) { Rex::Logger::debug("CMDB - Opening $file"); if ( -f $file ) { #my $content = eval { local ( @ARGV, $/ ) = ($file); <>; }; #$content .= "\n"; # for safety my $ref = YAML::LoadFile($file); $all = $self->{merger}->merge( $all, $ref ); } } if ( !$item ) { return $all; } else { return $all->{$item}; } Rex::Logger::debug("CMDB - no item ($item) found"); return; } 1; Rex-1.3.3/lib/Rex/CMDB/Base.pm0000644000175000017500000000064612572251052015370 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::CMDB::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::Path; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub _parse_path { my ( $self, $path ) = @_; return parse_path($path); } 1; Rex-1.3.3/lib/Rex/Cron.pm0000644000175000017500000000073712572251052014713 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Cron; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Gather; sub create { my ($class) = @_; my $type = "Linux"; if ( operating_system_is("SunOS") ) { $type = "SunOS"; } my $klass = "Rex::Cron::$type"; eval "use $klass;"; if ($@) { die("Error creating cron class: $klass\n$@"); } return $klass->new; } 1; Rex-1.3.3/lib/Rex/Value.pm0000644000175000017500000000065712572251052015067 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: # # this is a simple helper class for the get() function package Rex::Value; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub value { my ($self) = @_; return $self->{value}; } 1; Rex-1.3.3/lib/Rex/PkgConf.pm0000644000175000017500000000267112572251052015340 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::PkgConf; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Config; use Rex::Commands::Gather; use Rex::Hardware; use Rex::Hardware::Host; use Rex::Logger; my %PKG_PROVIDER; sub register_package_provider { my ( $class, $service_name, $service_class ) = @_; $PKG_PROVIDER{"\L$service_name"} = $service_class; return 1; } sub get { my ($self) = @_; my %_host = %{ Rex::Hardware::Host->get() }; my $host = {%_host}; my $pkg_provider_for = Rex::Config->get("package_provider") || {}; if ( is_redhat() ) { $host->{"operatingsystem"} = "Redhat"; } my $class = "Rex::PkgConf::" . $host->{"operatingsystem"}; my $provider; if ( ref($pkg_provider_for) && exists $pkg_provider_for->{ $host->{"operatingsystem"} } ) { $provider = $pkg_provider_for->{ $host->{"operatingsystem"} }; $class .= "::$provider"; } elsif ( exists $PKG_PROVIDER{$pkg_provider_for} ) { $class = $PKG_PROVIDER{$pkg_provider_for}; } Rex::Logger::debug("Using $class for package management"); eval "use $class"; if ($@) { if ($provider) { Rex::Logger::info( "Provider not supported (" . $provider . ")" ); } else { Rex::Logger::info( "OS not supported (" . $host->{"operatingsystem"} . ")" ); } die("OS/Provider not supported"); } return $class->new; } 1; Rex-1.3.3/lib/Rex/Task.pm0000644000175000017500000004205612572251052014714 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Task - The Task Object =head1 DESCRIPTION The Task Object. Typically you only need this class if you want to manipulate tasks after their initial creation. =head1 SYNOPSIS use Rex::Task my $task = Rex::Task->new(name => "testtask"); $task->set_server("remoteserver"); $task->set_code(sub { say "Hello"; }); $task->modify("no_ssh", 1); =head1 METHODS =cut package Rex::Task; use strict; use warnings; use Data::Dumper; use Time::HiRes qw(time); our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::TaskList; use Rex::Interface::Connection; use Rex::Interface::Executor; use Rex::Group::Entry::Server; use Rex::Profiler; use Rex::Hardware; use Rex::Interface::Cache; use Rex::Report; use Rex::Helper::Run; use Rex::Helper::Path; use Rex::Notify; use Carp; require Rex::Commands; require Rex::Args; =head2 new This is the constructor. $task = Rex::Task->new( func => sub { some_code_here }, server => [ @server ], desc => $description, no_ssh => $no_ssh, hidden => $hidden, auth => { user => $user, password => $password, private_key => $private_key, public_key => $public_key, }, before => [sub {}, sub {}, ...], after => [sub {}, sub {}, ...], around => [sub {}, sub {}, ...], before_task_start => [sub {}, sub {}, ...], after_task_finished => [sub {}, sub {}, ...], name => $task_name, executor => Rex::Interface::Executor->create, ); =cut sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); if ( !exists $self->{name} ) { die("You have to define a task name."); } $self->{no_ssh} ||= 0; $self->{func} ||= sub { }; $self->{executor} ||= Rex::Interface::Executor->create; $self->{connection} = undef; # set to true as default if ( !exists $self->{exit_on_connect_fail} ) { $self->{exit_on_connect_fail} = 1; } return $self; } =head2 connection Returns the current connection object. =cut sub connection { my ($self) = @_; if ( !exists $self->{connection} || !$self->{connection} ) { $self->{connection} = Rex::Interface::Connection->create( $self->get_connection_type ); } $self->{connection}; } =head2 executor Returns the current executor object. =cut sub executor { my ($self) = @_; $self->{executor}->set_task($self); return $self->{executor}; } =head2 hidden Returns true if the task is hidden. (Should not be displayed on ,,rex -T''.) =cut sub hidden { my ($self) = @_; return $self->{hidden}; } =head2 server Returns the servers on which the task should be executed as an ArrayRef. =cut sub server { my ($self) = @_; my @server = @{ $self->{server} }; my @ret = (); if ( ref( $server[-1] ) eq "HASH" ) { Rex::deprecated( undef, "0.40", "Defining extra credentials within the task creation is deprecated.", "Please use set auth => task => 'taskname' instead." ); # use extra defined credentials my $data = pop(@server); $self->set_auth( "user", $data->{'user'} ); $self->set_auth( "password", $data->{'password'} ); if ( exists $data->{"private_key"} ) { $self->set_auth( "private_key", $data->{"private_key"} ); $self->set_auth( "public_key", $data->{"public_key"} ); } } if ( ref( $self->{server} ) eq "ARRAY" && scalar( @{ $self->{server} } ) > 0 ) { for my $srv ( @{ $self->{server} } ) { if ( ref($srv) eq "CODE" ) { push( @ret, &$srv() ); } else { if ( ref $srv && $srv->isa("Rex::Group::Entry::Server") ) { push( @ret, $srv->get_servers ); } else { push( @ret, $srv ); } } } } elsif ( ref( $self->{server} ) eq "CODE" ) { push( @ret, &{ $self->{server} }() ); } else { push( @ret, Rex::Group::Entry::Server->new( name => "" ) ); } return [@ret]; } =head2 set_server(@server) With this method you can set new servers on which the task should be executed on. =cut sub set_server { my ( $self, @server ) = @_; $self->{server} = \@server; } =head2 delete_server Delete every server registered to the task. =cut sub delete_server { my ($self) = @_; delete $self->{current_server}; delete $self->{server}; $self->rethink_connection; } =head2 current_server Returns the current server on which the tasks gets executed right now. =cut sub current_server { my ($self) = @_; return $self->{current_server} || Rex::Group::Entry::Server->new( name => "" ); } =head2 desc Returns the description of a task. =cut sub desc { my ($self) = @_; return $self->{desc}; } =head2 set_desc($description) Set the description of a task. =cut sub set_desc { my ( $self, $desc ) = @_; $self->{desc} = $desc; } =head2 is_remote Returns true (1) if the task will be executed remotely. =cut sub is_remote { my ($self) = @_; if ( exists $self->{current_server} ) { if ( $self->{current_server} ne '' ) { return 1; } } else { if ( exists $self->{server} && scalar( @{ $self->{server} } ) > 0 ) { return 1; } } return 0; } =head2 is_local Returns true (1) if the task gets executed on the local host. =cut sub is_local { my ($self) = @_; return $self->is_remote() == 0 ? 1 : 0; } =head2 is_http Returns true (1) if the task gets executed over http protocol. =cut sub is_http { my ($self) = @_; return ( $self->{"connection_type"} && lc( $self->{"connection_type"} ) eq "http" ); } sub is_https { my ($self) = @_; return ( $self->{"connection_type"} && lc( $self->{"connection_type"} ) eq "https" ); } sub is_openssh { my ($self) = @_; return ( $self->{"connection_type"} && lc( $self->{"connection_type"} ) eq "openssh" ); } =head2 want_connect Returns true (1) if the task will establish a connection to a remote system. =cut sub want_connect { my ($self) = @_; return $self->{no_ssh} == 0 ? 1 : 0; } =head2 get_connection_type This method tries to guess the right connection type for the task and returns it. Current return values are SSH, Fake and Local. SSH - will create a ssh connection to the remote server Local - will not create any connections Fake - will not create any connections. But it populates the connection properties so you can use this type to iterate over a list of remote hosts but don't let rex build a connection. For example if you want to use Sys::Virt or other modules. =cut sub get_connection_type { my ($self) = @_; if ( $self->is_http ) { return "HTTP"; } elsif ( $self->is_https ) { return "HTTPS"; } elsif ( $self->is_remote && $self->is_openssh && $self->want_connect ) { return "OpenSSH"; } elsif ( $self->is_remote && $self->want_connect ) { return Rex::Config->get_connection_type(); } elsif ( $self->is_remote ) { return "Fake"; } else { return "Local"; } } =head2 modify($key, $value) With this method you can modify values of the task. =cut sub modify { my ( $self, $key, $value ) = @_; if ( ref( $self->{$key} ) eq "ARRAY" ) { push( @{ $self->{$key} }, $value ); } else { $self->{$key} = $value; } $self->rethink_connection; } sub rethink_connection { my ($self) = @_; delete $self->{connection}; } =head2 user Returns the current user the task will use. =cut sub user { my ($self) = @_; if ( exists $self->{auth} && $self->{auth}->{user} ) { return $self->{auth}->{user}; } } =head2 set_user($user) Set the user of a task. =cut sub set_user { my ( $self, $user ) = @_; $self->{auth}->{user} = $user; } =head2 password Returns the password that will be used. =cut sub password { my ($self) = @_; if ( exists $self->{auth} && $self->{auth}->{password} ) { return $self->{auth}->{password}; } } =head2 set_password($password) Set the password of the task. =cut sub set_password { my ( $self, $password ) = @_; $self->{auth}->{password} = $password; } =head2 name Returns the name of the task. =cut sub name { my ($self) = @_; return $self->{name}; } =head2 code Returns the code of the task. =cut sub code { my ($self) = @_; return $self->{func}; } =head2 set_code(\&code_ref) Set the code of the task. =cut sub set_code { my ( $self, $code ) = @_; $self->{func} = $code; } =head2 run_hook($server, $hook) This method is used internally to execute the specified hooks. =cut sub run_hook { my ( $self, $server, $hook, @more_args ) = @_; for my $code ( @{ $self->{$hook} } ) { if ( $hook eq "after" ) { # special case for after hooks &$code( $$server, ( $self->{"__was_authenticated"} ? undef : 1 ), { Rex::Args->get }, @more_args ); } else { my $old_server = $$server if $server; &$code( $$server, $server, { Rex::Args->get }, @more_args ); if ( $old_server && $old_server ne $$server ) { $self->{current_server} = $$server; } } } } =head2 set_auth($key, $value) Set the authentication of the task. $task->set_auth("user", "foo"); $task->set_auth("password", "bar"); =cut sub set_auth { my ( $self, $key, $value ) = @_; if ( scalar(@_) > 3 ) { my $_d = shift; $self->{auth} = {@_}; } else { $self->{auth}->{$key} = $value; } } =head2 merge_auth($server) Merges the authentication information from $server into the task. Tasks authentication information have precedence. =cut sub merge_auth { my ( $self, $server ) = @_; # merge auth hashs # task auth as precedence my %auth = $server->merge_auth( $self->{auth} ); return \%auth; } sub get_sudo_password { my ($self) = @_; my $server = $self->connection->server; my %auth = $server->merge_auth( $self->{auth} ); return $auth{sudo_password}; } =head2 parallelism Get the parallelism count of a task. =cut sub parallelism { my ($self) = @_; return $self->{parallelism}; } =head2 set_parallelism($count) Set the parallelism of the task. =cut sub set_parallelism { my ( $self, $para ) = @_; $self->{parallelism} = $para; } =head2 connect($server) Initiate the connection to $server. =cut sub connect { my ( $self, $server, %override ) = @_; if ( !ref $server ) { $server = Rex::Group::Entry::Server->new( name => $server ); } $self->{current_server} = $server; my $user = $self->user; #print Dumper($self); my $auth = $self->merge_auth($server); if ( exists $override{auth} ) { $auth = $override{auth}; $user = $auth->{user}; } my $rex_int_conf = Rex::Commands::get("rex_internals"); Rex::Logger::debug( Dumper($rex_int_conf) ); Rex::Logger::debug("Auth-Information inside Task:"); for my $key ( keys %{$auth} ) { my $data = $auth->{$key}; if ( $key eq "password" ) { $data = Rex::Logger::masq( "%s", $data ); } $data ||= ""; Rex::Logger::debug("$key => [[$data]]"); } $auth->{public_key} = resolv_path( $auth->{public_key}, 1 ) if ( $auth->{public_key} ); $auth->{private_key} = resolv_path( $auth->{private_key}, 1 ) if ( $auth->{private_key} ); my $profiler = Rex::Profiler->new; # task specific auth rules over all my %connect_hash = %{$auth}; $connect_hash{server} = $server; # need to get rid of this Rex::push_connection( { conn => $self->connection, ssh => $self->connection->get_connection_object, server => $server, cache => Rex::Interface::Cache->create(), task => $self, profiler => $profiler, reporter => Rex::Report->create( Rex::Config->get_report_type ), notify => Rex::Notify->new(), } ); $profiler->start("connect"); eval { $self->connection->connect(%connect_hash); 1; } or do { if ( !defined Rex::Config->get_fallback_auth ) { croak $@; } }; $profiler->end("connect"); if ( !$self->connection->is_connected ) { Rex::pop_connection(); croak("Couldn't connect to $server."); } elsif ( !$self->connection->is_authenticated ) { Rex::pop_connection(); my $message = "Wrong username/password or wrong key on $server."; $message .= " Or root is not permitted to login over SSH." if ( $connect_hash{user} eq 'root' ); if ( !exists $override{auth} ) { my $fallback_auth = Rex::Config->get_fallback_auth; if ( ref $fallback_auth eq "ARRAY" ) { my $ret_eval; for my $fallback_a ( @{$fallback_auth} ) { $ret_eval = eval { $self->connect( $server, auth => $fallback_a ); }; } return $ret_eval if $ret_eval; } } croak($message); } else { Rex::Logger::info("Successfully authenticated on $server.") if ( $self->connection->get_connection_type ne "Local" ); $self->{"__was_authenticated"} = 1; } $self->run_hook( \$server, "around" ); return 1; } =head2 disconnect Disconnect from the current connection. =cut sub disconnect { my ( $self, $server ) = @_; $self->run_hook( \$server, "around", 1 ); $self->connection->disconnect; my %args = Rex::Args->getopts; if ( defined $args{'d'} && $args{'d'} > 2 ) { Rex::Commands::profiler()->report; } delete $self->{connection}; # need to get rid of this Rex::pop_connection(); } sub get_data { my ($self) = @_; return { func => $self->{func}, server => $self->{server}, desc => $self->{desc}, no_ssh => $self->{no_ssh}, hidden => $self->{hidden}, auth => $self->{auth}, before => $self->{before}, after => $self->{after}, around => $self->{around}, name => $self->{name}, executor => $self->{executor}, connection_type => $self->{connection_type}, }; } ##################################### # deprecated functions # for compatibility ##################################### =head2 run($server, %options) Run the task on $server. =cut sub run { # someone used this function directly... bail out if ( ref( $_[0] ) ) { my ( $self, $server, %options ) = @_; if ( !ref $server ) { $server = Rex::Group::Entry::Server->new( name => $server ); } if ( !$_[1] ) { # run is called without any server. # so just connect to any servers. return Rex::TaskList->create()->run( $self->name, %options ); } # this is a method call # so run the task my $in_transaction = $options{in_transaction}; $self->run_hook( \$server, "before" ); $self->connect($server); my $start_time = time; if ( Rex::Args->is_opt("c") ) { # get and cache all os info if ( !Rex::get_cache()->load() ) { Rex::Logger::debug("No cache found, need to collect new data."); $server->gather_information; } } if ( !$server->test_perl ) { Rex::Logger::info( "There is no perl interpreter found on this system. Some commands may not work. Sudo won't work.", "warn" ); sleep 3; } # execute code my $ret; eval { $ret = $self->executor->exec( $options{params} ); my $notify = Rex::get_current_connection()->{notify}; $notify->run_postponed(); } or do { if ($@) { my $error = $@; Rex::get_current_connection()->{reporter} ->report_resource_failed( message => $error ); Rex::get_current_connection()->{reporter}->report_task_execution( failed => 1, start_time => $start_time, end_time => time, message => $error, ); Rex::get_current_connection()->{reporter}->write_report(); die($error); } }; if ( Rex::Args->is_opt("c") ) { # get and cache all os info Rex::get_cache()->save(); } Rex::get_current_connection()->{reporter}->report_task_execution( failed => 0, start_time => $start_time, end_time => time, ); Rex::get_current_connection()->{reporter}->write_report(); $self->disconnect($server) unless ($in_transaction); $self->run_hook( \$server, "after" ); return $ret; } else { my ( $class, $task, $server_overwrite, $params ) = @_; Rex::deprecated( "Rex::Task->run()", "0.40" ); if ($server_overwrite) { Rex::TaskList->create()->get_task($task)->set_server($server_overwrite); } # this is a deprecated static call Rex::TaskList->create()->run( $task, params => $params ); } } sub modify_task { my $class = shift; my $task = shift; my $key = shift; my $value = shift; Rex::TaskList->create()->get_task($task)->modify( $key => $value ); } sub is_task { my ( $class, $task ) = @_; return Rex::TaskList->create()->is_task($task); } sub get_tasks { my ( $class, @tmp ) = @_; return Rex::TaskList->create()->get_tasks(@tmp); } sub get_desc { my ( $class, @tmp ) = @_; return Rex::TaskList->create()->get_desc(@tmp); } =head2 exit_on_connect_fail() Returns true if rex should exit on connect failure. =cut sub exit_on_connect_fail { my ($self) = @_; return $self->{exit_on_connect_fail}; } sub set_exit_on_connect_fail { my ( $self, $exit ) = @_; $self->{exit_on_connect_fail} = $exit; } 1; Rex-1.3.3/lib/Rex/Report/0000755000175000017500000000000012572251052014720 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Report/YAML.pm0000644000175000017500000000324012572251052016017 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Report::YAML; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex; use Data::Dumper; use Rex::Report::Base; require Rex::Commands; use YAML; use base qw(Rex::Report::Base); our $REPORT_PATH = "./reports"; my $report_name_generator = sub { my $str = time(); return $str; }; sub set_report_name { my ( $class, $code ) = @_; if ( ref $class eq "CODE" ) { $code = $class; } if ( ref $code ne "CODE" ) { die "Rex::Report::YAML->set_report_name(\$code_ref) wrong arguments."; } $report_name_generator = $code; } sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub write_report { my ($self) = @_; $REPORT_PATH = Rex::Commands::get('report_path') || "reports"; if ( !-d $REPORT_PATH ) { mkdir $REPORT_PATH or die( $! . ": $REPORT_PATH" ); } my $server_name = Rex::Commands::connection()->server; if ( $server_name eq "" ) { $server_name = "_local_"; } if ( !-d $REPORT_PATH . "/" . $server_name ) { mkdir "$REPORT_PATH/$server_name"; } open( my $fh, ">", "$REPORT_PATH/$server_name/" . $report_name_generator->($server_name) . ".yml" ) or die($!); print $fh Dump( $self->{__reports__} ); close($fh); $self->{__reports__} = {}; } # $self->report({ # command => $export, # module => "Rex::Commands::$mod", # start_time => $start_time, # end_time => time, # data => [ @_ ], # success => 1, # changed => 1, # message => "", 1; Rex-1.3.3/lib/Rex/Report/Base.pm0000644000175000017500000000473512572251052016141 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Report::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; use Rex::Logger; use Time::HiRes qw(time); use Carp; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{__reports__} = {}; $self->{__current_resource__} = ""; return $self; } sub report { my ( $self, %option ) = @_; confess "not inside a resource." if ( !$self->{__current_resource__} ); if ( $option{changed} && !exists $option{message} ) { $option{message} = "Resource updated."; } elsif ( $option{changed} == 0 && !exists $option{message} ) { $option{message} = "Resource already up-to-date."; } # push @{$self->{__reports__}}, $msg; $self->{__reports__}->{ $self->{__current_resource__} }->{changed} = $option{changed} || 0; push @{ $self->{__reports__}->{ $self->{__current_resource__} }->{messages} }, $option{message}; } sub report_task_execution { my ( $self, %option ) = @_; $self->{__reports__}->{task} = \%option; } sub report_resource_start { my ( $self, %option ) = @_; if ( $self->{__current_resource__} ) { Rex::Logger::debug("Another resource is in progress."); return; } if ( exists $self->{__reports__}->{ $self->{__current_resource__} } ) { Rex::Logger::debug( "Multiple definitions of the same resource found. ($self->{__current_resource__})", ); } $self->{__current_resource__} = $self->_gen_res_name(%option); $self->{__reports__}->{ $self->{__current_resource__} } = { changed => 0, messages => [], start_time => time, }; } sub report_resource_end { my ( $self, %option ) = @_; confess "not inside a resource." if ( !$self->{__current_resource__} ); if ( $self->_gen_res_name(%option) ne $self->{__current_resource__} ) { Rex::Logger::debug("Another resource is in progress"); return; } $self->{__reports__}->{ $self->{__current_resource__} }->{end_time} = time; $self->{__current_resource__} = ""; } sub report_resource_failed { my ( $self, %opt ) = @_; $self->{__reports__}->{ $self->{__current_resource__} }->{failed} = 1; push @{ $self->{__reports__}->{ $self->{__current_resource__} }->{messages} }, $opt{message}; } sub write_report { my ($self) = @_; } sub _gen_res_name { my ( $self, %option ) = @_; return $option{type} . "[" . $option{name} . "]"; } 1; Rex-1.3.3/lib/Rex/Shared/0000755000175000017500000000000012572251052014653 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Shared/Var.pm0000644000175000017500000000200012572251052015731 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Shared::Var; use strict qw(vars subs); use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); use Data::Dumper; @EXPORT = qw(share); sub share { my @vars = @_; my ( $package, $file, $line ) = caller; my ( $sigil, $sym ); for my $var (@vars) { if ( ( $sigil, $sym ) = ( $var =~ /^([\$\@\%\*\&])(.+)/ ) ) { $sym = "${package}::$sym"; if ( $sigil eq "\$" ) { eval "use Rex::Shared::Var::Scalar;"; tie $$sym, "Rex::Shared::Var::Scalar", $sym; *$sym = \$$sym; } elsif ( $sigil eq "\@" ) { eval "use Rex::Shared::Var::Array;"; tie @$sym, "Rex::Shared::Var::Array", $sym; *$sym = \@$sym; } elsif ( $sigil eq "\%" ) { eval "use Rex::Shared::Var::Hash;"; tie %$sym, "Rex::Shared::Var::Hash", $sym; *$sym = \%$sym; } } } } 1; Rex-1.3.3/lib/Rex/Shared/Var/0000755000175000017500000000000012572251052015403 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Shared/Var/Array.pm0000644000175000017500000000441512572251052017023 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Shared::Var::Array; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl qw(:DEFAULT :flock); use Data::Dumper; use Storable; sub __lock; sub __retr; sub __store; sub TIEARRAY { my $self = { varname => $_[1], }; bless $self, $_[0]; } sub STORE { my $self = shift; my $index = shift; my $value = shift; return __lock sub { my $ref = __retr; my $ret = $ref->{ $self->{varname} }->{data}->[$index] = $value; __store $ref; return $ret; }; } sub FETCH { my $self = shift; my $index = shift; return __lock sub { my $ref = __retr; my $ret = $ref->{ $self->{varname} }->{data}->[$index]; return $ret; }; } sub CLEAR { my $self = shift; __lock sub { my $ref = __retr; $ref->{ $self->{varname} } = { data => [] }; __store $ref; }; } sub DELETE { my $self = shift; my $index = shift; __lock sub { my $ref = __retr; delete $ref->{ $self->{varname} }->{data}->[$index]; __store $ref; }; } sub EXISTS { my $self = shift; my $index = shift; return __lock sub { my $ref = __retr; return exists $ref->{ $self->{varname} }->{data}->[$index]; }; } sub PUSH { my $self = shift; my @data = @_; __lock sub { my $ref = __retr; if ( !ref( $ref->{ $self->{varname} }->{data} ) eq "ARRAY" ) { $ref->{ $self->{varname} }->{data} = []; } push( @{ $ref->{ $self->{varname} }->{data} }, @data ); __store $ref; }; } sub EXTEND { my $self = shift; my $count = shift; } sub STORESIZE { my $self = shift; my $newsize = shift; } sub FETCHSIZE { my $self = shift; return __lock sub { my $ref = __retr; if ( !exists $ref->{ $self->{varname} } ) { return 0; } return scalar( @{ $ref->{ $self->{varname} }->{data} } ); }; } sub DESTROY { my $self = shift; } sub __lock { sysopen( my $dblock, "vars.db.lock", O_RDONLY | O_CREAT ) or die($!); flock( $dblock, LOCK_SH ) or die($!); my $ret = &{ $_[0] }(); close($dblock); return $ret; } sub __store { my $ref = shift; store( $ref, "vars.db" ); } sub __retr { if ( !-f "vars.db" ) { return {}; } return retrieve("vars.db"); } 1; Rex-1.3.3/lib/Rex/Shared/Var/Hash.pm0000644000175000017500000000364412572251052016633 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Shared::Var::Hash; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; use Fcntl qw(:DEFAULT :flock); use Data::Dumper; use Storable; sub __lock; sub __retr; sub __store; sub TIEHASH { my $self = { varname => $_[1], }; bless $self, $_[0]; } sub STORE { my $self = shift; my $key = shift; my $value = shift; return __lock sub { my $ref = __retr; my $ret = $ref->{ $self->{varname} }->{$key} = $value; __store $ref; return $ret; }; } sub FETCH { my $self = shift; my $key = shift; return __lock sub { my $ref = __retr; return $ref->{ $self->{varname} }->{$key}; }; } sub DELETE { my $self = shift; my $key = shift; __lock sub { my $ref = __retr; delete $ref->{ $self->{varname} }->{$key}; __store $ref; }; } sub CLEAR { my $self = shift; __lock sub { my $ref = __retr; $ref->{ $self->{varname} } = {}; __store $ref; }; } sub EXISTS { my $self = shift; my $key = shift; return __lock sub { my $ref = __retr; return exists $ref->{ $self->{varname} }->{$key}; }; } sub FIRSTKEY { my $self = shift; return __lock sub { my $ref = __retr; $self->{__iter__} = $ref->{ $self->{varname} }; my $temp = keys %{ $self->{__iter__} }; return scalar each %{ $self->{__iter__} }; }; } sub NEXTKEY { my $self = shift; my $prevkey = shift; return scalar each %{ $self->{__iter__} }; } sub DESTROY { my $self = shift; } sub __lock { sysopen( my $dblock, "vars.db.lock", O_RDONLY | O_CREAT ) or die($!); flock( $dblock, LOCK_SH ) or die($!); my $ret = &{ $_[0] }(); close($dblock); return $ret; } sub __store { my $ref = shift; store( $ref, "vars.db" ); } sub __retr { if ( !-f "vars.db" ) { return {}; } return retrieve("vars.db"); } 1; Rex-1.3.3/lib/Rex/Shared/Var/Scalar.pm0000644000175000017500000000202412572251052017144 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Shared::Var::Scalar; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl qw(:DEFAULT :flock); use Data::Dumper; use Storable; sub __lock; sub __retr; sub __store; sub TIESCALAR { my $self = { varname => $_[1], }; bless $self, $_[0]; } sub STORE { my $self = shift; my $value = shift; return __lock sub { my $ref = __retr; my $ret = $ref->{ $self->{varname} } = $value; __store $ref; return $ret; }; } sub FETCH { my $self = shift; return __lock sub { my $ref = __retr; return $ref->{ $self->{varname} }; }; } sub __lock { sysopen( my $dblock, "vars.db.lock", O_RDONLY | O_CREAT ) or die($!); flock( $dblock, LOCK_SH ) or die($!); my $ret = &{ $_[0] }(); close($dblock); return $ret; } sub __store { my $ref = shift; store( $ref, "vars.db" ); } sub __retr { if ( !-f "vars.db" ) { return {}; } return retrieve("vars.db"); } 1; Rex-1.3.3/lib/Rex/Inventory.pm0000644000175000017500000001260412572251052016003 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Inventory; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Inventory::DMIDecode; use Rex::Inventory::Hal; use Rex::Inventory::Proc; use Rex::Commands::Network; use Rex::Commands::Run; use Rex::Commands::Gather; use Rex::Commands::LVM; use Rex::Commands::Fs; use Rex::Inventory::HP::ACU; use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub get { my ($self) = @_; my $dmi = Rex::Inventory::DMIDecode->new; my ( $base_board, $bios, @cpus, @dimms, @mem_arrays, $sys_info ); $base_board = $dmi->get_base_board; $bios = $dmi->get_bios; @cpus = $dmi->get_cpus; @dimms = $dmi->get_memory_modules; @mem_arrays = $dmi->get_memory_arrays; $sys_info = $dmi->get_system_information; my $hal = {}; my ( @net_devs, @storage, @volumes ); eval { $hal = Rex::Inventory::Hal->new; @net_devs = $hal->get_network_devices; @storage = $hal->get_storage_devices; @volumes = $hal->get_storage_volumes; }; eval { if ( scalar @cpus == 0 ) { # get cpu info from /proc if ( is_dir("/proc") ) { Rex::Logger::info( "Got no cpu information from dmidecode. Falling back to /proc/cpuinfo" ); my $proc_i = Rex::Inventory::Proc->new; @cpus = @{ $proc_i->get_cpus }; } } }; my @routes = route; my @netstat = netstat; my $default_gw = default_gateway; my ( @pvs, @vgs, @lvs ); eval { @pvs = pvs; @vgs = vgs; @lvs = lvs; }; my @raid_controller; eval { if ( my $hp_raid = Rex::Inventory::HP::ACU->get() ) { # hp raid entdeckt for my $key ( keys %{$hp_raid} ) { my %raid_shelfs; for my $shelf ( keys %{ $hp_raid->{$key}->{"array"} } ) { my $shelf_data = $hp_raid->{$key}->{"array"}->{$shelf}; my @raid_logical_drives; for my $l_drive ( keys %{ $hp_raid->{$key}->{"array"}->{$shelf}->{"logical_drive"} } ) { my $l_drive_data = $hp_raid->{$key}->{"array"}->{$shelf}->{"logical_drive"} ->{$l_drive}; my ($size) = ( $l_drive_data->{"size"} =~ m/^([0-9\.]+)/ ); my $multi = 1024 * 1024 * 1024; if ( $l_drive_data->{"size"} =~ m/TB$/ ) { $multi *= 1024; } push( @raid_logical_drives, { status => ( $l_drive_data->{"status"} eq "OK" ? 1 : 0 ), raid_level => $l_drive_data->{"fault_tolerance"}, size => sprintf( "%i", $size * $multi ), dev => $l_drive_data->{"disk_name"}, shelf => $shelf, } ); } $raid_shelfs{$shelf} = { type => $shelf_data->{"interface_type"}, status => ( $shelf_data->{"status"} eq "OK" ? 1 : 0 ), logical_drives => \@raid_logical_drives, }; } push( @raid_controller, { type => $hp_raid->{$key}->{"description"}, model => $hp_raid->{$key}->{"model"}, serial_number => $hp_raid->{$key}->{"serial_number"}, cache_status => ( $hp_raid->{$key}->{"cache_status"} eq "OK" ? 1 : 0 ), shelfs => \%raid_shelfs, } ); } } }; my ($fusion_inventory_xmlref); if ( can_run("fusioninventory-agent") ) { require XML::Simple; my $xml = XML::Simple->new; my $fusion_inventory = run "fusioninventory-agent --stdout 2>/dev/null"; $fusion_inventory_xmlref = $xml->XMLin($fusion_inventory); } return { base_board => ( $base_board ? $base_board->get_all() : {} ), bios => $bios->get_all(), system_info => $sys_info->get_all(), cpus => sub { my $ret = []; push( @{$ret}, ( ref $_ ne "HASH" ? $_->get_all() : $_ ) ) for @cpus; return $ret; } ->(), dimms => sub { my $ret = []; push( @{$ret}, $_->get_all() ) for @dimms; return $ret; } ->(), mem_arrays => sub { my $ret = []; push( @{$ret}, $_->get_all() ) for @mem_arrays; return $ret; } ->(), net => sub { my $ret = []; push( @{$ret}, $_->get_all() ) for @net_devs; return $ret; } ->(), storage => sub { my $ret = []; push( @{$ret}, $_->get_all() ) for @storage; return $ret; } ->(), volumes => sub { my $ret = []; push( @{$ret}, $_->get_all() ) for @volumes; return $ret; } ->(), raid => { controller => \@raid_controller, }, lvm => { physical_volumes => \@pvs, volume_groups => \@vgs, logical_volumes => \@lvs, }, configuration => { network => { routes => \@routes, current_connections => \@netstat, default_gateway => $default_gw, current_configuration => network_interfaces(), }, host => { name => [ run "hostname -s" ]->[0], domain => [ run "hostname -d" || qw() ]->[0], kernel => [ run "uname -r" || qw() ]->[0], }, }, fusion_inventory => $fusion_inventory_xmlref, }; } 1; Rex-1.3.3/lib/Rex/Cloud/0000755000175000017500000000000012572251052014513 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Cloud/Jiffybox.pm0000644000175000017500000001507512572251052016641 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Cloud::Jiffybox; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; BEGIN { use Rex::Require; LWP::UserAgent->use; HTTP::Request::Common->use; JSON::XS->use; } use Data::Dumper; use Rex::Cloud::Base; use base qw(Rex::Cloud::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{"__endpoint"} = "https://api.jiffybox.de/%s/v1.0/%s"; Rex::Logger::debug( "Creating new Jiffybox Object, with endpoint: " . $self->{"__endpoint"} ); return $self; } sub _auth_key { my ($self) = @_; return $self->{"__auth_key"}; } sub _do_request { my ( $self, $type, $action, @params ) = @_; my $url = sprintf( $self->{"__endpoint"}, $self->_auth_key, $action ); Rex::Logger::debug("Requesting $url"); my $ua = LWP::UserAgent->new; $ua->env_proxy; my ($res); if ( $type eq "GET" ) { $res = $ua->request( GET $url); } elsif ( $type eq "POST" ) { $res = $ua->request( POST $url, \@params ); } elsif ( $type eq "PUT" ) { my $req = POST $url, \@params; $req->method("PUT"); $res = $ua->request($req); } elsif ( $type eq "DELETE" ) { my $req = GET $url; $req->method("DELETE"); $res = $ua->request($req); } if ( $res->code >= 500 ) { Rex::Logger::info( $res->content ); die("Error on request."); } my $json = JSON::XS->new; my $data = $json->decode( $res->decoded_content ); Rex::Logger::debug( Dumper($data) ); unless ( $data->{"result"} ) { die( "Error talking to jiffybox: " . $data->{"messages"}->[0]->{"message"} ); } return $data; } sub _result_to_array { my ( $self, $data, $with_key ) = @_; my @ret = (); for my $key ( keys %{ $data->{"result"} } ) { if ($with_key) { $data->{"result"}->{$key}->{$with_key} = $key; } push( @ret, $data->{"result"}->{$key} ); } return @ret; } sub set_auth { my ( $self, $key ) = @_; $self->{"__auth_key"} = $key; } sub list_plans { my ($self) = @_; Rex::Logger::debug("Listing plans"); my $data = $self->_do_request( "GET", "plans" ); return $self->_result_to_array($data); } sub list_operating_systems { my ($self) = @_; Rex::Logger::debug("Listing operating systems"); my $data = $self->_do_request( "GET", "distributions" ); return $self->_result_to_array( $data, "os_id" ); } sub run_instance { my ( $self, %data ) = @_; my @jiffy_data; Rex::Logger::debug("Trying to start a new instance with data:"); Rex::Logger::debug( " $_ -> " . ( $data{$_} ? $data{$_} : "undef" ) ) for keys %data; push( @jiffy_data, "name" => $data{"name"}, "planid" => $data{"plan_id"}, "distribution" => $data{"image_id"} ); if ( exists $data{"password"} ) { push( @jiffy_data, "password" => $data{"password"} ); } if ( exists $data{"key"} ) { push( @jiffy_data, "use_sshkey" => $data{"key"} ); } if ( exists $data{"metadata"} ) { push( @jiffy_data, "metadata" => $data{"metadata"} ); } my $data; if ( exists $data{"clone_id"} ) { $data = $self->_do_request( "POST", "jiffyBoxes/" . $data{"clone_id"}, @jiffy_data ); } else { $data = $self->_do_request( "POST", "jiffyBoxes", @jiffy_data ); } my $instance_id = $data->{"result"}->{"id"}; my $sleep_countdown = 10; sleep $sleep_countdown; # wait 10 seconds ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances(); while ( $data->{"state"} ne "STOPPED" && $data->{"state"} ne "RUNNING" ) { Rex::Logger::debug("Waiting for instance to be created..."); ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances(); sleep $sleep_countdown; --$sleep_countdown; if ( $sleep_countdown <= 3 ) { $sleep_countdown = 7; } } $self->start_instance( instance_id => $instance_id ); ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances(); while ( $data->{"state"} ne "RUNNING" ) { Rex::Logger::debug("Waiting for instance to be started..."); ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances(); sleep $sleep_countdown; --$sleep_countdown; if ( $sleep_countdown <= 3 ) { $sleep_countdown = 7; } } return $data; } sub start_instance { my ( $self, %data ) = @_; my $instance_id = $data{"instance_id"}; Rex::Logger::debug("Starting instance $instance_id"); $self->_do_request( "PUT", "jiffyBoxes/$instance_id", status => "START" ); } sub terminate_instance { my ( $self, %data ) = @_; my $instance_id = $data{"instance_id"}; Rex::Logger::debug("Terminating instance $instance_id"); $self->stop_instance(%data); $self->_do_request( "DELETE", "jiffyBoxes/$instance_id" ); } sub stop_instance { my ( $self, %data ) = @_; my $instance_id = $data{"instance_id"}; Rex::Logger::debug("Stopping instance $instance_id"); $self->_do_request( "PUT", "jiffyBoxes/$instance_id", status => "SHUTDOWN" ); my $sleep_countdown = 10; sleep $sleep_countdown; # wait 10 seconds my ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances(); while ( $data->{"state"} ne "STOPPED" ) { Rex::Logger::debug("Waiting for instance to be stopped..."); ($data) = grep { $_->{"id"} eq $instance_id } $self->list_instances(); sleep $sleep_countdown; --$sleep_countdown; if ( $sleep_countdown <= 3 ) { $sleep_countdown = 7; } } return 1; } sub list_instances { my ($self) = @_; my @ret; my $data = $self->_do_request( "GET", "jiffyBoxes" ); for my $instance_id ( keys %{ $data->{"result"} } ) { my $state = $data->{"result"}->{$instance_id}->{"status"}; if ( $state eq "READY" ) { if ( $data->{"result"}->{$instance_id}->{"running"} ) { $state = "RUNNING"; } else { $state = "STOPPED"; } } push( @ret, { ip => $data->{"result"}->{$instance_id}->{"ips"}->{"public"}->[0], id => $instance_id, architecture => undef, type => $data->{"result"}->{$instance_id}->{"plan"}->{"name"}, dns_name => "j$instance_id.servers.jiffybox.net", state => $state, __state => $data->{"result"}->{$instance_id}->{"status"}, launch_time => undef, name => $data->{"result"}->{$instance_id}->{"name"}, } ); } return @ret; } sub list_running_instances { my ($self) = @_; return grep { $_->{"__state"} eq "READY" || $_->{"__state"} eq "UPDATING" } $self->list_instances(); } 1; Rex-1.3.3/lib/Rex/Cloud/Base.pm0000644000175000017500000000322012572251052015720 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Cloud::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub set_auth { Rex::Logger::debug("Not implemented"); } sub set_endpoint { my ( $self, $endpoint ) = @_; # only set endpoint if defined if ( defined $endpoint ) { $self->{__endpoint} = $endpoint; } } sub list_plans { Rex::Logger::debug("Not implemented"); } sub list_operating_systems { Rex::Logger::debug("Not implemented"); } sub run_instance { Rex::Logger::debug("Not implemented"); } sub terminate_instance { Rex::Logger::debug("Not implemented"); } sub start_instance { Rex::Logger::debug("Not implemented"); } sub stop_instance { Rex::Logger::debug("Not implemented"); } sub list_instances { Rex::Logger::debug("Not implemented"); } sub list_running_instances { Rex::Logger::debug("Not implemented"); } sub create_volume { Rex::Logger::debug("Not implemented"); } sub attach_volume { Rex::Logger::debug("Not implemented"); } sub detach_volume { Rex::Logger::debug("Not implemented"); } sub delete_volume { Rex::Logger::debug("Not implemented"); } sub list_volumes { Rex::Logger::debug("Not implemented"); } sub list_images { Rex::Logger::debug("Not implemented"); } sub add_tag { Rex::Logger::debug("Not implemented"); } sub get_regions { Rex::Logger::debug("Not implemented"); } sub get_availability_zones { Rex::Logger::debug("Not implemented"); } 1; Rex-1.3.3/lib/Rex/Cloud/OpenStack.pm0000644000175000017500000003041112572251052016737 0ustar jenkinsjenkins# # (c) Ferenc Erki # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Cloud::OpenStack; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use base 'Rex::Cloud::Base'; BEGIN { use Rex::Require; JSON::XS->use; HTTP::Request::Common->use(qw(:DEFAULT DELETE)); LWP::UserAgent->use; } use Data::Dumper; use Carp; use MIME::Base64 qw(decode_base64); use Digest::MD5 qw(md5_hex); use File::Basename; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{_agent} = LWP::UserAgent->new; $self->{_agent}->env_proxy; return $self; } sub set_auth { my ( $self, %auth ) = @_; $self->{auth} = \%auth; } sub _request { my ( $self, $method, $url, %params ) = @_; my $response; Rex::Logger::debug("Sending request to $url"); Rex::Logger::debug(" $_ => $params{$_}") for keys %params; { no strict 'refs'; $response = $self->{_agent}->request( $method->( $url, %params ) ); } Rex::Logger::debug( Dumper($response) ); if ( $response->is_error ) { Rex::Logger::info( 'Response indicates an error', 'warn' ); Rex::Logger::debug( $response->content ); } return decode_json( $response->content ) if $response->content; } sub _authenticate { my $self = shift; my $auth_data = { auth => { tenantName => $self->{auth}{tenant_name} || '', passwordCredentials => { username => $self->{auth}{username}, password => $self->{auth}{password}, } } }; my $content = $self->_request( POST => $self->{__endpoint} . '/tokens', content_type => 'application/json', content => encode_json($auth_data), ); $self->{auth}{tokenId} = $content->{access}{token}{id}; $self->{_agent}->default_header( 'X-Auth-Token' => $self->{auth}{tokenId} ); $self->{_catalog} = $content->{access}{serviceCatalog}; } sub get_nova_url { my $self = shift; $self->_authenticate unless $self->{auth}{tokenId}; my @nova_services = grep { $_->{type} eq 'compute' } @{ $self->{_catalog} }; return $nova_services[0]{endpoints}[0]{publicURL}; } sub get_cinder_url { my $self = shift; $self->_authenticate unless $self->{auth}{tokenId}; my @cinder_services = grep { $_->{type} eq 'volume' } @{ $self->{_catalog} }; return $cinder_services[0]{endpoints}[0]{publicURL}; } sub run_instance { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; Rex::Logger::debug('Trying to start a new instance with data:'); Rex::Logger::debug(" $_ => $data{$_}") for keys %data; my $request_data = { server => { flavorRef => $data{plan_id}, imageRef => $data{image_id}, name => $data{name}, key_name => $data{key}, } }; my $content = $self->_request( POST => $nova_url . '/servers', content_type => 'application/json', content => encode_json($request_data), ); my $id = $content->{server}{id}; my $info; until ( ($info) = grep { $_->{id} eq $id } $self->list_running_instances ) { Rex::Logger::debug('Waiting for instance to be created...'); sleep 1; } if ( exists $data{volume} ) { $self->attach_volume( instance_id => $id, volume_id => $data{volume}, ); } if ( exists $data{floating_ip} ) { $self->associate_floating_ip( instance_id => $id, floating_ip => $data{floating_ip}, ); ($info) = grep { $_->{id} eq $id } $self->list_running_instances; } return $info; } sub terminate_instance { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; Rex::Logger::debug("Terminating instance $data{instance_id}"); $self->_request( DELETE => $nova_url . '/servers/' . $data{instance_id} ); until ( !grep { $_->{id} eq $data{instance_id} } $self->list_running_instances ) { Rex::Logger::debug('Waiting for instance to be deleted...'); sleep 1; } } sub list_instances { my $self = shift; my %options = @_; $options{private_network} ||= "private"; $options{public_network} ||= "public"; $options{public_ip_type} ||= "floating"; $options{private_ip_type} ||= "fixed"; my $nova_url = $self->get_nova_url; my @instances; my $content = $self->_request( GET => $nova_url . '/servers/detail' ); for my $instance ( @{ $content->{servers} } ) { my %networks; for my $net ( keys %{ $instance->{addresses} } ) { for my $ip_conf ( @{ $instance->{addresses}->{$net} } ) { push @{ $networks{$net} }, { mac => $ip_conf->{'OS-EXT-IPS-MAC:mac_addr'}, ip => $ip_conf->{addr}, type => $ip_conf->{'OS-EXT-IPS:type'}, }; } } push @instances, { ip => ( [ map { $_->{"OS-EXT-IPS:type"} eq $options{public_ip_type} ? $_->{'addr'} : () } @{ $instance->{addresses}{ $options{public_network} } } ]->[0] || undef ), id => $instance->{id}, architecture => undef, type => $instance->{flavor}{id}, dns_name => undef, state => ( $instance->{status} eq 'ACTIVE' ? 'running' : 'stopped' ), __state => $instance->{status}, launch_time => $instance->{'OS-SRV-USG:launched_at'}, name => $instance->{name}, private_ip => ( [ map { $_->{"OS-EXT-IPS:type"} eq $options{private_ip_type} ? $_->{'addr'} : () } @{ $instance->{addresses}{ $options{private_network} } } ]->[0] || undef ), security_groups => ( join ',', map { $_->{name} } @{ $instance->{security_groups} } ), networks => \%networks, }; } return @instances; } sub list_running_instances { my $self = shift; return grep { $_->{state} eq 'running' } $self->list_instances; } sub stop_instance { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; Rex::Logger::debug("Suspending instance $data{instance_id}"); $self->_request( POST => $nova_url . '/servers/' . $data{instance_id} . '/action', content_type => 'application/json', content => encode_json( { suspend => 'null' } ), ); while ( grep { $_->{id} eq $data{instance_id} } $self->list_running_instances ) { Rex::Logger::debug('Waiting for instance to be stopped...'); sleep 5; } } sub start_instance { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; Rex::Logger::debug("Resuming instance $data{instance_id}"); $self->_request( POST => $nova_url . '/servers/' . $data{instance_id} . '/action', content_type => 'application/json', content => encode_json( { resume => 'null' } ), ); until ( grep { $_->{id} eq $data{instance_id} } $self->list_running_instances ) { Rex::Logger::debug('Waiting for instance to be started...'); sleep 5; } } sub list_flavors { my $self = shift; my $nova_url = $self->get_nova_url; Rex::Logger::debug('Listing flavors'); my $flavors = $self->_request( GET => $nova_url . '/flavors' ); confess "Error getting cloud flavors." if ( !exists $flavors->{flavors} ); return @{ $flavors->{flavors} }; } sub list_plans { return shift->list_flavors; } sub list_images { my $self = shift; my $nova_url = $self->get_nova_url; Rex::Logger::debug('Listing images'); my $images = $self->_request( GET => $nova_url . '/images' ); confess "Error getting cloud images." if ( !exists $images->{images} ); return @{ $images->{images} }; } sub create_volume { my ( $self, %data ) = @_; my $cinder_url = $self->get_cinder_url; Rex::Logger::debug('Creating a new volume'); my $request_data = { volume => { size => $data{size} || 1, availability_zone => $data{zone}, } }; my $content = $self->_request( POST => $cinder_url . '/volumes', content_type => 'application/json', content => encode_json($request_data), ); my $id = $content->{volume}{id}; until ( grep { $_->{id} eq $id and $_->{status} eq 'available' } $self->list_volumes ) { Rex::Logger::debug('Waiting for volume to become available...'); sleep 1; } return $id; } sub delete_volume { my ( $self, %data ) = @_; my $cinder_url = $self->get_cinder_url; Rex::Logger::debug('Trying to delete a volume'); $self->_request( DELETE => $cinder_url . '/volumes/' . $data{volume_id} ); until ( !grep { $_->{id} eq $data{volume_id} } $self->list_volumes ) { Rex::Logger::debug('Waiting for volume to be deleted...'); sleep 1; } } sub list_volumes { my $self = shift; my $cinder_url = $self->get_cinder_url; my @volumes; my $content = $self->_request( GET => $cinder_url . '/volumes' ); for my $volume ( @{ $content->{volumes} } ) { push @volumes, { id => $volume->{id}, status => $volume->{status}, zone => $volume->{availability_zone}, size => $volume->{size}, attached_to => join ',', map { $_->{server_id} } @{ $volume->{attachments} }, }; } return @volumes; } sub attach_volume { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; Rex::Logger::debug('Trying to attach a new volume'); my $request_data = { volumeAttachment => { volumeId => $data{volume_id}, name => $data{name}, } }; $self->_request( POST => $nova_url . '/servers/' . $data{instance_id} . '/os-volume_attachments', content_type => 'application/json', content => encode_json($request_data), ); } sub detach_volume { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; Rex::Logger::debug('Trying to detach a volume'); $self->_request( DELETE => $nova_url . '/servers/' . $data{instance_id} . '/os-volume_attachments/' . $data{volume_id} ); } sub get_floating_ip { my $self = shift; my $nova_url = $self->get_nova_url; # look for available floating IP my $floating_ips = $self->_request( GET => $nova_url . '/os-floating-ips' ); for my $floating_ip ( @{ $floating_ips->{floating_ips} } ) { return $floating_ip->{ip} if ( !$floating_ip->{instance_id} ); } confess "No floating IP available."; } sub associate_floating_ip { my ( $self, %data ) = @_; my $nova_url = $self->get_nova_url; # associate available floating IP to instance id my $request_data = { addFloatingIp => { address => $data{floating_ip} } }; Rex::Logger::debug('Associating floating IP to instance'); my $content = $self->_request( POST => $nova_url . '/servers/' . $data{instance_id} . '/action', content_type => 'application/json', content => encode_json($request_data), ); } sub list_keys { my $self = shift; my $nova_url = $self->get_nova_url; my $content = $self->_request( GET => $nova_url . '/os-keypairs' ); # remove ':' from fingerprint string foreach ( @{ $content->{keypairs} } ) { $_->{keypair}->{fingerprint} =~ s/://g; } return @{ $content->{keypairs} }; } sub upload_key { my ($self) = shift; my $nova_url = $self->get_nova_url; my $public_key = glob( Rex::Config->get_public_key ); my ( $public_key_name, undef, undef ) = fileparse( $public_key, qr/\.[^.]*/ ); my ( $type, $key, $comment ); # read public key my $fh; unless ( open( $fh, "<", glob($public_key) ) ) { Rex::Logger::debug("Cannot read $public_key"); return; } { local $/ = undef; ( $type, $key, $comment ) = split( /\s+/, <$fh> ); } close $fh; # calculate key fingerprint so we can compare them my $fingerprint = md5_hex( decode_base64($key) ); Rex::Logger::debug("Public key fingerprint is $fingerprint"); # upoad only new key my $online_key = pop @{ [ map { $_->{keypair}->{fingerprint} eq $fingerprint ? $_ : () } $self->list_keys() ] }; if ($online_key) { Rex::Logger::debug("Public key already uploaded"); return $online_key->{keypair}->{name}; } my $request_data = { keypair => { public_key => "$type $key", name => $public_key_name, } }; Rex::Logger::info('Uploading public key'); $self->_request( POST => $nova_url . '/os-keypairs', content_type => 'application/json', content => encode_json($request_data), ); return $public_key_name; } 1; Rex-1.3.3/lib/Rex/Cloud/Amazon.pm0000644000175000017500000003027312572251052016303 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: # # Some of the code is based on Net::Amazon::EC2 # package Rex::Cloud::Amazon; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Cloud::Base; use base qw(Rex::Cloud::Base); BEGIN { use Rex::Require; LWP::UserAgent->use; Digest::HMAC_SHA1->use; HTTP::Date->use(qw(time2isoz)); MIME::Base64->use(qw(encode_base64 decode_base64)); XML::Simple->require; } use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); #$self->{"__version"} = "2009-11-30"; $self->{"__version"} = "2011-05-15"; $self->{"__signature_version"} = 1; $self->{"__endpoint"} = "us-east-1.ec2.amazonaws.com"; Rex::Logger::debug( "Creating new Amazon Object, with endpoint: " . $self->{"__endpoint"} ); Rex::Logger::debug( "Using API Version: " . $self->{"__version"} ); return $self; } sub set_auth { my ( $self, $access_key, $secret_access_key ) = @_; $self->{"__access_key"} = $access_key; $self->{"__secret_access_key"} = $secret_access_key; } sub set_endpoint { my ( $self, $endpoint ) = @_; Rex::Logger::debug("Setting new endpoint to $endpoint"); $self->{'__endpoint'} = $endpoint; } sub timestamp { my $t = time2isoz(); chop($t); $t .= ".000Z"; $t =~ s/\s+/T/g; return $t; } sub run_instance { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to start a new Amazon instance with data:"); Rex::Logger::debug( " $_ -> " . ( $data{$_} ? $data{$_} : "undef" ) ) for keys %data; my $security_groups; if ( ref( $data{security_group} ) eq "ARRAY" ) { $security_groups = $data{security_group}; } elsif ( exists $data{security_groups} ) { $security_groups = $data{security_groups}; } else { $security_groups = $data{security_group}; } my %security_group = (); if ( ref($security_groups) eq "ARRAY" ) { my $i = 0; for my $sg ( @{$security_groups} ) { $security_group{"SecurityGroup.$i"} = $sg; $i++; } } else { $security_group{SecurityGroup} = $security_groups || "default"; } my $xml = $self->_request( "RunInstances", ImageId => $data{"image_id"}, MinCount => 1, MaxCount => 1, KeyName => $data{"key"}, InstanceType => $data{"type"} || "m1.small", "Placement.AvailabilityZone" => $data{"zone"} || "", %security_group ); my $ref = $self->_xml($xml); if ( exists $data{"name"} ) { $self->add_tag( id => $ref->{"instancesSet"}->{"item"}->{"instanceId"}, name => "Name", value => $data{"name"} ); } my ($info) = grep { $_->{"id"} eq $ref->{"instancesSet"}->{"item"}->{"instanceId"} } $self->list_instances(); while ( $info->{"state"} ne "running" ) { Rex::Logger::debug("Waiting for instance to be created..."); ($info) = grep { $_->{"id"} eq $ref->{"instancesSet"}->{"item"}->{"instanceId"} } $self->list_instances(); sleep 1; } if ( exists $data{"volume"} ) { $self->attach_volume( volume_id => $data{"volume"}, instance_id => $ref->{"instancesSet"}->{"item"}->{"instanceId"}, name => "/dev/sdh", # default for new instances ); } return $info; } sub attach_volume { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to attach a new volume"); $self->_request( "AttachVolume", VolumeId => $data{"volume_id"}, InstanceId => $data{"instance_id"}, Device => $data{"name"} || "/dev/sdh" ); } sub detach_volume { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to detach a volume"); $self->_request( "DetachVolume", VolumeId => $data{"volume_id"}, ); } sub delete_volume { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to delete a volume"); $self->_request( "DeleteVolume", VolumeId => $data{"volume_id"}, ); } sub terminate_instance { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to terminate an instance"); $self->_request( "TerminateInstances", "InstanceId.1" => $data{"instance_id"} ); } sub start_instance { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to start an instance"); $self->_request( "StartInstances", "InstanceId.1" => $data{instance_id} ); my ($info) = grep { $_->{"id"} eq $data{"instance_id"} } $self->list_instances(); while ( $info->{"state"} ne "running" ) { Rex::Logger::debug("Waiting for instance to be started..."); ($info) = grep { $_->{"id"} eq $data{"instance_id"} } $self->list_instances(); sleep 5; } } sub stop_instance { my ( $self, %data ) = @_; Rex::Logger::debug("Trying to stop an instance"); $self->_request( "StopInstances", "InstanceId.1" => $data{instance_id} ); my ($info) = grep { $_->{"id"} eq $data{"instance_id"} } $self->list_instances(); while ( $info->{"state"} ne "stopped" ) { Rex::Logger::debug("Waiting for instance to be stopped..."); ($info) = grep { $_->{"id"} eq $data{"instance_id"} } $self->list_instances(); sleep 5; } } sub add_tag { my ( $self, %data ) = @_; Rex::Logger::debug( "Adding a new tag: " . $data{id} . " -> " . $data{name} . " -> " . $data{value} ); $self->_request( "CreateTags", "ResourceId.1" => $data{"id"}, "Tag.1.Key" => $data{"name"}, "Tag.1.Value" => $data{"value"} ); } sub create_volume { my ( $self, %data ) = @_; Rex::Logger::debug("Creating a new volume"); my $xml = $self->_request( "CreateVolume", "Size" => $data{"size"} || 1, "AvailabilityZone" => $data{"zone"}, ); my $ref = $self->_xml($xml); return $ref->{"volumeId"}; my ($info) = grep { $_->{"id"} eq $ref->{"volumeId"} } $self->list_volumes(); while ( $info->{"status"} ne "available" ) { Rex::Logger::debug("Waiting for volume to become ready..."); ($info) = grep { $_->{"id"} eq $ref->{"volumeId"} } $self->list_volumes(); sleep 1; } } sub list_volumes { my ($self) = @_; my $xml = $self->_request("DescribeVolumes"); my $ref = $self->_xml($xml); return unless ($ref); return unless ( exists $ref->{"volumeSet"}->{"item"} ); if ( ref( $ref->{"volumeSet"}->{"item"} ) eq "HASH" ) { $ref->{"volumeSet"}->{"item"} = [ $ref->{"volumeSet"}->{"item"} ]; } my @volumes; for my $vol ( @{ $ref->{"volumeSet"}->{"item"} } ) { push( @volumes, { id => $vol->{"volumeId"}, status => $vol->{"status"}, zone => $vol->{"availabilityZone"}, size => $vol->{"size"}, attached_to => $vol->{"attachmentSet"}->{"item"}->{"instanceId"}, } ); } return @volumes; } sub _make_instance_map { my ( $self, $instance_set ) = @_; return ( ip => $_[1]->{"ipAddress"}, id => $_[1]->{"instanceId"}, image_id => $_[1]->{"imageId"}, architecture => $_[1]->{"architecture"}, type => $_[1]->{"instanceType"}, dns_name => $_[1]->{"dnsName"}, state => $_[1]->{"instanceState"}->{"name"}, launch_time => $_[1]->{"launchTime"}, ( name => exists( $instance_set->{"tagSet"}->{"item"}->{"value"} ) ? $instance_set->{"tagSet"}->{"item"}->{"value"} : $instance_set->{"tagSet"}->{"item"}->{"Name"}->{"value"} ), private_ip => $_[1]->{"privateIpAddress"}, ( security_group => ref $_[1]->{"groupSet"}->{"item"} eq 'ARRAY' ? join ',', map { $_->{groupName} } @{ $_[1]->{"groupSet"}->{"item"} } : $_[1]->{"groupSet"}->{"item"}->{"groupName"} ), ( security_groups => ref $_[1]->{"groupSet"}->{"item"} eq 'ARRAY' ? [ map { $_->{groupName} } @{ $_[1]->{"groupSet"}->{"item"} } ] : [ $_[1]->{"groupSet"}->{"item"}->{"groupName"} ] ), ( tags => { map { if ( ref $instance_set->{"tagSet"}->{"item"}->{$_} eq 'HASH' ) { $_ => $instance_set->{"tagSet"}->{"item"}->{$_}->{value}; } else { $instance_set->{"tagSet"}->{"item"}->{key} => $instance_set->{"tagSet"}->{"item"}->{value}; } } keys %{ $instance_set->{"tagSet"}->{"item"} } } ), ); } sub list_instances { my ($self) = @_; my @ret; my $xml = $self->_request("DescribeInstances"); my $ref = $self->_xml($xml); return unless ($ref); return unless ( exists $ref->{"reservationSet"} ); return unless ( exists $ref->{"reservationSet"}->{"item"} ); if ( ref $ref->{"reservationSet"}->{"item"} eq "HASH" ) { # if only one instance is returned, turn it to an array $ref->{"reservationSet"}->{"item"} = [ $ref->{"reservationSet"}->{"item"} ]; } for my $instance_set ( @{ $ref->{"reservationSet"}->{"item"} } ) { # push(@ret, $instance_set); my $isi = $instance_set->{"instancesSet"}->{"item"}; if ( ref $isi eq 'HASH' ) { push( @ret, { $self->_make_instance_map($isi) } ); } elsif ( ref $isi eq 'ARRAY' ) { for my $iset (@$isi) { push( @ret, { $self->_make_instance_map($iset) } ); } } } return @ret; } sub list_running_instances { my ($self) = @_; return grep { $_->{"state"} eq "running" } $self->list_instances(); } sub get_regions { my ($self) = @_; my $content = $self->_request("DescribeRegions"); my %items = ( $content =~ m/([^<]+)<\/regionName>\s+([^<]+)<\/regionEndpoint>/gsim ); return %items; } sub get_availability_zones { my ($self) = @_; my $xml = $self->_request("DescribeAvailabilityZones"); my $ref = $self->_xml($xml); my @zones; for my $item ( @{ $ref->{"availabilityZoneInfo"}->{"item"} } ) { push( @zones, { zone_name => $item->{"zoneName"}, region_name => $item->{"regionName"}, zone_state => $item->{"zoneState"}, } ); } return @zones; } sub _request { my ( $self, $action, %args ) = @_; my $ua = LWP::UserAgent->new; $ua->env_proxy; my %param = $self->_sign( $action, %args ); Rex::Logger::debug( "Sending request to: https://" . $self->{'__endpoint'} ); Rex::Logger::debug( " $_ -> " . $param{$_} ) for keys %param; my $res = $ua->post( "https://" . $self->{'__endpoint'}, \%param ); if ( $res->code >= 500 ) { Rex::Logger::info( "Error on request", "warn" ); Rex::Logger::debug( $res->content ); return; } else { my $ret; eval { no warnings; $ret = $res->content; Rex::Logger::debug($ret); use warnings; }; return $ret; } } sub _sign { my ( $self, $action, %o_args ) = @_; my %args; for my $key ( keys %o_args ) { next unless $key; next unless $o_args{$key}; $args{$key} = $o_args{$key}; } my %sign_hash = ( AWSAccessKeyId => $self->{"__access_key"}, Action => $action, Timestamp => $self->timestamp(), Version => $self->{"__version"}, SignatureVersion => $self->{"__signature_version"}, %args ); my $sign_this; foreach my $key ( sort { lc($a) cmp lc($b) } keys %sign_hash ) { $sign_this .= $key . $sign_hash{$key}; } Rex::Logger::debug("Signed: $sign_this"); my $encoded = $self->_hash($sign_this); my %params = ( Action => $action, SignatureVersion => $self->{"__signature_version"}, AWSAccessKeyId => $self->{"__access_key"}, Timestamp => $self->timestamp(), Version => $self->{"__version"}, Signature => $encoded, %args ); return %params; } sub _hash { my ( $self, $query_string ) = @_; my $hashed = Digest::HMAC_SHA1->new( $self->{"__secret_access_key"} ); $hashed->add($query_string); return encode_base64( $hashed->digest, "" ); } sub _xml { my ( $self, $xml ) = @_; my $x = XML::Simple->new; my $res = $x->XMLin($xml); if ( defined $res->{"Errors"} ) { if ( ref( $res->{"Errors"} ) ne "ARRAY" ) { $res->{"Errors"} = [ $res->{"Errors"} ]; } my @error_msg = (); for my $error ( @{ $res->{"Errors"} } ) { push( @error_msg, $error->{"Error"}->{"Message"} . " (Code: " . $error->{"Error"}->{"Code"} . ")" ); } die( join( "\n", @error_msg ) ); } return $res; } 1; Rex-1.3.3/lib/Rex/Profiler.pm0000644000175000017500000000322312572251052015565 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Profiler; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Time::HiRes qw(gettimeofday tv_interval); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{__data} = {}; return $self; } sub start { my ( $self, $info ) = @_; push( @{ $self->{__data}->{$info} }, { start => [gettimeofday] } ); } sub end { my ( $self, $info ) = @_; return unless ( $self->{__data}->{$info}->[-1] ); my $data = $self->{__data}->{$info}->[-1]; $data->{end} = [gettimeofday]; $data->{duration} = tv_interval( $data->{start}, $data->{end} ); $self->{__data}->{$info}->[-1] = $data; } sub report { my ($self) = @_; for my $info ( keys %{ $self->{__data} } ) { print "# $info (count: " . scalar( @{ $self->{__data}->{$info} } ) . ")\n"; print " Timings:\n"; my ( $max, $min, $avg, $all ); for my $entry ( @{ $self->{__data}->{$info} } ) { if ( !$max || $max < $entry->{duration} ) { $max = $entry->{duration}; } if ( !$min || $min > $entry->{duration} ) { $min = $entry->{duration}; } $all += $entry->{duration}; } $avg = $all / scalar( @{ $self->{__data}->{$info} } ); print " min: $min / max: $max / avg: $avg / all: $all\n"; print " Overview:\n"; for my $entry ( @{ $self->{__data}->{$info} } ) { print " " . $entry->{duration} . "\n"; } print "--------------------------------------------------------------------------------\n"; } } 1; Rex-1.3.3/lib/Rex/Report.pm0000644000175000017500000000104212572251052015253 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Report; use strict; use warnings; use Data::Dumper; our $VERSION = '1.3.3'; # VERSION my $report; sub create { my ( $class, $type ) = @_; if ( $report && $type && ref($report) =~ m/::\Q$type\E$/ ) { return $report; } $type ||= "Base"; my $c = "Rex::Report::$type"; eval "use $c"; if ($@) { die("No reporting class $type found."); } $report = $c->new; return $report; } sub destroy { $report = undef; } 1; Rex-1.3.3/lib/Rex/Fork/0000755000175000017500000000000012572251052014346 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Fork/Manager.pm0000644000175000017500000000305512572251052016261 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Fork::Manager; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Fork::Task; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{'forks'} = []; $self->{'running'} = 0; return $self; } sub add { my ( $self, $task, $start ) = @_; my $f = Rex::Fork::Task->new( task => $task ); push( @{ $self->{'forks'} }, $f ); if ($start) { $f->start; ++$self->{'running'}; if ( $self->{'running'} >= $self->{'max'} ) { $self->wait_for_one; } } } sub start { my ($self) = @_; my @threads = @{ $self->{'forks'} }; for ( my $i = 0 ; $i < scalar(@threads) ; ++$i ) { $threads[$i]->start; ++$self->{'running'}; if ( $self->{'running'} >= $self->{'max'} ) { $self->wait_for_one; } } $self->wait_for_all; } sub wait_for_one { my ($self) = @_; $self->wait_for; } sub wait_for_all { my ($self) = @_; $self->wait_for(1); } sub wait_for { my ( $self, $all ) = @_; do { for ( my $i = 0 ; $i < scalar( @{ $self->{'forks'} } ) ; $i++ ) { my $thr = $self->{'forks'}->[$i]; unless ( $thr->{'running'} ) { next; } my $kid; $kid = $thr->wait; if ( $kid == -1 ) { $thr = undef; $thr->{running} = 0; --$self->{'running'}; return 1 unless $all; } select undef, undef, undef, .1; } } until $self->{'running'} == 0; } 1; Rex-1.3.3/lib/Rex/Fork/Task.pm0000644000175000017500000000231312572251052015605 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Fork::Task; use strict; use warnings; use POSIX ":sys_wait_h"; our $VERSION = '1.3.3'; # VERSION BEGIN { use Rex::Shared::Var; share qw(@PROCESS_LIST); } sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{'running'} = 0; return $self; } sub start { my ($self) = @_; $self->{'running'} = 1; if ( $self->{pid} = fork ) { return $self->{pid}; } else { $self->{chld} = 1; my $func = $self->{task}; # only allow this if no parallelism is given. # with parallelism active it doesn't make sense. if ($Rex::WITH_EXIT_STATUS) { eval { &$func($self); 1; } or do { push( @PROCESS_LIST, $? || 1 ); $self->{'running'} = 0; die($@); }; $self->{'running'} = 0; push( @PROCESS_LIST, 0 ); exit(); } else { &$func($self); $self->{'running'} = 0; exit(); } } } sub wait { my ($self) = @_; my $rpid = waitpid( $self->{pid}, &WNOHANG ); if ( $rpid == -1 ) { $self->{'running'} = 0; } return $rpid; } 1; Rex-1.3.3/lib/Rex/Test.pm0000644000175000017500000000126312572251052014724 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Test; use strict; use warnings; use Rex -base; use Data::Dumper; use Rex::Commands::Box; our $VERSION = '1.3.3'; # VERSION desc 'Run tests specified with --test=testfile (default: t/*.t)'; task run => make { Rex::Logger::info("Running integration tests..."); my $parameters = shift; my @files; LOCAL { @files = defined $parameters->{test} ? glob( $parameters->{test} ) : glob('t/*.t'); }; for my $file (@files) { Rex::Logger::info("Running test: $file."); do "$file"; Rex::Logger::info( "Error running $file: $@", "error" ) if $@; } }; 1; Rex-1.3.3/lib/Rex/TaskList/0000755000175000017500000000000012572251052015203 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/TaskList/Base.pm0000644000175000017500000002403112572251052016413 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::TaskList::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; use Rex::Logger; use Rex::Task; use Rex::Config; use Rex::Interface::Executor; use Rex::Fork::Manager; use Rex::Report; use Rex::Group; use Time::HiRes qw(time); use POSIX qw(floor); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{IN_TRANSACTION} = 0; $self->{DEFAULT_AUTH} = 1; $self->{tasks} = {}; return $self; } sub create_task { my $self = shift; my $task_name = shift; my $options = pop; my $desc = pop; if ( exists $self->{tasks}->{$task_name} ) { Rex::Logger::info( "Task $task_name already exists. Overwriting...", "warn" ); } Rex::Logger::debug("Creating task: $task_name"); my $func; if ( ref($desc) eq "CODE" ) { $func = $desc; $desc = ""; } else { $func = pop; } # matching against a task count of 2 because of the two internal tasks (filtered below) if ( ( scalar( keys %{ $self->{tasks} } ) ) == 2 ) { my $requested_env = Rex::Config->get_environment; my @environments = Rex::Commands->get_environments; if ( $task_name ne 'Commands:Box:get_sys_info' && $task_name ne 'Test:run' && $requested_env ne '' && !grep { $_ eq $requested_env } @environments ) { Rex::Logger::info( "Environment '$requested_env' has been requested, but it could not be found in the Rexfile. This is most likely only by mistake.", 'warn' ); Rex::Logger::info( "If it is intentional, you can suppress this warning by specifying an empty environment: environment '$requested_env' => sub {};", 'warn' ); } } my @server = (); if ($::FORCE_SERVER) { if ( ref $::FORCE_SERVER eq "ARRAY" ) { my $group_name_arr = $::FORCE_SERVER; for my $group_name ( @{$group_name_arr} ) { if ( !Rex::Group->is_group($group_name) ) { Rex::Logger::debug("Using late group-lookup"); push @server, sub { if ( !Rex::Group->is_group($group_name) ) { Rex::Logger::info( "No group $group_name defined.", "error" ); exit 1; } return map { Rex::Group::Entry::Server->new( name => $_ )->get_servers; } Rex::Group->get_group($group_name); }; } else { push( @server, map { Rex::Group::Entry::Server->new( name => $_ ); } Rex::Group->get_group($group_name) ); } } } else { my @servers = split( /\s+/, $::FORCE_SERVER ); push( @server, map { Rex::Group::Entry::Server->new( name => $_ ); } @servers ); Rex::Logger::debug("\tserver: $_") for @server; } } else { if ( scalar(@_) >= 1 ) { if ( $_[0] eq "group" ) { my $groups; if ( ref( $_[1] ) eq "ARRAY" ) { $groups = $_[1]; } else { $groups = [ $_[1] ]; } for my $group ( @{$groups} ) { if ( Rex::Group->is_group($group) ) { my @group_server = Rex::Group->get_group($group); # check if the group is empty. this is mostly due to a failure. # so report it, and exit. if ( scalar @group_server == 0 && Rex::Config->get_allow_empty_groups() == 0 ) { Rex::Logger::info( "The group $group is empty. This is mostly due to a failure.", "warn" ); Rex::Logger::info( "If this is an expected behaviour, please add the feature flag 'empty_groups'.", "warn" ); CORE::exit(1); } push( @server, @group_server ); } else { Rex::Logger::debug("Using late group-lookup"); push @server, sub { if ( !Rex::Group->is_group($group) ) { Rex::Logger::info( "No group $group defined.", "error" ); exit 1; } return map { if ( ref $_ && $_->isa("Rex::Group::Entry::Server") ) { $_->get_servers; } else { Rex::Group::Entry::Server->new( name => $_ )->get_servers; } } Rex::Group->get_group($group); }; } } } else { for my $entry (@_) { push( @server, ( ref $entry && $entry->isa("Rex::Group::Entry::Server") ? $entry : Rex::Group::Entry::Server->new( name => $entry ) ) ); } } } } my %task_hash = ( func => $func, server => [@server], desc => $desc, no_ssh => ( $options->{"no_ssh"} ? 1 : 0 ), hidden => ( $options->{"dont_register"} ? 1 : 0 ), exit_on_connect_fail => ( exists $options->{exit_on_connect_fail} ? $options->{exit_on_connect_fail} : 1 ), before => [], after => [], around => [], after_task_finished => [], before_task_start => [], name => $task_name, executor => Rex::Interface::Executor->create, connection_type => Rex::Config->get_connection_type, ); if ( $self->{DEFAULT_AUTH} ) { $task_hash{auth} = { user => Rex::Config->get_user || undef, password => Rex::Config->get_password || undef, private_key => Rex::Config->get_private_key || undef, public_key => Rex::Config->get_public_key || undef, sudo_password => Rex::Config->get_sudo_password || undef, }; } if ( exists $Rex::Commands::auth_late{$task_name} ) { $task_hash{auth} = $Rex::Commands::auth_late{$task_name}; } $self->{tasks}->{$task_name} = Rex::Task->new(%task_hash); } sub get_tasks { my $self = shift; return grep { $self->{tasks}->{$_}->hidden() == 0 } sort { $a cmp $b } keys %{ $self->{tasks} }; } sub get_all_tasks { my $self = shift; my $regexp = shift; return grep { $_ =~ $regexp } keys %{ $self->{tasks} }; } sub get_tasks_for { my $self = shift; my $host = shift; my @tasks; for my $task_name ( keys %{ $self->{tasks} } ) { my @servers = @{ $self->{tasks}->{$task_name}->server() }; if ( ( grep { /^$host$/ } @servers ) || $#servers == -1 ) { push @tasks, $task_name; } } my @ret = sort { $a cmp $b } @tasks; return @ret; } sub get_task { my ( $self, $task ) = @_; return $self->{tasks}->{$task}; } sub clear_tasks { my $self = shift; $self->{tasks} = {}; } sub get_desc { my $self = shift; my $task = shift; return $self->{tasks}->{$task}->desc(); } sub is_task { my $self = shift; my $task = shift; if ( exists $self->{tasks}->{$task} ) { return 1; } return 0; } sub run { my ( $self, $task_name, %option ) = @_; my $task = $self->get_task($task_name); $option{params} ||= { Rex::Args->get }; my @all_server = @{ $task->server }; my $fm = Rex::Fork::Manager->new( max => $self->get_thread_count($task) ); for my $server (@all_server) { my $forked_sub = sub { Rex::Logger::init(); # create a single task object for the run on $server Rex::Logger::info("Running task $task_name on $server"); my $run_task = Rex::Task->new( %{ $task->get_data } ); $run_task->run( $server, in_transaction => $self->{IN_TRANSACTION}, params => $option{params} ); # destroy cached os info Rex::Logger::debug("Destroying all cached os information"); Rex::Logger::shutdown(); }; # add the worker (forked_sub) to the fork queue unless ( $self->{IN_TRANSACTION} ) { # not inside a transaction, so lets fork happyly... $fm->add( $forked_sub, 1 ); } else { # inside a transaction, no little small funny kids, ... and no chance to get zombies :( &$forked_sub(); } } Rex::Logger::debug("Waiting for children to finish"); my $ret = $fm->wait_for_all; Rex::reconnect_lost_connections(); return $ret; } sub modify { my ( $self, $type, $task, $code, $package, $file, $line ) = @_; return if defined $Rex::Test::Rexfile::Syntax::syntax_check; if ( $package ne "main" && $package ne "Rex::CLI" ) { if ( $task !~ m/:/ ) { #do we need to detect for base -Rex ? $package =~ s/^Rex:://; $package =~ s/::/:/g; } } my @all_tasks = map { $self->get_task($_); } grep { if ( $package ne "main" && $package ne "Rex::CLI" ) { $_ =~ m/^\Q$package\E:/; } else { $_ !~ m/:/; } } $self->get_all_tasks($task); if ( !@all_tasks ) { Rex::Logger::info( "Can't add $type $task, as it is not yet defined\nsee $file line $line"); return; } for my $taskref (@all_tasks) { $taskref->modify( $type => $code ); } } sub set_default_auth { my ( $self, $auth ) = @_; $self->{DEFAULT_AUTH} = $auth; } sub is_default_auth { my ($self) = @_; return $self->{DEFAULT_AUTH}; } sub set_in_transaction { my ( $self, $val ) = @_; $self->{IN_TRANSACTION} = $val; } sub is_transaction { my ($self) = @_; return $self->{IN_TRANSACTION}; } sub get_exit_codes { my ($self) = @_; return @Rex::Fork::Task::PROCESS_LIST; } sub get_thread_count { my ( $self, $task ) = @_; my $threads = $task->parallelism || Rex::Config->get_parallelism; my $server_count = scalar @{ $task->server }; return $1 if $threads =~ /^(\d+)$/; return floor( $server_count / $1 ) if $threads =~ /^max\s?\/(\d+)$/; return floor( $server_count * $1 / 100 ) if $threads =~ /^max (\d+)%$/; return $server_count if $threads eq 'max'; Rex::Logger::info( "Unrecognized thread count requested: '$threads'. Falling back to a single thread.", 'warn' ); return 1; } 1; Rex-1.3.3/lib/Rex/TaskList/Parallel_ForkManager.pm0000644000175000017500000000444512572251052021560 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::TaskList::Parallel_ForkManager; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; use Rex::Logger; use Rex::Task; use Rex::Config; use Rex::Interface::Executor; use Rex::TaskList::Base; use Rex::Report; use Time::HiRes qw(time); BEGIN { use Rex::Require; Parallel::ForkManager->require; } use base qw(Rex::TaskList::Base); my @PROCESS_LIST; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub run { my ( $self, $task_name, %option ) = @_; my $task = $self->get_task($task_name); $option{params} ||= { Rex::Args->get }; my @all_server = @{ $task->server }; my $fm = Parallel::ForkManager->new( $self->get_thread_count($task) ); $fm->run_on_finish( sub { my ( $pid, $exit_code ) = @_; Rex::Logger::debug("Fork exited: $pid -> $exit_code"); push @PROCESS_LIST, $exit_code; } ); for my $server (@all_server) { my $forked_sub = sub { Rex::Logger::init(); # create a single task object for the run on $server Rex::Logger::info("Running task $task_name on $server"); my $run_task = Rex::Task->new( %{ $task->get_data } ); $run_task->run( $server, in_transaction => $self->{IN_TRANSACTION}, params => $option{params} ); # destroy cached os info Rex::Logger::debug("Destroying all cached os information"); Rex::Logger::shutdown(); }; # add the worker (forked_sub) to the fork queue unless ( $self->{IN_TRANSACTION} ) { # not inside a transaction, so lets fork happyly... $fm->start and next; eval { $forked_sub->(); 1; } or do { # exit with error $? = 255 if !$?; # unknown error exit $?; }; $fm->finish; } else { # inside a transaction, no little small funny kids, ... and no chance to get zombies :( &$forked_sub(); } } Rex::Logger::debug("Waiting for children to finish"); my $ret = $fm->wait_all_children; Rex::reconnect_lost_connections(); return $ret; } sub get_exit_codes { my ($self) = @_; return @PROCESS_LIST; } 1; Rex-1.3.3/lib/Rex/Hook.pm0000644000175000017500000000156712572251052014714 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Hook; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(register_function_hooks); my $__hooks = {}; sub register_function_hooks { my ($hooks) = @_; for my $state ( keys %{$hooks} ) { for my $func ( keys %{ $hooks->{$state} } ) { if ( !exists $__hooks->{$state}->{$func} ) { $__hooks->{$state}->{$func} = []; } push @{ $__hooks->{$state}->{$func} }, $hooks->{$state}->{$func}; } } } sub run_hook { my ( $command, $state, @args ) = @_; if ( !exists $__hooks->{$state}->{$command} ) { return; } my $func_arr = $__hooks->{$state}->{$command}; for my $func ( @{$func_arr} ) { @args = $func->(@args); } return @args; } 1; Rex-1.3.3/lib/Rex/Interface/0000755000175000017500000000000012572251052015345 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Shell.pm0000644000175000017500000000246112572251052016755 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; my %SHELL_PROVIDER = ( ash => "Rex::Interface::Shell::Ash", bash => "Rex::Interface::Shell::Bash", csh => "Rex::Interface::Shell::Csh", idrac => "Rex::Interface::Shell::Idrac", ksh => "Rex::Interface::Shell::Ksh", sh => "Rex::Interface::Shell::Sh", tcsh => "Rex::Interface::Shell::Tcsh", zsh => "Rex::Interface::Shell::Zsh", ); sub register_shell_provider { my ( $class, $shell_name, $shell_class ) = @_; $SHELL_PROVIDER{"\L$shell_name"} = $shell_class; return 1; } sub get_shell_provider { return %SHELL_PROVIDER; } sub create { my ( $class, $shell ) = @_; $shell =~ s/[\r\n]//gms; # sometimes there are some wired things... my $klass = "Rex::Interface::Shell::\u$shell"; eval "use $klass"; if ($@) { Rex::Logger::info( "Can't load wanted shell: '$shell' ('$klass'). Using default shell.", "warn" ); Rex::Logger::info( "If you want to help the development of Rex please report this issue in our Github issue tracker.", "warn" ); $klass = "Rex::Interface::Shell::Default"; eval "use $klass"; } return $klass->new; } 1; Rex-1.3.3/lib/Rex/Interface/Fs/0000755000175000017500000000000012572251052015715 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Fs/Sudo.pm0000644000175000017500000001241612572251052017171 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs::Sudo; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Rex::Commands; use Rex::Interface::Fs::Base; use Rex::Helper::Path; use Rex::Helper::Encode; use JSON::XS; use base qw(Rex::Interface::Fs::Base); use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub ls { my ( $self, $path ) = @_; my @ret; my @out = split( /\n/, $self->_exec("ls -a1 $path") ); # failed open directory, return undef if ( $? != 0 ) { return; } @ret = grep { !m/^\.\.?$/ } @out; # return directory content return @ret; } sub upload { my ( $self, $source, $target ) = @_; my $rnd_file = get_tmp_file; if ( my $ssh = Rex::is_ssh() ) { if ( ref $ssh eq "Net::OpenSSH" ) { $ssh->sftp->put( $source, $rnd_file ); } else { $ssh->scp_put( $source, $rnd_file ); } $self->_exec("mv $rnd_file '$target'"); } else { $self->cp( $source, $target ); } } sub download { my ( $self, $source, $target ) = @_; my $rnd_file = get_tmp_file; if ( my $ssh = Rex::is_ssh() ) { $self->_exec("cp '$source' $rnd_file"); $self->chmod( 444, $rnd_file ); if ( ref $ssh eq "Net::OpenSSH" ) { $ssh->sftp->get( $rnd_file, $target ); } else { $ssh->scp_get( $rnd_file, $target ); } Rex::get_current_connection_object()->run_sudo_unmodified( sub { $self->unlink($rnd_file); } ); } else { $self->cp( $source, $target ); } } sub is_dir { my ( $self, $path ) = @_; ($path) = $self->_normalize_path($path); $self->_exec("test -d $path"); my $ret = $?; $ret == 0 ? return 1 : return undef; } sub is_file { my ( $self, $file ) = @_; ($file) = $self->_normalize_path($file); $self->_exec("test -e $file"); my $is_file = $?; $self->_exec("test -d $file"); my $is_dir = $?; ( $is_file == 0 && $is_dir != 0 ) ? return 1 : return undef; } sub unlink { my ( $self, @files ) = @_; (@files) = $self->_normalize_path(@files); $self->_exec( "rm " . join( " ", @files ) ); if ( $? == 0 ) { return 1; } } sub mkdir { my ( $self, $dir ) = @_; ($dir) = $self->_normalize_path($dir); $self->_exec("mkdir $dir >/dev/null 2>&1"); if ( $? == 0 ) { return 1; } } sub stat { my ( $self, $file ) = @_; my $script = q| unlink $0; if(my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat($ARGV[0])) { my %ret; $ret{'mode'} = sprintf("%04o", $mode & 07777); $ret{'size'} = $size; $ret{'uid'} = $uid; $ret{'gid'} = $gid; $ret{'atime'} = $atime; $ret{'mtime'} = $mtime; print to_json(\%ret); } |; $script .= func_to_json(); my $rnd_file = $self->_write_to_rnd_file($script); ($file) = $self->_normalize_path($file); my $out = $self->_exec("perl $rnd_file $file"); Rex::get_current_connection_object()->run_sudo_unmodified( sub { $self->unlink($rnd_file); } ); if ( !$out ) { return undef; } my $tmp = decode_json($out); return %{$tmp}; } sub is_readable { my ( $self, $file ) = @_; ($file) = $self->_normalize_path($file); $self->_exec("test -r $file"); if ( $? == 0 ) { return 1; } } sub is_writable { my ( $self, $file ) = @_; ($file) = $self->_normalize_path($file); $self->_exec("test -w $file"); if ( $? == 0 ) { return 1; } } sub readlink { my ( $self, $file ) = @_; my $script = q|unlink $0; print readlink($ARGV[0]) . "\n"; |; ($file) = $self->_normalize_path($file); my $rnd_file = $self->_write_to_rnd_file($script); my $out = $self->_exec("perl $rnd_file $file"); my $ret = $?; chomp $out; Rex::get_current_connection_object()->run_sudo_unmodified( sub { $self->unlink($rnd_file); } ); $? = $ret; return $out; } sub rename { my ( $self, $old, $new ) = @_; ($old) = $self->_normalize_path($old); ($new) = $self->_normalize_path($new); $self->_exec("mv $old $new"); if ( $? == 0 ) { return 1; } } sub glob { my ( $self, $glob ) = @_; my $script = q| unlink $0; print to_json([ glob("| . $glob . q|") ]); |; $script .= func_to_json(); my $rnd_file = $self->_write_to_rnd_file($script); my $content = $self->_exec("perl $rnd_file"); my $ret = $?; Rex::get_current_connection_object()->run_sudo_unmodified( sub { $self->unlink($rnd_file); } ); $? = $ret; my $tmp = decode_json($content); return @{$tmp}; } sub _get_file_writer { my ($self) = @_; my $fh; if ( my $o = Rex::is_ssh() ) { if ( ref $o eq "Net::OpenSSH" ) { $fh = Rex::Interface::File->create("OpenSSH"); } else { $fh = Rex::Interface::File->create("SSH"); } } else { $fh = Rex::Interface::File->create("Local"); } return $fh; } sub _write_to_rnd_file { my ( $self, $content ) = @_; my $fh = $self->_get_file_writer(); my $rnd_file = get_tmp_file; $fh->open( ">", $rnd_file ); $fh->write($content); $fh->close; return $rnd_file; } sub _exec { my ( $self, $cmd ) = @_; my $exec = Rex::Interface::Exec->create("Sudo"); return $exec->exec($cmd); } 1; Rex-1.3.3/lib/Rex/Interface/Fs/SSH.pm0000644000175000017500000001436312572251052016717 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs::SSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::File::Stat; use Rex::Helper::Encode; use Rex::Interface::Exec; use Rex::Interface::Fs::Base; use base qw(Rex::Interface::Fs::Base); require Rex::Commands; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub ls { my ( $self, $path ) = @_; my @ret; Rex::Commands::profiler()->start("ls: $path"); eval { my $sftp = Rex::get_sftp(); my $dir = $sftp->opendir($path); unless ($dir) { die("$path is not a directory"); } while ( my $entry = $dir->read ) { push @ret, $entry->{'name'}; } }; Rex::Commands::profiler()->end("ls: $path"); # failed open directory, return undef if ($@) { return; } # return directory content return @ret; } sub is_dir { my ( $self, $path ) = @_; Rex::Commands::profiler()->start("is_dir: $path"); my $sftp = Rex::get_sftp(); my $stat = $sftp->stat($path); Rex::Commands::profiler()->end("is_dir: $path"); defined $stat ? return Rex::Helper::File::Stat->S_ISDIR( $stat->{mode} ) : return undef; } sub is_file { my ( $self, $file ) = @_; Rex::Commands::profiler()->start("is_file: $file"); my $sftp = Rex::get_sftp(); my $stat = $sftp->stat($file); Rex::Commands::profiler()->end("is_file: $file"); defined $stat ? return ( Rex::Helper::File::Stat->S_ISREG( $stat->{mode} ) || Rex::Helper::File::Stat->S_ISLNK( $stat->{mode} ) || Rex::Helper::File::Stat->S_ISBLK( $stat->{mode} ) || Rex::Helper::File::Stat->S_ISCHR( $stat->{mode} ) || Rex::Helper::File::Stat->S_ISFIFO( $stat->{mode} ) || Rex::Helper::File::Stat->S_ISSOCK( $stat->{mode} ) ) : return undef; } sub unlink { my ( $self, @files ) = @_; my $sftp = Rex::get_sftp(); for my $file (@files) { Rex::Commands::profiler()->start("unlink: $file"); eval { $sftp->unlink($file); 1; } or do { die "Error unlinking file: $file." if ( Rex::Config->get_autodie ); }; Rex::Commands::profiler()->end("unlink: $file"); } } sub mkdir { my ( $self, $dir ) = @_; my $ret; Rex::Commands::profiler()->start("mkdir: $dir"); my $sftp = Rex::get_sftp(); $sftp->mkdir($dir); if ( $self->is_dir($dir) ) { $ret = 1; } else { die "Error creating directory: $dir." if ( Rex::Config->get_autodie ); } Rex::Commands::profiler()->end("mkdir: $dir"); return $ret; } sub stat { my ( $self, $file ) = @_; Rex::Commands::profiler()->start("stat: $file"); my $sftp = Rex::get_sftp(); my %ret = $sftp->stat($file); if ( !%ret ) { return undef; } $ret{'mode'} = sprintf( "%04o", $ret{'mode'} & 07777 ); Rex::Commands::profiler()->end("stat: $file"); return %ret; } sub is_readable { my ( $self, $file ) = @_; Rex::Commands::profiler()->start("is_readable: $file"); ($file) = $self->_normalize_path($file); my $exec = Rex::Interface::Exec->create; $exec->exec("perl -le 'if(-r \"$file\") { exit 0; } exit 1'"); Rex::Commands::profiler()->end("is_readable: $file"); if ( $? == 0 ) { return 1; } } sub is_writable { my ( $self, $file ) = @_; Rex::Commands::profiler()->start("is_writable: $file"); ($file) = $self->_normalize_path($file); my $exec = Rex::Interface::Exec->create; $exec->exec("perl -le 'if(-w \"$file\") { exit 0; } exit 1'"); Rex::Commands::profiler()->end("is_writable: $file"); if ( $? == 0 ) { return 1; } } sub readlink { my ( $self, $file ) = @_; my $ret; Rex::Commands::profiler()->start("readlink: $file"); my $sftp = Rex::get_sftp(); $ret = $sftp->readlink($file); Rex::Commands::profiler()->end("readlink: $file"); return $ret; } sub rename { my ( $self, $old, $new ) = @_; my $ret; my $orig_path_old = $old; my $orig_path_new = $new; Rex::Commands::profiler()->start("rename: $old -> $new"); ($old) = $self->_normalize_path($old); ($new) = $self->_normalize_path($new); # don't use rename() doesn't work with different file systems / partitions my $exec = Rex::Interface::Exec->create; $exec->exec("/bin/mv $old $new"); if ( ( !$self->is_file($orig_path_old) && !$self->is_dir($orig_path_old) ) && ( $self->is_file($orig_path_new) || $self->is_dir($orig_path_new) ) ) { $ret = 1; } else { die "Error renaming file or directory ($orig_path_old -> $orig_path_new)." if ( Rex::Config->get_autodie ); } Rex::Commands::profiler()->end("rename: $orig_path_old -> $orig_path_new"); return $ret; } sub glob { my ( $self, $glob ) = @_; Rex::Commands::profiler()->start("glob: $glob"); my $ssh = Rex::is_ssh(); my $exec = Rex::Interface::Exec->create; my $content = $exec->exec("perl -le'print join(\"*,*,*\", glob(\"$glob\"))'"); chomp $content; my @files = split( /\*,\*,\*/, $content ); Rex::Commands::profiler()->end("glob: $glob"); return @files; } sub upload { my ( $self, $source, $target ) = @_; Rex::Commands::profiler()->start("upload: $source -> $target"); my $ssh = Rex::is_ssh(); unless ( $ssh->scp_put( $source, $target ) ) { Rex::Logger::debug("upload: $target is not writable"); Rex::Commands::profiler()->end("upload: $source -> $target"); die("upload: $target is not writable."); } Rex::Commands::profiler()->end("upload: $source -> $target"); } sub download { my ( $self, $source, $target ) = @_; Rex::Commands::profiler()->start("download: $source -> $target"); if ( $^O =~ m/^MSWin/ ) { # fix for: #271 my $ssh = Rex::is_ssh(); my $sftp = $ssh->sftp(); eval { my $fh = $sftp->open($source) or die($!); open( my $out, ">", $target ) or die($!); binmode $out; print $out $_ while (<$fh>); close $out; close $fh; 1; } or do { Rex::Commands::profiler()->end("download: $source -> $target"); die( $ssh->error ); }; } else { my $ssh = Rex::is_ssh(); if ( !$ssh->scp_get( $source, $target ) ) { Rex::Commands::profiler()->end("download: $source -> $target"); die( $ssh->error ); } } Rex::Commands::profiler()->end("download: $source -> $target"); } 1; Rex-1.3.3/lib/Rex/Interface/Fs/Local.pm0000644000175000017500000000637012572251052017313 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs::Local; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Fs::Base; use base qw(Rex::Interface::Fs::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub upload { my ( $self, $source, $target ) = @_; $self->cp( $source, $target ); } sub download { my ( $self, $source, $target ) = @_; $self->cp( $source, $target ); } sub ls { my ( $self, $path ) = @_; my @ret; eval { opendir( my $dh, $path ) or die("$path is not a directory"); while ( my $entry = readdir($dh) ) { next if ( $entry =~ /^\.\.?$/ ); push @ret, $entry; } closedir($dh); }; # failed open directory, return undef die "Error listing directory content ($path)" if ( $@ && Rex::Config->get_autodie ); if ($@) { return; } # return directory content return @ret; } sub rmdir { my ( $self, @dirs ) = @_; Rex::Logger::debug( "Removing directories: " . join( ", ", @dirs ) ); my $exec = Rex::Interface::Exec->create; if ( $^O =~ m/^MSWin/ ) { for (@dirs) { s/\//\\/g; } $exec->exec( "rd /Q /S " . join( " ", @dirs ) ); } else { @dirs = $self->_normalize_path(@dirs); $exec->exec( "/bin/rm -rf " . join( " ", @dirs ) ); } if ( $? == 0 ) { return 1; } die( "Error removing directory: " . join( ", ", @dirs ) ) if ( Rex::Config->get_autodie ); } sub is_dir { my ( $self, $path ) = @_; ( -d $path ) ? return 1 : return undef; } sub is_file { my ( $self, $file ) = @_; ( -f $file || -l $file || -b $file || -c $file || -p $file || -S $file ) ? return 1 : return undef; } sub unlink { my ( $self, @files ) = @_; CORE::unlink(@files); } sub mkdir { my ( $self, $dir ) = @_; if ( CORE::mkdir($dir) == 0 ) { die "Error creating directory: $dir" if ( Rex::Config->get_autodie ); return 0; } return 1; } sub stat { my ( $self, $file ) = @_; if ( my ( $dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks ) = CORE::stat($file) ) { my %ret; $ret{'mode'} = sprintf( "%04o", $mode & 07777 ); $ret{'size'} = $size; $ret{'uid'} = $uid; $ret{'gid'} = $gid; $ret{'atime'} = $atime; $ret{'mtime'} = $mtime; return %ret; } return undef; } sub is_readable { my ( $self, $file ) = @_; if ( -r $file ) { return 1; } } sub is_writable { my ( $self, $file ) = @_; if ( -w $file ) { return 1; } } sub readlink { my ( $self, $file ) = @_; return CORE::readlink($file); } sub rename { my ( $self, $old, $new ) = @_; my $exec = Rex::Interface::Exec->create; if ( $^O =~ m/^MSWin/ ) { $old =~ s/\//\\/g; $new =~ s/\//\\/g; $exec->exec("move \"$old\" \"$new\""); } else { ($old) = $self->_normalize_path($old); ($new) = $self->_normalize_path($new); $exec->exec("/bin/mv $old $new"); } if ( $? == 0 ) { return 1; } die "Error renaming file or directory: $old -> $new" if ( Rex::Config->get_autodie ); } sub glob { my ( $self, $glob ) = @_; return CORE::glob($glob); } 1; Rex-1.3.3/lib/Rex/Interface/Fs/Base.pm0000644000175000017500000001161012572251052017124 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Exec; use Rex::Helper::File::Spec; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub ls { die("Must be implemented by Interface Class"); } sub unlink { die("Must be implemented by Interface Class"); } sub mkdir { die("Must be implemented by Interface Class"); } sub glob { die("Must be implemented by Interface Class"); } sub rename { die("Must be implemented by Interface Class"); } sub stat { die("Must be implemented by Interface Class"); } sub readlink { die("Must be implemented by Interface Class"); } sub is_file { die("Must be implemented by Interface Class"); } sub is_dir { die("Must be implemented by Interface Class"); } sub is_readable { die("Must be implemented by Interface Class"); } sub is_writable { die("Must be implemented by Interface Class"); } sub upload { die("Must be implemented by Interface Class"); } sub download { die("Must be implemented by Interface Class"); } sub is_symlink { my ( $self, $path ) = @_; ($path) = $self->_normalize_path($path); $self->_exec("/bin/sh -c '[ -L \"$path\" ]'"); my $ret = $?; if ( $ret == 0 ) { return 1; } } sub ln { my ( $self, $from, $to ) = @_; Rex::Logger::debug("Symlinking files: $to -> $from"); ($from) = $self->_normalize_path($from); ($to) = $self->_normalize_path($to); my $exec = Rex::Interface::Exec->create; $exec->exec("ln -snf $from $to"); if ( $? == 0 ) { return 1; } die "Error creating symlink. ($from -> $to)" if ( Rex::Config->get_autodie ); } sub rmdir { my ( $self, @dirs ) = @_; @dirs = $self->_normalize_path(@dirs); Rex::Logger::debug( "Removing directories: " . join( ", ", @dirs ) ); my $exec = Rex::Interface::Exec->create; $exec->exec( "/bin/rm -rf " . join( " ", @dirs ) ); if ( $? == 0 ) { return 1; } die( "Error removing directory: " . join( ", ", @dirs ) ) if ( Rex::Config->get_autodie ); } sub chown { my ( $self, $user, $file, @opts ) = @_; my $options = {@opts}; ($file) = $self->_normalize_path($file); my $recursive = ""; if ( exists $options->{"recursive"} && $options->{"recursive"} == 1 ) { $recursive = " -R "; } my $exec = Rex::Interface::Exec->create; if ( $exec->can_run( ['chown'] ) ) { $exec->exec("chown $recursive $user $file"); if ( $? == 0 ) { return 1; } die("Error running chown $recursive $user $file") if ( Rex::Config->get_autodie ); } else { Rex::Logger::debug("Can't find `chown`."); return 1; # fake success for windows } } sub chgrp { my ( $self, $group, $file, @opts ) = @_; my $options = {@opts}; ($file) = $self->_normalize_path($file); my $recursive = ""; if ( exists $options->{"recursive"} && $options->{"recursive"} == 1 ) { $recursive = " -R "; } my $exec = Rex::Interface::Exec->create; if ( $exec->can_run( ['chgrp'] ) ) { $exec->exec("chgrp $recursive $group $file"); if ( $? == 0 ) { return 1; } die("Error running chgrp $recursive $group $file") if ( Rex::Config->get_autodie ); } else { Rex::Logger::debug("Can't find `chgrp`."); return 1; # fake success for windows } } sub chmod { my ( $self, $mode, $file, @opts ) = @_; my $options = {@opts}; ($file) = $self->_normalize_path($file); my $recursive = ""; if ( exists $options->{"recursive"} && $options->{"recursive"} == 1 ) { $recursive = " -R "; } my $exec = Rex::Interface::Exec->create; if ( $exec->can_run( ['chmod'] ) ) { $exec->exec("chmod $recursive $mode $file"); if ( $? == 0 ) { return 1; } die("Error running chmod $recursive $mode $file") if ( Rex::Config->get_autodie ); } else { Rex::Logger::debug("Can't find `chmod`."); return 1; # fake success for windows } } sub cp { my ( $self, $source, $dest ) = @_; ($source) = $self->_normalize_path($source); ($dest) = $self->_normalize_path($dest); my $exec = Rex::Interface::Exec->create; $exec->exec("cp -R $source $dest"); if ( $? == 0 ) { return 1; } die("Error copying $source -> $dest") if ( Rex::Config->get_autodie ); } sub _normalize_path { my ( $self, @dirs ) = @_; my @ret; for my $d (@dirs) { my @t; if (Rex::is_ssh) { @t = Rex::Helper::File::Spec->splitdir($d); } else { @t = Rex::Helper::File::Spec->splitdir($d); } push( @ret, Rex::Helper::File::Spec->catfile( map { $self->_quotepath($_) } @t ) ); } # for (@dirs) { # s/ /\\ /g; # } return @ret; } sub _quotepath { my ( $self, $p ) = @_; $p =~ s/([\@\$\% ])/\\$1/g; return $p; } sub _exec { my ( $self, $cmd ) = @_; my $exec = Rex::Interface::Exec->create; return $exec->exec($cmd); } 1; Rex-1.3.3/lib/Rex/Interface/Fs/HTTP.pm0000644000175000017500000000761212572251052017040 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs::HTTP; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands; use Rex::Interface::Exec; use Rex::Interface::Fs::Base; use Data::Dumper; BEGIN { use Rex::Require; MIME::Base64->use; } use base qw(Rex::Interface::Fs::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub ls { my ( $self, $path ) = @_; my $resp = connection->post( "/fs/ls", { path => $path } ); if ( $resp->{ok} ) { return @{ $resp->{ls} }; } } sub is_dir { my ( $self, $path ) = @_; my $resp = connection->post( "/fs/is_dir", { path => $path } ); return $resp->{ok}; } sub is_file { my ( $self, $file ) = @_; my $resp = connection->post( "/fs/is_file", { path => $file } ); return $resp->{ok}; } sub unlink { my ( $self, @files ) = @_; my $ok = 0; for my $file (@files) { my $resp = connection->post( "/fs/unlink", { path => $file } ); $ok = $resp->{ok}; } return $ok; } sub mkdir { my ( $self, $dir ) = @_; my $resp = connection->post( "/fs/mkdir", { path => $dir } ); return $resp->{ok}; } sub stat { my ( $self, $file ) = @_; my $resp = connection->post( "/fs/stat", { path => $file } ); if ( $resp->{ok} ) { return %{ $resp->{stat} }; } return undef; } sub is_readable { my ( $self, $file ) = @_; my $resp = connection->post( "/fs/is_readable", { path => $file } ); return $resp->{ok}; } sub is_writable { my ( $self, $file ) = @_; my $resp = connection->post( "/fs/is_writable", { path => $file } ); return $resp->{ok}; } sub readlink { my ( $self, $file ) = @_; my $resp = connection->post( "/fs/readlink", { path => $file } ); if ( $resp->{ok} ) { return $resp->{link}; } } sub rename { my ( $self, $old, $new ) = @_; my $resp = connection->post( "/fs/rename", { old => $old, new => $new } ); return $resp->{ok}; } sub glob { my ( $self, $glob ) = @_; my $resp = connection->post( "/fs/glob", { glob => $glob } ); if ( $resp->{ok} ) { return @{ $resp->{glob} }; } } sub upload { my ( $self, $source, $target ) = @_; my $resp = connection->upload( [ content => [$source], path => $target ] ); return $resp->{ok}; } sub download { my ( $self, $source, $target ) = @_; my $resp = connection->post( "/fs/download", { path => $source } ); if ( $resp->{ok} ) { open( my $fh, ">", $target ) or die($!); print $fh decode_base64( $resp->{content} ); close($fh); return 1; } return 0; } sub ln { my ( $self, $from, $to ) = @_; Rex::Logger::debug("Symlinking files: $to -> $from"); my $resp = connection->post( "/fs/ln", { from => $from, to => $to } ); return $resp->{ok}; } sub rmdir { my ( $self, @dirs ) = @_; Rex::Logger::debug( "Removing directories: " . join( ", ", @dirs ) ); my $ok = 0; for my $dir (@dirs) { my $resp = connection->post( "/fs/rmdir", { path => $dir } ); $ok = $resp->{ok}; } return $ok; } sub chown { my ( $self, $user, $file, @opts ) = @_; my $resp = connection->post( "/fs/chown", { user => $user, path => $file, options => {@opts}, } ); return $resp->{ok}; } sub chgrp { my ( $self, $group, $file, @opts ) = @_; my $resp = connection->post( "/fs/chgrp", { group => $group, path => $file, options => {@opts}, } ); return $resp->{ok}; } sub chmod { my ( $self, $mode, $file, @opts ) = @_; my $resp = connection->post( "/fs/chmod", { mode => $mode, path => $file, options => {@opts}, } ); return $resp->{ok}; } sub cp { my ( $self, $source, $dest ) = @_; my $resp = connection->post( "/fs/cp", { source => $source, dest => $dest, } ); return $resp->{ok}; } 1; Rex-1.3.3/lib/Rex/Interface/Fs/OpenSSH.pm0000644000175000017500000000704212572251052017535 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs::OpenSSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::File::Stat; use Rex::Interface::Exec; use Rex::Interface::Fs::SSH; BEGIN { use Rex::Require; Net::SFTP::Foreign::Constants->use(qw(:flags)); } use base qw(Rex::Interface::Fs::SSH); require Rex::Commands; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub ls { my ( $self, $path ) = @_; my @ret; Rex::Commands::profiler()->start("ls: $path"); eval { my $sftp = Rex::get_sftp(); my $ls = $sftp->ls($path); for my $entry ( @{$ls} ) { push @ret, $entry->{'filename'}; } }; Rex::Commands::profiler()->end("ls: $path"); # failed open directory, return undef die "Error listing directory content ($path)" if ( $@ && Rex::Config->get_autodie ); if ($@) { return; } # return directory content return @ret; } sub is_dir { my ( $self, $path ) = @_; Rex::Commands::profiler()->start("is_dir: $path"); my $sftp = Rex::get_sftp(); my $attr = $sftp->stat($path); Rex::Commands::profiler()->end("is_dir: $path"); defined $attr ? return Rex::Helper::File::Stat->S_ISDIR( $attr->perm ) : return undef; } sub is_file { my ( $self, $file ) = @_; Rex::Commands::profiler()->start("is_file: $file"); my $sftp = Rex::get_sftp(); my $attr = $sftp->stat($file); Rex::Commands::profiler()->end("is_file: $file"); defined $attr ? return ( Rex::Helper::File::Stat->S_ISREG( $attr->perm ) || Rex::Helper::File::Stat->S_ISLNK( $attr->perm ) || Rex::Helper::File::Stat->S_ISBLK( $attr->perm ) || Rex::Helper::File::Stat->S_ISCHR( $attr->perm ) || Rex::Helper::File::Stat->S_ISFIFO( $attr->perm ) || Rex::Helper::File::Stat->S_ISSOCK( $attr->perm ) ) : return undef; } sub unlink { my ( $self, @files ) = @_; my $sftp = Rex::get_sftp(); for my $file (@files) { Rex::Commands::profiler()->start("unlink: $file"); eval { $sftp->remove($file); 1; } or do { die "Error unlinking file: $file." if ( Rex::Config->get_autodie ); }; Rex::Commands::profiler()->end("unlink: $file"); } } sub stat { my ( $self, $file ) = @_; Rex::Commands::profiler()->start("stat: $file"); my $sftp = Rex::get_sftp(); my $ret = $sftp->stat($file); if ( !$ret ) { return undef; } my %ret = ( mode => sprintf( "%04o", $ret->perm & 07777 ), size => $ret->size, uid => $ret->uid, gid => $ret->gid, atime => $ret->atime, mtime => $ret->mtime, ); Rex::Commands::profiler()->end("stat: $file"); return %ret; } sub upload { my ( $self, $source, $target ) = @_; Rex::Commands::profiler()->start("upload: $source -> $target"); my $sftp = Rex::get_sftp(); unless ( $sftp->put( $source, $target ) ) { Rex::Logger::debug("upload: $target is not writable"); Rex::Commands::profiler()->end("upload: $source -> $target"); die("upload: $target is not writable."); } Rex::Commands::profiler()->end("upload: $source -> $target"); } sub download { my ( $self, $source, $target ) = @_; Rex::Commands::profiler()->start("download: $source -> $target"); my $sftp = Rex::get_sftp(); if ( !$sftp->get( $source, $target ) ) { Rex::Commands::profiler()->end("download: $source -> $target"); die( $sftp->error ); } Rex::Commands::profiler()->end("download: $source -> $target"); } 1; Rex-1.3.3/lib/Rex/Interface/File.pm0000644000175000017500000000143312572251052016563 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex; sub create { my ( $class, $type ) = @_; unless ($type) { #$type = Rex::Commands::task()->get_connection_type; $type = Rex::get_current_connection()->{conn}->get_connection_type; #Rex::Commands::task()->get_connection_type; #if(Rex::is_ssh() && ! Rex::is_sudo()) { # $type = "SSH"; #} #elsif(Rex::is_sudo()) { # $type = "Sudo"; #} #else { # $type = "Local"; #} } my $class_name = "Rex::Interface::File::$type"; eval "use $class_name;"; if ($@) { die("Error loading file interface $type.\n$@"); } return $class_name->new; } 1; Rex-1.3.3/lib/Rex/Interface/Executor/0000755000175000017500000000000012572251052017143 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Executor/Default.pm0000644000175000017500000000243012572251052021064 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Executor::Default; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Hook; use Rex::Logger; use Data::Dumper; use Rex::Interface::Executor::Base; use base qw(Rex::Interface::Executor::Base); require Rex::Args; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub exec { my ( $self, $opts ) = @_; $opts ||= { Rex::Args->get }; my $task = $self->{task}; Rex::Logger::debug( "Executing " . $task->name ); my $ret; eval { my $code = $task->code; Rex::Hook::run_hook( task => "before_execute", $task->name, @_ ); $ret = &$code($opts); Rex::Hook::run_hook( task => "after_execute", $task->name, @_ ); }; my %opts = Rex::Args->getopts; if ($@) { my $error = $@; if ( exists $opts{o} ) { Rex::Output->get->add( $task->name, error => 1, msg => $@ ); } else { Rex::Logger::info( "Error executing task:", "error" ); Rex::Logger::info( "$error", "error" ); die($@); } } else { if ( exists $opts{o} ) { Rex::Output->get->add( $task->name ); } } return $ret; } 1; Rex-1.3.3/lib/Rex/Interface/Executor/Base.pm0000644000175000017500000000075012572251052020355 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Executor::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub exec { die("Should be implemented by interface class."); } sub set_task { my ( $self, $task ) = @_; $self->{task} = $task; } 1; Rex-1.3.3/lib/Rex/Interface/Exec/0000755000175000017500000000000012572251052016231 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Exec/Sudo.pm0000644000175000017500000001134112572251052017501 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec::Sudo; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Config; use Rex::Interface::Exec::Local; use Rex::Interface::Exec::SSH; use Rex::Helper::Encode; use Rex::Interface::File::Local; use Rex::Interface::File::SSH; use Rex::Commands; use Rex::Helper::Path; use base 'Rex::Interface::Exec::Base'; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub exec { my ( $self, $cmd, $path, $option ) = @_; if ( exists $option->{cwd} ) { $cmd = "cd " . $option->{cwd} . " && $cmd"; } if ( exists $option->{path} ) { $path = $option->{path}; } my ( $exec, $file, $shell ); if ( my $ssh = Rex::is_ssh() ) { if ( ref $ssh eq "Net::OpenSSH" ) { $exec = Rex::Interface::Exec->create("OpenSSH"); $file = Rex::Interface::File->create("OpenSSH"); } else { $exec = Rex::Interface::Exec->create("SSH"); $file = Rex::Interface::File->create("SSH"); } } else { $exec = Rex::Interface::Exec->create("Local"); $file = Rex::Interface::File->create("Local"); } $shell = Rex::Interface::Shell->create("Sh"); # we're using sh for sudo ######## envs setzen. aber erst nachdem wir wissen ob wir sh forcen duerfen # if(exists $option->{env}) { # $shell->set_environment($option->{env}); # } my $sudo_password = ( defined task() ? task->get_sudo_password : Rex::Config->get_sudo_password ); my $enc_pw; my $random_file = ""; Rex::Logger::debug("Sudo: Executing: $cmd"); if ($sudo_password) { my $random_string = get_random( length($sudo_password), 'a' .. 'z' ); my $crypt = $sudo_password ^ $random_string; $random_file = get_tmp_file; $file->open( '>', $random_file ); $file->write(<close; $enc_pw = Rex::Helper::Encode::url_encode($crypt); } else { $enc_pw = ""; } #my $sudo_options = Rex::get_current_connection()->{sudo_options}; my $sudo_options = Rex::get_current_connection_object()->get_current_sudo_options; my $sudo_options_str = ""; if ( exists $sudo_options->{user} ) { $sudo_options_str .= " -u " . $sudo_options->{user}; } if ( Rex::Config->get_sudo_without_locales() ) { Rex::Logger::debug( "Using sudo without locales. If the locale is NOT C or en_US it will break many things!" ); $option->{no_locales} = 1; } my $sudo_command = "sudo $sudo_options_str -p '' -S"; if ( Rex::Config->get_sudo_without_sh() ) { Rex::Logger::debug( "Using sudo without sh will break things like file editing."); # $option->{no_sh} = 1; $shell->set_inner_shell(0); $shell->set_sudo_env(1); if ( exists $option->{env} ) { $shell->set_environment( $option->{env} ); } if ($enc_pw) { # $option->{format_cmd} = # "perl $random_file '$enc_pw' | sudo $sudo_options_str -p '' -S {{CMD}}"; $sudo_command = "perl $random_file '$enc_pw' 2>/dev/null | $sudo_command"; } # else { # $option->{format_cmd} = "sudo $sudo_options_str -p '' -S {{CMD}}"; # } } else { $shell->set_locale("C"); $shell->path($path); if ( Rex::Config->get_source_global_profile ) { $shell->source_global_profile(1); } if ( Rex::Config->get_source_profile ) { $shell->source_profile(1); } if ( exists $option->{env} ) { $shell->set_environment( $option->{env} ); } # escape some special shell things # $option->{preprocess_command} = sub { # my ($_cmd) = @_; # $_cmd =~ s/\\/\\\\/gms; # $_cmd =~ s/"/\\"/gms; # $_cmd =~ s/\$/\\\$/gms; # }; $shell->set_inner_shell(1); # $cmd =~ s/\\/\\\\/gms; # $cmd =~ s/"/\\"/gms; # $cmd =~ s/\$/\\\$/gms; # Calling sudo with sh(1) in this case we don't need to respect current user shell, pass _force_sh flag to ssh layer # $option->{_force_sh} = 1; if ($enc_pw) { $sudo_command = "perl $random_file '$enc_pw' 2>/dev/null | $sudo_command"; # $option->{format_cmd} = # "perl $random_file '$enc_pw' | sudo $sudo_options_str -p '' -S sh -c \"{{CMD}}\""; } # else { # $option->{format_cmd} = # "sudo $sudo_options_str -p '' -S sh -c \"{{CMD}}\""; # } } $option->{prepend_command} = $sudo_command; my $real_exec = $shell->exec( $cmd, $option ); Rex::Logger::debug("sudo: exec: $real_exec"); return $exec->direct_exec( $real_exec, $option ); } 1; Rex-1.3.3/lib/Rex/Interface/Exec/SSH.pm0000644000175000017500000000604312572251052017227 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec::SSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::SSH2; use File::Basename 'basename'; use Rex::Interface::Shell; require Rex::Commands; # Use 'parent' is recommended, but from Perl 5.10.1 its in core use base 'Rex::Interface::Exec::Base'; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub direct_exec { my ( $self, $exec, $option ) = @_; Rex::Commands::profiler()->start("direct_exec: $exec"); Rex::Logger::debug("SSH/executing: $exec"); my ( $out, $err ) = $self->_exec( $exec, $option ); Rex::Commands::profiler()->end("direct_exec: $exec"); Rex::Logger::debug($out) if ($out); if ($err) { Rex::Logger::debug("========= ERR ============"); Rex::Logger::debug($err); Rex::Logger::debug("========= ERR ============"); } if (wantarray) { return ( $out, $err ); } return $out; } sub exec { my ( $self, $cmd, $path, $option ) = @_; Rex::Logger::debug("Executing: $cmd"); Rex::Commands::profiler()->start("exec: $cmd"); my $used_shell = $self->_get_shell(); my $shell; if ( $option->{_force_sh} ) { $shell = Rex::Interface::Shell->create("Sh"); } else { $shell = Rex::Interface::Shell->create($used_shell); } $shell->set_locale("C"); $shell->path($path); if ( Rex::Config->get_source_global_profile ) { $shell->source_global_profile(1); } if ( Rex::Config->get_source_profile ) { $shell->source_profile(1); } if ( exists $option->{env} ) { $shell->set_environment( $option->{env} ); } my $exec = $shell->exec( $cmd, $option ); Rex::Logger::debug("SSH/executing: $exec"); my ( $out, $err ) = $self->_exec( $exec, $option ); Rex::Commands::profiler()->end("exec: $cmd"); Rex::Logger::debug($out) if ($out); if ($err) { Rex::Logger::debug("========= ERR ============"); Rex::Logger::debug($err); Rex::Logger::debug("========= ERR ============"); } if (wantarray) { return ( $out, $err ); } return $out; } sub _exec { my ( $self, $exec, $option ) = @_; # my $callback = $option->{continuous_read} || undef; # $option->{continuous_read} ||= $callback; my $ssh = Rex::is_ssh(); my ( $out, $err ) = net_ssh2_exec( $ssh, $exec, $self, $option ); return ( $out, $err ); } sub _get_shell { my ($self) = @_; Rex::Logger::debug("Detecting shell..."); my $cache = Rex::get_cache(); if ( $cache->valid("shell") ) { Rex::Logger::debug( "Found shell in cache: " . $cache->get("shell") ); return $cache->get("shell"); } my %shells = Rex::Interface::Shell->get_shell_provider; for my $shell ( keys %shells ) { Rex::Logger::debug( "Searching for shell: " . $shell ); $shells{$shell}->require; if ( $shells{$shell}->detect($self) ) { Rex::Logger::debug( "Found shell and using: " . $shell ); $cache->set( "shell", $shell ); return $shell; } } return "sh"; } 1; Rex-1.3.3/lib/Rex/Interface/Exec/Local.pm0000644000175000017500000000566212572251052017632 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec::Local; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands; use Symbol 'gensym'; use IPC::Open3; # Use 'parent' is recommended, but from Perl 5.10.1 its in core use base 'Rex::Interface::Exec::Base'; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub set_env { my ( $self, $env ) = @_; my $cmd = undef; die("Error: env must be a hash") if ( ref $env ne "HASH" ); while ( my ( $k, $v ) = each(%$env) ) { $cmd .= "export $k='$v'; "; } $self->{env} = $cmd; } sub exec { my ( $self, $cmd, $path, $option ) = @_; my ( $out, $err, $pid ); if ( exists $option->{cwd} ) { $cmd = "cd " . $option->{cwd} . " && $cmd"; } if ( exists $option->{path} ) { $path = $option->{path}; } if ( exists $option->{env} ) { $self->set_env( $option->{env} ); } if ( exists $option->{format_cmd} ) { $option->{format_cmd} =~ s/\{\{CMD\}\}/$cmd/; $cmd = $option->{format_cmd}; } Rex::Commands::profiler()->start("exec: $cmd"); if ( $^O !~ m/^MSWin/ ) { if ($path) { $path = "PATH=$path" } $path ||= ""; my $new_cmd = "LC_ALL=C $cmd"; if ($path) { $new_cmd = "export $path ; $new_cmd"; } if ( $self->{env} ) { $new_cmd = $self->{env} . " $new_cmd"; } if ( Rex::Config->get_source_global_profile ) { $new_cmd = ". /etc/profile >/dev/null 2>&1; $new_cmd"; } $cmd = $new_cmd; } Rex::Logger::debug("Executing: $cmd"); my ( $writer, $reader, $error ); $error = gensym; if ( Rex::Config->get_no_tty ) { $pid = open3( $writer, $reader, $error, $cmd ); while ( my $output = <$reader> ) { $out .= $output; $self->execute_line_based_operation( $output, $option ) && goto END_OPEN3; } while ( my $errout = <$error> ) { $err .= $errout; $self->execute_line_based_operation( $errout, $option ) && goto END_OPEN3; } END_OPEN3: waitpid( $pid, 0 ) or die($!); } else { $pid = open( my $fh, "-|", "$cmd 2>&1" ) or die($!); while (<$fh>) { $out .= $_; $self->execute_line_based_operation( $_, $option ) && do { kill( 'KILL', $pid ); last }; } waitpid( $pid, 0 ) or die($!); } $? >>= 8; Rex::Logger::debug($out) if ($out); if ($err) { Rex::Logger::debug("========= ERR ============"); Rex::Logger::debug($err); Rex::Logger::debug("========= ERR ============"); } Rex::Commands::profiler()->end("exec: $cmd"); if (wantarray) { return ( $out, $err ); } return $out; } sub can_run { my ( $self, $commands_to_check, $check_with_command ) = @_; $check_with_command ||= $^O =~ /^MSWin/i ? 'where' : 'which'; return $self->SUPER::can_run( $commands_to_check, $check_with_command ); } 1; Rex-1.3.3/lib/Rex/Interface/Exec/Base.pm0000644000175000017500000000252412572251052017444 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec::Base; use strict; use warnings; use Carp; use Rex::Helper::Run; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub exec { die("Must be implemented by Interface Class"); } sub _continuous_read { my ( $self, $line, $option ) = @_; my $cb = $option->{continuous_read} || undef; if ( defined($cb) && ref($cb) eq 'CODE' ) { &$cb($line); } } sub _end_if_matched { my ( $self, $line, $option ) = @_; my $regex = $option->{end_if_matched} || undef; if ( defined($regex) && ref($regex) eq 'Regexp' && $line =~ m/$regex/ ) { return 1; } return; } sub execute_line_based_operation { my ( $self, $line, $option ) = @_; $self->_continuous_read( $line, $option ); return $self->_end_if_matched( $line, $option ); } sub can_run { my ( $self, $commands_to_check, $check_with_command ) = @_; $check_with_command ||= "which"; for my $command ( @{$commands_to_check} ) { my @output = Rex::Helper::Run::i_run "$check_with_command $command"; next if ( $? != 0 ); next if ( grep { /^no $command in/ } @output ); # for solaris return $output[0]; } return undef; } 1; Rex-1.3.3/lib/Rex/Interface/Exec/HTTP.pm0000644000175000017500000000263112572251052017350 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec::HTTP; use strict; use warnings; use Rex::Commands; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub exec { my ( $self, $cmd, $path, $option ) = @_; Rex::Logger::debug("Executing: $cmd"); if ( exists $option->{path} ) { $path = $option->{path}; } if ($path) { $path = "PATH=$path" } $path ||= ""; # let the other side descide if LC_ALL=C should be used # for example, this will not work on windows #$cmd = "LC_ALL=C $path " . $cmd; Rex::Commands::profiler()->start("exec: $cmd"); my $new_cmd = $cmd; if ( Rex::Config->get_source_global_profile ) { $new_cmd = ". /etc/profile >/dev/null 2>&1; $new_cmd"; } my $resp = connection->post( "/execute", { exec => $new_cmd, options => $option } ); Rex::Commands::profiler()->end("exec: $cmd"); if ( $resp->{ok} ) { $? = $resp->{retval}; my ( $out, $err ) = ( $resp->{output}, "" ); Rex::Logger::debug($out); if ($err) { Rex::Logger::debug("========= ERR ============"); Rex::Logger::debug($err); Rex::Logger::debug("========= ERR ============"); } if (wantarray) { return ( $out, $err ); } return $out; } else { $? = 1; } } 1; Rex-1.3.3/lib/Rex/Interface/Exec/OpenSSH.pm0000644000175000017500000000227312572251052020052 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec::OpenSSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::SSH2; require Rex::Commands; use Rex::Interface::Exec::SSH; use base qw(Rex::Interface::Exec::SSH); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub _exec { my ( $self, $exec, $option ) = @_; my ( $out, $err, $pid, $out_fh, $err_fh ); my $ssh = Rex::is_ssh(); my $tty = !Rex::Config->get_no_tty; ( undef, $out_fh, $err_fh, $pid ) = $ssh->open3( { tty => $tty }, $exec ); while ( my $line = <$out_fh> ) { $line =~ s/(\r?\n)$/\n/; $out .= $line; $self->execute_line_based_operation( $line, $option ) && do { kill( 'KILL', $pid ); goto END_OPEN }; } while ( my $line = <$err_fh> ) { $line =~ s/(\r?\n)$/\n/; $err .= $line; $self->execute_line_based_operation( $line, $option ) && do { kill( 'KILL', $pid ); goto END_OPEN }; } END_OPEN: waitpid( $pid, 0 ) or die($!); if ( $ssh->error || $? ) { $? = $? >> 8; } return ( $out, $err ); } 1; Rex-1.3.3/lib/Rex/Interface/File/0000755000175000017500000000000012572251052016224 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/File/Sudo.pm0000644000175000017500000000561612572251052017504 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File::Sudo; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl; use File::Basename; require Rex::Commands; use Rex::Interface::Fs; use Rex::Interface::File::Base; use Rex::Helper::Path; use base qw(Rex::Interface::File::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub open { my ( $self, $mode, $file ) = @_; if ( my $ssh = Rex::is_ssh() ) { if ( ref $ssh eq "Net::OpenSSH" ) { $self->{fh} = Rex::Interface::File->create("OpenSSH"); } else { $self->{fh} = Rex::Interface::File->create("SSH"); } } else { $self->{fh} = Rex::Interface::File->create("Local"); } # always use current logged in user for sudo fs operations Rex::get_current_connection_object()->push_sudo_options( {} ); $self->{mode} = $mode; $self->{file} = $file; $self->{rndfile} = get_tmp_file; if ( $self->_fs->is_file($file) ) { # resolving symlinks while ( my $link = $self->_fs->readlink($file) ) { if ( $link !~ m/^\// ) { $file = dirname($file) . "/" . $link; } else { $file = $link; } $link = $self->_fs->readlink($link); } $self->{file_stat} = { $self->_fs->stat( $self->{file} ) }; $self->_fs->cp( $file, $self->{rndfile} ); $self->_fs->chmod( 600, $self->{rndfile} ); $self->_fs->chown( Rex::Commands::connection->get_auth_user, $self->{rndfile} ); } $self->{fh}->open( $mode, $self->{rndfile} ); Rex::get_current_connection_object()->pop_sudo_options(); return $self->{fh}; } sub read { my ( $self, $len ) = @_; return $self->{fh}->read($len); } sub write { my ( $self, $buf ) = @_; $self->{fh}->write($buf); } sub seek { my ( $self, $pos ) = @_; $self->{fh}->seek($pos); } sub close { my ($self) = @_; return unless $self->{fh}; # always use current logged in user for sudo fs operations Rex::get_current_connection_object()->push_sudo_options( {} ); $self->{fh}->close; if ( exists $self->{mode} && ( $self->{mode} eq ">" || $self->{mode} eq ">>" ) ) { my $exec = Rex::Interface::Exec->create; if ( $self->{file_stat} ) { my %stat = $self->_fs->stat( $self->{file} ); $self->_fs->chmod( $stat{mode}, $self->{rndfile} ); $self->_fs->chown( $stat{uid}, $self->{rndfile} ); $self->_fs->chgrp( $stat{gid}, $self->{rndfile} ); } $self->_fs->rename( $self->{rndfile}, $self->{file} ); #$exec->exec("cat " . $self->{rndfile} . " >'" . $self->{file} . "'"); } $self->{fh} = undef; $self->_fs->unlink( $self->{rndfile} ); Rex::get_current_connection_object()->pop_sudo_options(); $self = undef; } sub _fs { my ($self) = @_; return Rex::Interface::Fs->create("Sudo"); } 1; Rex-1.3.3/lib/Rex/Interface/File/SSH.pm0000644000175000017500000000244612572251052017225 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File::SSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl; use Rex::Interface::Fs; use Rex::Interface::File::Base; use base qw(Rex::Interface::File::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub open { my ( $self, $mode, $file ) = @_; Rex::Logger::debug("Opening $file with mode: $mode"); my $sftp = Rex::get_sftp(); if ( $mode eq ">" ) { $self->{fh} = $sftp->open( $file, O_WRONLY | O_CREAT | O_TRUNC ); } elsif ( $mode eq ">>" ) { $self->{fh} = $sftp->open( $file, O_WRONLY | O_APPEND ); my $fs = Rex::Interface::Fs->create; my %stat = $fs->stat($file); $self->{fh}->seek( $stat{size} ); } elsif ( $mode eq "<" ) { $self->{fh} = $sftp->open( $file, O_RDONLY ); } return $self->{fh}; } sub read { my ( $self, $len ) = @_; my $buf; $self->{fh}->read( $buf, $len ); return $buf; } sub write { my ( $self, $buf ) = @_; $self->{fh}->write($buf); } sub seek { my ( $self, $pos ) = @_; $self->{fh}->seek($pos); } sub close { my ($self) = @_; $self->{fh} = undef; $self = undef; } 1; Rex-1.3.3/lib/Rex/Interface/File/Local.pm0000644000175000017500000000173412572251052017621 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File::Local; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::File::Base; use base qw(Rex::Interface::File::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub open { my ( $self, $mode, $file ) = @_; Rex::Logger::debug("Opening $file with mode: $mode"); open( $self->{fh}, $mode, $file ) or return; return 1; } sub read { my ( $self, $len ) = @_; my $buf; read( $self->{fh}, $buf, $len ); return $buf; } sub write { my ( $self, $buf ) = @_; my $fh = $self->{fh}; print $fh $buf; } sub seek { my ( $self, $pos ) = @_; my $fh = $self->{fh}; seek( $fh, $pos, 0 ); } sub close { my ($self) = @_; my $fh = $self->{fh}; close $fh if $fh; $self->{fh} = undef; $self = undef; } 1; Rex-1.3.3/lib/Rex/Interface/File/Base.pm0000644000175000017500000000120212572251052017427 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub open { die("Must be implemented by Interface Class."); } sub read { die("Must be implemented by Interface Class."); } sub write { die("Must be implemented by Interface Class."); } sub close { die("Must be implemented by Interface Class."); } sub seek { die("Must be implemented by Interface Class."); } 1; Rex-1.3.3/lib/Rex/Interface/File/HTTP.pm0000644000175000017500000000343412572251052017345 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File::HTTP; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; BEGIN { use Rex::Require; MIME::Base64->use; } use Rex::Commands; use Rex::Interface::Fs; use Rex::Interface::File::Base; use base qw(Rex::Interface::File::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub open { my ( $self, $mode, $file ) = @_; $self->{__file} = $file; $self->{__current_pos} = 0; if ( $mode eq ">>" ) { my $fs = Rex::Interface::Fs->create; eval { my %stat = $fs->stat($file); $self->{__current_pos} = $stat{size}; }; } Rex::Logger::debug("Opening $file with mode: $mode"); my $resp = connection->post( "/file/open", { path => $file, mode => $mode } ); return $resp->{ok}; } sub read { my ( $self, $len ) = @_; my $resp = connection->post( "/file/read", { path => $self->{__file}, start => $self->{__current_pos}, len => $len, } ); if ( $resp->{ok} ) { my $buf = decode_base64( $resp->{buf} ); $self->{__current_pos} += length($buf); return $buf; } return; } sub write { my ( $self, $buf ) = @_; my $resp = connection->post( "/file/write_fh", { path => $self->{__file}, start => $self->{__current_pos}, buf => encode_base64($buf), } ); if ( $resp->{ok} ) { $self->{__current_pos} += length($buf); return length($buf); } return; } sub seek { my ( $self, $pos ) = @_; $self->{__current_pos} = $pos; } sub close { my ($self) = @_; delete $self->{__current_pos}; delete $self->{__file}; } 1; Rex-1.3.3/lib/Rex/Interface/File/OpenSSH.pm0000644000175000017500000000306412572251052020044 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::File::OpenSSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl; use Rex::Interface::Fs; use Rex::Interface::File::Base; BEGIN { use Rex::Require; Net::SFTP::Foreign::Constants->use(qw(:flags :fxp)); } use base qw(Rex::Interface::File::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub open { my ( $self, $mode, $file ) = @_; Rex::Logger::debug("Opening $file with mode: $mode"); my $sftp = Rex::get_sftp(); if ( $mode eq ">" ) { $self->{fh} = $sftp->open( $file, SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_TRUNC ); } elsif ( $mode eq ">>" ) { $self->{fh} = $sftp->open( $file, SSH2_FXF_WRITE | SSH2_FXF_APPEND ); my $fs = Rex::Interface::Fs->create; my %stat = $fs->stat($file); $self->{fh}->seek( $stat{size}, 0 ); } elsif ( $mode eq "<" ) { $self->{fh} = $sftp->open( $file, SSH2_FXF_READ ); } return $self->{fh}; } sub read { my ( $self, $len ) = @_; my $sftp = Rex::get_sftp(); my $buf = $sftp->read( $self->{fh}, $len ); return $buf; } sub write { my ( $self, $buf ) = @_; my $sftp = Rex::get_sftp(); $sftp->write( $self->{fh}, $buf ); } sub seek { my ( $self, $pos ) = @_; my $sftp = Rex::get_sftp(); $sftp->seek( $self->{fh}, $pos, 0 ); } sub close { my ($self) = @_; my $sftp = Rex::get_sftp(); $sftp->close( $self->{fh} ); } 1; Rex-1.3.3/lib/Rex/Interface/Cache.pm0000644000175000017500000000073612572251052016714 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Cache; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub create { my ( $class, $type ) = @_; unless ($type) { $type = Rex::Config->get_cache_type; } my $class_name = "Rex::Interface::Cache::$type"; eval "use $class_name;"; if ($@) { die("Error loading connection interface $type.\n$@"); } return $class_name->new; } 1; Rex-1.3.3/lib/Rex/Interface/Cache/0000755000175000017500000000000012572251052016350 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Cache/YAML.pm0000644000175000017500000000245312572251052017454 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Cache::YAML; use strict; use warnings; use Rex::Interface::Cache::Base; use base qw(Rex::Interface::Cache::Base); our $VERSION = '1.3.3'; # VERSION require Rex::Commands; require Rex::Commands::Fs; require YAML; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub save { my ($self) = @_; my $path = Rex::Commands::get("cache_path") || ".cache"; if ( exists $ENV{REX_CACHE_PATH} ) { $path = $ENV{REX_CACHE_PATH}; } if ( !-d $path ) { Rex::Commands::LOCAL( sub { mkdir $path } ); } open( my $fh, ">", "$path/" . Rex::Commands::connection->server . ".yml" ) or die($!); print $fh YAML::Dump( $self->{__data__} ); close($fh); } sub load { my ($self) = @_; my $path = Rex::Commands::get("cache_path") || ".cache"; if ( exists $ENV{REX_CACHE_PATH} ) { $path = $ENV{REX_CACHE_PATH}; } my $file_name = "$path/" . Rex::Commands::connection->server . ".yml"; if ( !-f $file_name ) { # no cache found return; } my $yaml = eval { local ( @ARGV, $/ ) = ($file_name); <>; }; $yaml .= "\n"; $self->{__data__} = YAML::Load($yaml); } 1; Rex-1.3.3/lib/Rex/Interface/Cache/Base.pm0000644000175000017500000000215712572251052017565 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Cache::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub gen_key_name { my ( $self, $key_name ) = @_; return $key_name if $key_name; my ( $package, $filename, $line, $subroutine ) = caller(1); $package =~ s/::/_/g; my $gen_key_name = "\L${package}_\L${subroutine}"; return $gen_key_name; } sub set { my ( $self, $key, $val, $timeout ) = @_; if ( Rex::Config->get_use_cache ) { $self->{__data__}->{$key} = $val; } } sub valid { my ( $self, $key ) = @_; return exists $self->{__data__}->{$key}; } sub get { my ( $self, $key ) = @_; return $self->{__data__}->{$key}; } sub reset { my ($self) = @_; $self->{__data__} = {}; } # have to be overwritten by subclass sub save { my ($self) = @_; return 1; } # have to be overwritten by subclass sub load { my ($self) = @_; return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Executor.pm0000644000175000017500000000074012572251052017502 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Executor; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; sub create { my ( $class, $type ) = @_; unless ($type) { $type = "Default"; } my $class_name = "Rex::Interface::Executor::$type"; eval "use $class_name;"; if ($@) { die("Error loading file interface $type.\n$@"); } return $class_name->new; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/0000755000175000017500000000000012572251052016414 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Shell/Default.pm0000644000175000017500000000065712572251052020346 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Default; use strict; use warnings; use Rex::Interface::Shell::Bash; our $VERSION = '1.3.3'; # VERSION use base qw(Rex::Interface::Shell::Bash); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Ksh.pm0000644000175000017500000000111512572251052017475 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Ksh; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Bash; use base qw(Rex::Interface::Shell::Bash); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/ksh$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Bash.pm0000644000175000017500000000702712572251052017635 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Bash; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Base; use base qw(Rex::Interface::Shell::Base); use Data::Dumper; sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub path { my ( $self, $path ) = @_; $self->{path} = $path; } sub source_global_profile { my ( $self, $parse ) = @_; $self->{source_global_profile} = $parse; } sub source_profile { my ( $self, $parse ) = @_; $self->{source_profile} = $parse; } # sub set_env { # my ( $self, $env ) = @_; # my $cmd = undef; # # die("Error: env must be a hash") # if ( ref $env ne "HASH" ); # # while ( my ( $k, $v ) = each($env) ) { # $cmd .= "export $k=$v; "; # } # $self->{env} = $cmd; # } sub exec { my ( $self, $cmd, $option ) = @_; if ( exists $option->{path} ) { $self->path( $option->{path} ); } Rex::Logger::debug("Shell/Bash: Got options:"); Rex::Logger::debug( Dumper($option) ); my $complete_cmd = $cmd; # if we need to execute without an sh command, # use the format_cmd key # if ( exists $option->{no_sh} ) { # $complete_cmd = $option->{format_cmd}; # } if ( exists $option->{cwd} ) { $complete_cmd = "cd $option->{cwd} && $complete_cmd"; } if ( $self->{path} && !exists $self->{__env__}->{PATH} ) { $complete_cmd = "PATH=$self->{path}; export PATH; $complete_cmd "; } if ( $self->{locale} && !exists $option->{no_locales} ) { $complete_cmd = "LC_ALL=$self->{locale} ; export LC_ALL; $complete_cmd "; } if ( $self->{source_profile} ) { $complete_cmd = ". ~/.profile >/dev/null 2>&1 ; $complete_cmd"; } if ( $self->{source_global_profile} ) { $complete_cmd = ". /etc/profile >/dev/null 2>&1 ; $complete_cmd"; } if ( exists $self->{__env__} ) { if ( ref $self->{__env__} eq "HASH" ) { for my $key ( keys %{ $self->{__env__} } ) { my $val = $self->{__env__}->{$key}; $val =~ s/"/\\"/gms; if ( exists $self->{__sudo_env__} && $self->{__sudo_env__} ) { $complete_cmd = " $key=\"$val\" $complete_cmd "; } else { $complete_cmd = " export $key=\"$val\" ; $complete_cmd "; } } } else { $complete_cmd = $self->{__env__} . " $complete_cmd "; } } # this is due to a strange behaviour with Net::SSH2 / libssh2 # it may occur when you run rex inside a kvm virtualized host connecting to another virtualized vm on the same hardware if ( Rex::Config->get_sleep_hack ) { $complete_cmd .= " ; f=\$? ; sleep .00000001 ; exit \$f"; } if ( exists $option->{preprocess_command} && ref $option->{preprocess_command} eq "CODE" ) { $complete_cmd = $option->{preprocess_command}->($complete_cmd); } # rewrite the command again if ( exists $option->{format_cmd} ) { $complete_cmd =~ s/\{\{CMD\}\}/$cmd/; } if ( $self->{__inner_shell__} ) { $complete_cmd =~ s/\\/\\\\/gms; $complete_cmd =~ s/"/\\"/gms; $complete_cmd =~ s/\$/\\\$/gms; $complete_cmd = "sh -c \"$complete_cmd\""; } if ( exists $option->{prepend_command} && $option->{prepend_command} ) { $complete_cmd = $option->{prepend_command} . " $complete_cmd"; } return $complete_cmd; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/bash$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Zsh.pm0000644000175000017500000000111512572251052017514 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Zsh; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Bash; use base qw(Rex::Interface::Shell::Bash); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/zsh$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Base.pm0000644000175000017500000000132712572251052017627 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $class = shift; my $self = {}; $self->{path} = undef; $self->{__inner_shell__} = undef; bless( $self, $class ); return $self; } sub set_environment { my ( $self, $env ) = @_; $self->{__env__} = $env; } sub set_inner_shell { my ( $self, $use_inner_shell ) = @_; $self->{__inner_shell__} = $use_inner_shell; } sub set_locale { my ( $self, $locale ) = @_; $self->{locale} = $locale; } sub set_sudo_env { my ( $self, $sudo_env ) = @_; $self->{__sudo_env__} = $sudo_env; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Sh.pm0000644000175000017500000000111312572251052017320 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Sh; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Bash; use base qw(Rex::Interface::Shell::Bash); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/sh$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Tcsh.pm0000644000175000017500000000111412572251052017650 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Tcsh; use strict; use warnings; use Rex::Interface::Shell::Csh; our $VERSION = '1.3.3'; # VERSION use base qw(Rex::Interface::Shell::Csh); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/tcsh$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Ash.pm0000644000175000017500000000111512572251052017463 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Ash; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Bash; use base qw(Rex::Interface::Shell::Bash); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/ash$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Idrac.pm0000644000175000017500000000126112572251052017774 0ustar jenkinsjenkins# # (c) Ferenc Erki , adjust GmbH # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Idrac; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Default; use base qw(Rex::Interface::Shell::Default); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub detect { my ( $self, $con ) = @_; my ($output) = $con->_exec('version'); if ( defined $output && $output =~ m/SM CLP Version: / ) { return 1; } return 0; } sub exec { my ( $self, $cmd, $option ) = @_; return $cmd; } 1; Rex-1.3.3/lib/Rex/Interface/Shell/Csh.pm0000644000175000017500000000565612572251052017503 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Shell::Csh; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Shell::Base; use base qw(Rex::Interface::Shell::Base); sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, $class ); return $self; } sub path { my ( $self, $path ) = @_; $self->{path} = $path; } sub source_global_profile { my ( $self, $parse ) = @_; $self->{source_global_profile} = $parse; } sub source_profile { my ( $self, $parse ) = @_; $self->{source_profile} = $parse; } sub set_locale { my ( $self, $locale ) = @_; $self->{locale} = $locale; } # sub set_env { # my ( $self, $env ) = @_; # my $cmd = undef; # # die("Error: env must be a hash") # if ( ref $env ne "HASH" ); # # while ( my ( $k, $v ) = each($env) ) { # $cmd .= "setenv $k \"$v\"; "; # $self->{env_raw} .= "$k $v"; # } # # $self->{env} = $cmd; # } sub exec { my ( $self, $cmd, $option ) = @_; if ( exists $option->{path} ) { $self->path( $option->{path} ); } # if ( exists $option->{env} ) { # $self->set_env( $option->{env} ); # } my $complete_cmd = $cmd; # if we need to execute without an sh command, # use the format_cmd key if ( exists $option->{no_sh} ) { $complete_cmd = $option->{format_cmd}; } if ( exists $option->{cwd} ) { $complete_cmd = "cd $option->{cwd} && $complete_cmd"; } if ( $self->{path} && !exists $self->{__env__}->{PATH} ) { $complete_cmd = "set PATH=$self->{path}; $complete_cmd "; } if ( $self->{locale} ) { $complete_cmd = "set LC_ALL=$self->{locale} ; $complete_cmd "; } if ( $self->{source_profile} ) { # csh is using .login $complete_cmd = "source ~/.login >& /dev/null ; $complete_cmd"; } if ( $self->{source_global_profile} ) { $complete_cmd = "source /etc/profile >& /dev/null ; $complete_cmd"; } if ( exists $self->{__env__} ) { if ( ref $self->{__env__} eq "HASH" ) { for my $key ( keys %{ $self->{__env__} } ) { my $val = $self->{__env__}->{$key}; $val =~ s/"/"'"'"/gms; $complete_cmd = " setenv $key \"$val\" ; $complete_cmd "; } } else { $complete_cmd = $self->{__env__} . " $complete_cmd "; } } # this is due to a strange behaviour with Net::SSH2 / libssh2 # it may occur when you run rex inside a kvm virtualized host connecting to another virtualized vm on the same hardware if ( Rex::Config->get_sleep_hack ) { $complete_cmd .= " ; set f=\$? ; sleep .00000001 ; exit \$f"; } # rewrite the command again if ( exists $option->{format_cmd} ) { $complete_cmd =~ s/\{\{CMD\}\}/$cmd/; } return $complete_cmd; } sub detect { my ( $self, $con ) = @_; my ($shell_path) = $con->_exec("echo \$SHELL"); if ( $shell_path =~ m/\/csh$/ ) { return 1; } return 0; } 1; Rex-1.3.3/lib/Rex/Interface/Connection/0000755000175000017500000000000012572251052017444 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Interface/Connection/SSH.pm0000644000175000017500000001047112572251052020442 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::SSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION BEGIN { use Rex::Require; Net::SSH2->require; } use Carp; use Rex::Interface::Connection::Base; use base qw(Rex::Interface::Connection::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); bless( $self, $proto ); return $self; } sub connect { my ( $self, %option ) = @_; my ( $user, $pass, $private_key, $public_key, $server, $port, $timeout, $auth_type, $is_sudo ); Rex::Logger::debug("Using Net::SSH2 for connection"); $user = $option{user}; $pass = $option{password}; $server = $option{server}; $port = $option{port}; $timeout = $option{timeout}; $public_key = $option{public_key}; $private_key = $option{private_key}; $auth_type = $option{auth_type}; $is_sudo = $option{sudo}; $self->{is_sudo} = $is_sudo; $self->{__auth_info__} = \%option; Rex::Logger::debug( "Using user: " . $user ); Rex::Logger::debug( Rex::Logger::masq( "Using password: %s", ( $pass || "" ) ) ); $self->{server} = $server; $self->{ssh} = Net::SSH2->new; my $fail_connect = 0; CON_SSH: $port ||= Rex::Config->get_port( server => $server ) || 22; $timeout ||= Rex::Config->get_timeout( server => $server ) || 3; $server = Rex::Config->get_ssh_config_hostname( server => $server ) || $server; if ( $server =~ m/^(.*?):(\d+)$/ ) { $server = $1; $port = $2; } Rex::Logger::info( "Connecting to $server:$port (" . $user . ")" ); unless ( $self->{ssh}->connect( $server, $port, Timeout => $timeout ) ) { ++$fail_connect; sleep 1; goto CON_SSH if ( $fail_connect < Rex::Config->get_max_connect_fails( server => $server ) ) ; # try connecting 3 times Rex::Logger::info( "Can't connect to $server", "warn" ); $self->{connected} = 0; return; } Rex::Logger::debug( "Current Error-Code: " . $self->{ssh}->error() ); Rex::Logger::info("Connected to $server, trying to authenticate."); $self->{connected} = 1; if ( $auth_type && $auth_type eq "pass" ) { Rex::Logger::debug("Using password authentication."); $self->{auth_ret} = $self->{ssh}->auth_password( $user, $pass ); if ( !$self->{auth_ret} ) { # try guessing $self->{auth_ret} = $self->{ssh}->auth( 'username' => $user, 'password' => $pass ); } } elsif ( $auth_type && $auth_type eq "key" ) { Rex::Logger::debug("Using key authentication."); croak "No public_key file defined." if !$public_key; croak "No private_key file defined." if !$private_key; $self->{auth_ret} = $self->{ssh}->auth_publickey( $user, $public_key, $private_key, $pass ); } else { Rex::Logger::debug("Trying to guess the authentication method."); $self->{auth_ret} = $self->{ssh}->auth( 'username' => $user, 'password' => $pass, 'publickey' => $public_key || "", 'privatekey' => $private_key || "" ); } $self->{sftp} = $self->{ssh}->sftp; } sub reconnect { my ($self) = @_; Rex::Logger::debug("Reconnecting SSH"); $self->connect( %{ $self->{__auth_info__} } ); } sub disconnect { my ($self) = @_; $self->get_connection_object->disconnect; } sub error { my ($self) = @_; return $self->get_connection_object->error; } sub get_connection_object { my ($self) = @_; return $self->{ssh}; } sub get_fs_connection_object { my ($self) = @_; if ( !defined $self->{sftp} ) { Rex::Logger::info( "It seems that you haven't installed or configured sftp on your server.", "warn" ); Rex::Logger::info( "Rex needs sftp for file operations, so please install one.", "warn" ); die("No SFTP server found on remote host."); } return $self->{sftp}; } sub is_connected { my ($self) = @_; return $self->{connected}; } sub is_authenticated { my ($self) = @_; return $self->{auth_ret}; } sub get_connection_type { my ($self) = @_; my $type = "SSH"; if ( $self->{is_sudo} && $self->{is_sudo} == 1 ) { return "Sudo"; } if ( Rex::is_ssh() && !Rex::is_sudo() ) { $type = "SSH"; } elsif ( Rex::is_sudo() ) { $type = "Sudo"; } return $type; } 1; Rex-1.3.3/lib/Rex/Interface/Connection/HTTPS.pm0000644000175000017500000000234112572251052020704 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::HTTPS; use strict; use warnings; use Rex::Interface::Connection::HTTP; use base qw(Rex::Interface::Connection::HTTP); our $VERSION = '1.3.3'; # VERSION use Rex::Logger; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); bless( $self, $proto ); return $self; } sub get_connection_type { return "HTTP"; } sub _get_proto { return "https"; } sub _get_port { my ( $self, $port ) = @_; return $port || 8443; } sub ua { my ($self) = @_; return $self->{ua} if $self->{ua}; my $ssl_opts = {}; if ( Rex::Config->get_ca ) { Rex::Logger::debug("SSL: Verifying Hostname"); $ssl_opts->{verify_hostname} = 1; $ssl_opts->{SSL_ca_file} = Rex::Config->get_ca; } else { Rex::Logger::debug("SSL: NOT Verifying Hostname"); $ssl_opts->{verify_hostname} = 0; } if ( Rex::Config->get_ca_cert ) { $ssl_opts->{SSL_cert_file} = Rex::Config->get_ca_cert; } if ( Rex::Config->get_ca_key ) { $ssl_opts->{SSL_key_file} = Rex::Config->get_ca_key; } $self->{ua} = LWP::UserAgent->new( ssl_opts => $ssl_opts, ); } 1; Rex-1.3.3/lib/Rex/Interface/Connection/Local.pm0000644000175000017500000000161212572251052021034 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::Local; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Connection::Base; use Rex::Group::Entry::Server; use base qw(Rex::Interface::Connection::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); $self->{server} = Rex::Group::Entry::Server->new( name => "" ); bless( $self, $proto ); return $self; } sub error { } sub connect { } sub disconnect { } sub get_connection_object { my ($self) = @_; return $self; } sub get_fs_connection_object { my ($self) = @_; return $self; } sub is_connected { return 1; } sub is_authenticated { return 1; } sub get_connection_type { return "Local"; } 1; Rex-1.3.3/lib/Rex/Interface/Connection/Base.pm0000644000175000017500000000446512572251052020665 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Fs; use Rex::Interface::Exec; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{__sudo_options__} = []; return $self; } sub error { die("Must be implemented by Interface Class"); } sub connect { die("Must be implemented by Interface Class"); } sub disconnect { die("Must be implemented by Interface Class"); } sub get_connection_object { die("Must be implemented by Interface Class"); } sub is_connected { die("Must be implemented by Interface Class"); } sub is_authenticated { die("Must be implemented by Interface Class"); } sub get_connection_type { die("Must be implemented by Interface Class") } sub reconnect { } sub get_fs_connection_object { my ($self) = @_; return $self; } sub get_fs { my $fs = Rex::Interface::Fs->create; return $fs; } sub get_exec { my $exec = Rex::Interface::Exec->create; return $exec; } sub server { my ($self) = @_; return $self->{server}; } sub get_auth_user { my ($self) = @_; if ( exists $self->{__auth_info__} ) { return $self->{__auth_info__}->{user}; } return ""; } sub get_auth { my ($self) = @_; if ( exists $self->{__auth_info__} ) { return $self->{__auth_info__}; } } sub push_sudo_options { my ( $self, @option ) = @_; if ( ref $option[0] eq "HASH" ) { push @{ $self->{__sudo_options__} }, $option[0]; } else { push @{ $self->{__sudo_options__} }, {@option}; } } sub get_current_sudo_options { my ($self) = @_; return $self->{__sudo_options__}->[-1]; } sub push_use_sudo { my ( $self, $use ) = @_; push @{ $self->{__use_sudo__} }, $use; } sub get_current_use_sudo { my ($self) = @_; if ( $self->{is_sudo} ) { return 1; } return $self->{__use_sudo__}->[-1]; } sub pop_sudo_options { my ($self) = @_; pop @{ $self->{__sudo_options__} }; } sub pop_use_sudo { my ($self) = @_; pop @{ $self->{__use_sudo__} }; } sub run_sudo_unmodified { my ( $self, $code ) = @_; $self->push_sudo_options( {} ); $code->(); $self->pop_sudo_options(); } 1; Rex-1.3.3/lib/Rex/Interface/Connection/HTTP.pm0000644000175000017500000000664112572251052020570 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::HTTP; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Connection::Base; BEGIN { LWP::UserAgent->use; JSON::XS->use; } use Data::Dumper; use base qw(Rex::Interface::Connection::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); bless( $self, $proto ); # activate caching Rex::Config->set_use_cache(1); return $self; } sub error { } sub connect { my ( $self, %option ) = @_; my ( $user, $pass, $server, $port, $timeout ); $user = $option{user}; $pass = $option{password}; $server = $option{server}; $port = $self->_get_port( $option{port} ); $timeout = $option{timeout}; $self->{server} = $server; $self->{port} = $port; if ( $server =~ m/([^:]+):(\d+)/ ) { $server = $self->{server} = $1; $port = $self->{port} = $2; } $self->{__user} = $user; $self->{__pass} = $pass; if (!Rex::Config->has_user && Rex::Config->get_ssh_config_username( server => $server ) ) { $user = Rex::Config->get_ssh_config_username( server => $server ); } $self->ua->credentials( "$server:$port", "Rex::Endpoint::HTTP", $user => $pass, ); my $resp = $self->post("/login"); if ( $resp->{ok} ) { Rex::Logger::info("Connected to $server, trying to authenticate."); } else { Rex::Logger::info( "Can't connect to $server", "warn" ); $self->{connected} = 0; return; } Rex::Logger::info( "Connecting to $server:$port (" . $user . ")" ); } sub disconnect { } sub get_connection_object { my ($self) = @_; return $self; } sub get_fs_connection_object { my ($self) = @_; return $self; } sub is_connected { return 1; } sub is_authenticated { return 1; } sub exec { my ( $self, $cmd ) = @_; } sub ua { my ($self) = @_; return $self->{ua} if $self->{ua}; $self->{ua} = LWP::UserAgent->new; } sub upload { my ( $self, $data ) = @_; my $res = $self->ua->post( $self->_get_proto . "://" . $self->{server} . ":" . $self->{port} . "/fs/upload", Content_Type => "multipart/form-data", Content => $data ); if ( $res->is_success ) { return decode_json( $res->decoded_content ); } else { die("Error requesting /fs/upload."); } } sub post { my ( $self, $service, $data, $header ) = @_; $header ||= {}; $data ||= {}; if ( !ref($data) ) { die( "Invalid 2nd argument. must be arrayRef or hashRef!\npost(\$service, \$ref)" ); } my $res = $self->ua->post( $self->_get_proto . "://" . $self->{server} . ":" . $self->{port} . "$service", %{$header}, Content => encode_json($data) ); if ( $res->is_success ) { return decode_json( $res->decoded_content ); } else { die( "Error requesting $service.\n\nError: " . $res->{_content} ); } } sub get { my ( $self, $service ) = @_; my $res = $self->ua->get( $self->_get_proto . "://" . $self->{server} . ":" . $self->{port} . "$service" ); if ( $res->is_success ) { return decode_json( $res->decoded_content ); } else { die("Error requesting $service."); } } sub get_connection_type { return "HTTP"; } sub _get_proto { return "http"; } sub _get_port { my ( $self, $port ) = @_; return $port || 8080; } 1; Rex-1.3.3/lib/Rex/Interface/Connection/OpenSSH.pm0000644000175000017500000001314712572251052021267 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::OpenSSH; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION BEGIN { use Rex::Require; Net::OpenSSH->require; } use Rex::Interface::Connection::Base; use Data::Dumper; use base qw(Rex::Interface::Connection::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); bless( $self, $proto ); return $self; } sub connect { my ( $self, %option ) = @_; my ( $user, $pass, $private_key, $public_key, $server, $port, $timeout, $auth_type, $is_sudo ); Rex::Logger::debug("Using Net::OpenSSH for connection"); $user = $option{user}; $pass = $option{password}; $server = $option{server}; $port = $option{port}; $timeout = $option{timeout}; $public_key = $option{public_key}; $private_key = $option{private_key}; $auth_type = $option{auth_type}; $is_sudo = $option{sudo}; $self->{is_sudo} = $is_sudo; $self->{__auth_info__} = \%option; Rex::Logger::debug( "Using user: " . $user ); Rex::Logger::debug( Rex::Logger::masq( "Using password: %s", ( $pass || "" ) ) ); $self->{server} = $server; my $proxy_command = Rex::Config->get_proxy_command( server => $server ); $port ||= Rex::Config->get_port( server => $server ) || 22; $timeout ||= Rex::Config->get_timeout( server => $server ) || 3; $server = Rex::Config->get_ssh_config_hostname( server => $server ) || $server; if ( $server =~ m/^(.*?):(\d+)$/ ) { $server = $1; $port = $2; } Rex::Logger::info( "Connecting to $server:$port (" . $user . ")" ); my %ssh_opts = Rex::Config->get_openssh_opt(); Rex::Logger::debug("get_openssh_opt()"); Rex::Logger::debug( Dumper( \%ssh_opts ) ); $ssh_opts{LogLevel} ||= "QUIET"; $ssh_opts{ConnectTimeout} = $timeout; my %net_openssh_constructor_options = ( exists $ssh_opts{initialize_options} ? $ssh_opts{initialize_options} : () ); my @ssh_opts_line; for my $key ( keys %ssh_opts ) { push @ssh_opts_line, "-o" => $key . "=" . $ssh_opts{$key}; } my @connection_props = ( "" . $server ); # stringify server object, so that a dumper don't print out passwords. push @connection_props, ( user => $user, port => $port ); push @connection_props, master_opts => \@ssh_opts_line if @ssh_opts_line; push @connection_props, default_ssh_opts => \@ssh_opts_line if @ssh_opts_line; push @connection_props, proxy_command => $proxy_command if $proxy_command; my @auth_types_to_try; if ( $auth_type && $auth_type eq "pass" ) { Rex::Logger::debug( Rex::Logger::masq( "OpenSSH: pass_auth: $server:$port - $user - %s", $pass ) ); push @auth_types_to_try, "pass"; } elsif ( $auth_type && $auth_type eq "krb5" ) { Rex::Logger::debug("OpenSSH: krb5_auth: $server:$port - $user"); push @auth_types_to_try, "krb5"; # do nothing here } else { # for key auth, and others Rex::Logger::debug( "OpenSSH: key_auth or not defined: $server:$port - $user"); push @auth_types_to_try, "key", "pass"; } Rex::Logger::debug("OpenSSH options: "); Rex::Logger::debug( Dumper( \@connection_props ) ); Rex::Logger::debug("OpenSSH constructor options: "); Rex::Logger::debug( Dumper( \%net_openssh_constructor_options ) ); Rex::Logger::debug("Trying following auth types:"); Rex::Logger::debug( Dumper( \@auth_types_to_try ) ); my $fail_connect = 0; CONNECT_TRY: while ( $fail_connect < Rex::Config->get_max_connect_fails( server => $server ) ) { for my $_try_auth_type (@auth_types_to_try) { my @_internal_con_props = @connection_props; if ( $_try_auth_type eq "pass" ) { push @_internal_con_props, password => $pass; } elsif ( $_try_auth_type eq "key" ) { push @_internal_con_props, key_path => $private_key; if ($pass) { push @_internal_con_props, passphrase => $pass; } } $self->{ssh} = Net::OpenSSH->new( @_internal_con_props, %net_openssh_constructor_options ); if ( $self->{ssh} && !$self->{ssh}->error ) { last CONNECT_TRY; } } $fail_connect++; } if ( !$self->{ssh} ) { Rex::Logger::info( "Can't connect to $server", "warn" ); $self->{connected} = 0; return; } if ( $self->{ssh} && $self->{ssh}->error ) { Rex::Logger::info( "Can't connect to $server (" . $self->{ssh}->error() . ")", "warn" ); $self->{connected} = 1; return; } Rex::Logger::debug( "Current Error-Code: " . $self->{ssh}->error() ); Rex::Logger::info("Connected and authenticated to $server."); $self->{connected} = 1; $self->{auth_ret} = 1; $self->{sftp} = $self->{ssh}->sftp; } sub reconnect { my ($self) = @_; Rex::Logger::debug("Reconnecting SSH"); $self->connect( %{ $self->{__auth_info__} } ); } sub disconnect { my ($self) = @_; undef $self->{ssh}; return 1; } sub error { my ($self) = @_; return $self->get_connection_object->error; } sub get_connection_object { my ($self) = @_; return $self->{ssh}; } sub get_fs_connection_object { my ($self) = @_; return $self->{sftp}; } sub is_connected { my ($self) = @_; return $self->{connected}; } sub is_authenticated { my ($self) = @_; return $self->{auth_ret}; } sub get_connection_type { my ($self) = @_; my $type = "OpenSSH"; if ( $self->{is_sudo} && $self->{is_sudo} == 1 ) { return "Sudo"; } if ( Rex::is_ssh() && !Rex::is_sudo() ) { $type = "OpenSSH"; } elsif ( Rex::is_sudo() ) { $type = "Sudo"; } return $type; } 1; Rex-1.3.3/lib/Rex/Interface/Connection/Fake.pm0000644000175000017500000000150112572251052020645 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection::Fake; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Interface::Connection::Base; use base qw(Rex::Interface::Connection::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $that->SUPER::new(@_); bless( $self, $proto ); return $self; } sub error { } sub connect { my ( $self, %option ) = @_; $self->{server} = $option{server}; } sub disconnect { } sub get_connection_object { my ($self) = @_; return $self; } sub get_fs_connection_object { my ($self) = @_; return $self; } sub is_connected { return 1; } sub is_authenticated { return 1; } sub get_connection_type { return "Local"; } 1; Rex-1.3.3/lib/Rex/Interface/Fs.pm0000644000175000017500000000144712572251052016261 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Fs; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex; use Data::Dumper; sub create { my ( $class, $type ) = @_; unless ($type) { #$type = Rex::Commands::task()->get_connection_type; $type = Rex::get_current_connection()->{conn}->get_connection_type; #Rex::Commands::task()->get_connection_type; #if(Rex::is_ssh() && ! Rex::is_sudo()) { # $type = "SSH"; #} #elsif(Rex::is_sudo()) { # $type = "Sudo"; #} #else { # $type = "Local"; #} } my $class_name = "Rex::Interface::Fs::$type"; eval "use $class_name;"; if ($@) { die("Error loading Fs interface $type.\n$@"); } return $class_name->new; } 1; Rex-1.3.3/lib/Rex/Interface/Exec.pm0000644000175000017500000000106112572251052016565 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Exec; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex; sub create { my ( $class, $type ) = @_; unless ($type) { $type = Rex::get_current_connection()->{conn}->get_connection_type; #Rex::Commands::task()->get_connection_type; } my $class_name = "Rex::Interface::Exec::$type"; eval "use $class_name;"; if ($@) { die("Error loading exec interface $type.\n$@"); } return $class_name->new; } 1; Rex-1.3.3/lib/Rex/Interface/Connection.pm0000644000175000017500000000075712572251052020013 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Interface::Connection; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub create { my ( $class, $type ) = @_; unless ($type) { $type = Rex::Config->get_connection_type(); } my $class_name = "Rex::Interface::Connection::$type"; eval "use $class_name;"; if ($@) { die("Error loading connection interface $type.\n$@"); } return $class_name->new; } 1; Rex-1.3.3/lib/Rex/Resource.pm0000644000175000017500000000630312572251052015574 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Resource; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Constants; our $INSIDE_RES = 0; our @CURRENT_RES; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{__status__} = "unchanged"; return $self; } sub name { (shift)->{name}; } sub display_name { (shift)->{display_name}; } sub type { (shift)->{type}; } sub call { my ( $self, $name, %params ) = @_; if ( ref $name eq "HASH" ) { # multiple resource call for my $n ( keys %{$name} ) { $self->call( $n, %{ $name->{$n} } ); } return; } $INSIDE_RES = 1; push @CURRENT_RES, $self; $self->{res_name} = $name; $self->{res_ensure} = $params{ensure} ||= present; Rex::get_current_connection()->{reporter} ->report_resource_start( type => $self->display_name, name => $name ); # make parameters automatically availabel in templates # store old values so that we can recover them after resource finish my %old_values; for my $key ( keys %params ) { $old_values{$key} = Rex::Config->get($key); Rex::Config->set( $key => $params{$key} ); } my $failed = 0; eval { $self->{cb}->( \%params ); 1; } or do { Rex::Logger::info( $@, "error" ); Rex::Logger::info( "Resource execution failed: $name", "error" ); $failed = 1; }; if ( $self->was_updated ) { Rex::get_current_connection()->{reporter}->report( changed => 1, failed => $failed, message => $self->message, ); } else { Rex::get_current_connection()->{reporter}->report( changed => 0, failed => $failed, message => $self->display_name . " not changed.", ); } if ( exists $params{on_change} && $self->was_updated ) { $params{on_change}->( $self->{__status__} ); } Rex::get_current_connection()->{reporter} ->report_resource_end( type => $self->display_name, name => $name ); $INSIDE_RES = 0; pop @CURRENT_RES; # recover old values for my $key ( keys %old_values ) { if ( defined $old_values{$key} ) { Rex::Config->set( $key => $old_values{$key} ); } else { Rex::Config->set( $key => undef ); } } } sub was_updated { my ($self) = @_; if ( $self->changed || $self->created || $self->removed ) { return 1; } return 0; } sub changed { my ( $self, $changed ) = @_; if ( defined $changed ) { $self->{__status__} = "changed"; } else { return ( $self->{__status__} eq "changed" ? 1 : 0 ); } } sub created { my ( $self, $created ) = @_; if ( defined $created ) { $self->{__status__} = "created"; } else { return ( $self->{__status__} eq "created" ? 1 : 0 ); } } sub removed { my ( $self, $removed ) = @_; if ( defined $removed ) { $self->{__status__} = "removed"; } else { return ( $self->{__status__} eq "removed" ? 1 : 0 ); } } sub message { my ( $self, $message ) = @_; if ( defined $message ) { $self->{message} = $message; } else { return ( $self->{message} || ( $self->display_name . " changed." ) ); } } 1; Rex-1.3.3/lib/Rex/User.pm0000644000175000017500000000131112572251052014715 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::User; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Gather; use Rex::Logger; sub get { my $user_o = "Linux"; if (is_freebsd) { $user_o = "FreeBSD"; } elsif (is_netbsd) { $user_o = "NetBSD"; } elsif (is_openbsd) { $user_o = "OpenBSD"; } elsif ( operating_system_is("SunOS") ) { $user_o = "SunOS"; } elsif (is_openwrt) { $user_o = "OpenWrt"; } my $class = "Rex::User::" . $user_o; eval "use $class"; if ($@) { Rex::Logger::info("OS not supported"); die("OS not supported"); } return $class->new; } 1; Rex-1.3.3/lib/Rex/Notify.pm0000644000175000017500000000446512572251052015264 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Notify; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{__types__} = {}; $self->{__postponed__} = []; $self->{__running_postponed__} = 0; $self->{__in_notify__} = 0; return $self; } sub add { my ( $self, %option ) = @_; return if ( $self->{__in_notify__} ); if ( exists $self->{__types__}->{ $option{type} }->{ $option{name} } ) { Rex::Logger::debug( "A resource of the type $option{type} and name $option{name}" . "already exists.", "warn" ); return; } $self->{__types__}->{ $option{type} }->{ $option{name} } = { postpone => $option{postpone} || 0, options => $option{options}, cb => $option{cb}, }; } sub run { my ( $self, %option ) = @_; Rex::Logger::debug("Try to notify $option{type} -> $option{name}"); if ( exists $self->{__types__}->{ $option{type} } && exists $self->{__types__}->{ $option{type} }->{ $option{name} } && exists $self->{__types__}->{ $option{type} }->{ $option{name} }->{cb} && $self->{__types__}->{ $option{type} }->{ $option{name} }->{postpone} == 0 ) { Rex::Logger::debug("Running notify $option{type} -> $option{name}"); my $cb = $self->{__types__}->{ $option{type} }->{ $option{name} }->{cb}; $self->{__in_notify__} = 1; $cb->( $self->{__types__}->{ $option{type} }->{ $option{name} }->{options} ); $self->{__in_notify__} = 0; } else { if ( !$self->{__running_postponed__} ) { Rex::Logger::debug( "Can't notify $option{type} -> $option{name}. Postponing..."); $self->_postpone(%option); } else { Rex::Logger::info( "Can't run postponed notification. " . "Resource not found ($option{type} -> $option{name})", "warn" ); } } } sub run_postponed { my ($self) = @_; $self->{__running_postponed__} = 1; Rex::Logger::debug("Running postponed notifications."); for my $p ( @{ $self->{__postponed__} } ) { $self->run( %{$p} ); } } sub _postpone { my ( $self, %option ) = @_; push @{ $self->{__postponed__} }, \%option; } 1; Rex-1.3.3/lib/Rex/Logger.pm0000644000175000017500000001171012572251052015222 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Logger - Logging Module =head1 DESCRIPTION This module is the logging module. You can define custom logformats. =head1 SYNOPSIS $Rex::Logger::format = '[%D] %s'; # will output something like # [2012-04-12 18:35:12] Installing package vim $Rex::Logger::format = '%h - %D - %s'; # will output something like # srv001 - 2012-04-12 18:35:12 - Installing package vim =head1 VARIABLES =over 4 =cut package Rex::Logger; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION #use Rex; our $no_color = 0; eval "use Term::ANSIColor"; if ($@) { $no_color = 1; } # no colors under windows if ( $^O =~ m/MSWin/ ) { $no_color = 1; } my $has_syslog = 0; my $log_fh; =item $debug Setting this variable to 1 will enable debug logging. $Rex::Logger::debug = 1; =cut our $debug = 0; =item $silent If you set this variable to 1 nothing will be logged. $Rex::Logger::silent = 1; =cut our $silent = 0; =item $format You can define the logging format with the following parameters. %D - Appends the current date yyyy-mm-dd HH:mm:ss %h - The target host %p - The pid of the running process %l - Loglevel (INFO or DEBUG) %s - The Logstring Default is: [%D] %l - %s =cut our $format = "[%D] %l - %s"; my $log_opened = 0; sub init { return if $silent; eval { die if ( Rex::Config->get_log_filename || !Rex::Config->get_log_facility ); Sys::Syslog->use; openlog( "rex", "ndelay,pid", Rex::Config->get_log_facility ); $has_syslog = 1; }; $log_opened = 1; } sub info { my ( $msg, $type ) = @_; my $color = 'green'; if ( defined($type) ) { CHECK_COLOR: { $type eq 'warn' && do { $color = 'yellow'; last CHECK_COLOR; }; $type eq 'error' && do { $color = 'red'; last CHECK_COLOR; }; } } return if $silent; if ( defined($type) ) { $msg = format_string( $msg, uc($type) ); } else { $msg = format_string( $msg, "INFO" ); } # workaround for windows Sys::Syslog behaviour on forks # see: #6 unless ($log_opened) { init(); $log_opened = 2; } if ($has_syslog) { syslog( "info", $msg ); } if ( Rex::Config->get_log_filename() ) { open( $log_fh, ">>", Rex::Config->get_log_filename() ) or die($!); flock( $log_fh, 2 ); print {$log_fh} "$msg\n" if ($log_fh); close($log_fh); } if ($no_color) { print STDERR "$msg\n" if ( ( ( defined $::QUIET && $::QUIET == 2 ) && ( defined $type && $type ne 'info' ) ) || !defined $::QUIET ); } else { print STDERR colored( [$color], "$msg\n" ) if ( ( ( defined $::QUIET && $::QUIET == 2 ) && ( defined $type && $type ne 'info' ) ) || !defined $::QUIET ); } # workaround for windows Sys::Syslog behaviour on forks # see: #6 if ( $log_opened == 2 ) { &shutdown(); } } sub debug { my ($msg) = @_; return if $silent; return unless $debug; $msg = format_string( $msg, "DEBUG" ); # workaround for windows Sys::Syslog behaviour on forks # see: #6 unless ($log_opened) { init(); $log_opened = 2; } if ($has_syslog) { syslog( "debug", $msg ); } if ( Rex::Config->get_log_filename() ) { open( $log_fh, ">>", Rex::Config->get_log_filename() ) or die($!); flock( $log_fh, 2 ); print {$log_fh} "$msg\n" if ($log_fh); close($log_fh); } if ($no_color) { print STDERR "$msg\n" unless ($::QUIET); } else { print STDERR colored( ['red'], "$msg\n" ) unless ($::QUIET); } # workaround for windows Sys::Syslog behaviour on forks # see: #6 if ( $log_opened == 2 ) { &shutdown(); } } sub get_timestamp { my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time); $mon++; $year += 1900; return "$year-" . sprintf( "%02i", $mon ) . "-" . sprintf( "%02i", $mday ) . " " . sprintf( "%02i", $hour ) . ":" . sprintf( "%02i", $min ) . ":" . sprintf( "%02i", $sec ); } sub shutdown { return if $silent; return unless $log_opened; if ($has_syslog) { closelog(); } else { close($log_fh) if $log_fh; } $log_opened = 0; } # %D - Date # %h - Host # %s - Logstring sub format_string { my ( $s, $level ) = @_; my $date = get_timestamp; my $host = Rex::get_current_connection() ? Rex::get_current_connection()->{conn}->server : ""; my $pid = $$; my $line = $format; $line =~ s/\%D/$date/gms; $line =~ s/\%h/$host/gms; $line =~ s/\%s/$s/gms; $line =~ s/\%l/$level/gms; $line =~ s/\%p/$pid/gms; return $line; } sub masq { my ( $format, @params ) = @_; return $format if scalar @params == 0; return $format if scalar( grep { defined } @params ) == 0; if ( exists $ENV{REX_DEBUG_INSECURE} && $ENV{REX_DEBUG_INSECURE} eq "1" ) { return sprintf( $format, @params ); } return sprintf( $format, ("**********") x @params ); } =back =cut 1; Rex-1.3.3/lib/Rex/SCM/0000755000175000017500000000000012572251052014067 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/SCM/Subversion.pm0000644000175000017500000000335312572251052016570 0ustar jenkinsjenkinspackage Rex::SCM::Subversion; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Cwd qw(getcwd); use Rex::Commands::Fs; use Rex::Commands::Run; use vars qw($CHECKOUT_COMMAND); BEGIN { my $version = qx{svn --version --quiet 2>/dev/null}; if ($version) { my @parts = split( /\./, $version ); if ( $parts[1] <= 5 ) { $CHECKOUT_COMMAND = "svn --non-interactive %s checkout %s %s"; } else { $CHECKOUT_COMMAND = "svn --non-interactive --trust-server-cert %s checkout %s %s"; } } } sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub checkout { my ( $self, $repo_info, $checkout_to, $checkout_opt ) = @_; my $special_opts = ""; if ( exists $repo_info->{"username"} ) { $special_opts = " --username '" . $repo_info->{"username"} . "'"; } if ( exists $repo_info->{"password"} ) { $special_opts .= " --password '" . $repo_info->{"password"} . "'"; } my $checkout_cmd; if ( !is_dir($checkout_to) ) { $checkout_cmd = sprintf( $CHECKOUT_COMMAND, $special_opts, $repo_info->{"url"}, $checkout_to ); } elsif ( is_dir("$checkout_to/.svn") ) { $checkout_cmd = "svn up $checkout_to"; } else { Rex::Logger::info( "Error checking out repository.", "warn" ); die("Error checking out repository."); } Rex::Logger::debug("checkout_cmd: $checkout_cmd"); Rex::Logger::info( "Cloning " . $repo_info->{"url"} . " to " . ( $checkout_to ? $checkout_to : "." ) ); my $out = run "$checkout_cmd"; unless ( $? == 0 ) { Rex::Logger::info( "Error checking out repository.", "warn" ); Rex::Logger::info($out); die("Error checking out repository."); } } 1; Rex-1.3.3/lib/Rex/SCM/Git.pm0000644000175000017500000000523412572251052015154 0ustar jenkinsjenkinspackage Rex::SCM::Git; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Cwd qw(getcwd); use Rex::Commands::Fs; use Rex::Commands::Run; use File::Basename; use vars qw($CHECKOUT_BRANCH_COMMAND $CHECKOUT_TAG_COMMAND $CLONE_COMMAND); $CLONE_COMMAND = "git clone %s %s"; $CHECKOUT_BRANCH_COMMAND = "git checkout -b %s origin/%s"; $CHECKOUT_TAG_COMMAND = "git checkout -b %s %s"; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub checkout { my ( $self, $repo_info, $checkout_to, $checkout_opt ) = @_; if ( !is_dir($checkout_to) ) { my $clone_cmd = sprintf( $CLONE_COMMAND, $repo_info->{"url"}, $checkout_to ); Rex::Logger::debug("clone_cmd: $clone_cmd"); Rex::Logger::info( "Cloning " . $repo_info->{"url"} . " to " . ( $checkout_to ? $checkout_to : "." ) ); my $out = run "$clone_cmd", cwd => dirname($checkout_to); unless ( $? == 0 ) { Rex::Logger::info( "Error cloning repository.", "warn" ); Rex::Logger::info($out); die("Error cloning repository."); } Rex::Logger::debug($out); if ( exists $checkout_opt->{"branch"} ) { unless ($checkout_to) { $checkout_to = [ split( /\//, $repo_info->{"url"} ) ]->[-1]; $checkout_to =~ s/\.git$//; } my $checkout_cmd = sprintf( $CHECKOUT_BRANCH_COMMAND, $checkout_opt->{"branch"}, $checkout_opt->{"branch"} ); Rex::Logger::debug("checkout_cmd: $checkout_cmd"); Rex::Logger::info( "Switching to branch " . $checkout_opt->{"branch"} ); $out = run "$checkout_cmd", cwd => $checkout_to; Rex::Logger::debug($out); } if ( exists $checkout_opt->{"tag"} ) { my $checkout_cmd = sprintf( $CHECKOUT_TAG_COMMAND, $checkout_opt->{"tag"}, $checkout_opt->{"tag"} ); Rex::Logger::info( "Switching to tag " . $checkout_opt->{"tag"} ); $out = run "$checkout_cmd", cwd => $checkout_to; Rex::Logger::debug($out); } } elsif ( is_dir("$checkout_to/.git") ) { my $branch = $checkout_opt->{"branch"} || "master"; run "git pull origin $branch", cwd => $checkout_to; if ( exists $checkout_opt->{"tag"} ) { my $tag = $checkout_opt->{tag}; Rex::Logger::info( "Switching to tag " . $tag ); my $out = run "git fetch origin", cwd => $checkout_to; Rex::Logger::debug($out); $out = run "git checkout -b $tag $tag", cwd => $checkout_to; Rex::Logger::debug($out); } } else { Rex::Logger::info( "Error checking out repository.", "warn" ); die("Error checking out repository."); } } 1; Rex-1.3.3/lib/Rex/Group.pm0000644000175000017500000000535212572251052015104 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Group; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use attributes; use Rex::Group::Entry::Server; use vars qw(%groups); use List::MoreUtils qw(uniq); use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); for my $srv ( @{ $self->{servers} } ) { $srv->append_to_group( $self->{name} ); } return $self; } sub get_servers { my ($self) = @_; my @servers = map { ref( $_->to_s ) eq "CODE" ? &{ $_->to_s } : $_ } @{ $self->{servers} }; return uniq @servers; } sub set_auth { my ( $self, %data ) = @_; $self->{auth} = \%data; map { $_->set_auth( %{ $self->get_auth } ) } $self->get_servers; } sub get_auth { my ($self) = @_; return $self->{auth}; } ################################################################################ # STATIC FUNCTIONS ################################################################################ # Creates a new server group # Possible calls: # create_group(name => "g1", "srv1", "srv2"); # create_group(name => "g1", Rex::Group::Entry::Server->new(name => "srv1"), "srv2"); # create_group(name => "g1", "srv1" => { user => "other" }, "srv2"); sub create_group { my $class = shift; my $group_name = shift; my @server = uniq grep { defined } @_; my @server_obj; for ( my $i = 0 ; $i <= $#server ; $i++ ) { next if ref $server[$i] eq 'HASH'; # already processed by previous loop # if argument is already a Rex::Group::Entry::Server if ( ref $server[$i] && $server[$i]->isa("Rex::Group::Entry::Server") ) { push @server_obj, $server[$i]; next; } # if next argument is a HashRef, use it as options for the server my %options = ( $i < $#server and ref $server[ $i + 1 ] eq 'HASH' ) ? %{ $server[ $i + 1 ] } : (); my $obj = Rex::Group::Entry::Server->new( name => $server[$i], %options ); push @server_obj, $obj; } $groups{$group_name} = Rex::Group->new( servers => \@server_obj, name => $group_name ); } # returns the servers in the group sub get_group { my $class = shift; my $group_name = shift; if ( exists $groups{$group_name} ) { return $groups{$group_name}->get_servers; } return (); } sub is_group { my $class = shift; my $group_name = shift; if ( defined $groups{$group_name} ) { return 1; } return 0; } sub get_groups { my $class = shift; my %ret = (); for my $key ( keys %groups ) { $ret{$key} = [ $groups{$key}->get_servers ]; } return %ret; } sub get_group_object { my $class = shift; my $name = shift; return $groups{$name}; } 1; Rex-1.3.3/lib/Rex/Sudo/0000755000175000017500000000000012572251052014357 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Sudo/File.pm0000644000175000017500000000421612572251052015577 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: ###### DEPRECATED package Rex::Sudo::File; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex; use Rex::Commands; use Rex::Commands::Run; use Rex::Commands::Fs; use Rex::Helper::Path; use IO::File; sub open { my $that = shift; my $proto = ref($that) || $that; my $self = {}; $self->{mode} = shift; $self->{file} = shift; $self->{rndfile} = get_tmp_file; if ( my $sftp = Rex::get_sftp() ) { if ( $self->{mode} eq ">" ) { $self->{fh} = $sftp->open( $self->{rndfile}, O_WRONLY | O_CREAT | O_TRUNC ); } elsif ( $self->{mode} eq ">>" ) { cp( $self->{file}, $self->{rndfile} ); chmod( 666, $self->{rndfile} ); $self->{fh} = $sftp->open( $self->{rndfile}, O_WRONLY | O_APPEND ); my %stat = stat $self->{rndfile}; $self->{fh}->seek( $stat{size} ); } else { cp( $self->{file}, $self->{rndfile} ); chmod( 666, $self->{rndfile} ); $self->{fh} = $sftp->open( $self->{rndfile}, O_RDONLY ); } } else { $self->{fh} = IO::File->new; $self->{fh}->open( $self->{mode} . " " . $self->{rndfile} ); } bless( $self, $proto ); return $self; } sub write { my ( $self, $content ) = @_; if ( ref( $self->{fh} ) eq "Net::SSH2::File" ) { $self->{fh}->write($content); } else { $self->{fh}->print($content); } } sub seek { my ( $self, $offset ) = @_; if ( ref( $self->{fh} ) eq "Net::SSH2::File" ) { $self->{fh}->seek($offset); } else { $self->{fh}->seek( $offset, 0 ); } } sub read { my ( $self, $len ) = @_; $len ||= 64; my $buf; $self->{fh}->read( $buf, $len ); return $buf; } sub close { my ($self) = @_; return unless $self->{fh}; if ( ref( $self->{fh} ) eq "Net::SSH2::File" ) { $self->{fh} = undef; } else { $self->{fh}->close; } # use cat to not overwrite attributes/owner/group if ( $self->{mode} eq ">" || $self->{mode} eq ">>" ) { run "cat " . $self->{rndfile} . " >" . $self->{file}; rm( $self->{rndfile} ); } } sub DESTROY { my ($self) = @_; $self->close; } 1; Rex-1.3.3/lib/Rex/Template.pm0000644000175000017500000001101312572251052015552 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Template - Simple Template Engine. =head1 DESCRIPTION This is a simple template engine for configuration files. =head1 SYNOPSIS my $template = Rex::Template->new; print $template->parse($content, \%template_vars); =head1 EXPORTED FUNCTIONS =cut package Rex::Template; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Config; use Rex::Logger; require Rex::Args; our $DO_CHOMP = 0; our $BE_LOCAL = 1; sub function { my ( $class, $name, $code ) = @_; no strict 'refs'; *{ $class . "::" . $name } = $code; use strict; } sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub parse { my $self = shift; my $data = shift; my $vars = {}; if ( ref( $_[0] ) eq "HASH" ) { $vars = shift; } else { $vars = {@_}; } my $new_data; my $___r = ""; my $do_chomp = 0; $new_data = join( "\n", map { my ( $code, $type, $text ) = ( $_ =~ m/(\<%)*([+=])*(.+)%\>/s ); if ($code) { my $pcmd = substr( $text, -1 ); if ( $pcmd eq "-" ) { $text = substr( $text, 0, -1 ); $do_chomp = 1; } my ( $var_type, $var_name ) = ( $text =~ m/([\$])::([a-zA-Z0-9_]+)/ ); if ( $var_name && !ref( $vars->{$var_name} ) && !$BE_LOCAL ) { $text =~ s/([\$])::([a-zA-Z0-9_]+)/$1\{\$$2\}/g; } elsif ( $var_name && !ref( $vars->{$var_name} ) && $BE_LOCAL ) { $text =~ s/([\$])::([a-zA-Z0-9_]+)/$1$2/g; } else { $text =~ s/([\$])::([a-zA-Z0-9_]+)/\$$2/g; } if ( $type && $type =~ m/^[+=]$/ ) { "\$___r .= $text;"; } else { $text; } } else { my $chomped = $_; if ( $DO_CHOMP || $do_chomp ) { chomp $chomped; $do_chomp = 0; } '$___r .= "' . _quote($chomped) . '";'; } } split( /(\<%.*?%\>)/s, $data ) ); eval { no strict 'refs'; no strict 'vars'; for my $var ( keys %{$vars} ) { Rex::Logger::debug("Registering: $var"); unless ( ref( $vars->{$var} ) ) { $$var = \$vars->{$var}; } else { $$var = $vars->{$var}; } } if ( $BE_LOCAL == 1 ) { my $var_data = ' return sub { my $___r = ""; my ( '; my @code_values; for my $var ( keys %{$vars} ) { my $new_var = _normalize_var_name($var); Rex::Logger::debug("Registering local: $new_var"); $var_data .= '$' . $new_var . ", \n"; push( @code_values, $vars->{$var} ); } $var_data .= '$this_is_really_nothing) = @_;'; $var_data .= "\n"; $var_data .= $new_data; $var_data .= "\n"; $var_data .= ' return $___r;'; $var_data .= "\n};"; Rex::Logger::debug("BE_LOCAL==1"); my %args = Rex::Args->getopts; if ( defined $args{'d'} && $args{'d'} > 1 ) { Rex::Logger::debug($var_data); } my $tpl_code = eval($var_data); if ($@) { Rex::Logger::info($@); } $___r = $tpl_code->(@code_values); } else { Rex::Logger::debug("BE_LOCAL==0"); my %args = Rex::Args->getopts; if ( defined $args{'d'} && $args{'d'} > 1 ) { Rex::Logger::debug($new_data); } $___r = eval($new_data); if ($@) { Rex::Logger::info($@); } } # undef the vars for my $var ( keys %{$vars} ) { $$var = undef; } }; if ( !$___r ) { Rex::Logger::info( "It seems that there was an error processing the template", "warn" ); Rex::Logger::info( "because the result is empty.", "warn" ); die("Error processing template"); } return $___r; } sub _quote { my ($str) = @_; $str =~ s/\\/\\\\/g; $str =~ s/"/\\"/g; $str =~ s/\@/\\@/g; $str =~ s/\%/\\%/g; $str =~ s/\$/\\\$/g; return $str; } sub _normalize_var_name { my ($input) = @_; $input =~ s/[^A-Za-z0-9_]/_/g; return $input; } =head2 is_defined($variable, $default_value) This function will check if $variable is defined. If yes, it will return the value of $variable, otherwise it will return $default_value. You can use this function inside your templates. ServerTokens <%= is_defined($::server_tokens, "Prod") %> =cut sub is_defined { my ( $check_var, $default ) = @_; if ( defined $check_var ) { return $check_var; } return $default; } 1; Rex-1.3.3/lib/Rex/Batch.pm0000644000175000017500000000224012572251052015022 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Batch; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::TaskList; use vars qw(%batchs); sub create_batch { my $class = shift; my $batch_name = shift; my $batch_desc = pop; my @tasks = @_; $batchs{$batch_name} = { desc => $batch_desc, tasks => \@tasks }; } sub get_batch { my $class = shift; my $batch_name = shift; return @{ $batchs{$batch_name}->{'tasks'} }; } sub get_desc { my $class = shift; my $batch_name = shift; return $batchs{$batch_name}->{'desc'}; } sub get_batchs { my $class = shift; my @a = sort { $a cmp $b } keys %batchs; } sub is_batch { my $class = shift; my $batch_name = shift; if ( defined $batchs{$batch_name} ) { return 1; } return 0; } sub run { my $class = shift; my $batch = shift; my @tasks = $class->get_batch($batch); for my $t (@tasks) { if ( Rex::TaskList->create()->is_task($t) ) { Rex::TaskList->create()->run($t); } else { print STDERR "ERROR: no task: $t\n"; die; } } } 1; Rex-1.3.3/lib/Rex/File/0000755000175000017500000000000012572251052014324 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/File/Parser/0000755000175000017500000000000012572251052015560 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/File/Parser/Data.pm0000644000175000017500000000145712572251052016776 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::File::Parser::Data; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub read { my ( $self, $file ) = @_; return $self->_read_file($file); } sub _read_file { my ( $self, $file ) = @_; my $content = ""; my $in_file = 0; for my $line ( @{ $self->{"data"} } ) { chomp $line; if ( $line eq "\@end" ) { $in_file = 0; next; } if ($in_file) { $content .= $line . $/; } if ( $line eq "\@$file" ) { $in_file = 1; next; } } return $content; } sub get { my ( $self, $file ) = @_; } 1; Rex-1.3.3/lib/Rex/File/Parser/Ini.pm0000644000175000017500000000247612572251052016646 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::File::Parser::Ini; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } sub get { my ( $self, $section, $key ) = @_; unless ( exists $self->{"__data"}->{$section} ) { die("$section not found"); } unless ( exists $self->{"__data"}->{$section}->{$key} ) { die("$key not found in $section"); } return $self->{"__data"}->{$section}->{$key}; } sub get_sections { my ($self) = @_; return keys %{ $self->{"__data"} }; } sub read { my ($self) = @_; $self->{"__data"} = $self->_read_file; } sub _read_file { my ($self) = @_; my $data = {}; my $section; open( my $fh, "<", $self->{"file"} ); while ( my $line = <$fh> ) { chomp $line; next if ( $line =~ m/^\s*?;/ ); next if ( $line =~ m/^\s*?$/ ); if ( $line =~ m/^\[(.+)\]$/ ) { $section = $1; $data->{$section} = {}; next; } if ($section) { my ( $key, $val ) = split( /=/, $line, 2 ); $val =~ s/^\s+|\s+$//g; $key =~ s/^\s+|\s+$//g; $data->{$section}->{$key} = $val; } } close($fh); return $data; } 1; Rex-1.3.3/lib/Rex/Helper/0000755000175000017500000000000012572251052014664 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Helper/Misc.pm0000644000175000017500000000057112572251052016120 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::Misc; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub get_random { my $count = shift; my @chars = @_; srand(); my $ret = ""; for ( 1 .. $count ) { $ret .= $chars[ int( rand( scalar(@chars) - 1 ) ) ]; } return $ret; } 1; Rex-1.3.3/lib/Rex/Helper/Array.pm0000644000175000017500000000115612572251052016303 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::Array; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(array_uniq in_array); sub array_uniq { my (@array) = @_; my %all = (); @all{@array} = 1; return keys %all; } sub in_array { my ( $needle, @haystack ) = @_; my ($ret) = grep { if ( ref $needle eq "RegExp" && $_ =~ $needle ) { return $_; } elsif ( $_ eq $needle ) { return $_; } } @haystack; return $ret; } 1; Rex-1.3.3/lib/Rex/Helper/Encode.pm0000644000175000017500000000246612572251052016427 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::Encode; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(func_to_json); my %escapes; for ( 0 .. 255 ) { $escapes{ chr($_) } = sprintf( "%%%02X", $_ ); } sub url_encode { my ($txt) = @_; $txt =~ s/([^A-Za-z0-9_])/$escapes{$1}/g; return $txt; } sub url_decode { my ($txt) = @_; $txt =~ s/%([0-9A-Fa-f]{2})/chr(hex($1))/eg; return $txt; } sub func_to_json { return q| sub to_json { my ($ref) = @_; my $s = ""; if(ref $ref eq "ARRAY") { $s .= "["; for my $itm (@{ $ref }) { if(substr($s, -1) ne "[") { $s .= ","; } $s .= to_json($itm); } return $s . "]"; } elsif(ref $ref eq "HASH") { $s .= "{"; for my $key (keys %{ $ref }) { if(substr($s, -1) ne "{") { $s .= ","; } $s .= "\"$key\": " . to_json($ref->{$key}); } return $s . "}"; } else { if($ref =~ /^0\d+/) { return "\"$ref\""; } elsif($ref =~ /^\d+$/) { return $ref; } else { $ref =~ s/'/\\\'/g; return "\"$ref\""; } } } |; } 1; Rex-1.3.3/lib/Rex/Helper/DBI.pm0000644000175000017500000000136212572251052015622 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::DBI; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION BEGIN { use Rex::Require; DBI->require; } my %db_connections; sub perform_request { my ( $dsn, $user, $pass, $req ) = @_; $user ||= ""; $pass ||= ""; my $con_key = "$dsn-$user-$pass"; if ( !exists $db_connections{$dsn} ) { $db_connections{$con_key} = DBI->connect( $dsn, $user, $pass ) or die("Cannot connect: $DBI::errstr\n"); } my %res; my $sth = $db_connections{$con_key}->prepare($req); $sth->execute(); my $i = 1; while ( my $ref = $sth->fetchrow_hashref() ) { $res{$i} = $ref; $i++; } return \%res; } 1; Rex-1.3.3/lib/Rex/Helper/Path.pm0000644000175000017500000001133212572251052016116 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::Path; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::File::Spec; use File::Basename qw(dirname); require Exporter; use base qw(Exporter); use vars qw(@EXPORT); use Cwd 'realpath'; require Rex; use Rex::Commands; require Rex::Config; use Rex::Interface::Exec; @EXPORT = qw(get_file_path get_tmp_file resolv_path parse_path); set "path_map", {}; # # CALL: get_file_path("foo.txt", caller()); # RETURNS: module file # sub get_file_path { my ( $file_name, $caller_package, $caller_file ) = @_; $file_name = resolv_path($file_name); my $ends_with_slash = 0; if ( $file_name =~ m/\/$/ ) { $ends_with_slash = 1; } my $fix_path = sub { my ($path) = @_; $path =~ s:^\./::; if ($ends_with_slash) { if ( $path !~ m/\/$/ ) { return "$path/"; } } return $path; }; if ( !$caller_package ) { ( $caller_package, $caller_file ) = caller(); } # check if a file in $BASE overwrites the module file # first get the absolute path to the rexfile $::rexfile ||= $0; my @path_parts; if ( $^O =~ m/^MSWin/ && !Rex::is_ssh() ) { @path_parts = split( /\//, $::rexfile ); } else { @path_parts = split( /\//, realpath($::rexfile) ); } pop @path_parts; my $real_path = join( '/', @path_parts ); my $map_setting = get("path_map"); my %path_map = ( map { ( ( substr( $_, -1 ) eq '/' ) ? $_ : "$_/" ) => $map_setting->{$_} } keys %$map_setting ); foreach my $prefix ( sort { length($b) <=> length($a) } grep { $file_name =~ m/^$_/ } keys %path_map ) { foreach my $pattern ( @{ $path_map{$prefix} } ) { my $expansion = Rex::Helper::File::Spec->catfile( parse_path($pattern), substr( $file_name, length($prefix) ) ); if ( -e $expansion ) { return $fix_path->($expansion); } $expansion = Rex::Helper::File::Spec->catfile( $real_path, $expansion ); if ( -e $expansion ) { return $fix_path->($expansion); } } } if ( -e $file_name ) { return $fix_path->($file_name); } my $cat_file_name = Rex::Helper::File::Spec->catfile( $real_path, $file_name ); if ( -e $cat_file_name ) { return $fix_path->($cat_file_name); } # walk down the wire to find the file... my ($old_caller_file) = $caller_file; my $i = 0; while ( $caller_package && $i <= 50 ) { ( $caller_package, $caller_file ) = caller($i); if ( !$caller_package ) { last; } my $module_path = Rex::get_module_path($caller_package); $cat_file_name = Rex::Helper::File::Spec->catfile( $module_path, $file_name ); if ( -e $cat_file_name ) { return $fix_path->($cat_file_name); } $i++; } $file_name = Rex::Helper::File::Spec->catfile( dirname($old_caller_file), $file_name ); return $fix_path->($file_name); } sub get_tmp_file { return Rex::Helper::File::Spec->join( Rex::Config->get_tmp_dir(), Rex::Commands::get_random( 12, 'a' .. 'z' ) . '.tmp' ); } sub resolv_path { my ( $path, $local ) = @_; if ( $path !~ m/^~/ ) { # path starts not with ~ so we don't need to expand $HOME. # just return it. return $path; } my $home_path; require Rex::User; my $user_o = Rex::User->get; if ($local) { if ( $^O =~ m/^MSWin/ ) { # windows path: $home_path = $ENV{'USERPROFILE'}; } else { if ( $path =~ m/^~([a-zA-Z0-9_][^\/]+)\// ) { my $user_name = $1; my %user_info = $user_o->get_user($user_name); $home_path = $user_info{home}; $path =~ s/^~$user_name/$home_path/; } else { $home_path = $ENV{'HOME'}; $path =~ s/^~/$home_path/; } } } else { if ( $path =~ m/^~([a-zA-Z0-9_][^\/]+)\// ) { my $user_name = $1; my %user_info = $user_o->get_user($user_name); $home_path = $user_info{home}; $path =~ s/^~$user_name/$home_path/; } else { my $exec = Rex::Interface::Exec->create; my $remote_home = $exec->exec("echo \$HOME"); $remote_home =~ s/[\r\n]//gms; $home_path = $remote_home; $path =~ s/^~/$home_path/; } } return $path; } sub parse_path { my ($path) = @_; my %hw; require Rex::Commands::Gather; $hw{server} = Rex::Commands::connection()->server; $hw{environment} = Rex::Commands::environment(); $path =~ s/\{(server|environment)\}/$hw{$1}/gms; if ( $path =~ m/\{([^\}]+)\}/ ) { # if there are still some variables to replace, we need some information of # the system. %hw = Rex::Commands::Gather::get_system_information(); $path =~ s/\{([^\}]+)\}/$hw{$1}/gms; } return $path; } 1; Rex-1.3.3/lib/Rex/Helper/System.pm0000644000175000017500000000217212572251052016510 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::System; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::Hash; sub info { return ( eval { my %merge1 = (); my %merge2 = Rex::Hardware->get(qw/ All /); my %template_vars = ( %merge1, %merge2 ); for my $info_key (qw(Network Host Kernel Memory Swap)) { my $flatten_info = {}; if ( $info_key eq "Memory" ) { hash_flatten( $merge2{$info_key}, $flatten_info, "_", "memory" ); } elsif ( $info_key eq "Swap" ) { hash_flatten( $merge2{$info_key}, $flatten_info, "_", "swap" ); } elsif ( $info_key eq "Network" ) { hash_flatten( $merge2{$info_key}->{"networkconfiguration"}, $flatten_info, "_" ); } else { hash_flatten( $merge2{$info_key}, $flatten_info, "_" ); } for my $key ( keys %{$flatten_info} ) { $template_vars{$key} = $flatten_info->{$key}; } } return %template_vars; } ); } 1; Rex-1.3.3/lib/Rex/Helper/UserAgent.pm0000644000175000017500000000143612572251052017123 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::UserAgent; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use base 'LWP::UserAgent'; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } sub get_basic_credentials { my ($self) = @_; if ( exists $self->{__user__} && $self->{__password__} ) { return $self->{__user__}, $self->{__password__}; } return; } sub get { my ( $self, $url, %option ) = @_; if ( exists $option{user} ) { $self->{__user__} = $option{user}; } if ( exists $option{password} ) { $self->{__password__} = $option{password}; } return $self->SUPER::get($url); } 1; Rex-1.3.3/lib/Rex/Helper/Run.pm0000644000175000017500000000371712572251052015776 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::Run; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); use Rex::Interface::File; use Rex::Interface::Fs; use Rex::Helper::Path; require Rex::Commands; require Rex::Config; @EXPORT = qw(upload_and_run i_run); sub upload_and_run { my ( $template, %option ) = @_; my $rnd_file = get_tmp_file; my $fh = Rex::Interface::File->create; $fh->open( ">", $rnd_file ); $fh->write($template); $fh->close; my $fs = Rex::Interface::Fs->create; $fs->chmod( 755, $rnd_file ); my @argv; my $command = $rnd_file; if ( exists $option{with} ) { $command = Rex::Config->get_executor_for( $option{with} ) . " $command"; } if ( exists $option{args} ) { $command .= join( " ", @{ $option{args} } ); } return i_run("$command 2>&1"); } # internal run command, doesn't get reported sub i_run { my $cmd = shift; my ( $code, $option ); if ( ref $_[0] eq "CODE" ) { $code = shift; } elsif ( scalar @_ > 0 ) { $option = {@_}; } my $is_no_hup = 0; my $tmp_output_file = get_tmp_file(); if ( exists $option->{nohup} && $option->{nohup} ) { $cmd = "nohup $cmd >$tmp_output_file"; delete $option->{nohup}; $is_no_hup = 1; } my $path; if ( !Rex::Config->get_no_path_cleanup() ) { $path = join( ":", Rex::Config->get_path() ); } my $exec = Rex::Interface::Exec->create; my ( $out, $err ) = $exec->exec( $cmd, $path, $option ); chomp $out if $out; chomp $err if $err; my $ret_val = $?; $Rex::Commands::Run::LAST_OUTPUT = [ $out, $err ]; $out ||= ""; $err ||= ""; if ($code) { return &$code( $out, $err ); } if (wantarray) { return split( /\r?\n/, $out ); } if ($is_no_hup) { $out = $exec->exec("cat $tmp_output_file ; rm -f $tmp_output_file"); $? = $ret_val; } return $out; } 1; Rex-1.3.3/lib/Rex/Helper/File/0000755000175000017500000000000012572251052015543 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Helper/File/Stat.pm0000644000175000017500000000142212572251052017013 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::File::Stat; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Rex::Helper::File::Stat::Unix; require Rex::Helper::File::Stat::Win32; sub S_ISDIR { shift; _fcntl()->S_ISDIR(@_); } sub S_ISREG { shift; _fcntl()->S_ISREG(@_); } sub S_ISLNK { shift; _fcntl()->S_ISLNK(@_); } sub S_ISBLK { shift; _fcntl()->S_ISBLK(@_); } sub S_ISCHR { shift; _fcntl()->S_ISCHR(@_); } sub S_ISFIFO { shift; _fcntl()->S_ISFIFO(@_); } sub S_ISSOCK { shift; _fcntl()->S_ISSOCK(@_); } sub _fcntl { if ( $^O =~ m/^MSWin/ ) { return "Rex::Helper::File::Stat::Win32"; } else { return "Rex::Helper::File::Stat::Unix"; } } 1; Rex-1.3.3/lib/Rex/Helper/File/Stat/0000755000175000017500000000000012572251052016456 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Helper/File/Stat/Win32.pm0000644000175000017500000000204512572251052017717 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::File::Stat::Win32; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl; use Rex::Interface::Exec; sub S_ISDIR { shift; Fcntl::S_ISDIR(@_); } sub S_ISREG { shift; Fcntl::S_ISREG(@_); } sub S_ISLNK { shift; if ( Rex::is_ssh() ) { my $exec = Rex::Interface::Exec->create; $exec->exec("perl -le 'use Fcntl; exit Fcntl::S_ISLNK($_[0])'"); return $?; } else { Rex::Logger::info( "S_ISLNK not supported on your platform.", "warn" ); return 0; } } sub S_ISBLK { shift; Fcntl::S_ISBLK(@_); } sub S_ISCHR { shift; Fcntl::S_ISCHR(@_); } sub S_ISFIFO { shift; Fcntl::S_ISFIFO(@_); } sub S_ISSOCK { shift; if ( Rex::is_ssh() ) { my $exec = Rex::Interface::Exec->create; $exec->exec("perl -le 'use Fcntl; exit Fcntl::S_ISSOCK($_[0])'"); return $?; } else { Rex::Logger::info( "S_ISSOCK not supported on your platform.", "warn" ); return 0; } } 1; Rex-1.3.3/lib/Rex/Helper/File/Stat/Unix.pm0000644000175000017500000000110012572251052017727 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::File::Stat::Unix; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Fcntl; use Rex::Helper::Run; sub S_ISDIR { shift; Fcntl::S_ISDIR(@_); } sub S_ISREG { shift; Fcntl::S_ISREG(@_); } sub S_ISLNK { shift; Fcntl::S_ISLNK(@_); } sub S_ISBLK { shift; Fcntl::S_ISBLK(@_); } sub S_ISCHR { shift; Fcntl::S_ISCHR(@_); } sub S_ISFIFO { shift; Fcntl::S_ISFIFO(@_); } sub S_ISSOCK { shift; Fcntl::S_ISSOCK(@_); } 1; Rex-1.3.3/lib/Rex/Helper/File/Spec.pm0000644000175000017500000000137712572251052017003 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::File::Spec; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require File::Spec::Unix; require File::Spec::Win32; sub catfile { shift @_; _spec()->catfile(@_); } sub catdir { shift @_; _spec()->catdir(@_); } sub join { shift @_; _spec()->join(@_); } sub splitdir { shift @_; _spec()->splitdir(@_); } sub tmpdir { shift @_; _spec()->tmpdir(@_); } sub rootdir { shift @_; _spec()->rootdir(@_); } sub _spec { if ( Rex::is_ssh() ) { return "File::Spec::Unix"; } else { if ( $^O =~ m/^MSWin/ ) { return "File::Spec::Win32"; } else { return "File::Spec::Unix"; } } } 1; Rex-1.3.3/lib/Rex/Helper/Hash.pm0000644000175000017500000000223412572251052016106 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::Hash; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(hash_flatten); sub hash_flatten { my ( $in, $out, $sep, @super_keys ) = @_; if ( ref($in) eq "HASH" ) { for my $key ( keys %{$in} ) { push @super_keys, $key; if ( ref( $in->{$key} ) ) { hash_flatten( $in->{$key}, $out, $sep, @super_keys ); } else { my $new_key_name = join( $sep, @super_keys ); $new_key_name =~ s/[^A-Za-z0-9_]/_/g; $out->{$new_key_name} = $in->{$key}; } pop @super_keys; } } elsif ( ref($in) eq "ARRAY" ) { my $counter = 0; for my $val ( @{$in} ) { if ( ref($val) ) { push @super_keys, $counter; hash_flatten( $val, $out, $sep, @super_keys ); pop @super_keys; } else { my $new_key_name = join( $sep, @super_keys ) . "_$counter"; $new_key_name =~ s/[^A-Za-z0-9_]/_/g; $out->{$new_key_name} = $val; } $counter++; } } } 1; Rex-1.3.3/lib/Rex/Helper/INI.pm0000644000175000017500000000370412572251052015645 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::INI; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION BEGIN { String::Escape->use('string2hash'); } sub parse { my (@lines) = @_; my $ini; my $section; for (@lines) { chomp; s/\n|\r//g; (/^#|^;|^\s*$/) && (next); if ( /^\[(.*)\]/ && !/^\[(\d+((?:,)|(?:\.\.))*)+(\/\d+)*\]/ ) { # check for inheritance $section = $1; $ini->{$section} = {}; if ( $section =~ /{$section}; my @inherit = split( /{$is} } ) { $ini->{$section}->{$ik} = $ini->{$is}->{$ik}; } } } next; } my ( $key, $val ) = split( /[= ]/, $_, 2 ); $key =~ s/^\s*|\s*$//g if $key; $val =~ s/^\s*|\s*$//g if $val; my @splitted; if ( !$val ) { $val = $key; @splitted = ($key); } # commented out due to #184 else { #@splitted = split(/\./, $key); @splitted = ($key); } my $ref = $ini->{$section}; my $last = pop @splitted; for my $sub (@splitted) { unless ( exists $ini->{$section}->{$sub} ) { $ini->{$section}->{$sub} = {}; } $ref = $ini->{$section}->{$sub}; } # include other group if ( $key =~ m/^\@(.*)/ ) { for my $ik ( keys %{ $ini->{$1} } ) { $ini->{$section}->{$ik} = $ini->{$1}->{$ik}; } next; } if ( $val =~ m/\$\{(.*)\}/ ) { my $var_name = $1; my $ref = $ini; my @splitted = split( /\./, $var_name ); for my $s (@splitted) { $ref = $ref->{$s}; } $val = $ref; } if ( $val =~ m/=/ ) { $val = { string2hash($val) }; } $ref->{$last} = $val; } return $ini; } 1; Rex-1.3.3/lib/Rex/Helper/SSH2.pm0000644000175000017500000000573012572251052015746 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::SSH2; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; use Data::Dumper; require Rex::Commands; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(net_ssh2_exec net_ssh2_exec_output net_ssh2_shell_exec); our $READ_STDERR = 1; our $EXEC_AND_SLEEP = 0; sub net_ssh2_exec { my ( $ssh, $cmd, $base, $option ) = @_; my $chan = $ssh->channel; # REQUIRE_TTY can be turned off by feature no_tty if ( !Rex::Config->get_no_tty ) { $chan->pty("xterm"); # set to xterm, due to problems with vt100. # if vt100 sometimes the restart of services doesn't work and need a sleep .000001 after the command... # strange bug... $chan->pty_size( 4000, 80 ); } $chan->blocking(1); $chan->exec($cmd); my $in; my $in_err = ""; my $rex_int_conf = Rex::Commands::get("rex_internals") || {}; my $buffer_size = 1024; if ( exists $rex_int_conf->{read_buffer_size} ) { $buffer_size = $rex_int_conf->{read_buffer_size}; } my @lines; my $last_line; my $current_line = ""; while ( my $len = $chan->read( my $buf, $buffer_size ) ) { $in .= $buf; $current_line .= $buf; if ( $buf =~ m/\n/ms ) { @lines = split( /\n/, $current_line ); unshift @lines, $last_line if ($last_line); $last_line = pop @lines; for my $line (@lines) { $line =~ s/[\r\n]//gms; $line .= "\n"; $base->execute_line_based_operation( $line, $option ) && goto END_READ; } $current_line = ""; } } my @lines_err; my $last_line_err = ""; while ( my $len = $chan->read( my $buf_err, $buffer_size, 1 ) ) { $in_err .= $buf_err; @lines_err = split( /\n/, $buf_err ); unshift @lines_err, $last_line_err if ($last_line_err); $last_line_err = pop @lines_err; for my $line (@lines_err) { $line =~ s/[\r\n]//gms; $line .= "\n"; $base->execute_line_based_operation( $line, $option ) && goto END_READ; } } #select undef, undef, undef, 0.002; # wait a little before closing the channel #sleep 1; END_READ: $chan->send_eof; while ( !$chan->eof ) { Rex::Logger::debug("Waiting for eof on ssh channel."); } $chan->wait_closed; $? = $chan->exit_status; # if used with $chan->pty() we have to remove \r if ( !Rex::Config->get_no_tty ) { $in =~ s/\r//g if $in; $in_err =~ s/\r//g if $in_err; } if (wantarray) { return ( $in, $in_err ); } return $in; } sub net_ssh2_exec_output { my ( $ssh, $cmd, $callback ) = @_; my $chan = $ssh->channel; $chan->blocking(1); $chan->exec($cmd); while (1) { my $buf; my $buf_err; $chan->read( $buf, 15 ); $chan->read( $buf_err, 15 ); if ($callback) { &$callback( $buf, $buf_err ); } else { print $buf; print $buf_err; } last unless $buf; } $chan->close; $? = $chan->exit_status; } 1; Rex-1.3.3/lib/Rex/Helper/SSH2/0000755000175000017500000000000012572251052015403 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Helper/SSH2/Expect.pm0000644000175000017500000001003012572251052017163 0ustar jenkinsjenkins# # (c) 2011 Jan Gehring # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: # =head1 NAME Rex::Helper::SSH2::Expect - An Expect like module for Net::SSH2 =head1 DESCRIPTION This is a module to have expect like features for Net::SSH2. This is the first version of this module. Please report bugs at GitHub L =head1 DEPENDENCIES =over 4 =item * L =back =head1 SYNOPSIS use Rex::Helper::SSH2::Expect; my $exp = Rex::Helper::SSH2::Expect->new($ssh2); $exp->spawn("passwd"); $exp->expect($timeout, [ qr/Enter new UNIX password:/ => sub { my ($exp, $line) = @_; $exp->send($new_password); } ], [ qr/Retype new UNIX password:/ => sub { my ($exp, $line) = @_; $exp->send($new_password); } ], [ qr/passwd: password updated successfully/ => sub { my ($exp, $line) = @_; $exp->hard_close; } ]); =head1 CLASS METHODS =cut package Rex::Helper::SSH2::Expect; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION =head2 new($ssh2) Constructor: You need to parse an connected Net::SSH2 Object. =cut our $Log_Stdout = 1; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {}; bless( $self, $proto ); $self->{"__shell"} = $_[0]->channel(); $self->{"__shell"}->pty("vt100"); $self->{"__shell"}->shell; $self->{"__log_stdout"} = $Rex::Helper::SSH2::Expect::Log_Stdout; $self->{"__log_to"} = sub { }; return $self; } =head2 log_stdout(0|1) Log on STDOUT. =cut sub log_stdout { my ( $self, $log ) = @_; $self->{"__log_stdout"} = $log; } =head2 log_file($file) Log everything to a file. $file can be a filename, a filehandle or a subRef. =cut sub log_file { my ( $self, $file ) = @_; $self->{"__log_to"} = $file; } sub shell { my ($self) = @_; return $self->{"__shell"}; } =head2 spawn($command, @parameters) Spawn $command with @parameters as parameters. =cut sub spawn { my ( $self, $command, @parameters ) = @_; my $cmd = "$command " . join( " ", @parameters ); $self->shell->write("$cmd\n"); } =head2 soft_close() Currently only an alias to hard_close(); =cut sub soft_close { my ($self) = @_; $self->hard_close; } =head2 hard_close(); Stops the execution of the process. =cut sub hard_close { my ($self) = @_; die; } =head2 expect($timeout, @match_patters) This method controls the execution of your process. =cut sub expect { my ( $self, $timeout, @match_patterns ) = @_; eval { local $SIG{'ALRM'} = sub { die; }; alarm $timeout; my $line = ""; while (1) { my $buf; $self->shell->read( $buf, 1 ); # log to stdout if wanted print $buf if $self->{"__log_stdout"}; $self->_log($buf); if ( $self->_check_patterns( $line, @match_patterns ) ) { $line = ""; alarm $timeout; next; } $line .= $buf; } }; } =head2 send($string) Send a string to the running command. =cut sub send { my ( $self, $str ) = @_; $self->shell->write($str); } sub _check_patterns { my ( $self, $line, @match_patterns ) = @_; for my $pattern (@match_patterns) { if ( $line =~ $pattern->[0] ) { my $code = $pattern->[1]; &$code( $self, $line ); return 1; } } } sub _log { my ( $self, $str ) = @_; my $log_to = $self->{"__log_to"}; if ( ref($log_to) eq "CODE" ) { &$log_to($str); } elsif ( ref($log_to) eq "GLOB" ) { print $log_to $str; } else { # log to a file open( my $fh, ">>", $log_to ) or die($!); print $fh $str; close($fh); } } 1; Rex-1.3.3/lib/Rex/Helper/URI.pm0000644000175000017500000000056212572251052015664 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Helper::URI; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION sub encode { my ($part) = @_; $part =~ s/([^\w\-\.\@])/_encode_char($1)/eg; return $part; } sub _encode_char { my ($char) = @_; return "%" . sprintf "%lx", ord($char); } 1; Rex-1.3.3/lib/Rex/Service/0000755000175000017500000000000012572251052015045 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/ALT.pm0000644000175000017500000000130412572251052016021 0ustar jenkinsjenkins# # ALT sevice control support # package Rex::Service::ALT; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/sbin/service %s start', restart => '/sbin/service %s restart', stop => '/sbin/service %s stop', reload => '/sbin/service %s reload', status => '/sbin/service %s status', ensure_stop => '/sbin/chkconfig %s off', ensure_start => '/sbin/chkconfig %s on', action => '/sbin/service %s %s', }; return $self; } 1; Rex-1.3.3/lib/Rex/Service/Gentoo.pm0000644000175000017500000000160712572251052016642 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Gentoo; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/init.d/%s start', restart => '/etc/init.d/%s restart', stop => '/etc/init.d/%s stop', reload => '/etc/init.d/%s reload', status => '/etc/init.d/%s status', ensure_stop => 'rc-update del %s', ensure_start => 'rc-update add %s', action => '/etc/init.d/%s %s', service_exists => q(rc-config --brief list | awk '{print $1}' | grep '^%s$'), }; return $self; } 1; Rex-1.3.3/lib/Rex/Service/Debian.pm0000644000175000017500000000152512572251052016570 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Debian; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/init.d/%s start', restart => '/etc/init.d/%s restart', stop => '/etc/init.d/%s stop', reload => '/etc/init.d/%s reload', status => '/etc/init.d/%s status', ensure_stop => 'update-rc.d -f %s remove', ensure_start => 'update-rc.d %s defaults', action => '/etc/init.d/%s %s', service_exists => '/usr/sbin/service --status-all 2>&1 | grep %s', }; return $self; } 1; Rex-1.3.3/lib/Rex/Service/Ubuntu.pm0000644000175000017500000000236212572251052016670 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Ubuntu; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/usr/sbin/service %s start', restart => '/usr/sbin/service %s restart', stop => '/usr/sbin/service %s stop', reload => '/usr/sbin/service %s reload', status => '/usr/sbin/service %s status', ensure_stop => '/usr/sbin/update-rc.d -f %s remove', ensure_start => '/usr/sbin/update-rc.d %s defaults', action => '/usr/sbin/service %s %s', service_exists => '/usr/sbin/service --status-all 2>&1 | grep %s', }; return $self; } sub status { my ( $self, $service, $options ) = @_; my $ret = $self->SUPER::status( $service, $options ); # bad... really bad ... if ( $ret == 0 ) { return 0; } my $output = $self->get_output; if ( $output =~ m/NOT running|stop\//ms ) { return 0; } return 1; } 1; Rex-1.3.3/lib/Rex/Service/NetBSD.pm0000644000175000017500000000247712572251052016474 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::NetBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/rc.d/%s onestart', restart => '/etc/rc.d/%s onerestart', stop => '/etc/rc.d/%s onestop', reload => '/etc/rc.d/%s onereload', status => '/etc/rc.d/%s onestatus', action => '/etc/rc.d/%s %s', }; return $self; } sub ensure { my ( $self, $service, $options ) = @_; my $what = $options->{ensure}; if ( $what =~ /^stop/ ) { $self->stop( $service, $options ); file "/etc/rc.conf.d/${service}", ensure => "absent"; delete_lines_matching "/etc/rc.conf", matching => qr/^\s*${service}="?((?i)YES)"?/; } elsif ( $what =~ /^start/ || $what =~ m/^run/ ) { $self->start( $service, $options ); file "/etc/rc.conf.d/${service}", ensure => "absent"; append_or_amend_line "/etc/rc.conf", line => "${service}=YES", regexp => qr/^\s*${service}="?((?i)YES|NO)"?/; } return 1; } 1; Rex-1.3.3/lib/Rex/Service/SunOS.pm0000644000175000017500000000221612572251052016413 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::SunOS; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use Rex::Commands::Fs; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/init.d/%s start', restart => '/etc/init.d/%s restart', stop => '/etc/init.d/%s stop', reload => '/etc/init.d/%s reload', status => '/etc/init.d/%s status', action => '/etc/init.d/%s %s', }; return $self; } sub ensure { my ( $self, $service, $options ) = @_; my $what = $options->{ensure}; if ( $what =~ /^stop/ ) { $self->stop( $service, $options ); i_run "rm /etc/rc*.d/S*$service"; } elsif ( $what =~ /^start/ || $what =~ m/^run/ ) { $self->start( $service, $options ); my ($runlevel) = map { /run-level (\d)/ } i_run "who -r"; ln "/etc/init.d/$service", "/etc/rc${runlevel}.d/S99$service"; } return 1; } 1; Rex-1.3.3/lib/Rex/Service/SuSE.pm0000644000175000017500000000144012572251052016221 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::SuSE; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/rc.d/%s start', restart => '/etc/rc.d/%s restart', stop => '/etc/rc.d/%s stop', reload => '/etc/rc.d/%s reload', status => '/etc/rc.d/%s status', ensure_stop => 'chkconfig %s off', ensure_start => 'chkconfig %s on', action => '/etc/rc.d/%s %s', }; return $self; } 1; Rex-1.3.3/lib/Rex/Service/Gentoo/0000755000175000017500000000000012572251052016300 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/Gentoo/systemd.pm0000644000175000017500000000065712572251052020336 0ustar jenkinsjenkins# # Gentoo systemd support # package Rex::Service::Gentoo::systemd; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Logger; use Rex::Commands::Fs; use Rex::Service::Redhat::systemd; use base qw(Rex::Service::Redhat::systemd); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Service/SuSE/0000755000175000017500000000000012572251052015664 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/SuSE/systemd.pm0000644000175000017500000000075712572251052017723 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::SuSE::systemd; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Logger; use Rex::Commands::Fs; use Rex::Service::Redhat::systemd; use base qw(Rex::Service::Redhat::systemd); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Service/FreeBSD.pm0000644000175000017500000000444112572251052016620 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::FreeBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::Fs; use Rex::Commands::File; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/usr/sbin/service %s onestart', restart => '/usr/sbin/service %s onerestart', stop => '/usr/sbin/service %s onestop', reload => '/usr/sbin/service %s onereload', status => '/usr/sbin/service %s onestatus', action => '/usr/sbin/service %s %s', }; return $self; } sub ensure { my ( $self, $service, $options ) = @_; my $what = $options->{ensure}; my $rccom = "/usr/sbin/service $service rcvar"; my $rcout = i_run $rccom; if ( $? != 0 ) { Rex::Logger::info( "Running `$rccom` failed", "error" ); return 0; } my ( $rcvar, $rcvalue ) = $rcout =~ m/^\$?(\w+)="?(\w+)"?$/m; unless ($rcvar) { Rex::Logger::info( "Error getting service name.", "error" ); return 0; } if ( $what =~ /^stop/ ) { $self->stop( $service, $options ); my $stop_regexp = qr/^\s*${rcvar}=((?i)["']?YES["']?)/; if ( $rcvalue =~ m/^YES$/i ) { file "/etc/rc.conf.d/${service}", ensure => "absent"; file "/usr/local/etc/rc.conf.d/${service}", ensure => "absent"; if ( is_file("/etc/rc.conf.local") ) { delete_lines_matching "/etc/rc.conf.local", matching => $stop_regexp; } delete_lines_matching "/etc/rc.conf", matching => $stop_regexp; } } elsif ( $what =~ /^start/ || $what =~ m/^run/ ) { $self->start( $service, $options ); my $start_regexp = qr/^\s*${rcvar}=/; unless ( $rcvalue =~ m/^YES$/i ) { file "/etc/rc.conf.d/${service}", ensure => "absent"; file "/usr/local/etc/rc.conf.d/${service}", ensure => "absent"; if ( is_file("/etc/rc.conf.local") ) { delete_lines_matching "/etc/rc.conf.local", matching => $start_regexp; } append_or_amend_line "/etc/rc.conf", line => "${rcvar}=\"YES\"", regexp => $start_regexp; } } return 1; } 1; Rex-1.3.3/lib/Rex/Service/Base.pm0000644000175000017500000001023712572251052016260 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; my $known_services = {}; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); $self->{__cmd_output__} = ''; return $self; } sub get_output { shift->{__cmd_output__}; } sub _prepare_service_name { my ( $self, $service_name ) = @_; if ( !$self->service_exists($service_name) && Rex::Config->get_check_service_exists ) { die "Service $service_name not found."; } return $service_name; } sub _filter_options { my ( $self, $service, $options ) = @_; for my $key (qw/start stop status restart reload ensure_stop ensure_start/) { if ( exists $options->{$key} ) { $known_services->{$service}->{$key} = $options->{$key}; } } } sub _execute { my ( $self, $cmd ) = @_; $self->{__cmd_output__} = i_run $cmd, nohup => 1; if ( $? == 0 ) { return 1; } return 0; } sub start { my ( $self, $service, $options ) = @_; $service = $self->_prepare_service_name($service); $self->_filter_options( $service, $options ); my $cmd = sprintf $self->{commands}->{start}, $service; if ( exists $known_services->{$service}->{start} ) { $cmd = $known_services->{$service}->{start}; } return $self->_execute($cmd); } sub restart { my ( $self, $service, $options ) = @_; $service = $self->_prepare_service_name($service); $self->_filter_options( $service, $options ); my $cmd = sprintf $self->{commands}->{restart}, $service; if ( exists $known_services->{$service}->{restart} ) { $cmd = $known_services->{$service}->{restart}; } return $self->_execute($cmd); } sub stop { my ( $self, $service, $options ) = @_; $service = $self->_prepare_service_name($service); $self->_filter_options( $service, $options ); my $cmd = sprintf $self->{commands}->{stop}, $service; if ( exists $known_services->{$service}->{stop} ) { $cmd = $known_services->{$service}->{stop}; } return $self->_execute($cmd); } sub reload { my ( $self, $service, $options ) = @_; $service = $self->_prepare_service_name($service); $self->_filter_options( $service, $options ); my $cmd = sprintf $self->{commands}->{reload}, $service; if ( exists $known_services->{$service}->{reload} ) { $cmd = $known_services->{$service}->{reload}; } return $self->_execute($cmd); } sub status { my ( $self, $service, $options ) = @_; $service = $self->_prepare_service_name($service); $self->_filter_options( $service, $options ); my $cmd = sprintf $self->{commands}->{status}, $service; if ( exists $known_services->{$service}->{status} ) { $cmd = $known_services->{$service}->{status}; } return $self->_execute($cmd); } sub ensure { my ( $self, $service, $options ) = @_; $service = $self->_prepare_service_name($service); $self->_filter_options( $service, $options ); my $what = $options->{ensure}; if ( $what =~ /^stop/ ) { $self->stop( $service, $options ); my $cmd = sprintf $self->{commands}->{ensure_stop}, $service; if ( exists $known_services->{$service}->{ensure_stop} ) { $cmd = $known_services->{$service}->{ensure_stop}; } return $self->_execute($cmd); } elsif ( $what =~ /^start/ || $what =~ m/^run/ ) { $self->start( $service, $options ); my $cmd = sprintf $self->{commands}->{ensure_start}, $service; if ( exists $known_services->{$service}->{ensure_start} ) { $cmd = $known_services->{$service}->{ensure_start}; } return $self->_execute($cmd); } } sub action { my ( $self, $service, $action ) = @_; $service = $self->_prepare_service_name($service); my $cmd = sprintf $self->{commands}->{action}, $service, $action; return $self->_execute($cmd); } sub service_exists { my ( $self, $service ) = @_; # always return true if we can't verify if a service exists if ( !exists $self->{commands}->{service_exists} ) { return 1; } my $cmd = sprintf $self->{commands}->{service_exists}, $service; return $self->_execute($cmd); } 1; Rex-1.3.3/lib/Rex/Service/OpenBSD.pm0000644000175000017500000000224612572251052016641 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::OpenBSD; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/rc.d/%s start', restart => '/etc/rc.d/%s restart', stop => '/etc/rc.d/%s stop', reload => '/etc/rc.d/%s reload', status => '/etc/rc.d/%s status', action => '/etc/rc.d/%s %s', }; return $self; } sub ensure { my ( $self, $service, $options ) = @_; my $what = $options->{ensure}; if ( $what =~ /^stop/ ) { $self->stop( $service, $options ); delete_lines_matching "/etc/rc.conf", matching => qr/rc_scripts="\${rc_scripts} ${service}"/; } elsif ( $what =~ /^start/ || $what =~ m/^run/ ) { $self->start( $service, $options ); append_if_no_such_line "/etc/rc.conf", "rc_scripts=\"\${rc_scripts} ${service}\"\n"; } return 1; } 1; Rex-1.3.3/lib/Rex/Service/Mageia/0000755000175000017500000000000012572251052016230 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/Mageia/systemd.pm0000644000175000017500000000076112572251052020262 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Mageia::systemd; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Logger; use Rex::Commands::Fs; use Rex::Service::Redhat::systemd; use base qw(Rex::Service::Redhat::systemd); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Service/Debian/0000755000175000017500000000000012572251052016227 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/Debian/systemd.pm0000644000175000017500000000065712572251052020265 0ustar jenkinsjenkins# # Debian systemd support # package Rex::Service::Debian::systemd; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Logger; use Rex::Commands::Fs; use Rex::Service::Redhat::systemd; use base qw(Rex::Service::Redhat::systemd); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Service/SunOS/0000755000175000017500000000000012572251052016054 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/SunOS/svcadm.pm0000644000175000017500000000241712572251052017673 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::SunOS::svcadm; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use Rex::Commands::Fs; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => 'svcadm enable %s >/dev/null', restart => 'svcadm restart %s >/dev/null', stop => 'svcadm disable %s >/dev/null', reload => 'svcadm refresh %s >/dev/null', }; return $self; } sub status { my ( $self, $service, $options ) = @_; my ($state) = map { /state\s+([a-z]+)/ } i_run "svcs -l $service"; if ( $state eq "online" ) { return 1; } return 0; } sub ensure { my ( $self, $service, $options ) = @_; my $what = $options->{ensure}; if ( $what =~ /^stop/ ) { $self->stop( $service, $options ); } elsif ( $what =~ /^start/ || $what =~ m/^run/ ) { $self->start( $service, $options ); } return 1; } sub action { my ( $self, $service, $action ) = @_; i_run "svcadm $action $service >/dev/null", nohup => 1; if ( $? == 0 ) { return 1; } } 1; Rex-1.3.3/lib/Rex/Service/OpenWrt.pm0000644000175000017500000000155012572251052017002 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::OpenWrt; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use Rex::Service::Debian; use base qw(Rex::Service::Debian); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/init.d/%s start', restart => '/etc/init.d/%s restart', stop => '/etc/init.d/%s stop', reload => '/etc/init.d/%s reload', status => '/sbin/start-stop-daemon -K -t -q -n %s', ensure_stop => '/etc/init.d/%s disable', ensure_start => '/etc/init.d/%s enable', action => '/etc/init.d/%s %s', }; return $self; } 1; Rex-1.3.3/lib/Rex/Service/Redhat.pm0000644000175000017500000000161112572251052016611 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Redhat; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/rc.d/init.d/%s start', restart => '/etc/rc.d/init.d/%s restart', stop => '/etc/rc.d/init.d/%s stop', reload => '/etc/rc.d/init.d/%s reload', status => '/etc/rc.d/init.d/%s status', ensure_stop => 'chkconfig %s off', ensure_start => 'chkconfig %s on', action => '/etc/rc.d/init.d/%s %s', service_exists => 'chkconfig --list %s', }; return $self; } 1; Rex-1.3.3/lib/Rex/Service/ALT/0000755000175000017500000000000012572251052015465 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/ALT/systemd.pm0000644000175000017500000000065112572251052017515 0ustar jenkinsjenkins# # ALT systemd support # package Rex::Service::ALT::systemd; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Logger; use Rex::Commands::Fs; use Rex::Service::Redhat::systemd; use base qw(Rex::Service::Redhat::systemd); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Service/Redhat/0000755000175000017500000000000012572251052016254 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Service/Redhat/systemd.pm0000644000175000017500000000247112572251052020306 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Redhat::systemd; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use Rex::Commands::Fs; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => 'systemctl start %s', restart => 'systemctl restart %s', stop => 'systemctl stop %s', reload => 'systemctl reload %s', status => 'systemctl is-active %s', ensure_stop => 'systemctl disable %s', ensure_start => 'systemctl enable %s', service_exists => 'systemctl show %s | grep LoadState=loaded', }; return $self; } # all systemd services must end with .service # so it will be appended if there is no "." in the name. sub _prepare_service_name { my ( $self, $service ) = @_; unless ( $service =~ m/\./ ) { $service .= ".service"; } $self->SUPER::_prepare_service_name($service); return $service; } sub action { my ( $self, $service, $action ) = @_; i_run "systemctl $action $service >/dev/null", nohup => 1; if ( $? == 0 ) { return 1; } } 1; Rex-1.3.3/lib/Rex/Service/Mageia.pm0000644000175000017500000000151412572251052016567 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Service::Mageia; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Logger; use base qw(Rex::Service::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = $proto->SUPER::new(@_); bless( $self, $proto ); $self->{commands} = { start => '/etc/rc.d/init.d/%s start', restart => '/etc/rc.d/init.d/%s restart', stop => '/etc/rc.d/init.d/%s stop', reload => '/etc/rc.d/init.d/%s reload', status => '/etc/rc.d/init.d/%s status', ensure_stop => 'chkconfig %s off', ensure_start => 'chkconfig %s on', action => '/etc/rc.d/init.d/%s %s', }; return $self; } 1; Rex-1.3.3/lib/Rex/Box.pm0000644000175000017500000000160312572251052014533 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Box; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Config; use Rex::Logger; my %BOX_PROVIDER; sub register_box_provider { my ( $class, $service_name, $service_class ) = @_; $BOX_PROVIDER{"\L$service_name"} = $service_class; return 1; } sub create { my ( $class, @opts ) = @_; my $type = Rex::Config->get("box_type") || "VBox"; my $options = Rex::Config->get("box_options") || {}; my $klass = "Rex::Box::${type}"; if ( exists $BOX_PROVIDER{$type} ) { $klass = $BOX_PROVIDER{$type}; } Rex::Logger::debug("Using $klass as box provider"); eval "use $klass;"; if ($@) { Rex::Logger::info("Box Class $klass not found."); die("Box Class $klass not found."); } return $klass->new( @opts, options => $options ); } 1; Rex-1.3.3/lib/Rex/Hardware.pm0000644000175000017500000000360012572251052015537 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Hardware - Base Class for hardware / information gathering =head1 DESCRIPTION This module is the base class for hardware/information gathering. =head1 SYNOPSIS use Rex::Hardware; my %host_info = Rex::Hardware->get(qw/ Host /); my %all_info = Rex::Hardware->get(qw/ All /); =head1 CLASS METHODS =cut package Rex::Hardware; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; require Rex::Args; =head2 get(@modules) Returns a hash with the wanted information. task "get-info", "server1", sub { %hw_info = Rex::Hardware->get(qw/ Host Network /); }; Or if you want to get all information task "get-all-info", "server1", sub { %hw_info = Rex::Hardware->get(qw/ All /); }; Available modules: =over 4 =item Host =item Kernel =item Memory =item Network =item Swap =item VirtInfo =back =cut my %HW_PROVIDER; sub register_hardware_provider { my ( $class, $service_name, $service_class ) = @_; $HW_PROVIDER{"\L$service_name"} = $service_class; return 1; } sub get { my ( $class, @modules ) = @_; my %hardware_information; if ( "all" eq "\L$modules[0]" ) { @modules = qw(Host Kernel Memory Network Swap VirtInfo); push( @modules, keys(%HW_PROVIDER) ); } for my $mod_string (@modules) { Rex::Commands::profiler()->start("hardware: $mod_string"); my $mod = "Rex::Hardware::$mod_string"; if ( exists $HW_PROVIDER{$mod_string} ) { $mod = $HW_PROVIDER{$mod_string}; } Rex::Logger::debug("Loading $mod"); eval "use $mod"; if ($@) { Rex::Logger::info("$mod not found."); Rex::Logger::debug("$@"); next; } $hardware_information{$mod_string} = $mod->get(); Rex::Commands::profiler()->end("hardware: $mod_string"); } return %hardware_information; } 1; Rex-1.3.3/lib/Rex/Box/0000755000175000017500000000000012572251052014175 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Box/KVM.pm0000644000175000017500000000774412572251052015204 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=3 sw=3 tw=0: # vim: set expandtab: =head1 NAME Rex::Box::KVM - Rex/Boxes KVM Module =head1 DESCRIPTION This is a Rex/Boxes module to use KVM VMs. You need to have libvirt installed. =head1 EXAMPLES To use this module inside your Rexfile you can use the following commands. use Rex::Commands::Box; set box => "KVM"; task "prepare_box", sub { box { my ($box) = @_; $box->name("mybox"); $box->url("http://box.rexify.org/box/ubuntu-server-12.10-amd64.kvm.qcow2"); $box->network(1 => { name => "default", }); $box->auth( user => "root", password => "box", ); $box->setup("setup_task"); }; }; If you want to use a YAML file you can use the following template. type: KVM vms: vmone: url: http://box.rexify.org/box/ubuntu-server-12.10-amd64.kvm.qcow2 setup: setup_task And then you can use it the following way in your Rexfile. use Rex::Commands::Box init_file => "file.yml"; task "prepare_vms", sub { boxes "init"; }; =head1 METHODS See also the Methods of Rex::Box::Base. This module inherits all methods of it. =cut package Rex::Box::KVM; use strict; use warnings; use Data::Dumper; use Rex::Box::Base; use Rex::Commands -no => [qw/auth/]; use Rex::Commands::Run; use Rex::Commands::Fs; use Rex::Commands::Virtualization; use Rex::Commands::SimpleCheck; our $VERSION = '1.3.3'; # VERSION BEGIN { LWP::UserAgent->use; } use Time::HiRes qw(tv_interval gettimeofday); use File::Basename qw(basename); use base qw(Rex::Box::Base); set virtualization => "LibVirt"; $|++; ################################################################################ # BEGIN of class methods ################################################################################ =head2 new(name => $vmname) Constructor if used in OO mode. my $box = Rex::Box::KVM->new(name => "vmname"); =cut sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, ref($class) || $class ); return $self; } sub import_vm { my ($self) = @_; # check if machine already exists my $vms = vm list => "all"; my $vm_exists = 0; for my $vm ( @{$vms} ) { if ( $vm->{name} eq $self->{name} ) { Rex::Logger::debug("VM already exists. Don't import anything."); $vm_exists = 1; } } if ( !$vm_exists ) { # if not, create it $self->_download; my $filename = basename( $self->{url} ); Rex::Logger::info("Importing VM ./tmp/$filename"); my @options = ( import => $self->{name}, file => "./tmp/$filename", %{$self}, ); if (Rex::Config::get_use_rex_kvm_agent) { my $tcp_port = int( rand(40000) ) + 10000; push @options, 'serial_devices', [ { type => 'tcp', host => '127.0.0.1', port => $tcp_port, }, ]; Rex::Logger::info( "Binding a serial device to TCP port $tcp_port for rex-kvm-agent"); } vm @options; #unlink "./tmp/$filename"; } my $vminfo = vm info => $self->{name}; if ( $vminfo->{State} eq "shut off" ) { $self->start; } $self->{info} = vm guestinfo => $self->{name}; } sub provision_vm { my ( $self, @tasks ) = @_; if ( !@tasks ) { @tasks = @{ $self->{__tasks} }; } $self->wait_for_ssh(); for my $task (@tasks) { Rex::TaskList->create()->get_task($task)->set_auth( %{ $self->{__auth} } ); Rex::TaskList->create()->get_task($task)->run( $self->ip ); } } sub list_boxes { my ($self) = @_; my $vms = vm list => "all"; return @{$vms}; } =head2 info Returns a hashRef of vm information. =cut sub info { my ($self) = @_; $self->ip; return $self->{info}; } =head2 ip This method return the ip of a vm on which the ssh daemon is listening. =cut sub ip { my ($self) = @_; $self->{info} = vm guestinfo => $self->{name}; return $self->{info}->{network}->[0]->{ip}; } 1; Rex-1.3.3/lib/Rex/Box/VBox.pm0000644000175000017500000001763412572251052015424 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Box::VBox - Rex/Boxes VirtualBox Module =head1 DESCRIPTION This is a Rex/Boxes module to use VirtualBox VMs. =head1 EXAMPLES To use this module inside your Rexfile you can use the following commands. use Rex::Commands::Box; set box => "VBox"; task "prepare_box", sub { box { my ($box) = @_; $box->name("mybox"); $box->url("http://box.rexify.org/box/ubuntu-server-12.10-amd64.ova"); $box->network(1 => { type => "nat", }); $box->network(1 => { type => "bridged", bridge => "eth0", }); $box->forward_port(ssh => [2222, 22]); $box->share_folder(myhome => "/home/myuser"); $box->auth( user => "root", password => "box", ); $box->setup("setup_task"); }; }; If you want to use a YAML file you can use the following template. type: VBox vms: vmone: url: http://box.rexify.org/box/ubuntu-server-12.10-amd64.ova forward_port: ssh: - 2222 - 22 share_folder: myhome: /home/myhome setup: setup_task And then you can use it the following way in your Rexfile. use Rex::Commands::Box init_file => "file.yml"; task "prepare_vms", sub { boxes "init"; }; =head1 HEADLESS MODE It is also possible to run VirtualBox in headless mode. This only works on Linux and MacOS. If you want to do this you can use the following option at the top of your I. set box_options => { headless => TRUE }; =head1 METHODS See also the Methods of Rex::Box::Base. This module inherits all methods of it. =cut package Rex::Box::VBox; use strict; use warnings; use Data::Dumper; use Rex::Box::Base; use Rex::Commands -no => [qw/auth/]; use Rex::Commands::Run; use Rex::Commands::Fs; use Rex::Commands::Virtualization; use Rex::Commands::SimpleCheck; our $VERSION = '1.3.3'; # VERSION BEGIN { LWP::UserAgent->use; } use Time::HiRes qw(tv_interval gettimeofday); use File::Basename qw(basename); use base qw(Rex::Box::Base); set virtualization => "VBox"; $|++; ################################################################################ # BEGIN of class methods ################################################################################ =head2 new(name => $vmname) Constructor if used in OO mode. my $box = Rex::Box::VBox->new(name => "vmname"); =cut sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, ref($class) || $class ); if ( exists $self->{options} && exists $self->{options}->{headless} && $self->{options}->{headless} ) { set virtualization => { type => "VBox", headless => TRUE }; } $self->{get_ip_count} = 0; return $self; } sub import_vm { my ($self) = @_; # check if machine already exists my $vms = vm list => "all"; my $vm_exists = 0; for my $vm ( @{$vms} ) { if ( $vm->{name} eq $self->{name} ) { Rex::Logger::debug("VM already exists. Don't import anything."); $vm_exists = 1; } } if ( !$vm_exists ) { # if not, create it $self->_download; my $filename = basename( $self->{url} ); Rex::Logger::info("Importing VM ./tmp/$filename"); vm import => $self->{name}, file => "./tmp/$filename", %{$self}; #unlink "./tmp/$filename"; } my $vminfo = vm info => $self->{name}; # check if networksettings should be set if ( exists $self->{__network} && $vminfo->{VMState} ne "running" ) { my $option = $self->{__network}; for my $nic_no ( keys %{$option} ) { if ( $option->{$nic_no}->{type} ) { Rex::Logger::debug( "Setting network type (dev: $nic_no) to: " . $option->{$nic_no}->{type} ); vm option => $self->{name}, "nic$nic_no" => $option->{$nic_no}->{type}; if ( $option->{$nic_no}->{type} eq "bridged" ) { $option->{$nic_no}->{bridge} = select_bridge() if ( !$option->{$nic_no}->{bridge} ); Rex::Logger::debug( "Setting network bridge (dev: $nic_no) to: " . ( $option->{$nic_no}->{bridge} || "eth0" ) ); vm option => $self->{name}, "bridgeadapter$nic_no" => ( $option->{$nic_no}->{bridge} || "eth0" ); } } if ( $option->{$nic_no}->{driver} ) { Rex::Logger::debug( "Setting network driver (dev: $nic_no) to: " . $option->{$nic_no}->{driver} ); vm option => $self->{name}, "nictype$nic_no" => $option->{$nic_no}->{driver}; } } } if ( exists $self->{__forward_port} && $vminfo->{VMState} ne "running" ) { # remove all forwards vm forward_port => $self->{name}, delete => -all; # add forwards vm forward_port => $self->{name}, add => $self->{__forward_port}; } # shared folder if ( exists $self->{__shared_folder} && $vminfo->{VMState} ne "running" ) { vm share_folder => $self->{name}, add => $self->{__shared_folder}; } if ( $vminfo->{VMState} ne "running" ) { $self->start; } $self->{info} = vm guestinfo => $self->{name}; } sub provision_vm { my ( $self, @tasks ) = @_; if ( !@tasks ) { @tasks = @{ $self->{__tasks} } if ( exists $self->{__tasks} ); } $self->wait_for_ssh(); for my $task (@tasks) { Rex::TaskList->create()->get_task($task)->set_auth( %{ $self->{__auth} } ); Rex::TaskList->create()->get_task($task)->run( $self->ip ); } } sub select_bridge { my $bridges = vm "bridge"; my $ifname; if ( @$bridges == 1 ) { Rex::Logger::debug( "Only one bridged interface available. Using it by default."); $ifname = $bridges->[0]->{name}; } elsif ( @$bridges > 1 ) { for ( my $i = 0 ; $i < @$bridges ; $i++ ) { my $bridge = $bridges->[$i]; next if ( $bridge->{status} =~ /^down$/i ); local $Rex::Logger::format = "%s"; Rex::Logger::info( $i + 1 . " $bridge->{name}" ); } my $choice; do { print "What interface should network bridge to? "; chomp( $choice = ); $choice = int($choice); } while ( !$choice ); $ifname = $bridges->[ $choice - 1 ]->{name}; } return $ifname; } =head2 share_folder(%option) Creates a shared folder inside the VM with the content from a folder from the Host machine. This only works with VirtualBox. $box->share_folder( name => "/path/on/host", name2 => "/path_2/on/host", ); =cut sub share_folder { my ( $self, %option ) = @_; $self->{__shared_folder} = \%option; } =head2 info Returns a hashRef of vm information. =cut sub info { my ($self) = @_; $self->ip; my $vm_info = vm info => $self->{name}; # get forwarded ports my @forwarded_ports = grep { m/^Forwarding/ } keys %{$vm_info}; my %forward_port; for my $fwp (@forwarded_ports) { my ( $name, $proto, $host_ip, $host_port, $vm_ip, $vm_port ) = split( /,/, $vm_info->{$fwp} ); $forward_port{$name} = [ $host_port, $vm_port ]; } $self->forward_port(%forward_port); return $self->{info}; } =head2 ip This method return the ip of a vm on which the ssh daemon is listening. =cut sub ip { my ($self) = @_; $self->{info} = vm guestinfo => $self->{name}; if ( scalar keys %{ $self->{info} } == 0 ) { return; } my $server = $self->{info}->{net}->[0]->{ip}; if ( $self->{__forward_port} && $self->{__forward_port}->{ssh} && !Rex::is_local() ) { $server = connection->server . ":" . $self->{__forward_port}->{ssh}->[0]; } elsif ( $self->{__forward_port} && $self->{__forward_port}->{ssh} && Rex::is_local() ) { $server = "127.0.0.1:" . $self->{__forward_port}->{ssh}->[0]; } $self->{info}->{ip} = $server; if ( !$server ) { sleep 1; $self->{get_ip_count}++; if ( $self->{get_ip_count} >= 30 ) { die "Can't get ip of VM."; } my $ip = $self->ip; if ($ip) { $self->{get_ip_count} = 0; return $ip; } } return $server; } 1; Rex-1.3.3/lib/Rex/Box/Base.pm0000644000175000017500000001571412572251052015415 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Box::Base - Rex/Boxes Base Module =head1 DESCRIPTION This is a Rex/Boxes base module. =head1 METHODS These methods are shared across all other Rex::Box modules. =cut package Rex::Box::Base; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands -no => [qw/auth/]; use Rex::Commands::Run; use Rex::Commands::Fs; use Rex::Commands::Virtualization; use Rex::Commands::SimpleCheck; BEGIN { LWP::UserAgent->use; } use Time::HiRes qw(tv_interval gettimeofday); use File::Basename qw(basename); use Data::Dumper; sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); # default auth for rex boxes $self->{__auth} = { user => Rex::Config->get_user(), password => Rex::Config->get_password(), private_key => Rex::Config->get_private_key(), public_key => Rex::Config->get_public_key(), }; # for box this is needed, because we have changing ips Rex::Config->set_openssh_opt( StrictHostKeyChecking => "no", UserKnownHostsFile => "/dev/null", LogLevel => "QUIET" ); return $self; } =head2 info Returns a hashRef of vm information. =cut sub info { my ($self) = @_; return $self->{info}; } =head2 name($vmname) Sets the name of the virtual machine. =cut sub name { my ( $self, $name ) = @_; $self->{name} = $name; } =head2 setup(@tasks) Sets the tasks that should be executed as soon as the VM is available through SSH. =cut sub setup { my ( $self, @tasks ) = @_; $self->{__tasks} = \@tasks; } =head2 import_vm() This method must be overwritten by the implementing class. =cut sub import_vm { my ($self) = @_; die("This method must be overwritten."); } =head2 stop() Stops the VM. =cut sub stop { my ($self) = @_; $self->info; vm shutdown => $self->{name}; } =head2 start() Starts the VM. =cut sub start { my ($self) = @_; $self->info; vm start => $self->{name}; } =head2 ip() Return the ip:port to which rex will connect to. =cut sub ip { die("Must be implemented by box class.") } =head2 status() Returns the status of a VM. Valid return values are "running" and "stopped". =cut sub status { my ($self) = @_; return vm status => $self->{name}; } =head2 provision_vm([@tasks]) Executes the given tasks on the VM. =cut sub provision_vm { my ( $self, @tasks ) = @_; die("This method must be overwritten."); } =head2 cpus($count) Set the amount of CPUs for the VM. =cut sub cpus { my ( $self, $cpus ) = @_; $self->{cpus} = $cpus; } =head2 memory($memory_size) Sets the memory of a VM in megabyte. =cut sub memory { my ( $self, $mem ) = @_; $self->{memory} = $mem; } =head2 network(%option) Configure the network for a VM. Currently it supports 2 modes: I and I. Currently it supports only one network card. $box->network( 1 => { type => "nat", }, } $box->network( 1 => { type => "bridged", bridge => "eth0", }, ); =cut sub network { my ( $self, %option ) = @_; $self->{__network} = \%option; } =head2 forward_port(%option) Set ports to be forwarded to the VM. This is not supported by all Box providers. $box->forward_port( name => [$from_host_port, $to_vm_port], name2 => [$from_host_port_2, $to_vm_port_2], ... ); =cut sub forward_port { my ( $self, %option ) = @_; $self->{__forward_port} = \%option; } =head2 list_boxes List all available boxes. =cut sub list_boxes { my ($self) = @_; my $vms = vm list => "all"; return @{$vms}; } =head2 url($url) The URL where to download the Base VM Image. You can use self-made images or prebuild images from http://box.rexify.org/. =cut sub url { my ( $self, $url, $force ) = @_; $self->{url} = $url; $self->{force} = $force; } =head2 auth(%option) Configure the authentication to the VM. $box->auth( user => $user, password => $password, private_key => $private_key, public_key => $public_key, ); =cut sub auth { my ( $self, %auth ) = @_; $self->{__auth} = \%auth; } sub wait_for_ssh { my ( $self, $ip, $port ) = @_; if ( !$ip ) { ( $ip, $port ) = split( /:/, $self->ip ); $port ||= 22; } print "Waiting for SSH to come up on $ip:$port."; while ( !is_port_open( $ip, $port ) ) { print "."; sleep 1; } print "\n"; } sub _download { my ($self) = @_; my $filename = basename( $self->{url} ); my $force = $self->{force} || FALSE; if ( is_file("./tmp/$filename") ) { Rex::Logger::info( "File already downloaded. Please remove the file ./tmp/$filename if you want to download a fresh copy." ); } else { $force = TRUE; } if ($force) { Rex::Logger::info("Downloading $self->{url} to ./tmp/$filename"); mkdir "tmp"; if ( Rex::is_local() ) { my $ua = LWP::UserAgent->new(); $ua->env_proxy; my $final_data = ""; my $current_size = 0; my $current_modulo = 0; my $start_time = [ gettimeofday() ]; open( my $fh, ">", "./tmp/$filename" ) or die("Failed to open ./tmp/$filename for writing: $!"); binmode $fh; my $resp = $ua->get( $self->{url}, ':content_cb' => sub { my ( $data, $response, $protocol ) = @_; $current_size += length($data); my $content_length = $response->header("content-length"); print $fh $data; my $current_time = [ gettimeofday() ]; my $time_diff = tv_interval( $start_time, $current_time ); my $bytes_per_seconds = $current_size / $time_diff; my $mbytes_per_seconds = $bytes_per_seconds / 1024 / 1024; my $mbytes_current = $current_size / 1024 / 1024; my $mbytes_total = $content_length / 1024 / 1024; my $left_bytes = $content_length - $current_size; my $time_one_byte = $time_diff / $current_size; my $time_all_bytes = $time_one_byte * ( $content_length - $current_size ); if ( ( ( $current_size / ( 1024 * 1024 ) ) % ( 1024 * 1024 ) ) > $current_modulo ) { print "."; $current_modulo++; if ( $current_modulo % 10 == 0 ) { printf( ". %.2f MBytes/s (%.2f MByte / %.2f MByte) %.2f secs left\n", $mbytes_per_seconds, $mbytes_current, $mbytes_total, $time_all_bytes ); } } } ); close($fh); if ( $resp->is_success ) { print " done.\n"; } else { Rex::Logger::info( "Error downloading box image.", "warn" ); unlink "./tmp/$filename"; } } else { run "wget -c -qO ./tmp/$filename $self->{url}"; if ( $? != 0 ) { die( "Downloading of $self->{url} failed. Please verify if wget is installed and if you have the right permissions to download this box." ); } } } } 1; Rex-1.3.3/lib/Rex/Box/Amazon.pm0000644000175000017500000001313612572251052015764 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Box::Amazon - Rex/Boxes Amazon Module =head1 DESCRIPTION This is a Rex/Boxes module to use Amazon EC2. =head1 EXAMPLES To use this module inside your Rexfile you can use the following commands. use Rex::Commands::Box; set box => "Amazon", { access_key => "your-access-key", private_access_key => "your-private-access-key", region => "ec2.eu-west-1.amazonaws.com", zone => "eu-west-1a", authkey => "default", }; task "prepare_box", sub { box { my ($box) = @_; $box->name("mybox"); $box->ami("ami-c1aaabb5"); $box->type("m1.large"); $box->security_group("default"); $box->auth( user => "root", password => "box", ); $box->setup("setup_task"); }; }; If you want to use a YAML file you can use the following template. type: Amazon amazon: access_key: your-access-key private_access_key: your-private-access-key region: ec2.eu-west-1.amazonaws.com zone: eu-west-1a auth_key: default vms: vmone: ami: ami-c1aaabb5 type: m1.large security_group: default setup: setup_task And then you can use it the following way in your Rexfile. use Rex::Commands::Box init_file => "file.yml"; task "prepare_vms", sub { boxes "init"; }; =head1 METHODS See also the Methods of Rex::Box::Base. This module inherits all methods of it. =cut package Rex::Box::Amazon; use strict; use warnings; use Data::Dumper; use Rex::Box::Base; use Rex::Commands -no => [qw/auth/]; use Rex::Commands::Run; use Rex::Commands::Fs; use Rex::Commands::Cloud; our $VERSION = '1.3.3'; # VERSION BEGIN { LWP::UserAgent->use; } use Time::HiRes qw(tv_interval gettimeofday); use File::Basename qw(basename); use base qw(Rex::Box::Base); $|++; ################################################################################ # BEGIN of class methods ################################################################################ =head2 new(name => $vmname) Constructor if used in OO mode. my $box = Rex::Box::VBox->new(name => "vmname"); =cut sub new { my $class = shift; my $proto = ref($class) || $class; my $self = $proto->SUPER::new(@_); bless( $self, ref($class) || $class ); cloud_service "Amazon"; cloud_auth $self->{options}->{access_key}, $self->{options}->{private_access_key}; cloud_region $self->{options}->{region}; return $self; } sub import_vm { my ($self) = @_; # check if machine already exists # Rex::Logger::debug("VM already exists. Don't import anything."); #my @vms = cloud_instance_list; my @vms = $self->list_boxes; my $vminfo; my $vm_exists = 0; for my $vm (@vms) { if ( $vm->{name} && $vm->{name} eq $self->{name} ) { Rex::Logger::debug("VM already exists. Don't import anything."); $vm_exists = 1; $vminfo = $vm; } } if ( !$vm_exists ) { # if not, create it Rex::Logger::info("Creating Amazon instance $self->{name}."); $vminfo = cloud_instance create => { image_id => $self->{ami}, name => $self->{name}, key => $self->{options}->{auth_key}, zone => $self->{options}->{zone}, type => $self->{type} || "m1.large", security_group => $self->{security_group} || "default", }; } # start if stopped if ( $vminfo->{state} eq "stopped" ) { cloud_instance start => $vminfo->{id}; } $self->{info} = $vminfo; } =head2 ami($ami_id) Set the AMI ID for the box. =cut sub ami { my ( $self, $ami ) = @_; $self->{ami} = $ami; } =head2 type($type) Set the type of the Instance. For example "m1.large". =cut sub type { my ( $self, $type ) = @_; $self->{type} = $type; } =head2 security_group($sec_group) Set the Amazon security group for this Instance. =cut sub security_group { my ( $self, $sec_group ) = @_; $self->{security_group} = $sec_group; } sub provision_vm { my ( $self, @tasks ) = @_; if ( !@tasks ) { @tasks = @{ $self->{__tasks} }; } $self->wait_for_ssh(); for my $task (@tasks) { Rex::TaskList->create()->get_task($task)->set_auth( %{ $self->{__auth} } ); Rex::TaskList->create()->get_task($task)->run( $self->ip ); } } =head2 forward_port(%option) Not available for Amazon Boxes. =cut sub forward_port { Rex::Logger::debug("Not available for Amazon Boxes."); } =head2 share_folder(%option) Not available for Amazon Boxes. =cut sub share_folder { Rex::Logger::debug("Not available for Amazon Boxes."); } sub list_boxes { my ($self) = @_; my @vms = cloud_instance_list; my @ret = grep { $_->{name} && $_->{state} ne "terminated" && $_->{state} ne "shutting-down" } @vms; # only vms with names... return @ret; } sub status { my ($self) = @_; $self->info; if ( $self->{info}->{state} eq "running" ) { return "running"; } else { return "stopped"; } } sub start { my ($self) = @_; $self->info; Rex::Logger::info( "Starting instance: " . $self->{name} ); cloud_instance start => $self->{info}->{id}; } sub stop { my ($self) = @_; Rex::Logger::info( "Stopping instance: " . $self->{name} ); $self->info; cloud_instance stop => $self->{info}->{id}; } =head2 info Returns a hashRef of vm information. =cut sub info { my ($self) = @_; ( $self->{info} ) = grep { $_->{name} eq $self->{name} } $self->list_boxes; return $self->{info}; } sub ip { my ($self) = @_; # get instance info ( $self->{info} ) = grep { $_->{name} eq $self->{name} } $self->list_boxes; return $self->{info}->{ip}; } 1; Rex-1.3.3/lib/Rex/CMDB.pm0000644000175000017500000000753112572251052014516 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::CMDB - Function to access the CMDB (configuration management database) =head1 DESCRIPTION This module exports a function to access a CMDB via a common interface. =head1 SYNOPSIS use Rex::CMDB; set cmdb => { type => 'YAML', path => [ 'cmdb/{hostname}.yml', 'cmdb/default.yml', ], merge_behavior => 'LEFT_PRECEDENT', }; task "prepare", "server1", sub { my $virtual_host = cmdb("vhost"); my %all_information = cmdb; }; =head1 EXPORTED FUNCTIONS =cut package Rex::CMDB; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Commands; use Rex::Value; require Rex::Exporter; use base qw(Rex::Exporter); use vars qw(@EXPORT); @EXPORT = qw(cmdb); my $CMDB_PROVIDER; =head2 set cmdb CMDB is enabled by default, with Rex::CMDB::YAML as default provider. The path option specifies an ordered list of places to look for CMDB information. The path specification supports any Rex::Hardware variable as macros, when enclosed within curly braces. Macros are dynamically expanded during runtime. The default path settings is: [qw( cmdb/{operatingsystem}/{hostname}.yml cmdb/{operatingsystem}/default.yml cmdb/{environment}/{hostname}.yml cmdb/{environment}/default.yml cmdb/{hostname}.yml cmdb/default.yml )] Please note that the default environment is, well, "default". You can define additional CMDB paths via the `-O` command line option by using a semicolon-separated list of `cmdb_path=path` key-value pairs: rex -O 'cmdb_path=cmdb/{domain}.yml;cmdb_path=cmdb/{domain}/{hostname}.yml;' taskname Those additional paths will be prepended to the current list of CMDB paths (so the last one specified will get on top, and thus checked first). The CMDB module looks up the specified files in order and then returns the requested data. If multiple files specify the same data for a given case, then the first instance of the data will be returned by default. Rex uses Hash::Merge internally to merge the data found on different levels of the CMDB hierarchy. Any merge strategy supported by that module can be specified to override the default one. For example one of the built-in strategies: merge_behavior => 'LEFT_PRECEDENT' Or even custom ones: merge_behavior => { SCALAR => { ... }, ARRAY => { ... }, HASH => { ... }, } For full list of options, please see the documentation of Hash::Merge. =cut Rex::Config->register_set_handler( "cmdb" => sub { my ($option) = @_; my %args = Rex::Args->getopts; if ( exists $args{O} ) { for my $itm ( split( /;/, $args{O} ) ) { my ( $key, $val ) = split( /=/, $itm ); if ( $key eq "cmdb_path" ) { if ( ref $option->{path} eq "ARRAY" ) { unshift @{ $option->{path} }, $val; } else { $option->{path} = [$val]; } } } } $CMDB_PROVIDER = $option; } ); =head2 cmdb([$item, $server]) Function to query a CMDB. If this function is called without $item it should return a hash containing all the information for the requested server. If $item is given it should return only the value for $item. task "prepare", "server1", sub { my $virtual_host = cmdb("vhost"); my %all_information = cmdb; }; =cut sub cmdb { my ( $item, $server ) = @_; $server ||= connection->server; my $klass = $CMDB_PROVIDER->{type}; if ( !$klass ) { # no cmdb set return; } if ( $klass !~ m/::/ ) { $klass = "Rex::CMDB::$klass"; } eval "use $klass"; if ($@) { die("CMDB provider ($klass) not found: $@"); } my $cmdb = $klass->new( %{$CMDB_PROVIDER} ); return Rex::Value->new( value => ( $cmdb->get( $item, $server ) || undef ) ); } sub cmdb_active { return ( $CMDB_PROVIDER ? 1 : 0 ); } 1; Rex-1.3.3/lib/Rex/Commands.pm0000644000175000017500000012022512572251052015546 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Commands - All the basic commands =head1 DESCRIPTION This module is the core commands module. =head1 SYNOPSIS desc "Task description"; task "taskname", sub { ... }; task "taskname", "server1", ..., "server20", sub { ... }; group "group" => "server1", "server2", ...; user "user"; password "password"; environment live => sub { user "root"; password "foobar"; pass_auth; group frontend => "www01", "www02"; }; =head1 COMMANDLIST =over 4 =item * Augeas config file management library L =item * Cloud Management L =item * Cron Management L =item * Database Commands L =item * SCP Up- and Download L, L =item * File Manipulation L =item * Filesystem Manipulation L =item * Information Gathering L =item * Manipulation of /etc/hosts L =item * Get an inventory of your Hardware L =item * Manage your iptables rules L =item * Kernel Commands L =item * LVM Commands L =item * MD5 checksums L =item * Network commands L =item * Notify resources to execute L =item * Package Commands L =item * Partition your storage device(s) L =item * Configure packages (via debconf) L =item * Process Management L =item * Rsync Files L =item * Run Remote Commands L =item * Source control via Subversion/Git L =item * Manage System Services (sysvinit) L =item * Simple TCP/alive checks L =item * Sync directories L =item * Sysctl Commands L =item * Live Tail files L =item * Upload local file to remote server L =item * Manage user and group accounts L =item * Manage your virtual environments L =back =head1 EXPORTED FUNCTIONS =cut package Rex::Commands; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Rex::Exporter; use Rex::TaskList; use Rex::Logger; use Rex::Config; use Rex::Profiler; use Rex::Report; use Rex; use Rex::Helper::Misc; use vars qw(@EXPORT $current_desc $global_no_ssh $environments $dont_register_tasks $profiler %auth_late); use base qw(Rex::Exporter); @EXPORT = qw(task desc group user password port sudo_password public_key private_key pass_auth key_auth krb5_auth no_ssh get_random batch timeout max_connect_retries parallelism proxy_command do_task run_task run_batch needs exit evaluate_hostname logging include say environment LOCAL path set get before after around before_task_start after_task_finished logformat log_format sayformat say_format connection auth FALSE TRUE set_distributor set_executor_for template_function report make source_global_profile last_command_output case inspect tmp_dir cache ); our $REGISTER_SUB_HASH_PARAMETER = 0; =head2 no_ssh([$task]) Disable ssh for all tasks or a specified task. If you want to disable ssh connection for your complete tasks (for example if you only want to use libVirt) put this in the main section of your Rexfile. no_ssh; If you want to disable ssh connection for a given task, put I in front of the task definition. no_ssh task "mytask", "myserver", sub { say "Do something without a ssh connection"; }; =cut sub no_ssh { if (@_) { $_[0]->( no_ssh => 1 ); } else { $global_no_ssh = 1; } } =head2 task($name [, @servers], $funcref) This function will create a new task. =over 4 =item Create a local task (a server independent task) task "mytask", sub { say "Do something"; }; If you call this task with (R)?ex it will run on your local machine. You can explicit run this task on other machines if you specify the I<-H> command line parameter. =item Create a server bound task. task "mytask", "server1", sub { say "Do something"; }; You can also specify more than one server. task "mytask", "server1", "server2", "server3", sub { say "Do something"; }; Or you can use some expressions to define more than one server. task "mytask", "server[1..3]", sub { say "Do something"; }; If you want, you can overwrite the servers with the I<-H> command line parameter. =item Create a group bound task. You can define server groups with the I function. group "allserver" => "server[1..3]", "workstation[1..10]"; task "mytask", group => "allserver", sub { say "Do something"; }; =back =cut sub task { my ( $class, $file, @tmp ) = caller; my @_ARGS = @_; if ( !@_ ) { if ( my $t = Rex::get_current_connection ) { return $t->{task}; } return; } # for things like # no_ssh task ... if (wantarray) { return sub { my %option = @_; $option{class} = $class; $option{file} = $file; $option{tmp} = \@tmp; task( @_ARGS, \%option ); }; } if ( ref( $_ARGS[-1] ) eq "HASH" ) { if ( $_ARGS[-1]->{class} ) { $class = $_ARGS[-1]->{class}; } if ( $_ARGS[-1]->{file} ) { $file = $_ARGS[-1]->{file}; } if ( $_ARGS[-1]->{tmp} ) { @tmp = @{ $_ARGS[-1]->{tmp} }; } } my $task_name = shift; my $task_name_save = $task_name; if ( $task_name !~ m/^[a-zA-Z_][a-zA-Z0-9_]*$/ && !Rex::Config->get_disable_taskname_warning() ) { Rex::Logger::info( "Please use only the following characters for task names:", "warn" ); Rex::Logger::info( " A-Z, a-z, 0-9 and _", "warn" ); Rex::Logger::info( "Also the task should start with A-Z or a-z", "warn" ); Rex::Logger::info( "You can disable this warning by setting feature flag: disable_taskname_warning", "warn" ); } my $options = {}; if ( ref( $_[-1] ) eq "HASH" ) { $options = pop; } if ($global_no_ssh) { $options->{"no_ssh"} = 1; } if ( $class ne "main" && $class ne "Rex::CLI" ) { $task_name = $class . ":" . $task_name; } $task_name =~ s/^Rex:://; $task_name =~ s/::/:/g; if ($current_desc) { push( @_, $current_desc ); $current_desc = ""; } else { push( @_, "" ); } no strict 'refs'; no warnings; push( @{"${class}::tasks"}, { name => $task_name_save, code => $_[-2] } ); use strict; use warnings; if (!$class->can($task_name_save) && $task_name_save =~ m/^[a-zA-Z_][a-zA-Z0-9_]+$/ ) { no strict 'refs'; Rex::Logger::debug("Registering task: ${class}::$task_name_save"); my $code = $_[-2]; *{"${class}::$task_name_save"} = sub { Rex::Logger::info("Running task $task_name_save on current connection"); Rex::Hook::run_hook( task => "before_execute", $task_name_save, @_ ); if ( Rex::Config->get_task_call_by_method && $_[0] && $_[0] =~ m/^[A-Za-z0-9_:]+$/ && ref $_[1] eq "HASH" ) { shift; } my @ret; if ( ref( $_[0] ) eq "HASH" ) { if (wantarray) { @ret = $code->(@_); } else { my $t = $code->(@_); @ret = ($t); } } else { if ( $REGISTER_SUB_HASH_PARAMETER && scalar @_ % 2 == 0 ) { if (wantarray) { @ret = $code->( {@_} ); } else { my $t = $code->( {@_} ); @ret = ($t); } } else { if (wantarray) { @ret = $code->(@_); } else { my $t = $code->(@_); @ret = ($t); } } } Rex::Hook::run_hook( task => "after_execute", $task_name_save, @_ ); if (wantarray) { return @ret; } else { return $ret[0]; } }; use strict; } elsif ( ( $class ne "main" && $class ne "Rex::CLI" ) && !$class->can($task_name_save) && $task_name_save =~ m/^[a-zA-Z_][a-zA-Z0-9_]+$/ ) { # if not in main namespace, register the task as a sub no strict 'refs'; Rex::Logger::debug( "Registering task (not main namespace): ${class}::$task_name_save"); my $code = $_[-2]; *{"${class}::$task_name_save"} = sub { Rex::Logger::info("Running task $task_name_save on current connection"); Rex::Hook::run_hook( task => "before_execute", $task_name_save, @_ ); my @ret; if ( ref( $_[0] ) eq "HASH" ) { if (wantarray) { @ret = $code->(@_); } else { my $t = $code->(@_); @ret = ($t); } } else { if (wantarray) { @ret = $code->( {@_} ); } else { my $t = $code->( {@_} ); @ret = ($t); } } Rex::Hook::run_hook( task => "after_execute", $task_name_save, @_ ); return @ret; }; use strict; } $options->{'dont_register'} ||= $dont_register_tasks; Rex::TaskList->create()->create_task( $task_name, @_, $options ); } =head2 desc($description) Set the description of a task. desc "This is a task description of the following task"; task "mytask", sub { say "Do something"; } =cut sub desc { $current_desc = shift; } =head2 group($name, @servers) With this function you can group servers, so that you don't need to write too much ;-) group "servergroup", "www1", "www2", "www3", "memcache01", "memcache02", "memcache03"; Or with the expression syntax: group "servergroup", "www[1..3]", "memcache[01..03]"; You can also specify server options after a server name with a hash reference: group "servergroup", "www1" => { user => "other" }, "www2"; These expressions are allowed: =over 4 =item * \d+..\d+ (range) The first number is the start and the second number is the end for numbering the servers. group "name", "www[1..3]"; # www1, www2, www3 =item * \d+..\d+/\d+ (range with step) Just like the range notation, but with an additional "step" defined. If step is omitted, it defaults to 1 (i.e. it behaves like a simple range expression). group "name", "www[1..5/2]"; # www1, www3, www5 group "name", "www[111..133/11]"; # www111, www122, www133 =item * \d+,\d+,\d+ (list) With this variant you can define fixed values. group "name", "www[1,3,7,01]"; # www1, www3, www7, www01 =item * Mixed list, range and range with step You can mix the three variants above www[1..3,5,9..21/3]; # www1, www2, www3, www5, www9, www12, www15, www18, www21 =back =cut sub group { my @params = @_; if ( scalar @params <= 7 && ( defined $params[1] ? ( grep { $params[1] eq $_ } qw/ensure system gid/ ) : 0 ) && ( defined $params[3] ? ( grep { $params[3] eq $_ } qw/ensure system gid/ ) : 1 ) && ( defined $params[5] ? ( grep { $params[5] eq $_ } qw/ensure system gid/ ) : 1 ) ) { # call create_group Rex::Commands::User::group_resource(@params); } else { Rex::Group->create_group(@params); } } # Register set-handler for group Rex::Config->register_set_handler( group => sub { Rex::Commands::group(@_); } ); =head2 batch($name, @tasks) With the batch function you can call tasks in a batch. batch "name", "task1", "task2", "task3"; And call it with the I<-b> console parameter. I =cut sub batch { if ($current_desc) { push( @_, $current_desc ); $current_desc = ""; } else { push( @_, "" ); } Rex::Batch->create_batch(@_); } =head2 user($user) Set the user for the ssh connection. =cut sub user { Rex::Config->set_user(@_); } =head2 password($password) Set the password for the ssh connection (or for the private key file). =cut sub password { Rex::Config->set_password(@_); } =head2 auth(for => $entity, %data) With this function you can modify/set special authentication parameters for tasks and groups. If you want to modify a group's authentication you first have to create it. (Place the auth command after the group.) If you want to set special login information for a group you have to activate that feature first. use Rex -feature => 0.31; # activate setting auth for a group # auth for groups group frontends => "web[01..10]"; group backends => "be[01..05]"; auth for => "frontends" => user => "root", password => "foobar"; auth for => "backends" => user => "admin", private_key => "/path/to/id_rsa", public_key => "/path/to/id_rsa.pub", sudo => TRUE; # auth for tasks task "prepare", group => ["frontends", "backends"], sub { # do something }; auth for => "prepare" => user => "root"; # auth for multiple tasks with regular expression task "step_1", sub { # do something }; task "step_2", sub { # do something }; auth for => qr/step/ => user => $user, password => $password; # fallback auth auth fallback => { user => "fallback_user1", password => "fallback_pw1", public_key => "", private_key => "", }, { user => "fallback_user2", password => "fallback_pw2", public_key => "keys/public.key", private_key => "keys/private.key", sudo => TRUE, }; =cut sub auth { if ( !ref $_[0] && $_[0] eq "fallback" ) { # set fallback authentication shift; Rex::Config->set_fallback_auth(@_); return 1; } my ( $_d, $entity, %data ) = @_; my $group = Rex::Group->get_group_object($entity); if ( !$group ) { Rex::Logger::debug("No group $entity found, looking for a task."); if ( ref($entity) eq "Regexp" ) { my @tasks = Rex::TaskList->create()->get_tasks; my @selected_tasks = grep { m/$entity/ } @tasks; for my $t (@selected_tasks) { auth( $_d, $t, %data ); } return; } else { $group = Rex::TaskList->create()->get_task($entity); } } if ( !$group ) { Rex::Logger::info( "Group or Task $entity not found. Assuming late-binding for task."); $auth_late{$entity} = \%data; return; } if ( ref($group) eq "Rex::Group" ) { Rex::Logger::debug("================================================="); Rex::Logger::debug("You're setting special login credentials for a Group."); Rex::Logger::debug( "Please remember that the default auth information/task auth information has precedence." ); Rex::Logger::debug( "If you want to overwrite this behaviour please use ,,use Rex -feature => 0.31;'' in your Rexfile." ); Rex::Logger::debug("================================================="); } if ( exists $data{pass_auth} ) { $data{auth_type} = "pass"; } if ( exists $data{key_auth} ) { $data{auth_type} = "key"; } if ( exists $data{krb5_auth} ) { $data{auth_type} = "krb5"; } Rex::Logger::debug( "Setting auth info for " . ref($group) . " $entity" ); $group->set_auth(%data); } =head2 port($port) Set the port where the ssh server is listening. =cut sub port { Rex::Config->set_port(@_); } =head2 sudo_password($password) Set the password for the sudo command. =cut sub sudo_password { Rex::Config->set_sudo_password(@_); } =head2 timeout($seconds) Set the timeout for the ssh connection and other network related stuff. =cut sub timeout { Rex::Config->set_timeout(@_); } =head2 max_connect_retries($count) Set the maximum number of connection retries. =cut sub max_connect_retries { Rex::Config->set_max_connect_fails(@_); } =head2 get_random($count, @chars) Returns a random string of $count characters on the basis of @chars. my $rnd = get_random(8, 'a' .. 'z'); =cut sub get_random { return Rex::Helper::Misc::get_random(@_); } =head2 do_task($task) Call $task from another task. It will establish a new connection to the server defined in $task and then execute $task there. task "task1", "server1", sub { say "Running on server1"; do_task "task2"; }; task "task2", "server2", sub { say "Running on server2"; }; You may also use an arrayRef for $task if you want to call multiple tasks. do_task [ qw/task1 task2 task3/ ]; =cut sub do_task { my $task = shift; if ( ref($task) eq "ARRAY" ) { for my $t ( @{$task} ) { Rex::TaskList->run($t); } } else { return Rex::TaskList->run($task); } } =head2 run_task($task_name, %option) Run a task on a given host. my $return = run_task "taskname", on => "192.168.3.56"; Do something on server5 if memory is less than 100 MB free on server3. task "prepare", "server5", sub { my $free_mem = run_task "get_free_mem", on => "server3"; if($free_mem < 100) { say "Less than 100 MB free mem on server3"; # create a new server instance on server5 to unload server3 } }; task "get_free_mem", sub { return memory->{free}; }; If called without a hostname the task is run localy. # this task will run on server5 task "prepare", "server5", sub { # this will call task check_something. but this task will run on localhost. my $check = run_task "check_something"; } task "check_something", "server4", sub { return "foo"; }; If you want to add custom parameters for the task you can do it this way. task "prepare", "server5", sub { run_task "check_something", on => "foo", params => { param1 => "value1", param2 => "value2" }; }; =cut sub run_task { my ( $task_name, %option ) = @_; if ( exists $option{on} ) { my $task = Rex::TaskList->create()->get_task($task_name); if ( exists $option{params} ) { $task->run( $option{on}, params => $option{params} ); } else { $task->run( $option{on} ); } } else { my $task = Rex::TaskList->create()->get_task($task_name); if ( exists $option{params} ) { $task->run( "", params => $option{params} ); } else { $task->run(""); } } } =head2 run_batch($batch_name, %option) Run a batch on a given host. my @return = run_batch "batchname", on => "192.168.3.56"; It calls internally run_task, and passes it any option given. =cut sub run_batch { my ( $batch_name, %option ) = @_; my @tasks = Rex::Batch->get_batch($batch_name); my @results; for my $task (@tasks) { my $return = run_task $task, %option; push @results, $return; } return @results; } =head2 public_key($key) Set the public key. =cut sub public_key { Rex::Config->set_public_key(@_); } =head2 private_key($key) Set the private key. =cut sub private_key { Rex::Config->set_private_key(@_); } =head2 pass_auth If you want to use password authentication, then you need to call I. user "root"; password "root"; pass_auth; =cut sub pass_auth { if (wantarray) { return "pass"; } Rex::Config->set_password_auth(1); } =head2 key_auth If you want to use pubkey authentication, then you need to call I. user "bob"; private_key "/home/bob/.ssh/id_rsa"; # passphrase-less key public_key "/home/bob/.ssh/id_rsa.pub"; key_auth; =cut sub key_auth { if (wantarray) { return "key"; } Rex::Config->set_key_auth(1); } =head2 krb5_auth If you want to use kerberos authentication, then you need to call I. This authentication mechanism is only available if you use Net::OpenSSH. set connection => "OpenSSH"; user "root"; krb5_auth; =cut sub krb5_auth { if (wantarray) { return "krb5"; } Rex::Config->set_krb5_auth(1); } =head2 parallelism($count) Will execute the tasks in parallel on the given servers. $count is the thread count to be used: parallelism '2'; # set parallelism to 2 Alternatively, the following notation can be used to set thread count more dynamically: parallelism 'max'; # set parallelism to the number of servers a task is asked to run on parallelism 'max/3'; # set parallelism to 1/3 of the number of servers parallelism 'max 10%'; # set parallelism to 10% of the number of servers If an unrecognized value is passed, or the calculated thread count would be less than 1, Rex falls back to use a single thread. =cut sub parallelism { Rex::Config->set_parallelism( $_[0] ); } =head2 proxy_command($cmd) Set a proxy command to use for the connection. This is only possible with OpenSSH connection method. set connection => "OpenSSH"; proxy_command "ssh user@jumphost nc %h %p 2>/dev/null"; =cut sub proxy_command { Rex::Config->set_proxy_command( $_[0] ); } =head2 set_distributor($distributor) This sets the task distribution module. Default is "Base". Possible values are: Base, Gearman, Parallel_ForkManager =cut sub set_distributor { Rex::Config->set_distributor( $_[0] ); } =head2 template_function(sub { ... }) This function sets the template processing function. So it is possible to change the template engine. For example to Template::Toolkit. =cut sub template_function { Rex::Config->set_template_function( $_[0] ); } =head2 logging With this function you can define the logging behaviour of (R)?ex. =over 4 =item Logging to a file logging to_file => "rex.log"; =item Logging to syslog logging to_syslog => $facility; =back =cut sub logging { my $args; if ( $_[0] eq "-nolog" || $_[0] eq "nolog" ) { $Rex::Logger::silent = 1 unless $Rex::Logger::debug; return; } else { $args = {@_}; } if ( exists $args->{'to_file'} ) { Rex::Config->set_log_filename( $args->{'to_file'} ); } elsif ( exists $args->{'to_syslog'} ) { Rex::Config->set_log_facility( $args->{'to_syslog'} ); } else { Rex::Config->set_log_filename('rex.log'); } } =head2 needs($package [, @tasks]) With I you can define dependencies between tasks. The "needed" tasks will be called with the same server configuration as the calling task. I will not execute before, around and after hooks. =over 4 =item Depend on all tasks in a given package. Depend on all tasks in the package MyPkg. All tasks will be called with the server I. task "mytask", "server1", sub { needs MyPkg; }; =item Depend on a single task in a given package. Depend on the I task in the package MyPkg. The I task will be called with the server I. task "mytask", "server1", sub { needs MyPkg "uname"; }; =item To call tasks defined in the Rexfile from within a module task "mytask", "server1", sub { needs main "uname"; }; =back =cut sub needs { my ( $self, @args ) = @_; # if no namespace is given, use the current one if ( ref($self) eq "ARRAY" ) { @args = @{$self}; ($self) = caller; } if ( $self eq "main" ) { $self = "Rex::CLI"; } no strict 'refs'; my @maybe_tasks_to_run = @{"${self}::tasks"}; use strict; if ( !@args && !@maybe_tasks_to_run ) { @args = ($self); ($self) = caller; } if ( ref( $args[0] ) eq "ARRAY" ) { @args = @{ $args[0] }; } Rex::Logger::debug("need to call tasks from $self"); no strict 'refs'; my @tasks_to_run = @{"${self}::tasks"}; use strict; my %opts = Rex::Args->get; for my $task (@tasks_to_run) { my $task_name = $task->{"name"}; if ( @args && grep ( /^$task_name$/, @args ) ) { Rex::Logger::debug( "Calling " . $task->{"name"} ); &{ $task->{"code"} }( \%opts ); } elsif ( !@args ) { Rex::Logger::debug( "Calling " . $task->{"name"} ); &{ $task->{"code"} }( \%opts ); } } } # register needs in main namespace { my ($caller_pkg) = caller(1); if ( $caller_pkg eq "Rex::CLI" || $caller_pkg eq "main" ) { no strict 'refs'; *{"main::needs"} = \&needs; use strict; } }; =head2 include Module::Name Include a module without registering its tasks. include qw/ Module::One Module::Two /; =cut sub include { my (@mods) = @_; my $old_val = $dont_register_tasks; $dont_register_tasks = 1; for my $mod (@mods) { eval "require $mod"; if ($@) { die $@; } } $dont_register_tasks = $old_val; } =head2 environment($name => $code) Define an environment. With environments one can use the same task for different hosts. For example if you want to use the same task on your integration-, test- and production servers. # define default user/password user "root"; password "foobar"; pass_auth; # define default frontend group containing only testwww01. group frontend => "testwww01"; # define live environment, with different user/password # and a frontend server group containing www01, www02 and www03. environment live => sub { user "root"; password "livefoo"; pass_auth; group frontend => "www01", "www02", "www03"; }; # define stage environment with default user and password. but with # a own frontend group containing only stagewww01. environment stage => sub { group frontend => "stagewww01"; }; task "prepare", group => "frontend", sub { say run "hostname"; }; Calling this task I will execute on testwww01. Calling this task with I will execute on www01, www02, www03. Calling this task I will execute on stagewww01. You can call the function within a task to get the current environment. task "prepare", group => "frontend", sub { if(environment() eq "dev") { say "i'm in the dev environment"; } }; If no I<-E> option is passed on the command line, the default environment (named 'default') will be used. =cut sub environment { if (@_) { my ( $name, $code ) = @_; $environments->{$name} = { code => $code, description => $current_desc || '', name => $name, }; $current_desc = ""; if ( Rex::Config->get_environment eq $name ) { &$code(); } return 1; } else { return Rex::Config->get_environment || "default"; } } =head2 LOCAL(&) With the LOCAL function you can do local commands within a task that is defined to work on remote servers. task "mytask", "server1", "server2", sub { # this will call 'uptime' on the servers 'server1' and 'server2' say run "uptime"; # this will call 'uptime' on the local machine. LOCAL { say run "uptime"; }; }; =cut sub LOCAL (&) { my $cur_conn = Rex::get_current_connection(); my $local_connect = Rex::Interface::Connection->create("Local"); Rex::push_connection( { conn => $local_connect, ssh => 0, server => $cur_conn->{server}, cache => Rex::Interface::Cache->create(), task => task(), reporter => Rex::Report->create( Rex::Config->get_report_type ), notify => Rex::Notify->new(), } ); my $ret = $_[0]->(); Rex::pop_connection(); return $ret; } =head2 path(@path) Set the execution path for all commands. path "/bin", "/sbin", "/usr/bin", "/usr/sbin", "/usr/pkg/bin", "/usr/pkg/sbin"; =cut sub path { Rex::Config->set_path( [@_] ); } =head2 set($key, $value) Set a configuration parameter. These variables can be used in templates as well. set database => "db01"; task "prepare", sub { my $db = get "database"; }; Or in a template DB: <%= $::database %> The following list of configuration parameters are Rex specific: =over =back =cut sub set { my ( $key, @value ) = @_; Rex::Config->set( $key, @value ); } =head2 get($key, $value) Get a configuration parameter. set database => "db01"; task "prepare", sub { my $db = get "database"; }; Or in a template DB: <%= $::database %> =cut sub get { my ($key) = @_; if ( ref($key) eq "Rex::Value" ) { return $key->value; } return Rex::Config->get($key); } =head2 before($task => sub {}) Run code before executing the specified task. The special taskname 'ALL' can be used to run code before all tasks. If called repeatedly, each sub will be appended to a list of 'before' functions. In this hook you can overwrite the server to which the task will connect to. The second argument is a reference to the server object that will be used for the connection. Note: must come after the definition of the specified task before mytask => sub { my ($server, $server_ref, $cli_args) = @_; run "vzctl start vm$server"; }; =cut sub before { my ( $task, $code ) = @_; if ( $task eq "ALL" ) { $task = qr{.*}; } my ( $package, $file, $line ) = caller; Rex::TaskList->create() ->modify( 'before', $task, $code, $package, $file, $line ); } =head2 after($task => sub {}) Run code after the task is finished. The special taskname 'ALL' can be used to run code after all tasks. If called repeatedly, each sub will be appended to a list of 'after' functions. Note: must come after the definition of the specified task after mytask => sub { my ($server, $failed, $cli_args) = @_; if($failed) { say "Connection to $server failed."; } run "vzctl stop vm$server"; }; =cut sub after { my ( $task, $code ) = @_; if ( $task eq "ALL" ) { $task = qr{.*}; } my ( $package, $file, $line ) = caller; Rex::TaskList->create() ->modify( 'after', $task, $code, $package, $file, $line ); } =head2 around($task => sub {}) Run code before and after the task is finished. The special taskname 'ALL' can be used to run code around all tasks. If called repeatedly, each sub will be appended to a list of 'around' functions. In this hook you can overwrite the server to which the task will connect to. The second argument is a reference to the server object that will be used for the connection. Note: must come after the definition of the specified task around mytask => sub { my ($server, $server_ref, $cli_args, $position) = @_; unless($position) { say "Before Task\n"; } else { say "After Task\n"; } }; =cut sub around { my ( $task, $code ) = @_; if ( $task eq "ALL" ) { $task = qr{.*}; } my ( $package, $file, $line ) = caller; Rex::TaskList->create() ->modify( 'around', $task, $code, $package, $file, $line ); } =head2 before_task_start($task => sub {}) Run code before executing the specified task. This gets executed only once for a task. The special taskname 'ALL' can be used to run code before all tasks. If called repeatedly, each sub will be appended to a list of 'before' functions. Note: must come after the definition of the specified task before_task_start mytask => sub { # do some things }; =cut sub before_task_start { my ( $task, $code ) = @_; if ( $task eq "ALL" ) { $task = qr{.*}; } my ( $package, $file, $line ) = caller; Rex::TaskList->create() ->modify( 'before_task_start', $task, $code, $package, $file, $line ); } =head2 after_task_finished($task => sub {}) Run code after the task is finished (and after the ssh connection is terminated). This gets executed only once for a task. The special taskname 'ALL' can be used to run code before all tasks. If called repeatedly, each sub will be appended to a list of 'before' functions. Note: must come after the definition of the specified task after_task_finished mytask => sub { # do some things }; =cut sub after_task_finished { my ( $task, $code ) = @_; if ( $task eq "ALL" ) { $task = qr{.*}; } my ( $package, $file, $line ) = caller; Rex::TaskList->create() ->modify( 'after_task_finished', $task, $code, $package, $file, $line ); } =head2 logformat($format) You can define the logging format with the following parameters. %D - Appends the current date yyyy-mm-dd HH:mm:ss %h - The target host %p - The pid of the running process %l - Loglevel (INFO or DEBUG) %s - The Logstring Default is: [%D] %l - %s =cut sub logformat { my ($format) = @_; $Rex::Logger::format = $format; } sub log_format { logformat(@_); } =head2 connection This function returns the current connection object. task "foo", group => "baz", sub { say "Current Server: " . connection->server; }; =cut sub connection { return Rex::get_current_connection()->{conn}; } =head2 cache This function returns the current cache object. =cut sub cache { my ($type) = @_; if ( !$type ) { return Rex::get_cache(); } Rex::Config->set_cache_type($type); } =head2 profiler Returns the profiler object for the current connection. =cut sub profiler { my $c_profiler = Rex::get_current_connection()->{"profiler"}; unless ($c_profiler) { $c_profiler = $profiler || Rex::Profiler->new; $profiler = $c_profiler; } return $c_profiler; } =head2 report($switch, $type) This function will initialize the reporting. report -on => "YAML"; =cut sub report { my ( $str, $type ) = @_; $type ||= "Base"; Rex::Config->set_report_type($type); if ( $str && ( $str eq "-on" || $str eq "on" ) ) { Rex::Config->set_do_reporting(1); return; } elsif ( $str && ( $str eq "-off" || $str eq "off" ) ) { Rex::Config->set_do_reporting(0); return; } return Rex::get_current_connection()->{reporter}; } =head2 source_global_profile(0|1) If this option is set, every run() command will first source /etc/profile before getting executed. =cut sub source_global_profile { my ($source) = @_; Rex::Config->set_source_global_profile($source); } =head2 last_command_output This function returns the output of the last "run" command. On a debian system this example will return the output of I. task "mytask", "myserver", sub { install "foobar"; say last_command_output(); }; =cut sub last_command_output { return $Rex::Commands::Run::LAST_OUTPUT->[0]; } =head2 case($compare, $option) This is a function to compare a string with some given options. task "mytask", "myserver", sub { my $ntp_service = case operating_sytem, { Debian => "ntp", default => "ntpd", }; my $ntp_service = case operating_sytem, { qr{debian}i => "ntp", default => "ntpd", }; my $ntp_service = case operating_sytem, { qr{debian}i => "ntp", default => sub { return "foo"; }, }; }; =cut sub case { my ( $compare, $option ) = @_; my $to_return = undef; if ( exists $option->{$compare} ) { $to_return = $option->{$compare}; } else { for my $key ( keys %{$option} ) { if ( $compare =~ $key ) { $to_return = $option->{$key}; last; } } } if ( exists $option->{default} && !$to_return ) { $to_return = $option->{default}; } if ( ref $to_return eq "CODE" ) { $to_return = &$to_return(); } return $to_return; } =head2 set_executor_for($type, $executor) Set the executor for a special type. This is primary used for the upload_and_run helper function. set_executor_for perl => "/opt/local/bin/perl"; =cut sub set_executor_for { Rex::Config->set_executor_for(@_); } =head2 tmp_dir($tmp_dir) Set the tmp directory on the remote host to store temporary files. =cut sub tmp_dir { Rex::Config->set_tmp_dir(@_); } =head2 inspect($varRef) This function dumps the contents of a variable to STDOUT. task "mytask", "myserver", sub { my $myvar = { name => "foo", sys => "bar", }; inspect $myvar; }; =cut my $depth = 0; sub _dump_hash { my ( $hash, $option ) = @_; unless ( $depth == 0 && exists $option->{no_root} && $option->{no_root} ) { print "{\n"; } $depth++; for my $key ( keys %{$hash} ) { _print_indent($option); if ( exists $option->{prepend_key} ) { print $option->{prepend_key}; } print "$key" . ( exists $option->{key_value_sep} ? $option->{key_value_sep} : " => " ); _dump_var( $hash->{$key} ); } $depth--; _print_indent($option); unless ( $depth == 0 && exists $option->{no_root} && $option->{no_root} ) { print "}\n"; } } sub _dump_array { my ( $array, $option ) = @_; unless ( $depth == 0 && exists $option->{no_root} && $option->{no_root} ) { print "[\n"; } $depth++; for my $itm ( @{$array} ) { _print_indent($option); _dump_var($itm); } $depth--; _print_indent($option); unless ( $depth == 0 && exists $option->{no_root} && $option->{no_root} ) { print "]\n"; } } sub _print_indent { my ($option) = @_; unless ( $depth == 1 && exists $option->{no_root} && $option->{no_root} ) { print " " x $depth; } } sub _dump_var { my ( $var, $option ) = @_; if ( ref $var eq "HASH" ) { _dump_hash( $var, $option ); } elsif ( ref $var eq "ARRAY" ) { _dump_array( $var, $option ); } else { if ( defined $var ) { $var =~ s/\n/\\n/gms; $var =~ s/\r/\\r/gms; $var =~ s/'/\\'/gms; print "'$var'\n"; } else { print "no value\n"; } } } sub inspect { _dump_var(@_); } ######### private functions sub evaluate_hostname { my $str = shift; return unless $str; # e.g. server[0..4/2].domain.com my ( $start, $rule, $end ) = $str =~ m{ ^ ([0-9\.\w\-:]*) # prefix (e.g. server) \[ # rule -> 0..4 | 0..4/2 | 0,2,4 ( (?: \d+ \.\. \d+ # range-rule e.g. 0..4 (?:\/ \d+ )? # step for range-rule ) | (?: (?: \d+ (?:,\s*)? ) | (?: \d+ \.\. \d+ (?: \/ \d+ )? (?:,\s*)? ) )+ # list ) \] # end of rule ([0-9\w\.\-:]+)? # suffix (e.g. .domain.com) $ }xms; if ( !defined $rule ) { return $str; } my @ret; if ( $rule =~ m/,/ ) { @ret = _evaluate_hostname_list( $start, $rule, $end ); } else { @ret = _evaluate_hostname_range( $start, $rule, $end ); } return @ret; } sub _evaluate_hostname_range { my ( $start, $rule, $end ) = @_; my ( $from, $to, $step ) = $rule =~ m{(\d+) \.\. (\d+) (?:/(\d+))?}xms; $end ||= ''; $step ||= 1; my $strict_length = 0; if ( length $from == length $to ) { $strict_length = length $to; } my @ret = (); for ( ; $from <= $to ; $from += $step ) { my $format = "%0" . $strict_length . "i"; push @ret, $start . sprintf( $format, $from ) . $end; } return @ret; } sub _evaluate_hostname_list { my ( $start, $rule, $end ) = @_; my @values = split /,\s*/, $rule; $end ||= ''; my @ret; for my $value (@values) { if ( $value =~ m{\d+\.\.\d+(?:/\d+)?} ) { push @ret, _evaluate_hostname_range( $start, $value, $end ); } else { push @ret, "$start$value$end"; } } return @ret; } sub exit { Rex::Logger::info("Exiting Rex..."); Rex::Logger::info("Cleaning up..."); Rex::global_sudo(0); unlink("$::rexfile.lock") if ($::rexfile); CORE::exit( $_[0] || 0 ); } sub get_environment { my ( $class, $env ) = @_; if ( exists $environments->{$env} ) { return $environments->{$env}; } } sub get_environments { my $class = shift; my @ret = sort { $a cmp $b } keys %{$environments}; return @ret; } =head2 sayformat($format) You can define the format of the say() function. %D - The current date yyyy-mm-dd HH:mm:ss %h - The target host %p - The pid of the running process %s - The Logstring You can also define the following values: default - the default behaviour. asis - will print every single parameter in its own line. This is useful if you want to print the output of a command. =cut sub sayformat { my ($format) = @_; Rex::Config->set_say_format($format); } sub say_format { sayformat(@_); } sub say { my (@data) = @_; return unless defined $_[0]; my $format = Rex::Config->get_say_format; if ( !defined $format || $format eq "default" ) { print @_, "\n"; return; } if ( $format eq "asis" ) { print join( "\n", @_ ); return; } for my $line (@data) { print _format_string( $format, $line ) . "\n"; } } # %D - Date # %h - Host # %s - Logstring sub _format_string { my ( $format, $line ) = @_; my $date = _get_timestamp(); my $host = Rex::get_current_connection() ? Rex::get_current_connection()->{conn}->server : ""; my $pid = $$; $format =~ s/\%D/$date/gms; $format =~ s/\%h/$host/gms; $format =~ s/\%s/$line/gms; $format =~ s/\%p/$pid/gms; return $format; } sub _get_timestamp { my ( $sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst ) = localtime(time); $mon++; $year += 1900; return "$year-" . sprintf( "%02i", $mon ) . "-" . sprintf( "%02i", $mday ) . " " . sprintf( "%02i", $hour ) . ":" . sprintf( "%02i", $min ) . ":" . sprintf( "%02i", $sec ); } sub TRUE { return 1; } sub FALSE { return 0; } sub make(&) { return $_[0]; } 1; Rex-1.3.3/lib/Rex/Output.pm0000644000175000017500000000224512572251052015306 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Output; use strict; use warnings; my $handle; use vars qw($output_object); BEGIN { IPC::Shareable->use; } END { IPC::Shareable->clean_up_all; } use base 'Rex::Output::Base'; our $VERSION = '1.3.3'; # VERSION sub get { my ( $class, $output_module ) = @_; return $output_object if ($output_object); return unless ($output_module); $handle = tie $output_object, 'IPC::Shareable', undef, { destroy => 1 } unless $handle; eval "use Rex::Output::$output_module;"; if ($@) { die("Output Module ,,$output_module'' not found."); } my $output_class = "Rex::Output::$output_module"; $output_object = $output_class->new; return $class; } sub _action { my ( $class, $action, @args ) = @_; return unless ( defined $output_object ); $handle->shlock(); $output_object->$action(@args); $handle->shunlock(); } sub add { my $class = shift; return $class->_action( 'add', @_ ); } sub error { my $class = shift; return $class->_action( 'error', @_ ); } sub write { my $class = shift; return $class->_action( 'write', @_ ); } 1; Rex-1.3.3/lib/Rex/Args.pm0000644000175000017500000000643512572251052014707 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Args; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use vars qw(%task_opts %rex_opts); use Rex::Logger; use Data::Dumper; our $KEY_VAL = 1; our $REMOVE_TASK_OPTIONS = 0; our $CLEANUP = 1; sub import { my ( $class, %args ) = @_; #### clean up @ARGV my $runner = 0; for (@ARGV) { if ( /^\-[A-Za-z]+/ && length($_) > 2 && $CLEANUP ) { my @args = map { "-$_" } split( //, substr( $_, 1 ) ); splice( @ARGV, $runner, 1, @args ); } $runner++; } #### parse rex options my @params = @ARGV; for my $p (@params) { # shift off @ARGV my $shift = shift @ARGV; if ( length($p) >= 2 && substr( $p, 0, 1 ) eq "-" ) { my $name_param = substr( $p, 1, 2 ); # found a parameter if ( exists $args{$name_param} ) { Rex::Logger::debug("Option found: $name_param ($p)"); my $type = "Single"; if ( exists $args{$name_param}->{type} ) { $type = $args{$name_param}->{type}; Rex::Logger::debug(" is a $type"); shift @params; # remove the next parameter, because it must be an option if ( !exists $ARGV[0] || ( length( $ARGV[0] ) == 2 && exists $args{ substr( $ARGV[0], 1, 2 ) } && substr( $ARGV[0], 0, 1 ) eq "-" ) ) { # this is a typed parameter without an option! Rex::Logger::debug(" but there is no parameter"); Rex::Logger::debug( Dumper( \@params ) ); print("No parameter for $name_param\n"); CORE::exit 1; } } elsif ( exists $args{$name_param}->{func} ) { Rex::Logger::debug(" is a function - executing now"); $args{$name_param}->{func}->(); } my $c = "Rex::Args::\u$type"; eval "use $c"; if ($@) { die("No Argumentclass $type found!"); } if ( exists $rex_opts{$name_param} && $type eq "Single" ) { $rex_opts{$name_param}++; } else { # multiple params defined, create an array if ( exists $rex_opts{$name_param} ) { if ( !ref $rex_opts{$name_param} ) { $rex_opts{$name_param} = [ $rex_opts{$name_param} ]; } push @{ $rex_opts{$name_param} }, $c->get; } else { $rex_opts{$name_param} = $c->get; } } } else { Rex::Logger::debug("Option not known: $name_param ($p)"); next; } } else { # unshift the last parameter unshift @ARGV, $shift; last; } } #### parse task options @params = @ARGV[ 1 .. $#ARGV ]; my $counter = 1; for my $p (@params) { my ( $key, $val ) = split( /=/, $p, 2 ); if ( defined $val ) { if ($REMOVE_TASK_OPTIONS) { splice( @ARGV, $counter, 1 ); } } $key =~ s/^--//; if ( defined $val ) { $task_opts{$key} = $val; next; } $task_opts{$key} = $KEY_VAL; $counter++; } } sub getopts { return %rex_opts; } sub is_opt { my ( $class, $opt ) = @_; if ( exists $rex_opts{$opt} ) { return $rex_opts{$opt}; } } sub get { return %task_opts; } 1; Rex-1.3.3/lib/Rex/Virtualization.pm0000644000175000017500000000263212572251052017032 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Config; my %VM_PROVIDER; Rex::Config->register_config_handler( virtualization => sub { my ($param) = @_; if ( ref($param) eq '' ) { #support 'set virtualization => 'LibVirt', but leave the way open for using a hash in future #other virtualisation drivers may need more settings... $param = { type => $param }; } if ( exists $param->{type} ) { Rex::Config->set( virtualization => $param->{type} ); } } ); sub register_vm_provider { my ( $class, $service_name, $service_class ) = @_; $VM_PROVIDER{"\L$service_name"} = $service_class; return 1; } sub create { my ( $class, $wanted_provider ) = @_; $wanted_provider ||= Rex::Config->get("virtualization"); if ( ref($wanted_provider) ) { $wanted_provider = $wanted_provider->{type} || "LibVirt"; } my $klass = "Rex::Virtualization::$wanted_provider"; if ( exists $VM_PROVIDER{$wanted_provider} ) { $klass = $VM_PROVIDER{$wanted_provider}; } eval "use $klass"; if ($@) { Rex::Logger::info("Virtualization Class $klass not found."); die("Virtualization Class $klass not found."); } Rex::Logger::debug("Using $klass for virtualization"); my $mod = $klass->new; return $mod; } 1; Rex-1.3.3/lib/Rex/Config.pm0000644000175000017500000004725012572251052015220 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Config - Handles the configuration. =head1 DESCRIPTION This module holds all configuration parameters for Rex. With this module you can specify own configuration parameters for your modules. =head1 EXPORTED METHODS =cut package Rex::Config; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Helper::File::Spec; use Rex::Logger; use YAML; use Data::Dumper; use Rex::Require; our ( $user, $password, $port, $timeout, $max_connect_fails, $password_auth, $key_auth, $krb5_auth, $public_key, $private_key, $parallelism, $log_filename, $log_facility, $sudo_password, $ca_file, $ca_cert, $ca_key, $path, $no_path_cleanup, $set_param, $environment, $connection_type, $distributor, $template_function, $SET_HANDLER, $HOME_CONFIG, $HOME_CONFIG_YAML, %SSH_CONFIG_FOR, $sudo_without_locales, $sudo_without_sh, $no_tty, $source_global_profile, $source_profile, %executor_for, $allow_empty_groups, $use_server_auth, $tmp_dir, %openssh_opt, $use_cache, $cache_type, $use_sleep_hack, $report_type, $do_reporting, $say_format, $exec_autodie, $verbose_run, $disable_taskname_warning, $proxy_command, $task_call_by_method, $fallback_auth, $register_cmdb_template, $check_service_exists, $set_no_append, $use_net_openssh_if_present, $use_template_ng, $use_rex_kvm_agent, $autodie, ); # some defaults %executor_for = ( perl => "perl", python => "python", ruby => "ruby", bash => "bash", ); sub set_autodie { my $class = shift; $autodie = shift; } sub get_autodie { return $autodie; } sub set_use_net_openssh_if_present { my $class = shift; $use_net_openssh_if_present = shift; } sub get_use_net_openssh_if_present { return $use_net_openssh_if_present; } sub set_use_rex_kvm_agent { my $class = shift; $use_rex_kvm_agent = shift; } sub get_use_rex_kvm_agent { return $use_rex_kvm_agent; } sub set_use_template_ng { my $class = shift; $use_template_ng = shift; } sub get_use_template_ng { return $use_template_ng; } sub set_set_no_append { my $class = shift; $set_no_append = shift; } sub get_set_no_append { return $set_no_append; } sub set_check_service_exists { my $class = shift; $check_service_exists = shift; } sub get_check_service_exists { return $check_service_exists; } sub set_register_cmdb_template { my $class = shift; $register_cmdb_template = shift; } sub get_register_cmdb_template { return $register_cmdb_template; } sub set_fallback_auth { my $class = shift; $fallback_auth = [@_]; } sub get_fallback_auth { return $fallback_auth; } sub set_task_call_by_method { my $class = shift; $task_call_by_method = shift; } sub get_task_call_by_method { return $task_call_by_method; } sub set_disable_taskname_warning { my $class = shift; $disable_taskname_warning = shift; } sub get_disable_taskname_warning { return $disable_taskname_warning; } sub set_verbose_run { my $class = shift; $verbose_run = shift; } sub get_verbose_run { return $verbose_run; } sub set_exec_autodie { my $class = shift; $exec_autodie = shift; } sub get_exec_autodie { return $exec_autodie; } sub set_no_path_cleanup { my $class = shift; $no_path_cleanup = shift; } sub get_no_path_cleanup { return $no_path_cleanup; } sub set_source_profile { my $class = shift; $source_profile = shift; } sub get_source_profile { return $source_profile; } sub set_say_format { my $class = shift; $say_format = shift; } sub get_say_format { return $say_format; } sub set_do_reporting { my $class = shift; $do_reporting = shift; } sub get_do_reporting { return $do_reporting; } sub set_report_type { my $class = shift; $report_type = shift; } sub get_report_type { if ( exists $ENV{REX_REPORT_TYPE} ) { return $ENV{REX_REPORT_TYPE}; } return $report_type; } sub set_sleep_hack { my $class = shift; $use_sleep_hack = shift; } sub get_sleep_hack { return $use_sleep_hack; } sub set_cache_type { my $class = shift; $cache_type = shift; } sub get_cache_type { if ( exists $ENV{REX_CACHE_TYPE} ) { return $ENV{REX_CACHE_TYPE}; } return $cache_type || "Base"; } sub set_use_cache { my $class = shift; $use_cache = shift; } sub get_use_cache { return $use_cache; } sub get_sudo_without_locales { return $sudo_without_locales; } sub get_sudo_without_sh { return $sudo_without_sh; } sub set_openssh_opt { my ( $class, %opt ) = @_; for my $key ( keys %opt ) { if ( !defined $opt{$key} ) { $openssh_opt{$key} = undef; delete $openssh_opt{$key}; next; } $openssh_opt{$key} = $opt{$key}; } } sub get_openssh_opt { return %openssh_opt; } sub set_sudo_without_locales { my $class = shift; $sudo_without_locales = shift; } sub set_sudo_without_sh { my $class = shift; $sudo_without_sh = shift; } sub set_executor_for { my $class = shift; my $for = shift; my $e = shift; $executor_for{$for} = $e; } sub get_executor_for { my $class = shift; my $e = shift; return $executor_for{$e}; } sub set_tmp_dir { my ( $class, $dir ) = @_; if ( $class eq "Rex::Config" ) { $tmp_dir = $dir; } else { $tmp_dir = $class; } } sub get_tmp_dir { my $cache = Rex::get_cache(); if ( my $cached_tmp = $cache->get("tmpdir") ) { return $cached_tmp; } if ( !$tmp_dir ) { if ( my $ssh = Rex::is_ssh() ) { my $exec; if ( Rex::is_sudo() ) { if ( ref $ssh eq "Net::OpenSSH" ) { $exec = Rex::Interface::Exec->create("OpenSSH"); } else { $exec = Rex::Interface::Exec->create("SSH"); } } else { $exec = Rex::Interface::Exec->create; } my ($out) = $exec->exec("perl -MFile::Spec -le 'print File::Spec->tmpdir'"); if ( $? == 0 && $out ) { $out =~ s/[\r\n]//gms; $cache->set( "tmpdir", $out ); return $out; } $cache->set( "tmpdir", "/tmp" ); return "/tmp"; } else { $cache->set( "tmpdir", Rex::Helper::File::Spec->tmpdir ); return Rex::Helper::File::Spec->tmpdir; } } return $tmp_dir; } sub set_path { my $class = shift; $path = shift; } sub get_path { if ( !$path ) { return ( "/bin", "/sbin", "/usr/bin", "/usr/sbin", "/usr/local/bin", "/usr/local/sbin", "/usr/pkg/bin", "/usr/pkg/sbin" ); } return @{$path}; } sub set_user { my $class = shift; $user = shift; } sub set_password { my $class = shift; $password = shift; } sub set_port { my $class = shift; $port = shift; } sub set_sudo_password { my $class = shift; $sudo_password = shift; } sub set_source_global_profile { my $class = shift; $source_global_profile = shift; } sub get_source_global_profile { return $source_global_profile; } sub set_max_connect_fails { my $class = shift; $max_connect_fails = shift; } sub get_max_connect_fails { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{connectionattempts} ) { return $SSH_CONFIG_FOR{ $param->{server} }->{connectionattempts}; } return $max_connect_fails || 3; } sub has_user { my $class = shift; return $user; } sub get_user { my $class = shift; if ( exists $ENV{REX_USER} ) { return $ENV{REX_USER}; } if ($user) { return $user; } return getlogin || getpwuid($<) || "Kilroy"; } sub get_password { my $class = shift; if ( exists $ENV{REX_PASSWORD} ) { return $ENV{REX_PASSWORD}; } return $password; } sub get_port { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{port} ) { return $SSH_CONFIG_FOR{ $param->{server} }->{port}; } return $port; } sub set_proxy_command { my $class = shift; $proxy_command = shift; } sub get_proxy_command { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{proxycommand} ) { return $SSH_CONFIG_FOR{ $param->{server} }->{proxycommand}; } return $proxy_command; } sub get_sudo_password { my $class = shift; if ( exists $ENV{REX_SUDO_PASSWORD} ) { return $ENV{REX_SUDO_PASSWORD}; } if ($sudo_password) { return $sudo_password; } elsif ( !defined $sudo_password ) { return ""; } else { return $password; } return ""; } sub set_timeout { my $class = shift; $timeout = shift; } sub get_timeout { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{connecttimeout} ) { return $SSH_CONFIG_FOR{ $param->{server} }->{connecttimeout}; } return $timeout || 2; } sub set_password_auth { my $class = shift; $key_auth = 0; $krb5_auth = 0; $password_auth = shift || 1; } sub set_key_auth { my $class = shift; $password_auth = 0; $krb5_auth = 0; $key_auth = shift || 1; } sub set_krb5_auth { my $class = shift; $password_auth = 0; $key_auth = 0; $krb5_auth = shift || 1; } sub get_password_auth { if ( exists $ENV{REX_AUTH_TYPE} && $ENV{REX_AUTH_TYPE} eq "pass" ) { return 1; } return $password_auth; } sub get_key_auth { if ( exists $ENV{REX_AUTH_TYPE} && $ENV{REX_AUTH_TYPE} eq "key" ) { return 1; } return $key_auth; } sub get_krb5_auth { if ( exists $ENV{REX_AUTH_TYPE} && $ENV{REX_AUTH_TYPE} eq "krb5" ) { return 1; } return $krb5_auth; } sub set_public_key { my $class = shift; $public_key = shift; } sub has_public_key { return get_public_key(); } sub get_public_key { if ( exists $ENV{REX_PUBLIC_KEY} ) { return $ENV{REX_PUBLIC_KEY}; } if ($public_key) { return $public_key; } return; } sub set_private_key { my $class = shift; $private_key = shift; } sub has_private_key { return get_private_key(); } sub get_private_key { if ( exists $ENV{REX_PRIVATE_KEY} ) { return $ENV{REX_PRIVATE_KEY}; } if ($private_key) { return $private_key; } return; } sub set_parallelism { my $class = shift; $parallelism = $_[0]; } sub get_parallelism { my $class = shift; return $parallelism || 1; } sub set_log_filename { my $class = shift; $log_filename = shift; } sub get_log_filename { my $class = shift; return $log_filename; } sub set_log_facility { my $class = shift; $log_facility = shift; } sub get_log_facility { my $class = shift; return $log_facility || "local0"; } sub set_environment { my ( $class, $env ) = @_; $environment = $env; } sub get_environment { return $environment || ""; } sub get_ssh_config_username { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{user} ) { return $SSH_CONFIG_FOR{ $param->{server} }->{user}; } return 0; } sub get_ssh_config_hostname { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{hostname} ) { return $SSH_CONFIG_FOR{ $param->{server} }->{hostname}; } return 0; } sub get_ssh_config_private_key { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{identityfile} ) { my $file = $SSH_CONFIG_FOR{ $param->{server} }->{identityfile}; my $home_dir = _home_dir(); $file =~ s/^~/$home_dir/; return $file; } return 0; } sub get_ssh_config_public_key { my $class = shift; my $param = {@_}; if ( exists $param->{server} && exists $SSH_CONFIG_FOR{ $param->{server} } && exists $SSH_CONFIG_FOR{ $param->{server} }->{identityfile} ) { my $file = $SSH_CONFIG_FOR{ $param->{server} }->{identityfile} . ".pub"; my $home_dir = _home_dir(); $file =~ s/^~/$home_dir/; return $file; } return 0; } sub get_connection_type { my $class = shift; if ( $^O !~ m/^MSWin/ && !$connection_type && $use_net_openssh_if_present ) { my $has_net_openssh = 0; eval { Net::OpenSSH->require; Net::SFTP::Foreign->require; $has_net_openssh = 1; 1; }; if ($has_net_openssh) { Rex::Logger::debug( "Found Net::OpenSSH and Net::SFTP::Foreign - using it as default"); $connection_type = "OpenSSH"; return "OpenSSH"; } } if ( !$connection_type ) { my $has_net_ssh2 = 0; eval { Net::SSH2->require; $has_net_ssh2 = 1; 1; }; if ($has_net_ssh2) { $connection_type = "SSH"; return "SSH"; } } return $connection_type || "SSH"; } sub get_ca { my $class = shift; return $ca_file || ""; } sub get_ca_cert { my $class = shift; return $ca_cert || ""; } sub get_ca_key { my $class = shift; return $ca_key || ""; } sub set_distributor { my $class = shift; $distributor = shift; } sub get_distributor { my $class = shift; return $distributor || "Base"; } sub set_template_function { my $class = shift; ($template_function) = @_; } sub get_template_function { if ( ref($template_function) eq "CODE" ) { return $template_function; } if ( Rex::Template::NG->is_loadable && get_use_template_ng() ) { # new template engine return sub { my ( $content, $template_vars ) = @_; Rex::Template::NG->require; my $t = Rex::Template::NG->new; return $t->parse( $content, %{$template_vars} ); }; } return sub { my ( $content, $template_vars ) = @_; use Rex::Template; my $template = Rex::Template->new; return $template->parse( $content, $template_vars ); }; } sub set_no_tty { shift; $no_tty = shift; } sub get_no_tty { return $no_tty; } =head2 register_set_handler($handler_name, $code) Register a handler that gets called by I. Rex::Config->register_set_handler("foo", sub { my ($value) = @_; print "The user set foo -> $value\n"; }); And now you can use this handler in your I like this: set foo => "bar"; =cut sub register_set_handler { my ( $class, $handler_name, $code ) = @_; $SET_HANDLER->{$handler_name} = $code; } sub set { my ( $class, $var, $data ) = @_; if ( exists( $SET_HANDLER->{$var} ) ) { shift; shift; return &{ $SET_HANDLER->{$var} }(@_); } if ($set_no_append) { $set_param->{$var} = $data; } else { if ( ref($data) eq "HASH" ) { if ( !ref( $set_param->{$var} ) ) { $set_param->{$var} = {}; } for my $key ( keys %{$data} ) { $set_param->{$var}->{$key} = $data->{$key}; } } elsif ( ref($data) eq "ARRAY" ) { push( @{ $set_param->{$var} }, @{$data} ); } else { $set_param->{$var} = $data; } } } sub unset { my ( $class, $var ) = @_; $set_param->{$var} = undef; delete $set_param->{$var}; } sub get { my ( $class, $var ) = @_; if ( exists $set_param->{$var} ) { return $set_param->{$var}; } } sub get_all { my ($class) = @_; return $set_param; } =head2 register_config_handler($topic, $code) With this function it is possible to register own sections in the users config file ($HOME/.rex/config.yml). Example: Rex::Config->register_config_handler("foo", sub { my ($param) = @_; print "bar is: " . $param->{bar} . "\n"; }); And now the user can set this in his configuration file: base: user: theuser password: thepassw0rd foo: bar: baz =cut sub register_config_handler { my ( $class, $topic, $code ) = @_; if ( !ref($HOME_CONFIG) ) { $HOME_CONFIG = {}; } $HOME_CONFIG->{$topic} = $code; if ( ref($HOME_CONFIG_YAML) && exists $HOME_CONFIG_YAML->{$topic} ) { &$code( $HOME_CONFIG_YAML->{$topic} ); } } sub read_config_file { my ($config_file) = @_; $config_file ||= _home_dir() . "/.rex/config.yml"; if ( -f $config_file ) { my $yaml = eval { local ( @ARGV, $/ ) = ($config_file); <>; }; eval { $HOME_CONFIG_YAML = Load($yaml); }; if ($@) { print STDERR "Error loading $config_file\n"; print STDERR "$@\n"; exit 2; } for my $key ( keys %{$HOME_CONFIG} ) { if ( exists $HOME_CONFIG_YAML->{$key} ) { my $code = $HOME_CONFIG->{$key}; &$code( $HOME_CONFIG_YAML->{$key} ); } } } } sub read_ssh_config_file { my ($config_file) = @_; $config_file ||= _home_dir() . '/.ssh/config'; if ( -f $config_file ) { my @lines = eval { local (@ARGV) = ($config_file); <>; }; %SSH_CONFIG_FOR = _parse_ssh_config(@lines); } } sub _parse_ssh_config { my (@lines) = @_; my %ret = (); my ( @host, $in_host ); for my $line (@lines) { chomp $line; next if ( $line =~ m/^\s*#/ ); next if ( $line =~ m/^\s*$/ ); if ( $line =~ m/^Host(?:\s*=\s*|\s+)(.*)$/i ) { my $host_tmp = $1; @host = split( /\s+/, $host_tmp ); $in_host = 1; for my $h (@host) { $ret{$h} = {}; } next; } elsif ($in_host) { #my ($key, $val) = ($line =~ m/^\s*([^\s]+)\s+=?\s*(.*)$/); $line =~ s/^\s*//g; my ( $key, $val_tmp ) = split( /[\s=]/, $line, 2 ); $val_tmp =~ s/^[\s=]+//g; my $val = $val_tmp; $val =~ s/^\s+//; $val =~ s/\s+$//; for my $h (@host) { $ret{$h}->{ lc($key) } = $val; } } } return %ret; } sub set_allow_empty_groups { my ( $class, $set ) = @_; if ($set) { $allow_empty_groups = 1; } else { $allow_empty_groups = 0; } } sub get_allow_empty_groups { if ($allow_empty_groups) { return 1; } return 0; } sub set_use_server_auth { my ( $class, $set ) = @_; if ($set) { $use_server_auth = 1; } else { $use_server_auth = 0; } } sub get_use_server_auth { if ($use_server_auth) { return 1; } return 0; } sub import { read_ssh_config_file(); read_config_file(); } no strict 'refs'; __PACKAGE__->register_config_handler( base => sub { my ($param) = @_; for my $key ( keys %{$param} ) { if ( $key eq "keyauth" ) { $key_auth = $param->{keyauth}; next; } if ( $key eq "passwordauth" ) { $password_auth = $param->{passwordauth}; next; } if ( $key eq "passauth" ) { $password_auth = $param->{passauth}; next; } $$key = $param->{$key}; } } ); my @set_handler = qw/user password private_key public_key -keyauth -passwordauth -passauth parallelism sudo_password connection ca cert key distributor template_function port/; for my $hndl (@set_handler) { __PACKAGE__->register_set_handler( $hndl => sub { my ($val) = @_; if ( $hndl =~ m/^\-/ ) { $hndl = substr( $hndl, 1 ); } if ( $hndl eq "keyauth" ) { $hndl = "key_auth"; $val = 1; } if ( $hndl eq "passwordauth" || $hndl eq "passauth" ) { $hndl = "password_auth"; $val = 1; } if ( $hndl eq "connection" ) { $hndl = "connection_type"; } if ( $hndl eq "ca" ) { $hndl = "ca_file"; } if ( $hndl eq "cert" ) { $hndl = "ca_cert"; } if ( $hndl eq "key" ) { $hndl = "ca_key"; } $$hndl = $val; } ); } use strict; sub _home_dir { if ( $^O =~ m/^MSWin/ ) { return $ENV{'USERPROFILE'}; } return $ENV{'HOME'} || ""; } 1; Rex-1.3.3/lib/Rex/Resource/0000755000175000017500000000000012572251052015234 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Resource/Common.pm0000644000175000017500000000610512572251052017024 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Resource::Common; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION require Exporter; require Rex::Config; use Rex::Resource; use Data::Dumper; use base qw(Exporter); use vars qw(@EXPORT); @EXPORT = qw(emit resource resource_name changed created removed); sub changed { return "changed"; } sub created { return "created"; } sub removed { return "removed"; } sub emit { my ( $type, $message ) = @_; if ( !$Rex::Resource::INSIDE_RES ) { die "emit() only allowed inside resource."; } Rex::Logger::debug( "Emiting change: " . $type . " - $message." ); if ( $type eq changed ) { current_resource()->changed(1); } if ( $type eq created ) { current_resource()->created(1); } if ( $type eq removed ) { current_resource()->removed(1); } if ($message) { current_resource()->message($message); } } =over 4 =item resource($name, $function) =cut sub resource { my ( $name, $options, $function ) = @_; my $name_save = $name; if ( ref $options eq "CODE" ) { $function = $options; $options = {}; } if ( $name_save !~ m/^[a-zA-Z_][a-zA-Z0-9_]+$/ ) { Rex::Logger::info( "Please use only the following characters for resource names:", "warn" ); Rex::Logger::info( " A-Z, a-z, 0-9 and _", "warn" ); Rex::Logger::info( "Also the resource should start with A-Z or a-z", "warn" ); die "Wrong resource name syntax."; } my ( $class, $file, @tmp ) = caller; my $res = Rex::Resource->new( type => "${class}::$name", name => $name, display_name => ( $options->{name} || $name ), cb => $function ); my $func = sub { $res->call(@_); }; if (!$class->can($name) && $name_save =~ m/^[a-zA-Z_][a-zA-Z0-9_]+$/ ) { no strict 'refs'; Rex::Logger::debug("Registering resource: ${class}::$name_save"); my $code = $_[-2]; *{"${class}::$name_save"} = $func; use strict; } elsif ( ( $class ne "main" && $class ne "Rex::CLI" ) && !$class->can($name_save) && $name_save =~ m/^[a-zA-Z_][a-zA-Z0-9_]+$/ ) { # if not in main namespace, register the task as a sub no strict 'refs'; Rex::Logger::debug( "Registering resource (not main namespace): ${class}::$name_save"); my $code = $_[-2]; *{"${class}::$name_save"} = $func; use strict; } if ( exists $options->{export} && $options->{export} ) { # register in caller namespace no strict 'refs'; my ($caller_pkg) = caller(1); if ( $caller_pkg eq "Rex" ) { ($caller_pkg) = caller(2); } Rex::Logger::debug("Registering $name_save in $caller_pkg namespace."); *{"${caller_pkg}::$name_save"} = $func; use strict; } } sub resource_name { Rex::Config->set( resource_name => current_resource()->{res_name} ); return current_resource()->{res_name}; } sub resource_ensure { my ($option) = @_; $option->{ current_resource()->{res_ensure} }->(); } sub current_resource { return $Rex::Resource::CURRENT_RES[-1]; } =back =cut 1; Rex-1.3.3/lib/Rex/FS/0000755000175000017500000000000012572251052013755 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/FS/File.pm0000644000175000017500000000663112572251052015200 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::FS::File - File Class =head1 DESCRIPTION This is the File Class used by I and I. =head1 SYNOPSIS use Rex::Interface::File; my $fh = Rex::Interface::File->create('Local'); $fh->open( '<', 'filename' ); my $file = Rex::FS::File->new(fh => $fh); $file->read($len); $file->read_all; $file->write($buf); $file->close; =head1 CLASS METHODS =cut package Rex::FS::File; use strict; use warnings; use Rex::Interface::File; our $VERSION = '1.3.3'; # VERSION use constant DEFAULT_READ_LEN => 64; =head2 new This is the constructor. You need to set the filehandle which the object should work on or pass a filename. If you pass a filehandle, it has to be a C object my $fh = Rex::Interface::File->create('Local'); $fh->open( '<', 'filename' ); my $file = Rex::FS::File->new(fh => $fh); Create a C object with a filename # open a local file in read mode my $file = Rex::FS::File->new( filename => 'filename', mode => 'r', # or '<' type => 'Local', ); # or shorter my $file = Rex::FS::File->new( filename => 'filename' ); # open a local file in write mode my $file = Rex::FS::File->new( filename => 'filename', mode => 'w', # or '>' ); Allowed modes: < read r read > write w write >> append a append For allowed C see documentation of L. =cut sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; my %modes = ( 'w' => '>', 'r' => '<', 'a' => '>>', '<' => '<', '>' => '>', '>>' => '>>', ); if ( $self->{filename} ) { $self->{mode} ||= '<'; my $mode = $modes{ $self->{mode} } || '<'; $self->{fh} = Rex::Interface::File->create( $self->{type} || 'Local' ); $self->{fh}->open( $mode, $self->{filename} ); } bless( $self, $proto ); if ( ref $self->{fh} !~ m{Rex::Interface::File} ) { die "Need an Rex::Interface::File object"; } return $self; } sub DESTROY { my ($self) = @_; if ( ref $self->{'fh'} =~ m/^Rex::Interface::File/ ) { $self->close if ( $self->{'fh'}->{'fh'} ); } else { $self->close if ( $self->{'fh'} ); } } =head2 write($buf) Write $buf into the filehandle. $file->write("Hello World"); =cut sub write { my ( $self, @buf ) = @_; my $fh = $self->{fh}; if ( scalar(@buf) > 1 ) { for my $line (@buf) { $fh->write($line); $fh->write($/); } } else { $fh->write( $buf[0] ); } } =head2 seek($offset) Seek to the file position $offset. Set the file pointer to the 5th byte. $file->seek(5); =cut sub seek { my ( $self, $offset ) = @_; my $fh = $self->{'fh'}; $fh->seek($offset); } =head2 read($len) Read $len bytes out of the filehandle. my $content = $file->read(1024); =cut sub read { my ( $self, $len ) = @_; $len = DEFAULT_READ_LEN if ( !$len ); my $fh = $self->{'fh'}; return $fh->read($len); } =head2 read_all Read everything out of the filehandle. my $content = $file->read_all; =cut sub read_all { my ($self) = @_; my $all = ''; while ( my $in = $self->read() ) { $all .= $in; } if (wantarray) { return split( /\n/, $all ); } return $all; } =head2 close Close the file. $file->close; =cut sub close { my ($self) = @_; my $fh = $self->{'fh'}; $fh->close; } 1; Rex-1.3.3/lib/Rex/Virtualization/0000755000175000017500000000000012572251052016471 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Virtualization/LibVirt.pm0000644000175000017500000000227712572251052020412 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Virtualization::LibVirt - LibVirt Virtualization Module =head1 DESCRIPTION With this module you can manage LibVirt. =head1 SYNOPSIS use Rex::Commands::Virtualization; set virtualization => "LibVirt"; print Dumper vm list => "all"; print Dumper vm list => "running"; vm destroy => "vm01"; vm delete => "vm01"; vm start => "vm01"; vm shutdown => "vm01"; vm reboot => "vm01"; vm option => "vm01", max_memory => 1024*1024, memory => 512*1024; print Dumper vm info => "vm01"; # creating a vm on a kvm host vm create => "vm01", storage => [ { file => "/mnt/data/libvirt/images/vm01.img", dev => "vda", } ]; print Dumper vm hypervisor => "capabilities"; =cut package Rex::Virtualization::LibVirt; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Virtualization::Base; use base qw(Rex::Virtualization::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Virtualization/Docker.pm0000644000175000017500000000217612572251052020244 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: =head1 NAME Rex::Virtualization::Docker - Docker Virtualization Module =head1 DESCRIPTION With this module you can manage Docker. =head1 SYNOPSIS use Rex::Commands::Virtualization; set virtualization => "Docker"; use Data::Dumper; print Dumper vm list => "all"; print Dumper vm list => "running"; print Dumper vm info => "vm01"; vm destroy => "vm01"; vm delete => "vm01"; vm start => "vm01"; vm shutdown => "vm01"; vm reboot => "vm01"; # creating a vm my $id = vm create => "vm01", image => "ubuntu", command => 'echo hello world', memory => 512, cpus => 1, links => ['mysql:db'], forward_port => [8080 => 80], share_folder => ["hostdir" => "vmdir"], =cut package Rex::Virtualization::Docker; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Virtualization::Base; use base qw(Rex::Virtualization::Base); sub new { my $that = shift; my $proto = ref($that) || $that; my $self = {@_}; bless( $self, $proto ); return $self; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/0000755000175000017500000000000012572251052020044 5ustar jenkinsjenkinsRex-1.3.3/lib/Rex/Virtualization/LibVirt/start.pm0000644000175000017500000000146412572251052021544 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::start; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; sub execute { my ( $class, $arg1, %opt ) = @_; my $virt_settings = Rex::Config->get("virtualization"); Rex::Logger::debug("Starting vm: $arg1"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($arg1) { die("You have to define the vm name!"); } my $dom = $arg1; Rex::Logger::debug("starting domain: $dom"); unless ($dom) { die("VM $dom not found."); } my $output = i_run "virsh -c $uri start '$dom' 2>&1"; if ( $? != 0 ) { die("Error starting vm $dom\nError: $output"); } } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/import.pm0000644000175000017500000000565212572251052021724 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::import; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; use Rex::Commands::Fs; use File::Basename; use Rex::Virtualization::LibVirt::create; use Data::Dumper; # # %opt = (cpus => 2, memory => 512) # sub execute { my ( $class, $arg1, %opt ) = @_; unless ($arg1) { die("You have to define the vm name!"); } my $dom = $arg1; Rex::Logger::debug( "importing: $dom -> " . $opt{file} ); my $cwd = i_run "pwd"; chomp $cwd; my $dir = dirname $opt{file}; my ( undef, undef, $suffix ) = fileparse( $opt{file}, qr{\.[^.]*} ); my $file = "storage/" . $dom . $suffix; mkdir "./storage"; my $format = "qcow2"; my @serial_devices; if ( exists $opt{serial_devices} ) { @serial_devices = @{ $opt{serial_devices} }; } if ( $opt{file} =~ m/\.ova$/ ) { Rex::Logger::debug("Importing ova file. Try to convert with qemu-img"); $file =~ s/\.[a-z]+$//; my @vmdk = grep { m/\.vmdk$/ } i_run "tar -C $dir -vxf $opt{file}"; Rex::Logger::debug( "converting $cwd/tmp/$vmdk[0] -> $cwd/storage/$file.qcow2"); i_run "qemu-img convert -O qcow2 $cwd/tmp/$vmdk[0] $cwd/$file.qcow2"; if ( $? != 0 ) { Rex::Logger::info( "Can't import and convert $opt{file}. You qemu-img version seems not " . " to support this format.", "warn" ); die("Error importing VM $opt{file}"); } $file = "$file.qcow2"; } else { Rex::Logger::debug("Importing kvm compatible file."); Rex::Logger::debug("Copying $opt{file} -> $file"); cp $opt{file}, $file; if ( $file =~ m/\.gz$/ ) { Rex::Logger::debug("Extracting gzip'ed file $file"); i_run "gunzip -q -f $file"; $file =~ s/\.gz$//; } } my ($format_out) = grep { m/^file format:/ } i_run "qemu-img info $file"; if ( $format_out =~ m/^file format: (.*)$/i ) { $format = $1; } my @network = values %{ $opt{__network} }; if ( scalar @network == 0 ) { # create default network push @network, { type => "network", network => "default", }; } for (@network) { $_->{type} ||= "network"; $_->{type} = "bridge" if ( $_->{type} && $_->{type} eq "bridged" ); $_->{type} = "network" if ( $_->{type} eq "nat" ); if ( $_->{type} eq "network" && !exists $_->{network} ) { $_->{network} = "default"; } } Rex::Virtualization::LibVirt::create->execute( $dom, storage => [ { file => "$cwd/$file", dev => "vda", driver_type => $format, }, ], network => \@network, serial_devices => \@serial_devices, ); if ( exists $opt{__forward_port} ) { # currently not supported Rex::Logger::info( "Port-forwarding is currently not supported for KVM boxes.", "warn" ); } } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/list.pm0000644000175000017500000000221712572251052021357 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::list; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; use Data::Dumper; sub execute { my ( $class, $arg1, %opt ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); my @domains; if ( $arg1 eq "all" ) { @domains = i_run "virsh -c $uri list --all --name"; if ( $? != 0 ) { die("Error running virsh list --all --name"); } } elsif ( $arg1 eq "running" ) { @domains = i_run "virsh -c $uri list --name"; if ( $? != 0 ) { die("Error running virsh list --name"); } } else { return; } my @ret = (); for my $name (@domains) { my %data = map { my ( $key, $val ) = split( /:\s*/, $_ ); ( $key, $val ); } i_run "virsh -c $uri dominfo '$name'"; push( @ret, { id => $data{Id}, name => $data{Name}, status => $data{State} } ); } return \@ret; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/blklist.pm0000644000175000017500000000275512572251052022057 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::blklist; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Run; use Rex::Helper::Run; use Data::Dumper; sub execute { shift; my $vmname = shift; my %options = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($vmname) { die("You have to define the vm name!"); } Rex::Logger::debug("Getting block list of domain: $vmname"); my @blklist = i_run "virsh -c $uri domblklist '$vmname' --details"; if ( $? != 0 ) { die("Error running virsh domblklist '$vmname'"); } my %ret = (); my ( $k, $v ); shift @blklist; shift @blklist; for my $line (@blklist) { my ( $type, $device, $target, $source ) = split( /\s+/, $line ); $ret{$target} = { type => $type, device => $device, source => $source }; } if (%options) { if ( $options{details} ) { my $unit = $options{unit} || 1; for my $target ( keys %ret ) { my @infos = i_run "virsh -c $uri domblkinfo '$vmname' '$target' 2>/dev/null"; if ( $? == 0 ) { for my $line (@infos) { my ( $k, $v ) = split( /:\s+/, $line ); $ret{$target}->{$k} = $v / $unit; } } } } } return \%ret; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/vncdisplay.pm0000644000175000017500000000144112572251052022556 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::vncdisplay; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; use XML::Simple; use Data::Dumper; sub execute { my ( $class, $vmname ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($vmname) { die("You have to define the vm name!"); } Rex::Logger::debug("Getting info of domain: $vmname"); my $xml; my @vncdisplay = i_run "virsh -c $uri vncdisplay '$vmname'"; if ( $? != 0 ) { die("Error running virsh vncdisplay '$vmname'"); } return shift @vncdisplay; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/dumpxml.pm0000644000175000017500000000142512572251052022072 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::dumpxml; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; use XML::Simple; use Data::Dumper; sub execute { my ( $class, $vmname ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($vmname) { die("You have to define the vm name!"); } Rex::Logger::debug("Getting dumpxml of domain: $vmname"); my $xml; my $dumpxml = i_run "virsh -c $uri dumpxml '$vmname'"; if ( $? != 0 ) { die("Error running virsh dumpxml '$vmname'"); } return XMLin($dumpxml); } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/delete.pm0000644000175000017500000000134412572251052021646 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::delete; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; sub execute { my ( $class, $arg1 ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($arg1) { die("You have to define the vm name!"); } my $dom = $arg1; Rex::Logger::debug("deleting domain: $dom"); unless ($dom) { die("VM $dom not found."); } i_run "virsh -c $uri undefine '$dom'"; if ( $? != 0 ) { die("Error destroying vm $dom"); } } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/hypervisor.pm0000644000175000017500000000414612572251052022621 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::hypervisor; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; use XML::Simple; use Data::Dumper; sub execute { my ( $class, $arg1, %opt ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($arg1) { die("You have to define the vm name!"); } my ( $xml, @dominfo, $dom ); if ( $arg1 eq 'capabilities' ) { @dominfo = i_run "virsh -c $uri capabilities"; if ( $? != 0 ) { die("Error running virsh dominfo $dom"); } my $xs = XML::Simple->new(); $xml = $xs->XMLin( join( "", @dominfo ), KeepRoot => 1, KeyAttr => 1, ForceContent => 1 ); } else { Rex::Logger::debug("Unknown action $arg1"); die("Unknown action $arg1"); } my %ret = (); my ( $k, $v ); if ( ref( $xml->{'capabilities'}->{'guest'} ) ne "ARRAY" ) { $xml->{'capabilities'}->{'guest'} = [ $xml->{'capabilities'}->{'guest'} ]; } for my $line ( @{ $xml->{'capabilities'}->{'guest'} } ) { next if ( $line->{'arch'}->{'name'} ne "x86_64" ); $ret{ $line->{'arch'}->{'name'} } = 'true' if defined( $line->{'arch'}->{'name'} ); $ret{'emulator'} = $line->{'arch'}->{'emulator'}->{'content'} if defined( $line->{'arch'}->{'emulator'}->{'content'} ); $ret{'loader'} = $line->{'arch'}->{'loader'}->{'content'} if defined( $line->{'arch'}->{'loader'}->{'content'} ); $ret{ $line->{'os_type'}->{'content'} } = 'true' if defined( $line->{'os_type'}->{'content'} ); if ( defined( $line->{'arch'}->{'domain'} ) && ref( $line->{'arch'}->{'domain'} ) eq 'ARRAY' ) { for ( @{ $line->{'arch'}->{'domain'} } ) { $ret{ $_->{'type'} } = 'true'; } } else { $ret{ $line->{'arch'}->{'domain'}->{'type'} } = 'true' if defined( $line->{'arch'}->{'domain'}->{'type'} ); } } return \%ret; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/info.pm0000644000175000017500000000315212572251052021336 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::info; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; use XML::Simple; use Rex::Virtualization::LibVirt::dumpxml; use Data::Dumper; sub execute { my ( $class, $vmname ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($vmname) { die("You have to define the vm name!"); } Rex::Logger::debug("Getting info of domain: $vmname"); my $xml; my @dominfo = i_run "virsh -c $uri dominfo '$vmname'"; if ( $? != 0 ) { die("Error running virsh dominfo '$vmname'"); } my %ret = (); my ( $k, $v ); for my $line (@dominfo) { ( $k, $v ) = split( /:\s+/, $line ); $ret{$k} = $v; } if (Rex::Config::get_use_rex_kvm_agent) { my $xml_ref = Rex::Virtualization::LibVirt::dumpxml->execute($vmname); if ( $xml_ref && exists $xml_ref->{devices}->{serial} && ref $xml_ref->{devices}->{serial} eq "ARRAY" ) { my ($agent_serial) = grep { exists $_->{type} && $_->{type} eq "tcp" && $_->{target}->{port} == 1 } @{ $xml_ref->{devices}->{serial} }; #TODO: $xml_ref->{devices}->{serial} is an arrayref if there are multiple devices, hashref otherwise #TODO: it might be a better idea to name the serial device and match by its name here $ret{has_kvm_agent_on_port} = $agent_serial->{source}->{service}; } } return \%ret; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/iflist.pm0000644000175000017500000000314212572251052021674 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::iflist; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Run; use Rex::Helper::Run; use Data::Dumper; use Rex::Virtualization::LibVirt::dumpxml; sub execute { shift; my $vmname = shift; my %options = @_; unless ($vmname) { die("You have to define the vm name!"); } my $ref = Rex::Virtualization::LibVirt::dumpxml->execute($vmname); my $interfaces = $ref->{devices}->{interface}; if ( ref $interfaces ne "ARRAY" ) { $interfaces = [$interfaces]; } my %ret = (); my $iface_num = 0; for my $iface ( @{$interfaces} ) { $ret{"vnet$iface_num"} = { type => $iface->{model}->{type}, source => $iface->{source}->{network}, model => $iface->{model}->{type}, mac => $iface->{mac}->{address}, }; $iface_num++; } return \%ret; } 1; __END__ print Dumper($ref); return; Rex::Logger::debug("Getting interface list of domain: $vmname"); my @iflist = i_run "virsh domiflist $vmname"; if($? != 0) { die("Error running virsh domiflist $vmname"); } my ($k, $v); shift @iflist; shift @iflist; my $iface_num = 0; for my $line (@iflist) { my ($interface, $type, $source, $model, $mac) = split(/\s+/, $line); if($interface eq "-") { $interface = "vnet$iface_num"; } $ret{$interface} = { type => $type, source => $source, model => $model, mac => $mac }; $iface_num++; } return \%ret; } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/reboot.pm0000644000175000017500000000135012572251052021673 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::reboot; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Helper::Run; sub execute { my ( $class, $arg1, %opt ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); unless ($arg1) { die("You have to define the vm name!"); } my $dom = $arg1; Rex::Logger::debug("rebooting domain: $dom"); unless ($dom) { die("VM $dom not found."); } i_run "virsh -c $uri reboot '$dom'"; if ( $? != 0 ) { die("Error rebooting vm $dom"); } } 1; Rex-1.3.3/lib/Rex/Virtualization/LibVirt/create.pm0000644000175000017500000003512612572251052021654 0ustar jenkinsjenkins# # (c) Jan Gehring # # vim: set ts=2 sw=2 tw=0: # vim: set expandtab: package Rex::Virtualization::LibVirt::create; use strict; use warnings; our $VERSION = '1.3.3'; # VERSION use Rex::Logger; use Rex::Commands::Gather; use Rex::Hardware; use Rex::Commands::Fs; use Rex::Commands::Run; use Rex::Helper::Run; use Rex::Commands::File; use Rex::File::Parser::Data; use Rex::Template; use Rex::Helper::Path; use XML::Simple; use Rex::Virtualization::LibVirt::hypervisor; use Data::Dumper; my $QEMU_IMG; if ( can_run("qemu-img") ) { $QEMU_IMG = "qemu-img"; } elsif ( can_run("qemu-img-xen") ) { $QEMU_IMG = "qemu-img-xen"; } # read __DATA__ into an array my @data = ; sub execute { my ( $class, $name, %opt ) = @_; my $virt_settings = Rex::Config->get("virtualization"); chomp( my $uri = ref($virt_settings) ? $virt_settings->{connect} : i_run "virsh uri" ); my $opts = \%opt; $opts->{"name"} = $name; unless ($opts) { die("You have to define the create options!"); } ## detect the hypervisor caps my $hypervisor = Rex::Virtualization::LibVirt::hypervisor->execute('capabilities'); my $virt_type = "unknown"; _set_defaults( $opts, $hypervisor ); if ( exists $hypervisor->{"kvm"} ) { $virt_type = "kvm"; } elsif ( exists $hypervisor->{"xen"} ) { $virt_type = "xen-" . $opts->{"type"}; } else { die("Hypervisor not supported."); } my $fp = Rex::File::Parser::Data->new( data => \@data ); my $create_xml = $fp->read("create-${virt_type}.xml"); my $template = Rex::Template->new; my $parsed_template = $template->parse( $create_xml, $opts ); Rex::Logger::debug($parsed_template); ## create storage devices for ( @{ $opts->{'storage'} } ) { if ( !exists $_->{"template"} && $_->{"size"} && $_->{"type"} eq "file" ) { my $size = $_->{'size'}; if ( !is_file( $_->{"file"} ) ) { Rex::Logger::debug("creating storage disk: \"$_->{file}\""); i_run "$QEMU_IMG create -f raw $_->{'file'} $size"; if ( $? != 0 ) { die("Error creating storage disk: $_->{'file'}"); } } else { Rex::Logger::info("$_->{file} already exists. Using this."); } } elsif ( $_->{'template'} && $_->{'type'} eq "file" ) { Rex::Logger::info( "building domain: \"$opts->{'name'}\" from template: \"$_->{'template'}\"" ); Rex::Logger::info("Please wait ..."); i_run "$QEMU_IMG convert -f raw $_->{'template'} -O raw $_->{'file'}"; if ( $? != 0 ) { die( "Error building domain: \"$opts->{'name'}\" from template: \"$_->{'template'}\"\n Template doesn't exist or the qemu-img binary is missing" ); } } else { Rex::Logger::info("$_->{file} already exists. Using this."); } } Rex::Logger::info("Creating domain: \"$opts->{'name'}\""); $parsed_template =~ s/[\n\r]//gms; my $file_name = get_tmp_file; file "$file_name", content => $parsed_template; i_run "virsh -c $uri define $file_name"; if ( $? != 0 ) { die("Error defining vm $opts->{name}"); } unlink($file_name); return; } sub _set_defaults { my ( $opts, $hyper ) = @_; if ( !exists $opts->{"name"} ) { die("You have to give a name."); } if ( !exists $opts->{"storage"} ) { die("You have to add at least one storage disk."); } if ( !exists $opts->{"type"} ) { if ( exists $opts->{"os"} && exists $opts->{"os"}->{"kernel"} && !exists $hyper->{"kvm"} ) { $opts->{"type"} = "pvm"; } else { $opts->{"type"} = "hvm"; } } if ( !exists $opts->{"memory"} ) { $opts->{"memory"} = 512 * 1024; } if ( !exists $opts->{"cpus"} ) { $opts->{"cpus"} = 1; } if ( !exists $opts->{"clock"} ) { $opts->{"clock"} = "utc"; } if ( !exists $opts->{"arch"} ) { if ( exists $hyper->{"x86_64"} ) { $opts->{"arch"} = "x86_64"; } else { $opts->{"arch"} = "i686"; } } if ( !exists $opts->{"boot"} ) { $opts->{"boot"} = "hd"; } if ( !exists $opts->{"emulator"} ) { $opts->{"emulator"} = $hyper->{"emulator"}; if ( operating_system_is("Debian") && exists $hyper->{"xen"} ) { # fix for debian, because virsh capabilities don't give the correct # emulator. $opts->{"emulator"} = "/usr/lib/xen-4.0/bin/qemu-dm"; } } if ( exists $hyper->{"loader"} && !exists $opts->{"loader"} ) { $opts->{"loader"} = $hyper->{"loader"}; } if ( !exists $opts->{"on_poweroff"} ) { $opts->{"on_poweroff"} = "destroy"; } if ( !exists $opts->{"on_reboot"} ) { $opts->{"on_reboot"} = "restart"; } if ( !exists $opts->{"on_crash"} ) { $opts->{"on_crash"} = "restart"; } if ( exists $hyper->{"xen"} && $opts->{"type"} eq "pvm" ) { if ( !exists $opts->{"os"}->{"type"} ) { $opts->{"os"}->{"type"} = "linux"; } if ( !exists $opts->{"os"}->{"kernel"} ) { my %hw = Rex::Hardware->get(qw/ Kernel /); if ( is_redhat() ) { $opts->{"os"}->{"kernel"} = "/boot/vmlinuz-" . $hw{"Kernel"}->{"kernelrelease"}; } else { $opts->{"os"}->{"kernel"} = "/boot/vmlinuz-" . $hw{"Kernel"}->{"kernelrelease"}; } } if ( !exists $opts->{"os"}->{"initrd"} ) { my %hw = Rex::Hardware->get(qw/ Kernel /); if ( is_redhat() ) { $opts->{"os"}->{"initrd"} = "/boot/initrd-" . $hw{"Kernel"}->{"kernelrelease"} . ".img"; } else { $opts->{"os"}->{"initrd"} = "/boot/initrd.img-" . $hw{"Kernel"}->{"kernelrelease"}; } } if ( !exists $opts->{"os"}->{"cmdline"} ) { my @root_store = grep { $_->{"is_root"} && $_->{"is_root"} == 1 } @{ $opts->{"storage"} }; $opts->{"os"}->{"cmdline"} = "root=/dev/" . $root_store[0]->{"dev"} . " ro"; } } _set_storage_defaults( $opts, $hyper ); _set_network_defaults( $opts, $hyper ); } sub _set_storage_defaults { my ( $opts, $hyper ) = @_; my $store_letter = "a"; for my $store ( @{ $opts->{"storage"} } ) { if ( !exists $store->{"type"} ) { $store->{"type"} = "file"; } if ( !exists $store->{"driver_type"} ) { $store->{"driver_type"} = "raw"; } if ( !exists $store->{"size"} && $store->{"type"} eq "file" ) { if ( $store->{"file"} =~ m/swap/ ) { $store->{"size"} = "1G"; } else { $store->{"size"} = "10G"; } } if ( exists $store->{"file"} && $store->{"file"} =~ m/\.iso$/ && !exists $store->{"device"} ) { $store->{"device"} = "cdrom"; } if ( !exists $store->{"device"} ) { $store->{"device"} = "disk"; } if ( !exists $store->{"dev"} && $store->{"device"} eq "cdrom" ) { $store->{"dev"} = "hdc"; } if ( !exists $store->{"dev"} ) { if ( exists $hyper->{"kvm"} ) { $store->{"dev"} = "vd${store_letter}"; } else { $store->{"dev"} = "hd${store_letter}"; } } if ( !exists $store->{"bus"} ) { if ( exists $hyper->{"kvm"} && $store->{"device"} eq "disk" ) { $store->{"bus"} = "virtio"; } else { $store->{"bus"} = "ide"; } } if ( exists $hyper->{"kvm"} ) { if ( $store->{"bus"} eq "virtio" && !exists $store->{"address"} ) { $store->{"address"} = { type => "pci", domain => "0x0000", bus => "0x00", slot => "0x05", function => "0x0", }; } elsif ( $store->{"bus"} eq "ide" && !exists $store->{"address"} ) { $store->{"address"} = { type => "drive", controller => 0, bus => 1, unit => 0, }; } } if ( $store->{"device"} eq "cdrom" ) { $store->{"readonly"} = 1; } if ( is_redhat() ) { if ( !exists $store->{"aio"} ) { $store->{"aio"} = 1; } } $store_letter++; } } sub _set_network_defaults { my ( $opts, $hyper ) = @_; if ( !exists $opts->{"network"} ) { $opts->{"network"} = [ { type => "bridge", bridge => "virbr0", }, ]; } my $slot = 10; for my $netdev ( @{ $opts->{"network"} } ) { if ( !exists $netdev->{"type"} ) { $netdev->{"type"} = "bridge"; } if ( !exists $netdev->{"bridge"} ) { $netdev->{"bridge"} = "virbr0"; } if ( exists $hyper->{"kvm"} ) { if ( !exists $netdev->{"model"} ) { $netdev->{"model"} = "virtio"; } if ( !exists $netdev->{"address"} ) { $netdev->{"address"} = { type => "pci", domain => "0x0000", bus => "0x00", slot => "0x" . sprintf( '%02i', $slot ), function => "0x0", }; $slot++; } } } } 1; __DATA__ @create-kvm.xml <%= $::name %> <%= $::memory %> <%= $::memory %> <%= $::cpus %> hvm <%= $::on_poweroff %> <%= $::on_reboot %> <%= $::on_crash %> <%= $::emulator %> <% for my $disk (@{$::storage}) { %> <% if ($disk->{type} eq "file") { %> <% } elsif ($disk->{file} eq "block") { %> <% } %> <% if(exists $disk->{readonly}) { %> <% } %>
{address}}) { %> <%= $key %>="<%= $disk->{address}->{$key} %>" <% } %> /> <% } %>
<% for my $netdev (@{$::network}) { %> <% if(exists $netdev->{mac}) { %> <% } %> <% if($netdev->{type} =~ m/^bridge/) { %> <% } elsif($netdev->{type} eq "network") { %> <% } %>
{address}}) { %> <%= $key %>="<%= $netdev->{address}->{$key} %>" <% } %> /> <% } %> <% my $serial_i = 1; %> <% for my $serial (@{ $serial_devices }) { %> <% if($serial->{type} eq "tcp") { %> <% } %> <% $serial_i++; %> <% } %>