├── .gitignore ├── .kitchen.yml ├── .rubocop.yml ├── .travis.yml ├── Berksfile ├── CHANGELOG.md ├── Guardfile ├── LICENSE ├── README.md ├── chefignore ├── files └── default │ └── interfaces ├── libraries ├── matchers.rb ├── provider_debian_network_interface.rb ├── provider_network_interface.rb ├── provider_rhel_network_interface.rb ├── provider_win_network_interface.rb ├── resource_debian_network_interface.rb ├── resource_network_interface.rb ├── resource_rhel_network_interface.rb ├── resource_win_network_interface.rb ├── ruby_wmi_ext.rb └── wmi_helper.rb ├── metadata.rb ├── recipes ├── default.rb └── powershell_installer.rb ├── spec ├── helper_recipes │ ├── fake_bonding_spec.rb │ ├── fake_bridge_spec.rb │ ├── fake_core_spec.rb │ ├── fake_dhcp_spec.rb │ ├── fake_dns_spec.rb │ ├── fake_metrics_spec.rb │ ├── fake_multiple_int_defs_spec.rb │ ├── fake_override_spec.rb │ ├── fake_ovs_dhcp_spec.rb │ └── fake_vlan_spec.rb ├── libraries │ └── provider_win_network_interface_spec.rb ├── spec_helper.rb └── support │ └── matchers.rb ├── templates └── default │ ├── debian_interface.erb │ └── ifcfg.erb └── test ├── fixtures └── cookbooks │ ├── fake │ ├── metadata.rb │ └── recipes │ │ ├── _core_enp.rb │ │ ├── _core_eth.rb │ │ ├── _core_win.rb │ │ ├── _ovs_dhcp_enp.rb │ │ ├── _ovs_dhcp_eth.rb │ │ ├── bonding.rb │ │ ├── bridge.rb │ │ ├── core.rb │ │ ├── default.rb │ │ ├── dhcp.rb │ │ ├── dns.rb │ │ ├── metrics.rb │ │ ├── multiple_int_defs.rb │ │ ├── override.rb │ │ ├── ovs_dhcp.rb │ │ └── vlan.rb │ └── net_setup │ ├── metadata.rb │ └── recipes │ └── default.rb └── integration └── default └── serverspec ├── Gemfile ├── bonding_spec.rb ├── bridge_spec.rb ├── config_spec.rb ├── fixtures ├── enp0s4 ├── eth0 ├── eth4 ├── ifcfg-enp0s3 ├── ifcfg-enp0s4 ├── ifcfg-eth0 └── ifcfg-eth4 ├── interfaces_spec.rb ├── spec_helper.rb └── vlan_spec.rb /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *# 3 | .#* 4 | \#*# 5 | .*.sw[a-z] 6 | *.un~ 7 | pkg/ 8 | 9 | # Berkshelf 10 | .vagrant 11 | /cookbooks 12 | Berksfile.lock 13 | 14 | # Bundler 15 | Gemfile.lock 16 | bin/* 17 | .bundle/* 18 | 19 | .kitchen/ 20 | .kitchen.local.yml 21 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver: 3 | name: vagrant 4 | 5 | provisioner: 6 | name: chef_zero 7 | 8 | platforms: 9 | - name: ubuntu-14.04 10 | run_list: 11 | - recipe[net_setup::default] 12 | - name: ubuntu-16.04 13 | run_list: 14 | - recipe[net_setup::default] 15 | - name: centos-7.2 16 | run_list: 17 | - recipe[net_setup::default] 18 | - name: centos-6.7 19 | run_list: 20 | - recipe[net_setup::default] 21 | - name: win-2012r2 22 | driver: 23 | box: opentable/win-2012r2-standard-amd64-nocm 24 | network: 25 | - ["forwarded_port", {guest: 3389, host: 3389}] 26 | - ["private_network", {type: "dhcp", mac: "0025B55B0029", auto_config: false}] 27 | - ["private_network", {type: "dhcp", mac: "0025B55B0031", auto_config: false}] 28 | - ["private_network", {type: "dhcp", mac: "0025B55B0033"}] 29 | - ["private_network", {type: "dhcp", mac: "0025B55B0035", auto_config: false}] 30 | 31 | suites: 32 | - name: default 33 | run_list: 34 | - recipe[fake::default] 35 | -------------------------------------------------------------------------------- /.rubocop.yml: -------------------------------------------------------------------------------- 1 | AllCops: 2 | Exclude: 3 | - 'test/fixtures/cookbooks/**/*' 4 | 5 | WordArray: 6 | Enabled: false 7 | 8 | NumericLiterals: 9 | Enabled: false 10 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | addons: 3 | apt: 4 | sources: 5 | - chef-current-precise 6 | packages: 7 | - chefdk 8 | 9 | install: echo "skip bundle install" 10 | 11 | before_script: 12 | - eval "$(/opt/chefdk/bin/chef shell-init bash)" 13 | - berks install 14 | 15 | script: 16 | - cookstyle 17 | - foodcritic -f any -X spec . 18 | - rspec --color --format progress 19 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | source 'https://supermarket.getchef.com' 2 | 3 | metadata 4 | 5 | cookbook 'fake', path: 'test/fixtures/cookbooks/fake' 6 | cookbook 'net_setup', path: 'test/fixtures/cookbooks/net_setup' 7 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2.11.0 2 | * Add ability to define array of pre/up/post and pre/down/post commands. 3 | 4 | # 2.10.0 5 | * Add defroute attribute for rhel family interface 6 | * Add ovsbootproto attribute for rhel family interface 7 | * Add ovsdhcpinterfaces attribute for rhel family interface 8 | 9 | # 2.9.0 10 | * Support for Ubuntu 16.04 11 | * Support for multiple device definitions on ubuntu (#20 and #26) 12 | 13 | # 2.8.0 14 | * Add hw_address support for debian 15 | 16 | # 2.7.0 17 | * Add ipv6 support for debian 18 | 19 | # 2.6.0 20 | * Add management of debian DNS 21 | * Add management of RHEL firewalld zones 22 | 23 | # 2.5.1 24 | * Fix RHEL configs from on/off to yes/no 25 | 26 | # 2.5.0 27 | * Add powershell installer for Windows 2008 R2 to allow cookbook to work 28 | 29 | # 2.4.1 30 | * bug: Fix `win_interface` to be able to manage interfae via `index` 31 | * bug: Enable static on `win_interface` when DHCP with matching ip/subnet (#13) 32 | 33 | # 2.4.0 34 | * Add `dns_domain` attribute to network_interface for RHEL 35 | 36 | # 2.3.0 37 | * Add `ovs_bridge` attribtue to network_interface for RHEL 38 | 39 | # 2.2.0 40 | * Add `dns` attribute to network_interface for RHEL 41 | * Add `devicetype` attribute to network_interface for RHEL 42 | * Add `prefix` attribute to network_interface for RHEL 43 | 44 | # 2.1.2 45 | 46 | * Add supported platforms to metadata.rb 47 | * Update gem source for integration testing to https from http 48 | 49 | # 2.1.1 50 | 51 | * Update how to determine when to specify `provides` in providers 52 | 53 | # 2.1.0 54 | 55 | * Remove dependency on ruby-wmi gem 56 | 57 | # 2.0.1 58 | 59 | * Fix handling DNS for windows VLAN devices 60 | 61 | # 2.0.0 62 | 63 | * Fix providers not triggering notifications 64 | * No longer manage removal of 'extra' network config files in debian 65 | * Add ability to enable/disable NetBIOS on windows interfaces 66 | 67 | # 1.1.0 68 | 69 | * Add running post scripts on interface config to all platforms 70 | * On windows release DHCP address when configuring static from DHCP 71 | * Update logic for configuring static address 72 | * Update if address or netmask are missing or incorrect 73 | * Add IP to 'front' of array of addresses ... keep any extra addresses that may have been configured outside of Chef 74 | * I've heard this can happen from things like MSFT products/services being added to a system ... like clustering 75 | 76 | # 1.0.0 77 | 78 | Initial release of network_interfaces_v2 79 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | guard 'rspec', cmd: 'bundle exec rspec', all_on_start: true, all_after_pass: false do 2 | watch(%r{^spec/libraries/.+_spec\.rb$}) 3 | watch(%r{^spec/helper_recipes/.+_spec\.rb$}) 4 | 5 | watch(%r{^libraries/(.+)\.rb$}) { 'spec' } 6 | watch(%r{^test/fixtures/cookbooks/fake/recipes/(.+)\.rb$}) { |m| "spec/helper_recipes/fake_#{m[1]}_spec.rb" } 7 | watch('spec/spec_helper.rb') { 'spec' } 8 | end 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2013 Target Corporation 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cookbook network_interfaces_v2 2 | ============================== 3 | [![Build Status](https://travis-ci.org/target/network_interfaces_v2-cookbook.svg?branch=travis_ci)](https://travis-ci.org/target/network_interfaces_v2-cookbook) 4 | 5 | **Note:** No longer actively developed. 6 | 7 | A cookbook containing providers for defining network interfaces. 8 | 9 | Supported Platforms 10 | =================== 11 | 12 | * RHEL 6.x 13 | * RHEL 7.x 14 | * Ubuntu >= 14.x 15 | * Windows 2012R2 16 | 17 | ### Semi-supported 18 | These operating systems are not currently being tested on but have been confirmed by other users to be working. 19 | 20 | * Windows 2008R2 21 | * Works if PowerShell/WMF 4.0 is present, which can be installed via `network_interfaces_v2::powershell_installer` recipe 22 | 23 | Usage 24 | ===== 25 | 26 | Add `depends 'network_interfaces_v2'` to your cookbook metadata.rb file. This 27 | will give you access to the providers documented below. 28 | 29 | Recipes 30 | ======= 31 | 32 | default 33 | ------- 34 | Does nothing and does not need to be included. 35 | 36 | powershell_installer 37 | -------------------- 38 | Installs WMF 4.0 for Windows 2008 R2 which is a prereq for this cookbook's providers to work on Windows 2008 R2. 39 | 40 | network_interface 41 | ================= 42 | Provider for managing network interfaces. 43 | 44 | Attributes 45 | ---------- 46 | * device (**REQUIRED**) - Device name 47 | * onboot (default: true) - Wether or not to online device on boot 48 | * bootproto (default: 'dhcp') - Device protocol 49 | * bond_mode - Bonding mode 50 | * address - IP address 51 | * netmask - Netmask 52 | * gateway - Gateway IP address 53 | * broadcast - Broadcast address 54 | * mtu - MTU 55 | * hw_address - For linux it sets MAC address of device, for windows it selects device matching MAC to configure 56 | * vlan 57 | * debian - VLAN device interface 58 | * RHEL - true/false if device defined is a VLAN interface 59 | * Win - Integer VlanID to tag to defined device 60 | * post_up - Post up command(s) to run after modifying the interface 61 | * reload (default: true) - Wether or not to reload the device on config changes 62 | * reload_type (default: :immediately) - When to reload device on config changes 63 | * cookbook (default: 'network_interfaces_v2') - Cookbook to look for template files in 64 | * source (default: 'ifcfg.erb') - Template file to use for interface config 65 | 66 | #### Debian Only Attributes 67 | * ipv6 (true/false) - Wether this is an inet or inet6 network interface. 68 | * bridge_stp (true/false) - Wether to enable/disable bridge STP. Applies to debian only. 69 | * bridge_ports - Array of interfaces to add to defined bridge 70 | * metric - 71 | * bond_slaves - Array of interfaces to add to defined bond 72 | * pre_up (default: 'sleep 2')- Pre up command(s) 73 | * up - Up command(s) 74 | * post_up - Post up command(s) 75 | * pre_down - Pre down command(s) 76 | * down - Down command(s) 77 | * post_down - Post down command(s) 78 | * custom - Hash of extra attributes to put in device config 79 | 80 | #### RHEL Only Attributes 81 | * prefix - Netmask length (e.g. 24 for 255.255.255.0) 82 | * dns - Array of DNS servers 83 | * type - Protocol Type. Applies to RHEL only. 84 | * bond_master - Device that is the bond master for defined device. Applies to RHEL only. 85 | * nm_controlled (default: false)- If device should be controlled by network manager. 86 | * type (default: 'Ethernet') - 87 | * ipv6init - true/false 88 | * nozeroconf - true/false 89 | * userctl - true/false 90 | * peerdns - true/false 91 | * bridge_device - Bridge to add defined interface to 92 | * devicetype - Set the type of device (e.g. 'ovs') 93 | * ovs_bridge - OVS Bridge to bind ovs port to (primarily used when `type` is set as 'OVSPort') 94 | * dns_domain - DNS domain 95 | * zone - FirewallD zone 96 | * arpcheck - Whether to arping before bringing up an ethernet device to check for an IP conflict (default: true) 97 | * hotplug - Activate devices on hotplug (default: true) 98 | * defroute - Enable/Disable default route modification by ifup script 99 | * ovsbootproto - Set to 'dhcp' if you want to use DHCP on an OVSBridge 100 | * ovsdhcpinterfaces - List of physical devices to use for DHCP on an OVSBridge 101 | 102 | #### Windows Only Attributes 103 | * hw_address - Can be used to define what device to manage 104 | * index - Can be used to define what device to manage 105 | * dns - Array of DNS servers 106 | * dns_domain - DNS domain 107 | * ddns - true/false dynamic dns registration 108 | * netbios - Enable/Disable netbios on the interface. Valid values: true, false, 'dhcp' 109 | 110 | Providers 111 | --------- 112 | 113 | Long name | Short name 114 | ----------|----------- 115 | Chef::Provider::NetworkInterface::Rhel | rhel_network_interface 116 | Chef::Provider::NetworkInterface::Debian | debian_network_interface 117 | Chef::Provider::NetworkInterface::Win | win_network_interface 118 | 119 | Examples 120 | -------- 121 | 122 | Basic example: 123 | ```ruby 124 | network_interface 'eth1' do 125 | bootproto 'static' 126 | address '10.12.10.11' 127 | netmask '255.255.255.0' 128 | gateway '10.12.10.1' 129 | end 130 | ``` 131 | 132 | Two interface DHCP bond0 on rhel family 133 | ```ruby 134 | network_interface 'eth1' do 135 | bootproto 'none' 136 | bond_master 'bond0' 137 | end 138 | 139 | network_interface 'eth2' do 140 | bootproto 'none' 141 | bond_master 'bond0' 142 | end 143 | 144 | network_interface 'bond0' do 145 | bond_mode 'mode=1 miimon=100' 146 | end 147 | ``` 148 | 149 | Two interface DHCP bond0 on debian family 150 | ```ruby 151 | network_interface 'bond0' do 152 | bond_slaves ['eth1', 'eth2'] 153 | bond_mode '0' 154 | end 155 | 156 | network_interface 'eth1' do 157 | bootproto 'manual' 158 | bond_master 'bond0' 159 | end 160 | 161 | network_interface 'eth2' do 162 | bootproto 'manual' 163 | bond_master 'bond0' 164 | end 165 | ``` 166 | 167 | On windows manage device with MAC '00-25-B5-5B-00-25', name it 'eth2', 168 | make it DHCP (default bootproto) and VLAN tagged to VLAN 12 169 | ```ruby 170 | network_interface 'eth2' do 171 | hw_address '00-25-B5-5B-00-25' 172 | vlan 12 173 | end 174 | ``` 175 | 176 | Testing 177 | ======= 178 | Requires [ChefDK](https://downloads.chef.io/chef-dk/) 0.12.0. 179 | 180 | ``` 181 | rubocop 182 | foodcritic -f any -X spec . 183 | rspec --color --format progress 184 | kitchen test 185 | ``` 186 | 187 | License and Authors 188 | =================== 189 | 190 | Author:: Jacob McCann () 191 | 192 | Based on work from https://github.com/redguide/network_interfaces 193 | 194 | ```text 195 | Copyright:: 2015, Target Corporation 196 | 197 | Licensed under the Apache License, Version 2.0 (the "License"); 198 | you may not use this file except in compliance with the License. 199 | You may obtain a copy of the License at 200 | 201 | http://www.apache.org/licenses/LICENSE-2.0 202 | 203 | Unless required by applicable law or agreed to in writing, software 204 | distributed under the License is distributed on an "AS IS" BASIS, 205 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 206 | See the License for the specific language governing permissions and 207 | limitations under the License. 208 | ``` 209 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | 34 | ## COMPILED ## 35 | ############## 36 | a.out 37 | *.o 38 | *.pyc 39 | *.so 40 | *.com 41 | *.class 42 | *.dll 43 | *.exe 44 | */rdoc/ 45 | 46 | # Testing # 47 | ########### 48 | .watchr 49 | .rspec 50 | spec/* 51 | spec/fixtures/* 52 | test/* 53 | features/* 54 | Guardfile 55 | Procfile 56 | 57 | # SCM # 58 | ####### 59 | .git 60 | */.git 61 | .gitignore 62 | .gitmodules 63 | .gitconfig 64 | .gitattributes 65 | .svn 66 | */.bzr/* 67 | */.hg/* 68 | */.svn/* 69 | 70 | # Berkshelf # 71 | ############# 72 | cookbooks/* 73 | tmp 74 | 75 | # Cookbooks # 76 | ############# 77 | CONTRIBUTING 78 | CHANGELOG* 79 | 80 | # Strainer # 81 | ############ 82 | Colanderfile 83 | Strainerfile 84 | .colander 85 | .strainer 86 | 87 | # Vagrant # 88 | ########### 89 | .vagrant 90 | Vagrantfile 91 | 92 | # Travis # 93 | ########## 94 | .travis.yml 95 | -------------------------------------------------------------------------------- /files/default/interfaces: -------------------------------------------------------------------------------- 1 | # This file describes the network interfaces available on your system 2 | # and how to activate them. For more information, see interfaces(5). 3 | 4 | # The loopback network interface 5 | auto lo 6 | iface lo inet loopback 7 | 8 | source /etc/network/interfaces.d/* 9 | -------------------------------------------------------------------------------- /libraries/matchers.rb: -------------------------------------------------------------------------------- 1 | if defined?(ChefSpec) 2 | ChefSpec.define_matcher :network_interface 3 | ChefSpec.define_matcher :rhel_network_interface 4 | ChefSpec.define_matcher :debian_network_interface 5 | ChefSpec.define_matcher :win_network_interface 6 | 7 | def create_network_interface(resource_name) 8 | ChefSpec::Matchers::ResourceMatcher.new(:network_interface, :create, resource_name) 9 | end 10 | 11 | def create_rhel_network_interface(resource_name) 12 | ChefSpec::Matchers::ResourceMatcher.new(:rhel_network_interface, :create, resource_name) 13 | end 14 | 15 | def create_debian_network_interface(resource_name) 16 | ChefSpec::Matchers::ResourceMatcher.new(:debian_network_interface, :create, resource_name) 17 | end 18 | 19 | def create_win_network_interface(resource_name) 20 | ChefSpec::Matchers::ResourceMatcher.new(:win_network_interface, :create, resource_name) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /libraries/provider_debian_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Provider:: debian_network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require 'chef/provider/lwrp_base' 22 | require_relative 'provider_network_interface' 23 | 24 | class Chef 25 | class Provider 26 | class NetworkInterface 27 | # 28 | # Chef Provider for Debian Network Interfaces 29 | # 30 | class Debian < Chef::Provider::NetworkInterface 31 | provides :debian_network_interface, os: 'linux', platform_family: %w(debian) if respond_to?(:provides) 32 | 33 | action :create do 34 | # Manage common network files 35 | directory '/etc/network/interfaces.d' 36 | cookbook_file '/etc/network/interfaces' do 37 | cookbook 'network_interfaces_v2' 38 | end 39 | 40 | # Get vlan module setup if needed 41 | package 'vlan' do 42 | not_if { new_resource.vlan.nil? } 43 | end 44 | kernel_module '8021q' do 45 | not_if { new_resource.vlan.nil? } 46 | end 47 | 48 | # Get bonding module setup if needed 49 | package 'ifenslave-2.6' do 50 | only_if { bond_int? } 51 | end 52 | kernel_module 'bonding' do 53 | only_if { bond_int? } 54 | end 55 | 56 | # Install package for metric if needed 57 | package 'ifmetric' do 58 | not_if { new_resource.metric.nil? } 59 | end 60 | 61 | # Install package for bridging if needed 62 | package 'bridge-utils' do 63 | not_if { new_resource.bridge_ports.nil? } 64 | end 65 | 66 | network_type = new_resource.ipv6 ? 'inet6' : 'inet' 67 | 68 | # Dump config for the interface 69 | template "/etc/network/interfaces.d/#{new_resource.name}" do 70 | cookbook new_resource.cookbook 71 | source new_resource.source 72 | mode 0644 73 | variables device: new_resource.device, 74 | type: new_resource.type, 75 | network_type: network_type, 76 | auto: new_resource.onboot, 77 | hw_address: new_resource.hw_address, 78 | address: new_resource.address, 79 | netmask: new_resource.netmask, 80 | gateway: new_resource.gateway, 81 | dns: new_resource.dns, 82 | broadcast: new_resource.broadcast, 83 | bridge_ports: new_resource.bridge_ports, 84 | bridge_stp: new_resource.bridge_stp, 85 | vlan_dev: new_resource.vlan, 86 | bond_master: new_resource.bond_master, 87 | bond_slaves: new_resource.bond_slaves, 88 | bond_mode: new_resource.bond_mode, 89 | mtu: new_resource.mtu, 90 | metric: new_resource.metric, 91 | pre_up: new_resource.pre_up, 92 | up: new_resource.up, 93 | post_up: new_resource.post_up, 94 | pre_down: new_resource.pre_down, 95 | down: new_resource.down, 96 | post_down: new_resource.post_down, 97 | custom: new_resource.custom 98 | notifies :run, "execute[reload interface #{new_resource.name}]", new_resource.reload_type if new_resource.reload 99 | end 100 | 101 | execute "reload interface #{new_resource.name}" do 102 | command <<-EOF 103 | ifdown #{new_resource.device} -i /etc/network/interfaces.d/#{new_resource.name} 104 | ifup #{new_resource.device} -i /etc/network/interfaces.d/#{new_resource.name} 105 | EOF 106 | action :nothing 107 | end 108 | end 109 | 110 | def bond_int? 111 | !new_resource.bond_master.nil? || !new_resource.bond_slaves.nil? || !new_resource.bond_mode.nil? 112 | end 113 | end 114 | end 115 | end 116 | end 117 | -------------------------------------------------------------------------------- /libraries/provider_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Provider:: network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require 'chef/provider/lwrp_base' 22 | 23 | class Chef 24 | class Provider 25 | # 26 | # Chef Provider for Network Interfaces 27 | # 28 | class NetworkInterface < Chef::Provider::LWRPBase 29 | use_inline_resources if defined?(use_inline_resources) 30 | 31 | action :create do 32 | raise Chef::Exceptions::UnsupportedAction, "#{self} does not support :create" 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /libraries/provider_rhel_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Provider:: rhel_network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require_relative 'provider_network_interface' 22 | 23 | class Chef 24 | class Provider 25 | class NetworkInterface 26 | # 27 | # Chef Provider for RHEL Network Interfaces 28 | # 29 | class Rhel < Chef::Provider::NetworkInterface 30 | provides :rhel_network_interface, os: 'linux', platform_family: %w(rhel fedora) if respond_to?(:provides) 31 | 32 | action :create do 33 | package 'vconfig' do # ~FC005 Not sure why this triggered ... 34 | not_if { new_resource.vlan.nil? } 35 | only_if { node['platform_version'].to_i < 7 } 36 | end 37 | 38 | package 'iputils' do 39 | not_if { new_resource.bond_master.nil? && new_resource.bond_mode.nil? } 40 | end 41 | 42 | package 'bridge-utils' do 43 | not_if { new_resource.bridge_device.nil? } 44 | end 45 | 46 | template "/etc/sysconfig/network-scripts/ifcfg-#{new_resource.device}" do 47 | cookbook new_resource.cookbook 48 | source new_resource.source 49 | mode 0644 50 | variables device: new_resource.device, 51 | type: new_resource.type, 52 | onboot: new_resource.onboot, 53 | bootproto: new_resource.bootproto, 54 | address: new_resource.address, 55 | network: new_resource.network, 56 | netmask: new_resource.netmask, 57 | gateway: new_resource.gateway, 58 | mac_address: new_resource.mac_address, 59 | hw_address: new_resource.hw_address, 60 | broadcast: new_resource.broadcast, 61 | bridge_device: new_resource.bridge_device, 62 | bridge_stp: new_resource.bridge_stp, 63 | vlan: new_resource.vlan, 64 | bond_mode: new_resource.bond_mode, 65 | bond_master: new_resource.bond_master, 66 | nm_controlled: new_resource.nm_controlled, 67 | ipv6init: new_resource.ipv6init, 68 | nozeroconf: new_resource.nozeroconf, 69 | userctl: new_resource.userctl, 70 | peerdns: new_resource.peerdns, 71 | mtu: new_resource.mtu, 72 | devicetype: new_resource.devicetype, 73 | ovs_bridge: new_resource.ovs_bridge, 74 | dns: new_resource.dns, 75 | prefix: new_resource.prefix, 76 | domain: new_resource.dns_domain, 77 | zone: new_resource.zone, 78 | arpcheck: new_resource.arpcheck, 79 | hotplug: new_resource.hotplug, 80 | metric: new_resource.metric, 81 | defroute: new_resource.defroute, 82 | ovsbootproto: new_resource.ovsbootproto, 83 | ovsdhcpinterfaces: new_resource.ovsdhcpinterfaces 84 | notifies :run, "execute[reload interface #{new_resource.device}]", new_resource.reload_type if new_resource.reload 85 | notifies :run, "execute[post up command for #{new_resource.device}]", :immediately unless new_resource.post_up.nil? 86 | end 87 | 88 | execute "reload interface #{new_resource.device}" do 89 | command <<-EOF 90 | ifdown #{new_resource.device} 91 | ifup #{new_resource.device} 92 | EOF 93 | action :nothing 94 | end 95 | 96 | execute "post up command for #{new_resource.device}" do 97 | command new_resource.post_up 98 | action :nothing 99 | end 100 | end 101 | end 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /libraries/provider_win_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Provider:: win_network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require 'chef/provider/lwrp_base' 22 | require_relative 'provider_network_interface' 23 | require_relative 'wmi_helper' 24 | 25 | class Chef 26 | class Provider 27 | class NetworkInterface 28 | # 29 | # Chef Provider for Windows Network Interfaces 30 | # 31 | class Win < Chef::Provider::NetworkInterface 32 | provides :win_network_interface, os: 'windows' if respond_to?(:provides) 33 | 34 | # 35 | # Load current state of defined resource 36 | # 37 | def load_current_resource 38 | @current_resource = Chef::Resource::NetworkInterface::Win.new(@new_resource.name) 39 | @current_resource.name(@new_resource.name) 40 | @current_resource.hw_address(@new_resource.hw_address) 41 | 42 | @current_resource.device(adapter.NetConnectionID) 43 | @current_resource.gateway(nic.DefaultIPGateway.first) unless nic.DefaultIPGateway.nil? 44 | @current_resource.dns(nic.DNSServerSearchOrder) 45 | @current_resource.dns_domain(nic.DNSDomain) 46 | @current_resource.ddns(nic.FullDNSRegistrationEnabled) 47 | 48 | @current_resource.addresses = nic.IPAddress 49 | @current_resource.netmasks = nic.IPSubnet 50 | 51 | case nic.TCPIPNetbiosOptions 52 | when 0 53 | @current_resource.netbios 'dhcp' 54 | when 1 55 | @current_resource.netbios true 56 | when 2 57 | @current_resource.netbios false 58 | end 59 | 60 | case nic.DHCPEnabled 61 | when true 62 | @current_resource.bootproto('dhcp') 63 | else 64 | @current_resource.bootproto('static') 65 | end 66 | 67 | @current_resource 68 | end 69 | 70 | # 71 | # Create action to create/update the resource 72 | # 73 | action :create do 74 | manage_phys_name 75 | manage_vlan 76 | manage_address 77 | manage_dns 78 | manage_netbios 79 | post_updates 80 | end 81 | 82 | private 83 | 84 | # 85 | # Rename physical interface if needed 86 | # 87 | def manage_phys_name 88 | phys_rename unless phys_adapter.NetConnectionID == phys_adapter_name 89 | end 90 | 91 | # 92 | # Manage VLAN as needed 93 | # 94 | def manage_vlan 95 | return if new_resource.vlan.nil? 96 | create_vlan_dev unless vlan_dev_exist? || msft_vlan_dev_exist? 97 | set_vlan unless vlanid_set? || msft_vlan_dev_exist? 98 | rename_vlan_dev if msft_vlan_dev_exist? 99 | load_current_resource # Reload current resource with values from new vlan int 100 | end 101 | 102 | # 103 | # Manage IP addresses as needed 104 | # 105 | def manage_address 106 | enable_dhcp if new_resource.bootproto == 'dhcp' && current_resource.bootproto != 'dhcp' 107 | return unless new_resource.bootproto == 'static' 108 | 109 | config_static unless new_resource.address.nil? || (current_resource.bootproto == 'static' && ip_subnet_exist?) 110 | config_gateway unless new_resource.gateway.nil? || (current_resource.bootproto == 'static' && current_resource.gateway == new_resource.gateway) 111 | end 112 | 113 | # 114 | # Manage DNS as needed 115 | # 116 | def manage_dns 117 | config_dns unless new_resource.dns.nil? || current_resource.dns == new_resource.dns 118 | config_dns_domain unless new_resource.dns_domain.nil? || current_resource.dns_domain == new_resource.dns_domain 119 | config_ddns unless new_resource.ddns.nil? || current_resource.ddns == new_resource.ddns 120 | end 121 | 122 | # 123 | # Manage NetBIOS as needed 124 | # 125 | def manage_netbios 126 | config_netbios unless current_resource.netbios == new_resource.netbios 127 | end 128 | 129 | # 130 | # Manage additional updates after interface has been reconfigured 131 | # 132 | def post_updates 133 | reload if new_resource.updated_by_last_action? && new_resource.reload 134 | post_up(new_resource.post_up) unless new_resource.post_up.nil? || !new_resource.updated_by_last_action? 135 | end 136 | 137 | # 138 | # A WMI instance of the Network Adapter found by MAC 139 | # 140 | # @return [RubyWMI::Win32_NetworkAdapter] 141 | # 142 | def phys_adapter 143 | @phys_adapter ||= begin 144 | a = execute_wmi_query("select * from Win32_NetworkAdapter where #{conditions}") 145 | raise Chef::Exceptions::UnsupportedAction, "Failed to find interface with conditions: #{conditions}" if a.nil? 146 | wmi_object_array(a).first 147 | end 148 | end 149 | 150 | # 151 | # The data structure to search for the interface we want to manage 152 | # 153 | # @return [Hash] 154 | # 155 | def conditions 156 | c = [] 157 | c << "Index='#{new_resource.index}'" unless new_resource.index.nil? 158 | c << "MacAddress='#{new_resource.hw_address}'" unless new_resource.hw_address.nil? 159 | raise Chef::Exceptions::UnsupportedAction, 'Failed to find interface, no conditions provided' if c.empty? 160 | c.join(' AND ') 161 | end 162 | 163 | # 164 | # An WMI instance of the Network Adapter found by name 165 | # 166 | # @return [RubyWMI::Win32_NetworkAdapter] 167 | # 168 | def adapter 169 | a = execute_wmi_query("select * from Win32_NetworkAdapter where NetConnectionID='#{new_resource.device}'") 170 | a = execute_wmi_query("select * from Win32_NetworkAdapter where #{conditions}") if a.nil? 171 | wmi_object_array(a).first 172 | end 173 | 174 | # 175 | # NIC configuration for adapter 176 | # 177 | # @return [RubyWMI::Win32_NetworkAdapterConfiguration] 178 | # 179 | def nic 180 | a = execute_wmi_query("select * from Win32_NetworkAdapterConfiguration where InterfaceIndex='#{adapter.InterfaceIndex}'") 181 | wmi_object_array(a).first 182 | end 183 | 184 | # 185 | # converge_by wrapper 186 | # Adds logging and updating the updated_by_last_action 187 | # 188 | def converge_it(msg, &_block) 189 | converge_by(msg) do 190 | Chef::Log.info msg 191 | yield 192 | new_resource.updated_by_last_action true 193 | end 194 | end 195 | 196 | # 197 | # Check if initial VLAN device exists 198 | # 199 | def vlan_dev_exist? 200 | shell_out = Mixlib::ShellOut.new("powershell.exe -Command \"Get-NetlbfoTeam -Name '#{new_resource.device}'\"") 201 | shell_out.run_command 202 | !shell_out.error? 203 | end 204 | 205 | # 206 | # Check if VLAN device exists with MSFT naming 207 | # 208 | def msft_vlan_dev_exist? 209 | shell_out = Mixlib::ShellOut.new("powershell.exe -Command \"Get-NetlbfoTeamNic -Name '#{new_resource.device} - VLAN #{new_resource.vlan}'\"") 210 | shell_out.run_command 211 | !shell_out.error? 212 | end 213 | 214 | # 215 | # Check if VLANID is set on VLAN device 216 | # 217 | def vlanid_set? 218 | shell_out = Mixlib::ShellOut.new("powershell.exe -Command \"(Get-NetlbfoTeamNic -Name '#{new_resource.device}').VlanID -eq #{new_resource.vlan}\"") 219 | shell_out.run_command 220 | 221 | return false if shell_out.error? 222 | shell_out.stdout.chomp == 'True' 223 | end 224 | 225 | # 226 | # Check if IP/subnet is already configured 227 | # 228 | def ip_subnet_exist? 229 | ip_exist? && subnet_exist? 230 | end 231 | 232 | # 233 | # Chef if IP address is already configured 234 | # 235 | def ip_exist? 236 | return false if current_resource.addresses.nil? 237 | current_resource.addresses.include?(new_resource.address) 238 | end 239 | 240 | # 241 | # Chef if subnet address is already configured 242 | # 243 | def subnet_exist? 244 | return false if current_resource.netmasks.nil? || current_resource.addresses.nil? 245 | current_resource.netmasks[current_resource.addresses.index(new_resource.address)] == new_resource.netmask 246 | end 247 | 248 | # 249 | # Create new VLAN device 250 | # 251 | def create_vlan_dev 252 | converge_it("Create VLAN adapter #{new_resource.device}") do 253 | shell_out = Mixlib::ShellOut.new("powershell.exe -Command \"New-NetlbfoTeam -Name '#{new_resource.device}' -TeamMembers '#{new_resource.device}-NIC' -Confirm:$False\"") 254 | shell_out.run_command 255 | shell_out.error! 256 | end 257 | end 258 | 259 | # 260 | # Set VLAN ID on VLAN device 261 | # 262 | def set_vlan 263 | converge_it("Set VLAN #{new_resource.vlan} on adapter #{new_resource.device}") do 264 | shell_out = Mixlib::ShellOut.new("powershell.exe -Command \"Set-NetLbfoTeamNIC -Name '#{new_resource.device}' -VlanID #{new_resource.vlan}\"") 265 | shell_out.run_command 266 | shell_out.error! 267 | end 268 | end 269 | 270 | # 271 | # Rename VLAN device to name we want from MSFT naming convention 272 | # 273 | def rename_vlan_dev 274 | converge_it("Renaming VLAN dev '#{new_resource.device} - Vlan #{new_resource.vlan}' back to '#{new_resource.device}'") do 275 | shell_out = Mixlib::ShellOut 276 | .new("powershell.exe -Command \"Get-NetAdapter -Name '#{new_resource.device} - Vlan #{new_resource.vlan}' | Rename-NetAdapter -NewName '#{new_resource.device}'\"") 277 | shell_out.run_command 278 | shell_out.error! 279 | end 280 | end 281 | 282 | # 283 | # Enabled DHCP 284 | # 285 | def enable_dhcp 286 | converge_it('Enabling DHCP') do 287 | nic.EnableDhcp 288 | end 289 | end 290 | 291 | # 292 | # Configure NetBIOS 293 | # 294 | def config_netbios 295 | case new_resource.netbios 296 | when true 297 | converge_it('Enabling NetBIOS') do 298 | nic.SetTcpipNetbios(1) 299 | end 300 | when false 301 | converge_it('Disabling NetBIOS') do 302 | nic.SetTcpipNetbios(2) 303 | end 304 | when 'dhcp' 305 | converge_it('Enabling NetBIOS via DHCP') do 306 | nic.SetTcpipNetbios(0) 307 | end 308 | end 309 | end 310 | 311 | # 312 | # Release DHCP addresses 313 | # 314 | def release_dhcp_addresses 315 | converge_it("Released DHCP addresses on #{new_resource.device}") do 316 | nic.ReleaseDHCPLease 317 | end 318 | end 319 | 320 | # 321 | # IPs to set on interface 322 | # Takes existing IPs and adds the wanted IP to the front 323 | # Also removes IPv6 addresses 324 | # 325 | def wanted_ips 326 | ips = [new_resource.address, nic.IPAddress].flatten.compact 327 | 328 | # Return only IPv4 IPs 329 | ips.select { |ip| ip =~ /\./ } 330 | end 331 | 332 | # 333 | # Netmasks to set on interface 334 | # Takes existing netmasks and adds the wanted netmask to the front 335 | # Also removes IPv6 addresses 336 | # 337 | def wanted_netmasks 338 | netmasks = [new_resource.netmask, nic.IPSubnet].flatten.compact 339 | 340 | # Return only IPv4 netmasks 341 | netmasks.select { |ip| ip =~ /\./ } 342 | end 343 | 344 | # 345 | # Configure static address 346 | # 347 | def config_static 348 | release_dhcp_addresses if current_resource.bootproto == 'dhcp' 349 | 350 | converge_it("Set IP to #{new_resource.address}/#{new_resource.netmask}") do 351 | nic.EnableStatic(wanted_ips, wanted_netmasks) 352 | end 353 | end 354 | 355 | # 356 | # Configure gateway 357 | # 358 | def config_gateway 359 | converge_it("Setting gateway to #{new_resource.gateway}") do 360 | nic.SetGateways([new_resource.gateway]) 361 | end 362 | end 363 | 364 | # 365 | # Configure DNS 366 | # 367 | def config_dns 368 | converge_it("Setting DNS to: #{new_resource.dns.inspect}") do 369 | nic.SetDNSServerSearchOrder(new_resource.dns) 370 | end 371 | end 372 | 373 | # 374 | # Configure DNS Domain 375 | # 376 | def config_dns_domain 377 | converge_it("Setting DNS Domain to: #{new_resource.dns_domain}") do 378 | nic.SetDNSDomain(new_resource.dns_domain) 379 | end 380 | end 381 | 382 | # 383 | # Configure dynamic DNS registration 384 | # 385 | def config_ddns 386 | converge_it("#{new_resource.ddns ? 'Enabling' : 'Disabling'} dynamic DNS registration") do 387 | nic.SetDynamicDNSRegistration(new_resource.ddns) 388 | end 389 | end 390 | 391 | # 392 | # Name to set to physical adapter 393 | # Append '-NIC' to physical if tagging on VLANs 394 | # 395 | def phys_adapter_name 396 | new_resource.vlan.nil? ? new_resource.device : "#{new_resource.device}-NIC" 397 | end 398 | 399 | # 400 | # Rename the physical interface 401 | # 402 | def phys_rename 403 | converge_it("Renaming #{phys_adapter.NetConnectionID} to #{phys_adapter_name}") do 404 | phys_adapter.NetConnectionID = phys_adapter_name 405 | phys_adapter.Put_ 406 | end 407 | end 408 | 409 | # 410 | # Disable and Enable the interface 411 | # 412 | def reload 413 | converge_it("Reloading #{new_resource.device}") do 414 | adapter.disable 415 | sleep 5 416 | adapter.enable 417 | end 418 | end 419 | 420 | def post_up(cmd) 421 | shell_out = Mixlib::ShellOut.new("powershell.exe -Command '#{cmd}'") 422 | shell_out.run_command 423 | shell_out.error! 424 | end 425 | end 426 | end 427 | end 428 | end 429 | -------------------------------------------------------------------------------- /libraries/resource_debian_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Resource:: debian_network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require_relative 'resource_network_interface' 22 | 23 | class Chef 24 | class Resource 25 | class NetworkInterface 26 | # 27 | # Chef Resource for a debian_network_interface 28 | # 29 | class Debian < Chef::Resource::NetworkInterface 30 | provides :debian_network_interface 31 | provides :network_interface, os: 'linux', platform_family: %w(debian) if Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.0.0') 32 | provides :network_interface, on_platforms: [:debian, :ubuntu] unless Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.0.0') 33 | 34 | def initialize(name, run_context = nil) 35 | super 36 | @resource_name = :debian_network_interface 37 | @provider = Chef::Provider::NetworkInterface::Debian 38 | 39 | @source = 'debian_interface.erb' 40 | @pre_up = 'sleep 2' 41 | @ipv6 = false 42 | end 43 | 44 | def bridge_ports(arg = nil) 45 | set_or_return(:bridge_ports, arg, kind_of: Array) 46 | end 47 | 48 | def ipv6(arg = nil) 49 | set_or_return(:ipv6, arg, kind_of: [TrueClass, FalseClass]) 50 | end 51 | 52 | def metric(arg = nil) 53 | set_or_return(:metric, arg, kind_of: Integer) 54 | end 55 | 56 | def vlan(arg = nil) 57 | set_or_return(:vlan, arg, kind_of: String) 58 | end 59 | 60 | def bond_slaves(arg = nil) 61 | set_or_return(:bond_slaves, arg, kind_of: Array) 62 | end 63 | 64 | def type(arg = nil) 65 | set_or_return(:type, @bootproto, kind_of: String) if @type.nil? 66 | set_or_return(:type, arg, kind_of: String) 67 | end 68 | 69 | def dns(arg = nil) 70 | set_or_return(:dns, arg, kind_of: [String, Array]) 71 | end 72 | 73 | def pre_up(arg = 'NOVAL') 74 | # Handle 'unsetting' default value with nil or '' 75 | @pre_up = nil if arg.nil? || arg == '' 76 | arg = nil if arg == 'NOVAL' 77 | 78 | set_or_return(:pre_up, arg, kind_of: [String, Array]) 79 | end 80 | 81 | def up(arg = nil) 82 | set_or_return(:up, arg, kind_of: [String, Array]) 83 | end 84 | 85 | def pre_down(arg = nil) 86 | set_or_return(:pre_down, arg, kind_of: [String, Array]) 87 | end 88 | 89 | def down(arg = nil) 90 | set_or_return(:down, arg, kind_of: [String, Array]) 91 | end 92 | 93 | def post_down(arg = nil) 94 | set_or_return(:post_down, arg, kind_of: [String, Array]) 95 | end 96 | 97 | def custom(arg = nil) 98 | set_or_return(:custom, arg, kind_of: [Hash, Array]) 99 | end 100 | end 101 | end 102 | end 103 | end 104 | -------------------------------------------------------------------------------- /libraries/resource_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Resource:: network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require 'chef/resource' 22 | 23 | class Chef 24 | class Resource 25 | # 26 | # Chef Resource for a network_interface 27 | # 28 | class NetworkInterface < Chef::Resource 29 | def initialize(name, run_context = nil) 30 | super 31 | @resource_name = :network_interface 32 | @provider = Chef::Provider::NetworkInterface 33 | @action = :create 34 | @allowed_actions = [:create] 35 | 36 | # This is equivalent to setting :name_attribute => true 37 | @device = name 38 | 39 | @bootproto = 'dhcp' 40 | @onboot = true 41 | @cookbook = 'network_interfaces_v2' 42 | @source = 'ifcfg.erb' 43 | @reload = true 44 | @reload_type = :immediately 45 | end 46 | 47 | def cookbook(arg = nil) 48 | set_or_return(:cookbook, arg, kind_of: String) 49 | end 50 | 51 | def source(arg = nil) 52 | set_or_return(:source, arg, kind_of: String) 53 | end 54 | 55 | def device(arg = nil) 56 | set_or_return(:device, arg, kind_of: String) 57 | end 58 | 59 | def type(arg = nil) 60 | set_or_return(:type, arg, kind_of: String) 61 | end 62 | 63 | def bridge_stp(arg = nil) 64 | set_or_return(:bridge_stp, arg, kind_of: [TrueClass, FalseClass]) 65 | end 66 | 67 | def bond_master(arg = nil) 68 | set_or_return(:bond_master, arg, kind_of: String) 69 | end 70 | 71 | def bond_mode(arg = nil) 72 | set_or_return(:bond_mode, arg, kind_of: String) 73 | end 74 | 75 | def onboot(arg = nil) 76 | set_or_return(:onboot, arg, kind_of: [TrueClass, FalseClass]) 77 | end 78 | 79 | def bootproto(arg = nil) 80 | set_or_return(:bootproto, arg, kind_of: String) 81 | end 82 | 83 | def address(arg = nil) 84 | set_or_return(:address, arg, kind_of: String) 85 | end 86 | 87 | def gateway(arg = nil) 88 | set_or_return(:gateway, arg, kind_of: String) 89 | end 90 | 91 | def mtu(arg = nil) 92 | set_or_return(:mtu, arg, kind_of: Integer) 93 | end 94 | 95 | def netmask(arg = nil) 96 | set_or_return(:mask, arg, kind_of: String) 97 | end 98 | 99 | def broadcast(arg = nil) 100 | set_or_return(:broadcast, arg, kind_of: String) 101 | end 102 | 103 | def reload(arg = nil) 104 | set_or_return(:reload, arg, kind_of: [TrueClass, FalseClass]) 105 | end 106 | 107 | def reload_type(arg = nil) 108 | set_or_return(:reload_type, arg, kind_of: Symbol) 109 | end 110 | 111 | def hw_address(arg = nil) 112 | set_or_return(:hw_address, arg, kind_of: String, regex: /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/) 113 | end 114 | 115 | def vlan(arg = nil) 116 | set_or_return(:vlan, arg, kind_of: [TrueClass, FalseClass, String, Integer]) 117 | end 118 | 119 | def post_up(arg = nil) 120 | set_or_return(:post_up, arg, kind_of: [String, Array]) 121 | end 122 | end 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /libraries/resource_rhel_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Resource:: rhel_network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require_relative 'resource_network_interface' 22 | 23 | class Chef 24 | class Resource 25 | class NetworkInterface 26 | # 27 | # Chef Resource for a rhel_network_interface 28 | # 29 | class Rhel < Chef::Resource::NetworkInterface 30 | provides :rhel_network_interface 31 | provides :network_interface, os: 'linux', platform_family: %w(rhel fedora) if Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.0.0') 32 | provides :network_interface, on_platforms: [:redhat, :centos] unless Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.0.0') 33 | 34 | def initialize(name, run_context = nil) 35 | super 36 | @resource_name = :rhel_network_interface 37 | @provider = Chef::Provider::NetworkInterface::Rhel 38 | 39 | @type = 'Ethernet' 40 | @nm_controlled = false 41 | end 42 | 43 | def nm_controlled(arg = nil) 44 | set_or_return(:nm_controlled, arg, kind_of: [TrueClass, FalseClass]) 45 | end 46 | 47 | def ipv6init(arg = nil) 48 | set_or_return(:ipv6init, arg, kind_of: [TrueClass, FalseClass]) 49 | end 50 | 51 | def nozeroconf(arg = nil) 52 | set_or_return(:nozeroconf, arg, kind_of: [TrueClass, FalseClass]) 53 | end 54 | 55 | def userctl(arg = nil) 56 | set_or_return(:userctl, arg, kind_of: [TrueClass, FalseClass]) 57 | end 58 | 59 | def peerdns(arg = nil) 60 | set_or_return(:peerdns, arg, kind_of: [TrueClass, FalseClass]) 61 | end 62 | 63 | def bridge_device(arg = nil) 64 | set_or_return(:bridge_device, arg, kind_of: String) 65 | end 66 | 67 | def network(arg = nil) 68 | set_or_return(:network, arg, kind_of: String) 69 | end 70 | 71 | def type(arg = nil) 72 | set_or_return(:type, arg, kind_of: String) 73 | end 74 | 75 | def devicetype(arg = nil) 76 | set_or_return(:devicetype, arg, kind_of: String) 77 | end 78 | 79 | def ovs_bridge(arg = nil) 80 | set_or_return(:ovs_bridge, arg, kind_of: String) 81 | end 82 | 83 | def vlan(arg = nil) 84 | set_or_return(:vlan, arg, kind_of: [TrueClass, FalseClass]) 85 | end 86 | 87 | def mac_address(arg = nil) 88 | set_or_return(:mac_address, arg, kind_of: String, regex: /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/) 89 | end 90 | 91 | def dns(arg = nil) 92 | set_or_return(:dns, arg, kind_of: [String, Array]) 93 | end 94 | 95 | def prefix(arg = nil) 96 | set_or_return(:prefix, arg, kind_of: Integer) 97 | end 98 | 99 | def dns_domain(arg = nil) 100 | set_or_return(:dns_domain, arg, kind_of: String) 101 | end 102 | 103 | def zone(arg = nil) 104 | set_or_return(:zone, arg, kind_of: String) 105 | end 106 | 107 | def arpcheck(arg = nil) 108 | set_or_return(:arpcheck, arg, kind_of: [TrueClass, FalseClass]) 109 | end 110 | 111 | def hotplug(arg = nil) 112 | set_or_return(:hotplug, arg, kind_of: [TrueClass, FalseClass]) 113 | end 114 | 115 | def metric(arg = nil) 116 | set_or_return(:metric, arg, kind_of: Integer) 117 | end 118 | 119 | def defroute(arg = nil) 120 | set_or_return(:defroute, arg, kind_of: [TrueClass, FalseClass]) 121 | end 122 | 123 | def ovsbootproto(arg = nil) 124 | set_or_return(:ovsbootproto, arg, kind_of: String) 125 | end 126 | 127 | def ovsdhcpinterfaces(arg = nil) 128 | set_or_return(:ovsdhcpinterfaces, arg, kind_of: [String, Array]) 129 | end 130 | end 131 | end 132 | end 133 | end 134 | -------------------------------------------------------------------------------- /libraries/resource_win_network_interface.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Resource:: win_network_interface 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | require_relative 'resource_network_interface' 22 | 23 | class Chef 24 | class Resource 25 | class NetworkInterface 26 | # 27 | # Chef Resource for a win_network_interface 28 | # 29 | class Win < Chef::Resource::NetworkInterface 30 | provides :win_network_interface 31 | provides :network_interface, os: 'windows' if Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.0.0') 32 | provides :network_interface, on_platforms: :windows unless Gem::Version.new(Chef::VERSION) >= Gem::Version.new('12.0.0') 33 | 34 | attr_accessor :addresses, :netmasks 35 | 36 | def initialize(name, run_context = nil) 37 | super 38 | @resource_name = :win_network_interface 39 | @provider = Chef::Provider::NetworkInterface::Win 40 | 41 | @netbios = 'dhcp' 42 | end 43 | 44 | def hw_address(arg = nil) 45 | arg = arg.tr('-', ':').upcase unless arg.nil? 46 | set_or_return(:hw_address, arg, kind_of: String, regex: /^([0-9A-F]{2}[:-]){5}([0-9A-F]{2})$/) 47 | end 48 | 49 | def index(arg = nil) 50 | set_or_return(:index, arg, kind_of: Integer) 51 | end 52 | 53 | def vlan(arg = nil) 54 | set_or_return(:vlan, arg, kind_of: [Integer, String]) 55 | end 56 | 57 | def dns(arg = nil) 58 | set_or_return(:dns, arg, kind_of: Array) 59 | end 60 | 61 | def dns_domain(arg = nil) 62 | set_or_return(:dns_domain, arg, kind_of: String) 63 | end 64 | 65 | def ddns(arg = nil) 66 | set_or_return(:ddns, arg, kind_of: [TrueClass, FalseClass]) 67 | end 68 | 69 | def netbios(arg = nil) 70 | set_or_return(:netbios, arg, kind_of: [TrueClass, FalseClass, String], equal_to: [true, false, 'dhcp']) 71 | end 72 | end 73 | end 74 | end 75 | end 76 | -------------------------------------------------------------------------------- /libraries/ruby_wmi_ext.rb: -------------------------------------------------------------------------------- 1 | # Do not monkeypatch until RubyWMI has been loaded 2 | if defined?(RubyWMI) 3 | module RubyWMI 4 | class Base 5 | # Monkeypatch to add ability to pass args 6 | def method_missing(name, *args) 7 | name = camelize(name.to_s) 8 | @win32ole_object.send(name, *args) 9 | end 10 | 11 | # Monkeypatch to rename IPAddress to IpAddress to properly call method 12 | def attributes 13 | return @attributes if @attributes 14 | 15 | @attributes = {} 16 | @win32ole_object.properties_.each do |prop| 17 | name = prop.name 18 | name = 'IpAddress' if name == 'IPAddress' 19 | value = @win32ole_object.send(name) 20 | value = if prop.cimtype == 101 && value 21 | Time.parse_swbem_date_time(value) 22 | else 23 | value 24 | end 25 | @attributes[underscore(name)] = value 26 | end 27 | @attributes 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /libraries/wmi_helper.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Adam Edwards () 3 | # 4 | # Copyright:: 2014, Chef Software, Inc. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # http://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | # @see https://github.com/opscode-cookbooks/windows/blob/master/libraries/wmi_helper.rb 19 | # 20 | 21 | if RUBY_PLATFORM =~ /mswin|mingw32|windows/ 22 | require 'win32ole' 23 | 24 | # 25 | # Executes a WQL query and returns an array of WMI objects 26 | # 27 | # @param wmi_query [String] 28 | # 29 | # @return [WIN32OLE, nil] 30 | # 31 | def execute_wmi_query(wmi_query) 32 | wmi = ::WIN32OLE.connect('winmgmts://') 33 | result = wmi.ExecQuery(wmi_query) 34 | return nil unless result.each.count > 0 35 | result 36 | end 37 | 38 | # 39 | # Get property from WMI object 40 | # 41 | # @param wmi_object [??] 42 | # @param wmi_property [String] 43 | # 44 | def wmi_object_property(wmi_object, wmi_property) 45 | wmi_object.send(wmi_property) 46 | end 47 | end 48 | 49 | # 50 | # Return an array of WMI object from ISWbemObjectSet 51 | # 52 | # @param wmi_object [WIN32OLE] WIN32OLE_TYPE:ISWbemObjectSet 53 | # 54 | # @return [Array] 55 | def wmi_object_array(wmi_object) 56 | x = [] 57 | wmi_object.each do |o| 58 | x << o 59 | end 60 | x 61 | end 62 | -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name 'network_interfaces_v2' 2 | maintainer 'Jacob McCann' 3 | maintainer_email 'jacob.mccann2@target.com' 4 | license 'Apache-2.0' 5 | description 'Providers for configuring network on Ubuntu, RHEL, and Windows' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | source_url 'https://github.com/target/network_interfaces_v2-cookbook' 8 | issues_url 'https://github.com/target/network_interfaces_v2-cookbook/issues' 9 | version '2.11.0' 10 | chef_version '>= 12' 11 | 12 | supports 'ubuntu', '>= 14.04' 13 | supports 'windows' 14 | supports 'redhat', '>= 6.0' 15 | supports 'centos', '>= 6.0' 16 | 17 | depends 'kernel_module', '~> 1.0' 18 | depends 'powershell' 19 | -------------------------------------------------------------------------------- /recipes/default.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Jacob McCann () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Recipe:: default 5 | # 6 | # Copyright:: 2015, Target Corporation 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | -------------------------------------------------------------------------------- /recipes/powershell_installer.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Author:: Diego F. Duarte () 3 | # Cookbook Name:: network_interfaces_v2 4 | # Recipe:: powershell_installer.rb 5 | # 6 | # Copyright:: 2015 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | # Confirm whether Windows Update Service is enabled (necessary) 22 | 23 | windows_service 'wuauserv' do 24 | startup_type :automatic 25 | action [:enable, :start] 26 | end 27 | 28 | # Looks for powershell version Start the Powershell/WMF 4.0 install 29 | 30 | include_recipe 'powershell::powershell4' 31 | 32 | reboot 'now' do 33 | action :reboot_now 34 | reason 'Cannot continue Chef run without a reboot.' 35 | delay_mins 2 36 | retry_delay 2 37 | end 38 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_bonding_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::bonding' do 4 | describe 'rhel family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['network_interface']).converge(described_recipe) 7 | end 8 | 9 | it 'installs packages required for bonding config on interface' do 10 | expect(chef_run).to install_package 'iputils' 11 | end 12 | 13 | it 'configures slave devices for bonding' do 14 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth5').with_content('MASTER="bond0"') 15 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth5').with_content('SLAVE="yes"') 16 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth6').with_content('MASTER="bond0"') 17 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth6').with_content('SLAVE="yes"') 18 | end 19 | 20 | it 'configures bond device' do 21 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-bond0').with_content('BONDING_OPTS="mode=1 miimon=100"') 22 | end 23 | end 24 | 25 | describe 'debian family' do 26 | let(:chef_run) do 27 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface', 'network_interface']).converge(described_recipe) 28 | end 29 | 30 | it 'installs packages required for bonding config on interface' do 31 | expect(chef_run).to install_package 'ifenslave-2.6' 32 | end 33 | 34 | it 'loads modules required for bonding config on interface' do 35 | expect(chef_run).to install_kernel_module 'bonding' 36 | end 37 | 38 | it 'configures slave devices for bonding' do 39 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth5').with_content(' bond-master bond0') 40 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth6').with_content(' bond-master bond0') 41 | end 42 | 43 | it 'configures device for bonding' do 44 | expect(chef_run).to render_file('/etc/network/interfaces.d/bond0').with_content(' bond-slaves eth5 eth6') 45 | expect(chef_run).to render_file('/etc/network/interfaces.d/bond0').with_content(' bond-mode 0') 46 | end 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_bridge_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::bridge' do 4 | describe 'rhel family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['rhel_network_interface']).converge(described_recipe) 7 | end 8 | 9 | it 'installs packages required for bridge config on interface' do 10 | expect(chef_run).to install_package 'bridge-utils' 11 | end 12 | 13 | it 'configures interfaces as bridge members' do 14 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth7').with_content('BRIDGE="br0"') 15 | end 16 | end 17 | 18 | describe 'debian family' do 19 | let(:chef_run) do 20 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface']).converge(described_recipe) 21 | end 22 | 23 | it 'installs packages required for vlan config on interface' do 24 | expect(chef_run).to install_package 'bridge-utils' 25 | end 26 | 27 | it 'configures device for bridging' do 28 | expect(chef_run).to render_file('/etc/network/interfaces.d/br0').with_content(' bridge_ports eth7') 29 | end 30 | 31 | it 'disables bridge stp' do 32 | expect(chef_run).to render_file('/etc/network/interfaces.d/br0').with_content(' bridge_stp off') 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_core_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::core' do 4 | context 'when platform_family rhel 6.x' do 5 | cached(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['rhel_network_interface', 'network_interface']).converge(described_recipe) 7 | end 8 | 9 | let(:default_eth0_config_contents) do 10 | '# This file maintained by Chef. DO NOT EDIT! 11 | 12 | DEVICE="eth0" 13 | TYPE="Ethernet" 14 | ONBOOT="yes" 15 | BOOTPROTO="dhcp" 16 | NM_CONTROLLED="no" 17 | ' 18 | end 19 | 20 | let(:default_eth4_config_contents) do 21 | '# This file maintained by Chef. DO NOT EDIT! 22 | 23 | DEVICE="eth4" 24 | TYPE="OVSBridge" 25 | ONBOOT="yes" 26 | BOOTPROTO="none" 27 | IPADDR="10.12.10.11" 28 | PREFIX=24 29 | NETMASK="255.255.255.0" 30 | GATEWAY="10.0.0.1" 31 | NM_CONTROLLED="no" 32 | DEVICETYPE="ovs" 33 | DEFROUTE="no" 34 | ' 35 | end 36 | 37 | it 'does not install any extra packages' do 38 | expect(chef_run).not_to install_package 'vconfig' 39 | expect(chef_run).not_to install_package 'iputils' 40 | expect(chef_run).not_to install_package 'bridge-utils' 41 | end 42 | 43 | context 'for interface eth0 definition' do 44 | it 'creates the interface' do 45 | expect(chef_run).to create_network_interface 'eth0' 46 | expect(chef_run).to create_template '/etc/sysconfig/network-scripts/ifcfg-eth0' 47 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth0').with_content(default_eth0_config_contents) 48 | end 49 | 50 | it 'does not reload interface by default' do 51 | expect(chef_run).not_to run_execute('reload interface eth0') 52 | end 53 | 54 | it 'it reloads the interface after updating the config' do 55 | resource = chef_run.template('/etc/sysconfig/network-scripts/ifcfg-eth0') 56 | expect(resource).to notify('execute[reload interface eth0]').to(:run).immediately 57 | end 58 | 59 | it 'does not run post up by default' do 60 | expect(chef_run).not_to run_execute('post up command for eth0') 61 | end 62 | 63 | it 'does not run post up command after updating config' do 64 | resource = chef_run.template('/etc/sysconfig/network-scripts/ifcfg-eth0') 65 | expect(resource).not_to notify('execute[post up command for eth0]').to(:run).immediately 66 | end 67 | end 68 | 69 | context 'for interface eth4 definition' do 70 | it 'creates the interface' do 71 | expect(chef_run).to create_network_interface 'eth4' 72 | expect(chef_run).to create_template '/etc/sysconfig/network-scripts/ifcfg-eth4' 73 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth4').with_content(default_eth4_config_contents) 74 | end 75 | 76 | it 'does not reload interface by default' do 77 | expect(chef_run).not_to run_execute('reload interface eth4') 78 | end 79 | 80 | it 'it reloads the interface after updating the config' do 81 | resource = chef_run.template('/etc/sysconfig/network-scripts/ifcfg-eth4') 82 | expect(resource).to notify('execute[reload interface eth4]').to(:run).immediately 83 | end 84 | 85 | it 'does not run post up by default' do 86 | resource = chef_run.execute('post up command for eth4') 87 | expect(resource.command).to eq 'sleep 1' 88 | expect(chef_run).not_to run_execute('post up command for eth4') 89 | end 90 | 91 | it 'runs post up command after updating config' do 92 | resource = chef_run.template('/etc/sysconfig/network-scripts/ifcfg-eth4') 93 | expect(resource).to notify('execute[post up command for eth4]').to(:run).immediately 94 | end 95 | end 96 | end 97 | 98 | context 'when platform_family rhel 7.x' do 99 | cached(:chef_run) do 100 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '7.0', step_into: ['rhel_network_interface', 'network_interface']).converge(described_recipe) 101 | end 102 | 103 | let(:default_enp0s4_config_contents) do 104 | '# This file maintained by Chef. DO NOT EDIT! 105 | 106 | DEVICE="enp0s4" 107 | TYPE="OVSBridge" 108 | ONBOOT="yes" 109 | BOOTPROTO="none" 110 | IPADDR="10.12.10.11" 111 | PREFIX=24 112 | NETMASK="255.255.255.0" 113 | GATEWAY="10.0.0.1" 114 | NM_CONTROLLED="no" 115 | DEVICETYPE="ovs" 116 | ZONE="trusted" 117 | ARPCHECK="yes" 118 | HOTPLUG="no" 119 | ' 120 | end 121 | 122 | context 'for interface enp0s4 definition' do 123 | it 'configures firewalld zone' do 124 | expect(chef_run).to create_network_interface 'enp0s4' 125 | expect(chef_run).to create_template '/etc/sysconfig/network-scripts/ifcfg-enp0s4' 126 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-enp0s4').with_content(default_enp0s4_config_contents) 127 | end 128 | end 129 | end 130 | 131 | context 'debian family' do 132 | let(:chef_run) do 133 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface', 'network_interface']).converge(described_recipe) 134 | end 135 | 136 | it 'creates directory for interface config files' do 137 | expect(chef_run).to create_directory '/etc/network/interfaces.d' 138 | end 139 | 140 | it 'replaces main network config file to reference interface configs' do 141 | expect(chef_run).to create_cookbook_file '/etc/network/interfaces' 142 | end 143 | 144 | it 'does not install any extra packages' do 145 | expect(chef_run).not_to install_package 'vlan' 146 | expect(chef_run).not_to install_package 'ifenslave-2.6' 147 | expect(chef_run).not_to install_package 'ifmetric' 148 | expect(chef_run).not_to install_package 'bridge-utils' 149 | end 150 | 151 | it 'does not load any modules' do 152 | expect(chef_run).not_to save_modules '8021q' 153 | expect(chef_run).not_to save_modules 'bonding' 154 | end 155 | 156 | it 'creates interface eth4' do 157 | expect(chef_run).to create_network_interface 'eth4' 158 | end 159 | end 160 | 161 | describe 'windows family' do 162 | let(:chef_run) do 163 | ChefSpec::SoloRunner.new(platform: 'windows', version: '2012R2') do |node| 164 | node.automatic['network']['interfaces'] = { 165 | '0xc' => { 166 | 'addresses' => { 167 | '10.0.2.15' => { 168 | 'prefixlen' => '24', 169 | 'netmask' => '255.255.255.0', 170 | 'broadcast' => '10.0.2.255', 171 | 'family' => 'inet', 172 | }, 173 | 'fe80::e488:b85c:5262:ff86' => { 174 | 'prefixlen' => '64', 175 | 'family' => 'inet6', 176 | 'scope' => 'Link', 177 | }, 178 | '00:25:B5:5B:00:33' => { 179 | 'family' => 'lladdr', 180 | }, 181 | }, 182 | 'configuration' => { 183 | 'arp_always_source_route' => nil, 184 | 'arp_use_ether_snap' => nil, 185 | 'caption' => '[00000010] Intel(R) PRO/1000 MT Desktop Adapter', 186 | 'database_path' => '%SystemRoot%\System32\drivers\etc', 187 | 'dead_gw_detect_enabled' => nil, 188 | 'default_ip_gateway' => [ 189 | '10.0.2.2', 190 | ], 191 | 'default_tos' => nil, 192 | 'default_ttl' => nil, 193 | 'description' => 'Intel(R) PRO/1000 MT Desktop Adapter', 194 | 'dhcp_enabled' => true, 195 | 'dhcp_lease_expires' => '20151015214803.000000-420', 196 | 'dhcp_lease_obtained' => '20151014214803.000000-420', 197 | 'dhcp_server' => '10.0.2.2', 198 | 'dns_domain' => 'target.com', 199 | 'dns_domain_suffix_search_order' => [ 200 | 'test.it.com', 201 | 'target.com', 202 | ], 203 | 'dns_enabled_for_wins_resolution' => false, 204 | 'dns_host_name' => 'vagrant-2012-r2', 205 | 'dns_server_search_order' => [ 206 | '10.97.40.216', 207 | '10.64.40.216', 208 | ], 209 | 'domain_dns_registration_enabled' => false, 210 | 'forward_buffer_memory' => nil, 211 | 'full_dns_registration_enabled' => true, 212 | 'gateway_cost_metric' => [ 213 | 0, 214 | ], 215 | 'igmp_level' => nil, 216 | 'index' => 10, 217 | 'interface_index' => 12, 218 | 'ip_address' => [ 219 | '10.0.2.15', 220 | 'fe80:e488:b85c:5262:ff86', 221 | ], 222 | 'ip_connection_metric' => 10, 223 | 'ip_enabled' => true, 224 | 'ip_filter_security_enabled' => false, 225 | 'ip_port_security_enabled' => nil, 226 | 'ip_sec_permit_ip_protocols' => [ 227 | 228 | ], 229 | 'ip_sec_permit_tcp_ports' => [ 230 | 231 | ], 232 | 'ip_sec_permit_udp_ports' => [ 233 | 234 | ], 235 | 'ip_subnet' => [ 236 | '255.255.255.0', 237 | '64', 238 | ], 239 | 'ip_use_zero_broadcast' => nil, 240 | 'ipx_address' => nil, 241 | 'ipx_enabled' => nil, 242 | 'ipx_frame_type' => nil, 243 | 'ipx_media_type' => nil, 244 | 'ipx_network_number' => nil, 245 | 'ipx_virtual_net_number' => nil, 246 | 'keep_alive_interval' => nil, 247 | 'keep_alive_time' => nil, 248 | 'mac_address' => '08:00:27:D5:9D:5A', 249 | 'mtu' => nil, 250 | 'num_forward_packets' => nil, 251 | 'pmtubh_detect_enabled' => nil, 252 | 'pmtu_discovery_enabled' => nil, 253 | 'service_name' => 'E1G60', 254 | 'setting_id' => '{DD72B02C-4E48-4924-8D0F-F80EA2755534}', 255 | 'tcpip_netbios_options' => 0, 256 | 'tcp_max_connect_retransmissions' => nil, 257 | 'tcp_max_data_retransmissions' => nil, 258 | 'tcp_num_connections' => nil, 259 | 'tcp_use_rfc1122_urgent_pointer' => nil, 260 | 'tcp_window_size' => 64240, 261 | 'wins_enable_lm_hosts_lookup' => true, 262 | 'wins_host_lookup_file' => nil, 263 | 'wins_primary_server' => nil, 264 | 'wins_scope_id' => '', 265 | 'wins_secondary_server' => nil, 266 | }, 267 | 'instance' => { 268 | 'index' => 10, 269 | 'interface_index' => 12, 270 | 'net_connection_id' => 'Ethernet 4', 271 | }, 272 | }, 273 | } 274 | end.converge(described_recipe) 275 | end 276 | 277 | it 'creates interface eth2' do 278 | expect(chef_run).to create_win_network_interface 'eth2' 279 | end 280 | end 281 | 282 | context 'when platform_family debian 6.x' do 283 | cached(:chef_run) do 284 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface', 'network_interface']).converge(described_recipe) 285 | end 286 | 287 | let(:default_eth4_config_contents) do 288 | '# This file maintained by Chef. DO NOT EDIT! 289 | 290 | auto eth4 291 | iface eth4 inet static 292 | address 10.12.10.11 293 | netmask 255.255.255.0 294 | gateway 10.0.0.1 295 | pre-up sleep 2 296 | post-up sleep 1 297 | ' 298 | end 299 | 300 | context 'for interface eth4 definition' do 301 | it 'creates the interface' do 302 | expect(chef_run).to create_network_interface 'eth4' 303 | expect(chef_run).to create_template '/etc/network/interfaces.d/eth4' 304 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth4').with_content(default_eth4_config_contents) 305 | end 306 | end 307 | end 308 | end 309 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_dhcp_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::dhcp' do 4 | describe 'rhel family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['network_interface']).converge(described_recipe) 7 | end 8 | 9 | it 'configure dhcp' do 10 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth1').with_content('BOOTPROTO="dhcp"') 11 | end 12 | end 13 | 14 | describe 'debian family' do 15 | let(:chef_run) do 16 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['network_interface']).converge(described_recipe) 17 | end 18 | 19 | it 'configure dhcp' do 20 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth1').with_content('iface eth1 inet dhcp') 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_dns_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::dns' do 4 | describe 'rhel family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['network_interface']).converge(described_recipe) 7 | end 8 | 9 | it 'configure dns' do 10 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth1').with_content('DNS1="14.14.13.13"') 11 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth1').with_content('DNS2="14.14.14.13"') 12 | end 13 | end 14 | 15 | describe 'debian family' do 16 | let(:chef_run) do 17 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['network_interface']).converge(described_recipe) 18 | end 19 | 20 | it 'configure dns' do 21 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth1').with_content('dns-nameservers 14.14.13.13 14.14.14.13') 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_metrics_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::metrics' do 4 | describe 'debian family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface']).converge(described_recipe) 7 | end 8 | 9 | it 'installs packages required for vlan config on interface' do 10 | expect(chef_run).to install_package 'ifmetric' 11 | end 12 | 13 | it 'configures device for vlan' do 14 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content('metric 25') 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_multiple_int_defs_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::multiple_int_defs' do 4 | context 'debian family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface', 'network_interface']).converge(described_recipe) 7 | end 8 | 9 | context 'eth9 inet4 config' do 10 | it 'does not set ipv6' do 11 | expect(chef_run).to create_network_interface('eth9_inet4').with(ipv6: false) 12 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth9_inet4').with_content ' eth9 inet ' 13 | end 14 | end 15 | 16 | context 'eth9 inet6 config' do 17 | it 'sets ipv6' do 18 | expect(chef_run).to create_network_interface('eth9_inet6').with(ipv6: true) 19 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth9_inet6').with_content ' eth9 inet6 ' 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_override_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::override' do 4 | describe 'rhel family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['rhel_network_interface']) do |node| 7 | node.automatic['platform_family'] = 'rhel' 8 | end.converge(described_recipe) 9 | end 10 | 11 | it 'properly sets type attribtue in config' do 12 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('TYPE="IPsec"') 13 | end 14 | 15 | it 'properly sets bootproto attribtue in config' do 16 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('BOOTPROTO="static"') 17 | end 18 | 19 | it 'properly sets address attribtue in config' do 20 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('IPADDR="12.12.12.12"') 21 | end 22 | 23 | it 'properly sets netmask attribtue in config' do 24 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('NETMASK="255.255.255.0"') 25 | end 26 | 27 | it 'properly sets network attribtue in config' do 28 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('NETWORK="12.12.12.0"') 29 | end 30 | 31 | it 'properly sets broadcast attribtue in config' do 32 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('BROADCAST="12.12.12.255"') 33 | end 34 | 35 | it 'properly sets gateway attribtue in config' do 36 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('GATEWAY="12.12.12.1"') 37 | end 38 | 39 | it 'properly sets bond_master attribtue in config' do 40 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('MASTER="eth0"') 41 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('SLAVE="yes"') 42 | end 43 | 44 | it 'properly sets hw_address attribtue in config' do 45 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('HWADDR="13-13-13-13-13-13"') 46 | end 47 | 48 | it 'properly sets mac_address attribtue in config' do 49 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('MACADDR="12-12-12-12-12-12"') 50 | end 51 | 52 | it 'properly sets bond_mode attribtue in config' do 53 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('BONDING_OPTS="test opts"') 54 | end 55 | 56 | it 'properly sets bridge attribtue in config' do 57 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('BRIDGE="eth0"') 58 | end 59 | 60 | it 'properly sets bridge_stp attribtue in config' do 61 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('STP="no"') 62 | end 63 | 64 | it 'properly sets mtu attribtue in config' do 65 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('MTU="1501"') 66 | end 67 | 68 | it 'properly sets nm_controlled attribtue in config' do 69 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('NM_CONTROLLED="yes"') 70 | end 71 | 72 | it 'properly sets ipv6init attribtue in config' do 73 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('IPV6INIT="no"') 74 | end 75 | 76 | it 'properly sets nozeroconf attribtue in config' do 77 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('NOZEROCONF="yes"') 78 | end 79 | 80 | it 'properly sets userctl attribtue in config' do 81 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('USERCTL="no"') 82 | end 83 | 84 | it 'properly sets peerdns attribtue in config' do 85 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('PEERDNS="yes"') 86 | end 87 | 88 | it 'set dns domain attribtue in config' do 89 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth2').with_content('DOMAIN="example.domain.com"') 90 | end 91 | end 92 | 93 | describe 'debian family' do 94 | let(:chef_run) do 95 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface']).converge(described_recipe) 96 | end 97 | 98 | it 'properly sets address attribtue in config' do 99 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' address 12.12.12.12') 100 | end 101 | 102 | it 'properly sets netmask attribtue in config' do 103 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' netmask 255.255.255.0') 104 | end 105 | 106 | it 'properly sets broadcast attribtue in config' do 107 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' broadcast 12.12.12.255') 108 | end 109 | 110 | it 'properly sets gateway attribtue in config' do 111 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' gateway 12.12.12.1') 112 | end 113 | 114 | it 'properly sets ipv6 attribtue in config' do 115 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content('iface eth2 inet6 static') 116 | end 117 | 118 | it 'properly sets bridge_ports attribtue in config' do 119 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' bridge_ports eth3 eth4') 120 | end 121 | 122 | it 'properly sets bridge_stp attribtue in config' do 123 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' bridge_stp off') 124 | end 125 | 126 | it 'properly sets bond_slaves attribtue in config' do 127 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' bond-slaves eth0 eth1') 128 | end 129 | 130 | it 'properly sets bond_mode attribtue in config' do 131 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' bond-mode test mode') 132 | end 133 | 134 | it 'properly sets mtu attribtue in config' do 135 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' mtu 1501') 136 | end 137 | 138 | it 'properly sets pre_up attribtue in config' do 139 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2') 140 | .with_content(' pre-up 1st pre up code') 141 | .with_content(' pre-up 2nd pre up code') 142 | end 143 | 144 | it 'properly sets up attribtue in config' do 145 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' up code for up') 146 | end 147 | 148 | it 'properly sets post_up attribtue in config' do 149 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' post-up post up it') 150 | end 151 | 152 | it 'properly sets pre_down attribtue in config' do 153 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' pre-down pre down plz') 154 | end 155 | 156 | it 'properly sets down attribtue in config' do 157 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' down coming down') 158 | end 159 | 160 | it 'properly sets post_down attribtue in config' do 161 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' post-down im down') 162 | end 163 | 164 | it 'properly sets custom attribtue in config' do 165 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' abc 123') 166 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth2').with_content(' custom_attr custom_command') 167 | end 168 | end 169 | end 170 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_ovs_dhcp_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::ovs_dhcp' do 4 | context 'when platform_family rhel 6.x' do 5 | cached(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', 7 | step_into: ['rhel_network_interface', 8 | 'network_interface']) 9 | .converge(described_recipe) 10 | end 11 | 12 | let(:default_ovsbr0_config_contents) do 13 | '# This file maintained by Chef. DO NOT EDIT! 14 | 15 | DEVICE="ovsbr0" 16 | TYPE="OVSBridge" 17 | ONBOOT="yes" 18 | BOOTPROTO="none" 19 | NM_CONTROLLED="no" 20 | IPV6INIT="no" 21 | USERCTL="no" 22 | DEVICETYPE="ovs" 23 | ARPCHECK="no" 24 | HOTPLUG="no" 25 | OVSBOOTPROTO="dhcp" 26 | OVSDHCPINTERFACES="eth5" 27 | ' 28 | end 29 | 30 | let(:default_eth5_config_contents) do 31 | '# This file maintained by Chef. DO NOT EDIT! 32 | 33 | DEVICE="eth5" 34 | TYPE="OVSPort" 35 | ONBOOT="yes" 36 | BOOTPROTO="none" 37 | NM_CONTROLLED="no" 38 | IPV6INIT="no" 39 | DEVICETYPE="ovs" 40 | OVS_BRIDGE="ovsbr0" 41 | ' 42 | end 43 | 44 | let(:default_ovsbr1_config_contents) do 45 | '# This file maintained by Chef. DO NOT EDIT! 46 | 47 | DEVICE="ovsbr1" 48 | TYPE="OVSBridge" 49 | ONBOOT="yes" 50 | BOOTPROTO="none" 51 | NM_CONTROLLED="no" 52 | IPV6INIT="no" 53 | USERCTL="no" 54 | DEVICETYPE="ovs" 55 | ARPCHECK="no" 56 | HOTPLUG="no" 57 | OVSBOOTPROTO="dhcp" 58 | OVSDHCPINTERFACES="eth6" 59 | ' 60 | end 61 | 62 | let(:default_eth6_config_contents) do 63 | '# This file maintained by Chef. DO NOT EDIT! 64 | 65 | DEVICE="eth6" 66 | TYPE="OVSPort" 67 | ONBOOT="yes" 68 | BOOTPROTO="none" 69 | NM_CONTROLLED="no" 70 | IPV6INIT="no" 71 | DEVICETYPE="ovs" 72 | OVS_BRIDGE="ovsbr1" 73 | ' 74 | end 75 | 76 | it 'does not install any extra packages' do 77 | expect(chef_run).not_to install_package 'vconfig' 78 | expect(chef_run).not_to install_package 'iputils' 79 | expect(chef_run).not_to install_package 'bridge-utils' 80 | end 81 | 82 | context 'for interface ovsbr0 definition' do 83 | it 'creates the bridge' do 84 | expect(chef_run).to create_network_interface 'ovsbr0' 85 | expect(chef_run).to create_template( 86 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 87 | expect(chef_run).to render_file( 88 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 89 | .with_content(default_ovsbr0_config_contents) 90 | end 91 | 92 | it 'does not reload interface by default' do 93 | expect(chef_run).not_to run_execute('reload interface ovsbr0') 94 | end 95 | 96 | it 'it reloads the interface after updating the config' do 97 | resource = chef_run.template( 98 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 99 | expect(resource).to notify('execute[reload interface ovsbr0]') 100 | .to(:run).immediately 101 | end 102 | 103 | it 'does not run post up by default' do 104 | expect(chef_run).not_to run_execute('post up command for ovsbr0') 105 | end 106 | 107 | it 'does not run post up command after updating config' do 108 | resource = chef_run.template( 109 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 110 | expect(resource).not_to notify('execute[post up command for ovsbr0]') 111 | .to(:run).immediately 112 | end 113 | end 114 | 115 | context 'for interface eth5 definition' do 116 | it 'adds the device to the bridge' do 117 | expect(chef_run).to create_network_interface 'eth5' 118 | expect(chef_run).to create_template( 119 | '/etc/sysconfig/network-scripts/ifcfg-eth5') 120 | expect(chef_run).to render_file( 121 | '/etc/sysconfig/network-scripts/ifcfg-eth5') 122 | .with_content(default_eth5_config_contents) 123 | end 124 | 125 | it 'does not reload interface by default' do 126 | expect(chef_run).not_to run_execute('reload interface eth5') 127 | end 128 | 129 | it 'it reloads the interface after updating the config' do 130 | resource = chef_run.template( 131 | '/etc/sysconfig/network-scripts/ifcfg-eth5') 132 | expect(resource).to notify('execute[reload interface eth5]') 133 | .to(:run).immediately 134 | end 135 | 136 | it 'does not run post up by default' do 137 | expect(chef_run).not_to run_execute('post up command for eth5') 138 | end 139 | 140 | it 'does not run post up command after updating config' do 141 | resource = chef_run.template( 142 | '/etc/sysconfig/network-scripts/ifcfg-eth5') 143 | expect(resource).not_to notify('execute[post up command for eth5]') 144 | .to(:run).immediately 145 | end 146 | end 147 | 148 | context 'for interface ovsbr1 definition' do 149 | it 'creates the bridge' do 150 | expect(chef_run).to create_network_interface 'ovsbr1' 151 | expect(chef_run).to create_template( 152 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 153 | expect(chef_run).to render_file( 154 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 155 | .with_content(default_ovsbr1_config_contents) 156 | end 157 | 158 | it 'does not reload interface by default' do 159 | expect(chef_run).not_to run_execute('reload interface ovsbr1') 160 | end 161 | 162 | it 'it reloads the interface after updating the config' do 163 | resource = chef_run.template( 164 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 165 | expect(resource).to notify('execute[reload interface ovsbr1]') 166 | .to(:run).immediately 167 | end 168 | 169 | it 'does not run post up by default' do 170 | expect(chef_run).not_to run_execute('post up command for ovsbr1') 171 | end 172 | 173 | it 'does not run post up command after updating config' do 174 | resource = chef_run.template( 175 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 176 | expect(resource).not_to notify('execute[post up command for ovsbr1]') 177 | .to(:run).immediately 178 | end 179 | end 180 | 181 | context 'for interface eth6 definition' do 182 | it 'adds the device to the bridge' do 183 | expect(chef_run).to create_network_interface 'eth6' 184 | expect(chef_run).to create_template( 185 | '/etc/sysconfig/network-scripts/ifcfg-eth6') 186 | expect(chef_run).to render_file( 187 | '/etc/sysconfig/network-scripts/ifcfg-eth6') 188 | .with_content(default_eth6_config_contents) 189 | end 190 | 191 | it 'does not reload interface by default' do 192 | expect(chef_run).not_to run_execute('reload interface eth6') 193 | end 194 | 195 | it 'it reloads the interface after updating the config' do 196 | resource = chef_run.template( 197 | '/etc/sysconfig/network-scripts/ifcfg-eth6') 198 | expect(resource).to notify('execute[reload interface eth6]') 199 | .to(:run).immediately 200 | end 201 | 202 | it 'does not run post up by default' do 203 | expect(chef_run).not_to run_execute('post up command for eth6') 204 | end 205 | 206 | it 'does not run post up command after updating config' do 207 | resource = chef_run.template( 208 | '/etc/sysconfig/network-scripts/ifcfg-eth6') 209 | expect(resource).not_to notify('execute[post up command for eth6]') 210 | .to(:run).immediately 211 | end 212 | end 213 | end 214 | 215 | context 'when platform_family rhel 7.x' do 216 | cached(:chef_run) do 217 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '7.0', 218 | step_into: ['rhel_network_interface', 219 | 'network_interface']) 220 | .converge(described_recipe) 221 | end 222 | 223 | let(:default_ovsbr0_config_contents) do 224 | '# This file maintained by Chef. DO NOT EDIT! 225 | 226 | DEVICE="ovsbr0" 227 | TYPE="OVSBridge" 228 | ONBOOT="yes" 229 | BOOTPROTO="none" 230 | NM_CONTROLLED="no" 231 | IPV6INIT="no" 232 | USERCTL="no" 233 | DEVICETYPE="ovs" 234 | ARPCHECK="no" 235 | HOTPLUG="no" 236 | OVSBOOTPROTO="dhcp" 237 | OVSDHCPINTERFACES="enp0s5" 238 | ' 239 | end 240 | 241 | let(:default_enp0s5_config_contents) do 242 | '# This file maintained by Chef. DO NOT EDIT! 243 | 244 | DEVICE="enp0s5" 245 | TYPE="OVSPort" 246 | ONBOOT="yes" 247 | BOOTPROTO="none" 248 | NM_CONTROLLED="no" 249 | IPV6INIT="no" 250 | DEVICETYPE="ovs" 251 | OVS_BRIDGE="ovsbr0" 252 | ' 253 | end 254 | let(:default_ovsbr1_config_contents) do 255 | '# This file maintained by Chef. DO NOT EDIT! 256 | 257 | DEVICE="ovsbr1" 258 | TYPE="OVSBridge" 259 | ONBOOT="yes" 260 | BOOTPROTO="none" 261 | NM_CONTROLLED="no" 262 | IPV6INIT="no" 263 | USERCTL="no" 264 | DEVICETYPE="ovs" 265 | ARPCHECK="no" 266 | HOTPLUG="no" 267 | OVSBOOTPROTO="dhcp" 268 | OVSDHCPINTERFACES="enp0s6" 269 | ' 270 | end 271 | 272 | let(:default_enp0s6_config_contents) do 273 | '# This file maintained by Chef. DO NOT EDIT! 274 | 275 | DEVICE="enp0s6" 276 | TYPE="OVSPort" 277 | ONBOOT="yes" 278 | BOOTPROTO="none" 279 | NM_CONTROLLED="no" 280 | IPV6INIT="no" 281 | DEVICETYPE="ovs" 282 | OVS_BRIDGE="ovsbr1" 283 | ' 284 | end 285 | 286 | context 'for interface ovsbr0 definition' do 287 | it 'creates the bridge' do 288 | expect(chef_run).to create_network_interface 'ovsbr0' 289 | expect(chef_run).to create_template( 290 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 291 | expect(chef_run).to render_file( 292 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 293 | .with_content(default_ovsbr0_config_contents) 294 | end 295 | 296 | it 'does not reload interface by default' do 297 | expect(chef_run).not_to run_execute('reload interface ovsbr0') 298 | end 299 | 300 | it 'it reloads the interface after updating the config' do 301 | resource = chef_run.template( 302 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 303 | expect(resource).to notify('execute[reload interface ovsbr0]') 304 | .to(:run).immediately 305 | end 306 | 307 | it 'does not run post up by default' do 308 | expect(chef_run).not_to run_execute('post up command for ovsbr0') 309 | end 310 | 311 | it 'does not run post up command after updating config' do 312 | resource = chef_run.template( 313 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr0') 314 | expect(resource).not_to notify('execute[post up command for ovsbr0]') 315 | .to(:run).immediately 316 | end 317 | end 318 | 319 | context 'for interface enp0s5 definition' do 320 | it 'adds the device to the bridge' do 321 | expect(chef_run).to create_network_interface 'enp0s5' 322 | expect(chef_run).to create_template( 323 | '/etc/sysconfig/network-scripts/ifcfg-enp0s5') 324 | expect(chef_run).to render_file( 325 | '/etc/sysconfig/network-scripts/ifcfg-enp0s5') 326 | .with_content(default_enp0s5_config_contents) 327 | end 328 | 329 | it 'does not reload interface by default' do 330 | expect(chef_run).not_to run_execute('reload interface enp0s5') 331 | end 332 | 333 | it 'it reloads the interface after updating the config' do 334 | resource = chef_run.template( 335 | '/etc/sysconfig/network-scripts/ifcfg-enp0s5') 336 | expect(resource).to notify('execute[reload interface enp0s5]') 337 | .to(:run).immediately 338 | end 339 | 340 | it 'does not run post up by default' do 341 | expect(chef_run).not_to run_execute('post up command for enp0s5') 342 | end 343 | 344 | it 'does not run post up command after updating config' do 345 | resource = chef_run.template( 346 | '/etc/sysconfig/network-scripts/ifcfg-enp0s5') 347 | expect(resource).not_to notify('execute[post up command for enp0s5]') 348 | .to(:run).immediately 349 | end 350 | end 351 | 352 | context 'for interface ovsbr1 definition' do 353 | it 'creates the bridge' do 354 | expect(chef_run).to create_network_interface 'ovsbr1' 355 | expect(chef_run).to create_template( 356 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 357 | expect(chef_run).to render_file( 358 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 359 | .with_content(default_ovsbr1_config_contents) 360 | end 361 | 362 | it 'does not reload interface by default' do 363 | expect(chef_run).not_to run_execute('reload interface ovsbr1') 364 | end 365 | 366 | it 'it reloads the interface after updating the config' do 367 | resource = chef_run.template( 368 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 369 | expect(resource).to notify('execute[reload interface ovsbr1]') 370 | .to(:run).immediately 371 | end 372 | 373 | it 'does not run post up by default' do 374 | expect(chef_run).not_to run_execute('post up command for ovsbr1') 375 | end 376 | 377 | it 'does not run post up command after updating config' do 378 | resource = chef_run.template( 379 | '/etc/sysconfig/network-scripts/ifcfg-ovsbr1') 380 | expect(resource).not_to notify('execute[post up command for ovsbr1]') 381 | .to(:run).immediately 382 | end 383 | end 384 | 385 | context 'for interface enp0s6 definition' do 386 | it 'adds the device to the bridge' do 387 | expect(chef_run).to create_network_interface 'enp0s6' 388 | expect(chef_run).to create_template( 389 | '/etc/sysconfig/network-scripts/ifcfg-enp0s6') 390 | expect(chef_run).to render_file( 391 | '/etc/sysconfig/network-scripts/ifcfg-enp0s6') 392 | .with_content(default_enp0s6_config_contents) 393 | end 394 | 395 | it 'does not reload interface by default' do 396 | expect(chef_run).not_to run_execute('reload interface enp0s6') 397 | end 398 | 399 | it 'it reloads the interface after updating the config' do 400 | resource = chef_run.template( 401 | '/etc/sysconfig/network-scripts/ifcfg-enp0s6') 402 | expect(resource).to notify('execute[reload interface enp0s6]') 403 | .to(:run).immediately 404 | end 405 | 406 | it 'does not run post up by default' do 407 | expect(chef_run).not_to run_execute('post up command for enp0s6') 408 | end 409 | 410 | it 'does not run post up command after updating config' do 411 | resource = chef_run.template( 412 | '/etc/sysconfig/network-scripts/ifcfg-enp0s6') 413 | expect(resource).not_to notify('execute[post up command for enp0s6]') 414 | .to(:run).immediately 415 | end 416 | end 417 | end 418 | end 419 | -------------------------------------------------------------------------------- /spec/helper_recipes/fake_vlan_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe 'fake::vlan' do 4 | describe 'rhel family' do 5 | let(:chef_run) do 6 | ChefSpec::SoloRunner.new(platform: 'redhat', version: '6.5', step_into: ['rhel_network_interface']) do |node| 7 | node.automatic['platform_family'] = 'rhel' 8 | end.converge(described_recipe) 9 | end 10 | 11 | it 'installs packages required for vlan config on interface' do 12 | expect(chef_run).to install_package 'vconfig' 13 | end 14 | 15 | it 'configures device for vlan' do 16 | expect(chef_run).to render_file('/etc/sysconfig/network-scripts/ifcfg-eth8.12').with_content('VLAN="yes"') 17 | end 18 | end 19 | 20 | describe 'debian family' do 21 | let(:chef_run) do 22 | ChefSpec::SoloRunner.new(platform: 'ubuntu', version: '14.04', step_into: ['debian_network_interface']).converge(described_recipe) 23 | end 24 | 25 | it 'installs packages required for vlan config on interface' do 26 | expect(chef_run).to install_package 'vlan' 27 | end 28 | 29 | it 'loads modules required for vlan config on interface' do 30 | expect(chef_run).to install_kernel_module '8021q' 31 | end 32 | 33 | it 'configures device for vlan' do 34 | expect(chef_run).to render_file('/etc/network/interfaces.d/eth8.12').with_content('vlan-raw-device eth8') 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /spec/libraries/provider_win_network_interface_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | require 'chef/platform' 4 | require 'chef/run_context' 5 | require 'chef/resource' 6 | require 'chef/event_dispatch/base' 7 | require 'chef/event_dispatch/dispatcher' 8 | 9 | require "#{File.join(File.dirname(__FILE__), '..', '..', 'libraries')}/resource_win_network_interface.rb" 10 | require "#{File.join(File.dirname(__FILE__), '..', '..', 'libraries')}/provider_win_network_interface.rb" 11 | 12 | describe Chef::Provider::NetworkInterface::Win do 13 | # Create a provider instance 14 | let(:provider) { Chef::Provider::NetworkInterface::Win.new(new_resource, run_context) } 15 | 16 | # Some Chef stubbing 17 | let(:node) do 18 | node = Chef::Node.new 19 | node 20 | end 21 | let(:events) { Chef::EventDispatch::Dispatcher.new } 22 | let(:run_context) { Chef::RunContext.new(node, {}, events) } 23 | 24 | # Set current_resource and new_resource state 25 | let(:new_resource) do 26 | r = Chef::Resource::NetworkInterface::Win.new('eth1') 27 | r.index 8 28 | r 29 | end 30 | let(:current_resource) do 31 | r = Chef::Resource::NetworkInterface::Win.new('eth1') 32 | r.bootproto 'dhcp' 33 | r 34 | end 35 | 36 | let(:adapter) do 37 | double('WMI::Win32_NetworkAdapter', InterfaceIndex: 10, NetConnectionID: 'eth1', enable: nil, disable: nil) 38 | end 39 | let(:adapter_config) do 40 | double('Win32_NetworkAdapterConfiguration', IPAddress: ['12.13.14.15', '10.10.10.10', 'asdf:asdf:asdf:asdf'], 41 | IPSubnet: ['255.255.254.0', '255.255.255.0', '64'], 42 | DefaultIPGateway: ['10.10.10.1'], 43 | DNSServerSearchOrder: [], 44 | FullDNSRegistrationEnabled: false, 45 | DNSDomainSuffixSearchOrder: [], 46 | DHCPEnabled: false, 47 | DNSDomain: '', 48 | TCPIPNetbiosOptions: 0) 49 | end 50 | 51 | let(:shellout) { double('Mixlib::ShellOut', run_command: nil, error!: nil) } 52 | 53 | # Tie some things together 54 | before do 55 | allow(provider).to receive(:sleep).and_return(nil) # Speed up testing 56 | provider.new_resource = new_resource 57 | provider.current_resource = current_resource 58 | 59 | allow(provider).to receive(:execute_wmi_query).with(/Win32_NetworkAdapter /).and_return([adapter]) 60 | allow(provider).to receive(:execute_wmi_query).with(/Win32_NetworkAdapterConfiguration /).and_return([adapter_config]) 61 | end 62 | 63 | describe '#load_current_resource' do 64 | it 'grabs the correct address' do 65 | provider.load_current_resource 66 | expect(provider.current_resource.addresses).to eq ['12.13.14.15', '10.10.10.10', 'asdf:asdf:asdf:asdf'] 67 | end 68 | 69 | it 'grabs the correct netmask' do 70 | provider.load_current_resource 71 | expect(provider.current_resource.netmasks).to eq ['255.255.254.0', '255.255.255.0', '64'] 72 | end 73 | end 74 | 75 | describe '#action_create' do 76 | it 'renames the physical interface' do 77 | allow(adapter).to receive(:NetConnectionID).and_return('eth0') 78 | current_resource.device 'eth0' 79 | expect(adapter).to receive(:NetConnectionID=).with('eth1') 80 | expect(adapter).to receive(:Put_) 81 | provider.action_create 82 | end 83 | 84 | it 'does not rename a physical adapter with correct name' do 85 | expect(adapter).not_to receive(:NetConnectionID=) 86 | expect(adapter).not_to receive(:Put_) 87 | provider.action_create 88 | end 89 | 90 | it 'configures DHCP on the interface' do 91 | current_resource.bootproto 'static' 92 | expect(adapter_config).to receive(:EnableDhcp) 93 | provider.action_create 94 | end 95 | 96 | it 'does nothing if DHCP is already configured' do 97 | current_resource.bootproto 'dhcp' 98 | expect(adapter_config).not_to receive(:EnableDhcp) 99 | provider.action_create 100 | end 101 | 102 | it 'configures static IP on the interface' do 103 | new_resource.bootproto 'static' 104 | new_resource.address '10.10.10.12' 105 | new_resource.netmask '255.255.254.0' 106 | allow(adapter_config).to receive(:ReleaseDHCPLease) 107 | 108 | expect(adapter_config).to receive(:EnableStatic) 109 | .with(['10.10.10.12', '12.13.14.15', '10.10.10.10'], ['255.255.254.0', '255.255.254.0', '255.255.255.0']) 110 | provider.action_create 111 | end 112 | 113 | it 'releases DHCP address before setting IP' do 114 | new_resource.bootproto 'static' 115 | new_resource.address '10.10.10.12' 116 | new_resource.netmask '255.255.254.0' 117 | 118 | expect(adapter_config).to receive(:ReleaseDHCPLease) 119 | expect(adapter_config).to receive(:EnableStatic) 120 | provider.action_create 121 | end 122 | 123 | it 'does not release DHCP address before setting IP if DHCP is already disabled' do 124 | new_resource.bootproto 'static' 125 | new_resource.address '10.10.10.12' 126 | new_resource.netmask '255.255.254.0' 127 | 128 | current_resource.bootproto 'static' 129 | 130 | expect(adapter_config).not_to receive(:EnableDhcp) 131 | expect(adapter_config).not_to receive(:ReleaseDHCPLease) 132 | expect(adapter_config).to receive(:EnableStatic) 133 | provider.action_create 134 | end 135 | 136 | it 'configures static IP on the interface if IP is wrong' do 137 | current_resource.address '10.10.10.11' 138 | current_resource.netmask '255.255.254.0' 139 | current_resource.bootproto 'static' 140 | 141 | new_resource.bootproto 'static' 142 | new_resource.address '10.10.10.12' 143 | new_resource.netmask '255.255.254.0' 144 | expect(adapter_config).to receive(:EnableStatic) 145 | .with(['10.10.10.12', '12.13.14.15', '10.10.10.10'], ['255.255.254.0', '255.255.254.0', '255.255.255.0']) 146 | provider.action_create 147 | end 148 | 149 | it 'configures static IP on the interface if netmask is wrong' do 150 | current_resource.address '10.10.10.12' 151 | current_resource.netmask '255.255.255.0' 152 | current_resource.bootproto 'static' 153 | 154 | new_resource.bootproto 'static' 155 | new_resource.address '10.10.10.12' 156 | new_resource.netmask '255.255.254.0' 157 | expect(adapter_config).to receive(:EnableStatic) 158 | .with(['10.10.10.12', '12.13.14.15', '10.10.10.10'], ['255.255.254.0', '255.255.254.0', '255.255.255.0']) 159 | provider.action_create 160 | end 161 | 162 | it 'configures static IP on the interface if IP/netmask is correct but currently using DHCP' do 163 | allow(adapter_config).to receive(:ReleaseDHCPLease) 164 | allow(adapter_config).to receive(:EnableStatic) 165 | 166 | current_resource.address '10.10.10.12' 167 | current_resource.addresses = ['10.10.10.12', '12.13.14.15', '10.10.10.10'] 168 | current_resource.netmasks = ['255.255.255.0', '255.255.254.0', '255.255.255.0'] 169 | current_resource.netmask '255.255.255.0' 170 | current_resource.bootproto 'dhcp' 171 | 172 | new_resource.bootproto 'static' 173 | new_resource.address '10.10.10.12' 174 | new_resource.netmask '255.255.255.0' 175 | expect(adapter_config).to receive(:EnableStatic) 176 | .with(['10.10.10.12', '12.13.14.15', '10.10.10.10'], ['255.255.255.0', '255.255.254.0', '255.255.255.0']) 177 | provider.action_create 178 | end 179 | 180 | it 'does not configure static IP if already configured' do 181 | new_resource.bootproto 'static' 182 | new_resource.address '10.10.10.12' 183 | new_resource.netmask '255.255.254.0' 184 | 185 | current_resource.bootproto 'static' 186 | current_resource.addresses = ['12.13.14.15', '10.10.10.12', 'asdf:asdf:asdf:asdf'] 187 | current_resource.netmasks = ['255.255.255.0', '255.255.254.0', '64'] 188 | 189 | expect(adapter_config).not_to receive(:EnableStatic) 190 | provider.action_create 191 | end 192 | 193 | it 'does not configure static IP when DHCP is defined' do 194 | allow(adapter_config).to receive(:EnableDhcp) 195 | 196 | current_resource.bootproto 'static' 197 | expect(adapter_config).not_to receive(:EnableStatic) 198 | provider.action_create 199 | end 200 | 201 | it 'does not configure DHCP when static IP is defined' do 202 | allow(adapter_config).to receive(:ReleaseDHCPLease) 203 | allow(adapter_config).to receive(:EnableStatic) 204 | 205 | new_resource.bootproto 'static' 206 | new_resource.address '10.10.10.12' 207 | new_resource.netmask '255.255.254.0' 208 | 209 | expect(adapter_config).not_to receive(:EnableDhcp) 210 | provider.action_create 211 | end 212 | 213 | it 'configures the gateway' do 214 | new_resource.bootproto 'static' 215 | new_resource.gateway '10.10.10.1' 216 | expect(adapter_config).to receive(:SetGateways).with(['10.10.10.1']) 217 | provider.action_create 218 | end 219 | 220 | it 'does not configure gateway if already properly configured' do 221 | new_resource.bootproto 'static' 222 | new_resource.gateway '10.10.10.1' 223 | current_resource.bootproto 'static' 224 | current_resource.gateway '10.10.10.1' 225 | expect(adapter_config).not_to receive(:SetGateways) 226 | provider.action_create 227 | end 228 | 229 | it 'does not configure gateway with DHCP defined' do 230 | new_resource.gateway '10.10.10.1' 231 | expect(adapter_config).not_to receive(:SetGateways) 232 | provider.action_create 233 | end 234 | 235 | it 'configures DNS' do 236 | current_resource.dns ['10.10.10.10', '10.10.10.11'] 237 | new_resource.dns ['10.10.10.11', '10.10.10.10'] 238 | expect(adapter_config).to receive(:SetDNSServerSearchOrder).with(['10.10.10.11', '10.10.10.10']) 239 | provider.action_create 240 | end 241 | 242 | it 'does nothing if DNS already configured' do 243 | current_resource.dns ['10.10.10.10', '10.10.10.11'] 244 | new_resource.dns ['10.10.10.10', '10.10.10.11'] 245 | expect(adapter_config).not_to receive(:SetDNSServerSearchOrder) 246 | provider.action_create 247 | end 248 | 249 | it 'enables dynamic dns registration' do 250 | new_resource.ddns true 251 | expect(adapter_config).to receive(:SetDynamicDNSRegistration).with(true) 252 | provider.action_create 253 | end 254 | 255 | it 'disables dynamic dns registration' do 256 | new_resource.ddns false 257 | expect(adapter_config).to receive(:SetDynamicDNSRegistration).with(false) 258 | provider.action_create 259 | end 260 | 261 | it 'does nothing if dynamic DNS registration is properly configured' do 262 | new_resource.ddns true 263 | current_resource.ddns true 264 | expect(adapter_config).not_to receive(:SetDynamicDNSRegistration) 265 | provider.action_create 266 | end 267 | 268 | it 'configures DNS domain' do 269 | new_resource.dns_domain 'my_dns_domain.com' 270 | expect(adapter_config).to receive(:SetDNSDomain).with('my_dns_domain.com') 271 | provider.action_create 272 | end 273 | 274 | it 'does nothing if DNS domain is set' do 275 | new_resource.dns_domain 'my_dns_domain.com' 276 | current_resource.dns_domain 'my_dns_domain.com' 277 | expect(adapter_config).not_to receive(:SetDNSDomain) 278 | provider.action_create 279 | end 280 | 281 | it 'reloads interface if changes made' do 282 | allow(adapter_config).to receive(:SetDNSDomain) 283 | new_resource.dns_domain 'my_dns_domain.com' 284 | expect(adapter).to receive(:disable) 285 | expect(adapter).to receive(:enable) 286 | provider.action_create 287 | end 288 | 289 | it 'does not reload interface if no changes made' do 290 | allow(adapter_config).to receive(:SetDNSDomain) 291 | new_resource.dns_domain 'my_dns_domain.com' 292 | current_resource.dns_domain 'my_dns_domain.com' 293 | expect(adapter).not_to receive(:disable) 294 | expect(adapter).not_to receive(:enable) 295 | provider.action_create 296 | end 297 | 298 | it 'does not reloads interface if defined by user' do 299 | allow(adapter_config).to receive(:SetDNSDomain) 300 | new_resource.dns_domain 'my_dns_domain.com' 301 | new_resource.reload false # Defined by user not to reload 302 | expect(adapter).not_to receive(:disable) 303 | expect(adapter).not_to receive(:enable) 304 | provider.action_create 305 | end 306 | 307 | it 'runs post script if changes made' do 308 | allow(adapter_config).to receive(:SetDNSDomain) 309 | new_resource.dns_domain 'my_dns_domain.com' 310 | new_resource.post_up 'test command' 311 | expect(provider) .to receive(:post_up).with('test command').and_call_original 312 | expect(Mixlib::ShellOut).to receive(:new).with("powershell.exe -Command 'test command'").and_return(shellout) 313 | provider.action_create 314 | end 315 | 316 | it 'does not run post script if no changes made' do 317 | allow(adapter_config).to receive(:SetDNSDomain) 318 | new_resource.dns_domain 'my_dns_domain.com' 319 | current_resource.dns_domain 'my_dns_domain.com' 320 | expect(provider).not_to receive(:post_up) 321 | provider.action_create 322 | end 323 | 324 | it 'does run post script if not defined by user' do 325 | allow(adapter_config).to receive(:SetDNSDomain) 326 | new_resource.dns_domain 'my_dns_domain.com' 327 | expect(provider).not_to receive(:post_up) 328 | provider.action_create 329 | end 330 | 331 | describe 'managing vlans' do 332 | let(:adapter) do 333 | double('WMI::Win32_NetworkAdapter', InterfaceIndex: 10, NetConnectionID: 'eth1-NIC', enable: nil, disable: nil) 334 | end 335 | let(:vlan_adapter) do 336 | double('WMI::Win32_NetworkAdapter (VLAN)', InterfaceIndex: 12, NetConnectionID: 'eth1', enable: nil, disable: nil) 337 | end 338 | let(:adapter_config) do 339 | double('Win32_NetworkAdapterConfiguration', IPAddress: ['12.13.14.15', '10.10.10.10', 'asdf:asdf:asdf:asdf'], 340 | IPSubnet: ['255.255.254.0', '255.255.255.0', '64'], 341 | DefaultIPGateway: ['10.10.10.1'], 342 | DNSServerSearchOrder: ['my_dns_domain.com'], 343 | FullDNSRegistrationEnabled: false, 344 | DNSDomainSuffixSearchOrder: [], 345 | DHCPEnabled: true, 346 | DNSDomain: '', 347 | TCPIPNetbiosOptions: 0) 348 | end 349 | let(:vlan_adapter_config) do 350 | double('Win32_NetworkAdapterConfiguration (VLAN)', IPAddress: ['12.13.14.15', '10.10.10.10', 'asdf:asdf:asdf:asdf'], 351 | IPSubnet: ['255.255.254.0', '255.255.255.0', '64'], 352 | DefaultIPGateway: ['10.10.10.1'], 353 | DNSServerSearchOrder: [], 354 | FullDNSRegistrationEnabled: false, 355 | DNSDomainSuffixSearchOrder: [], 356 | DHCPEnabled: true, 357 | DNSDomain: '', 358 | TCPIPNetbiosOptions: 0) 359 | end 360 | 361 | before do 362 | current_resource.device 'eth1-NIC' 363 | new_resource.vlan 12 364 | 365 | allow(provider).to receive(:vlan_dev_exist?).and_return(false) 366 | allow(provider).to receive(:msft_vlan_dev_exist?).and_return(false) 367 | allow(provider).to receive(:vlanid_set?).and_return(false) 368 | 369 | allow(provider).to receive(:create_vlan_dev) 370 | allow(provider).to receive(:set_vlan) 371 | allow(provider).to receive(:rename_vlan_dev) 372 | 373 | allow(provider).to receive(:execute_wmi_query).with(/Win32_NetworkAdapter /).and_return([adapter], [adapter], [vlan_adapter]) 374 | allow(provider).to receive(:execute_wmi_query).with("select * from Win32_NetworkAdapterConfiguration where InterfaceIndex='12'").and_return([vlan_adapter_config]) 375 | end 376 | 377 | it 'appends -NIC to physical adapter name whe configuring VLANs' do 378 | current_resource.device 'eth1' 379 | allow(adapter).to receive(:NetConnectionID).and_return('eth1') 380 | 381 | expect(adapter).to receive(:NetConnectionID=).with('eth1-NIC') 382 | expect(adapter).to receive(:Put_) 383 | provider.action_create 384 | end 385 | 386 | it 'creates a VLAN device' do 387 | expect(provider).to receive(:create_vlan_dev) 388 | provider.action_create 389 | end 390 | 391 | it 'does not create a VLAN device that already exists' do 392 | allow(provider).to receive(:vlan_dev_exist?).and_return(true) 393 | expect(provider).not_to receive(:create_vlan_dev) 394 | provider.action_create 395 | end 396 | 397 | it 'does not create a VLAN device that already exists with MSFT naming' do 398 | allow(provider).to receive(:msft_vlan_dev_exist?).and_return(true) 399 | expect(provider).not_to receive(:create_vlan_dev) 400 | provider.action_create 401 | end 402 | 403 | it 'sets VLAN ID on the device if not set' do 404 | expect(provider).to receive(:set_vlan) 405 | provider.action_create 406 | end 407 | 408 | it 'does not set VLAN ID on a device that has it set and has been renamed' do 409 | allow(provider).to receive(:vlanid_set?).and_return(true) 410 | expect(provider).not_to receive(:set_vlan) 411 | provider.action_create 412 | end 413 | 414 | it 'does not set VLAN ID on a device that has it set with a MSFT naming convention' do 415 | allow(provider).to receive(:msft_vlan_dev_exist?).and_return(true) 416 | expect(provider).not_to receive(:set_vlan) 417 | provider.action_create 418 | end 419 | 420 | it 'renames the VLAN device to what we want' do 421 | allow(provider).to receive(:msft_vlan_dev_exist?).and_return(true) 422 | expect(provider).to receive(:rename_vlan_dev) 423 | provider.action_create 424 | end 425 | 426 | it 'does not rename a properly named VLAN device' do 427 | expect(provider).not_to receive(:rename_vlan_dev) 428 | provider.action_create 429 | end 430 | 431 | it 'configures DNS on the VLAN device' do 432 | new_resource.dns_domain 'my_dns_domain.com' 433 | expect(vlan_adapter_config).to receive(:SetDNSDomain).with('my_dns_domain.com') 434 | provider.action_create 435 | end 436 | end 437 | end 438 | end 439 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'chefspec' 2 | require 'chefspec/berkshelf' 3 | 4 | require_relative 'support/matchers' 5 | 6 | RSpec.configure do |config| 7 | config.log_level = :error 8 | 9 | config.color = true 10 | config.formatter = :documentation 11 | end 12 | 13 | # Add libraries to our LOAD_PATH 14 | $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'libraries')) 15 | 16 | at_exit { ChefSpec::Coverage.report! } unless Object.const_defined?('Guard') 17 | -------------------------------------------------------------------------------- /spec/support/matchers.rb: -------------------------------------------------------------------------------- 1 | ChefSpec.define_matcher :modules 2 | 3 | def save_modules(resource_name) 4 | ChefSpec::Matchers::ResourceMatcher.new(:modules, :save, resource_name) 5 | end 6 | -------------------------------------------------------------------------------- /templates/default/debian_interface.erb: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | <% if @auto -%> 4 | auto <%= @device %> 5 | <% end %> 6 | iface <%= @device %> <%= @network_type %> <%= @type %> 7 | <% if @hw_address -%> 8 | hwaddress <%= @hw_address %> 9 | <% end %> 10 | <% if @address -%> 11 | address <%= @address %> 12 | <% end %> 13 | <% if @netmask -%> 14 | netmask <%= @netmask %> 15 | <% end %> 16 | <% if @broadcast -%> 17 | broadcast <%= @broadcast %> 18 | <% end %> 19 | <% if @gateway -%> 20 | gateway <%= @gateway %> 21 | <% end %> 22 | <% if @dns -%> 23 | dns-nameservers <%= @dns.is_a?(Array) ? @dns.join(' ') : @dns %> 24 | <% end %> 25 | <% if @vlan_dev -%> 26 | vlan-raw-device <%= @vlan_dev %> 27 | <% end %> 28 | <% if @bridge_ports -%> 29 | bridge_ports<% @bridge_ports.each do |port| %> <%= port %><% end %> 30 | <% end %> 31 | <% unless @bridge_stp.nil? -%> 32 | bridge_stp <%= @bridge_stp ? "on" : "off" %> 33 | <% end %> 34 | <% if @bond_master -%> 35 | bond-master <%= @bond_master %> 36 | <% end %> 37 | <% if @bond_slaves -%> 38 | bond-slaves<% @bond_slaves.each do |iface| %> <%= iface %><% end %> 39 | <% end %> 40 | <% if @bond_mode -%> 41 | bond-mode <%= @bond_mode %> 42 | <% end %> 43 | <% if @metric -%> 44 | metric <%= @metric %> 45 | <% end %> 46 | <% if @mtu -%> 47 | mtu <%= @mtu %> 48 | <% end %> 49 | <% # Command block, order matters, so do not use a hash 50 | [ 51 | ['pre-up', @pre_up], 52 | ['up', @up], 53 | ['post-up', @post_up], 54 | ['pre-down', @pre_down], 55 | ['down', @down], 56 | ['post-down', @post_down], 57 | ].each { |c| Array(c[1]).each { |v| -%> 58 | <%= c[0] %> <%= v %> 59 | <% } %> 60 | <% } %> 61 | <% if @custom -%> 62 | <% @custom.sort_by{ |instruc, command| instruc }.each do |instruc, command| -%> 63 | <%= instruc %> <%= command %> 64 | <% end %> 65 | <% end %> 66 | -------------------------------------------------------------------------------- /templates/default/ifcfg.erb: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | DEVICE="<%= @device %>" 4 | TYPE="<%= @type %>" 5 | ONBOOT="<%= @onboot ? 'yes' : 'no' %>" 6 | BOOTPROTO="<%= @bootproto %>" 7 | <% if @bond_master -%> 8 | MASTER="<%= @bond_master %>" 9 | SLAVE="yes" 10 | <% end %> 11 | <% if @address -%> 12 | IPADDR="<%= @address %>" 13 | <% end %> 14 | <% unless @prefix.nil? -%> 15 | PREFIX=<%= @prefix %> 16 | <% end -%> 17 | <% if @netmask -%> 18 | NETMASK="<%= @netmask %>" 19 | <% end %> 20 | <% if @network -%> 21 | NETWORK="<%= @network %>" 22 | <% end %> 23 | <% if @broadcast -%> 24 | BROADCAST="<%= @broadcast %>" 25 | <% end %> 26 | <% if @gateway -%> 27 | GATEWAY="<%= @gateway %>" 28 | <% end %> 29 | <% unless @dns.nil? -%> 30 | <% dns = @dns.is_a?(String) ? [@dns] : @dns -%> 31 | <% dns.each_with_index do |d, i| -%> 32 | DNS<%= i + 1 %>="<%= d %>" 33 | <% end -%> 34 | <% end -%> 35 | <% if @hw_address -%> 36 | HWADDR="<%= @hw_address %>" 37 | <% end %> 38 | <% if @mac_address -%> 39 | MACADDR="<%= @mac_address %>" 40 | <% end %> 41 | <% if @vlan -%> 42 | VLAN="yes" 43 | <% end %> 44 | <% if @bridge_device -%> 45 | BRIDGE="<%= @bridge_device %>" 46 | <% end %> 47 | <% unless @bridge_stp.nil? -%> 48 | STP="<%= @bridge_stp ? 'yes' : 'no' %>" 49 | <% end %> 50 | <% if @bond_mode -%> 51 | BONDING_OPTS="<%= @bond_mode %>" 52 | <% end %> 53 | <% if @mtu -%> 54 | MTU="<%= @mtu %>" 55 | <% end %> 56 | NM_CONTROLLED="<%= @nm_controlled ? 'yes' : 'no' %>" 57 | <% unless @ipv6init.nil? -%> 58 | IPV6INIT="<%= @ipv6init ? 'yes' : 'no' %>" 59 | <% end %> 60 | <% unless @nozeroconf.nil? -%> 61 | NOZEROCONF="<%= @nozeroconf ? 'yes' : 'no' %>" 62 | <% end %> 63 | <% unless @userctl.nil? -%> 64 | USERCTL="<%= @userctl ? 'yes' : 'no' %>" 65 | <% end %> 66 | <% unless @peerdns.nil? -%> 67 | PEERDNS="<%= @peerdns ? 'yes' : 'no' %>" 68 | <% end %> 69 | <% unless @devicetype.nil? -%> 70 | DEVICETYPE="<%= @devicetype %>" 71 | <% end %> 72 | <% unless @ovs_bridge.nil? -%> 73 | OVS_BRIDGE="<%= @ovs_bridge %>" 74 | <% end %> 75 | <% unless @domain.nil? -%> 76 | DOMAIN="<%=@domain%>" 77 | <% end %> 78 | <% unless @zone.nil? -%> 79 | ZONE="<%= @zone %>" 80 | <% end %> 81 | <% unless @arpcheck.nil? -%> 82 | ARPCHECK="<%= @arpcheck ? 'yes' : 'no' %>" 83 | <% end %> 84 | <% unless @hotplug.nil? -%> 85 | HOTPLUG="<%= @hotplug ? 'yes' : 'no' %>" 86 | <% end %> 87 | <% if @metric -%> 88 | METRIC=<%= @metric %> 89 | <% end %> 90 | <% unless @defroute.nil? -%> 91 | DEFROUTE="<%= @defroute ? 'yes' : 'no' %>" 92 | <% end %> 93 | <% if @ovsbootproto -%> 94 | OVSBOOTPROTO="<%= @ovsbootproto %>" 95 | <% end -%> 96 | <% if @ovsdhcpinterfaces -%> 97 | <% if @ovsdhcpinterfaces.is_a?(Array) -%> 98 | OVSDHCPINTERFACES="<%= @ovsdhcpinterfaces.join(' ') %>" 99 | <% else -%> 100 | OVSDHCPINTERFACES="<%= @ovsdhcpinterfaces %>" 101 | <% end -%> 102 | <% end -%> 103 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'fake' 2 | maintainer 'Jacob McCann' 3 | maintainer_email 'jacob.mccann2@target.com' 4 | license 'All rights reserved' 5 | description 'Installs/Configures network_interfaces_v2' 6 | long_description 'Installs/Configures network_interfaces_v2' 7 | version '0.1.0' 8 | 9 | depends 'network_interfaces_v2' 10 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/_core_enp.rb: -------------------------------------------------------------------------------- 1 | # Add additional interface configs 2 | network_interface 'enp0s4' do 3 | bootproto 'none' unless node['platform_family'] == 'debian' 4 | bootproto 'static' if node['platform_family'] == 'debian' 5 | address '10.12.10.11' 6 | gateway node['network']['default_gateway'] 7 | metric 100 8 | netmask '255.255.255.0' 9 | post_up 'sleep 1' 10 | unless node['platform_family'] == 'debian' 11 | arpcheck true 12 | devicetype 'ovs' 13 | hotplug false 14 | onboot true 15 | prefix 24 16 | type 'OVSBridge' 17 | zone 'trusted' 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/_core_eth.rb: -------------------------------------------------------------------------------- 1 | # Make sure we don't wipe out eth0 2 | network_interface 'eth0' 3 | 4 | # Add additional interface configs 5 | network_interface 'eth4' do 6 | bootproto 'none' unless node['platform_family'] == 'debian' 7 | bootproto 'static' if node['platform_family'] == 'debian' 8 | address '10.12.10.11' 9 | gateway node['network']['default_gateway'] 10 | netmask '255.255.255.0' 11 | post_up 'sleep 1' 12 | unless node['platform_family'] == 'debian' 13 | devicetype 'ovs' 14 | onboot true 15 | prefix 24 16 | type 'OVSBridge' 17 | defroute false 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/_core_win.rb: -------------------------------------------------------------------------------- 1 | network_interface 'eth1' do 2 | bootproto 'static' 3 | address '10.12.10.13' 4 | netmask '255.255.255.0' 5 | hw_address '00-25-B5-5B-00-29' 6 | gateway '10.12.10.1' 7 | netbios false 8 | post_up 'sleep 1' 9 | dns ['14.13.13.13', '14.13.13.12'] 10 | end 11 | 12 | # Add an interface config using platform specific provider 13 | win_network_interface 'eth2' do 14 | hw_address '00-25-B5-5B-00-31' 15 | dns ['14.13.13.13', '14.13.13.12'] 16 | ddns false 17 | dns_domain 'test.it.com' 18 | netbios true 19 | end 20 | 21 | int_index = node['network']['interfaces'].select { |_i, d| d['addresses'].keys.include? '00:25:B5:5B:00:33' }.keys.first 22 | index = node['network']['interfaces'][int_index]['configuration']['index'] 23 | 24 | network_interface 'Ethernet 4' do 25 | index index 26 | bootproto 'static' 27 | address node['network']['interfaces'][int_index]['configuration']['ip_address'].first 28 | netmask node['network']['interfaces'][int_index]['configuration']['ip_subnet'].first 29 | end 30 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/_ovs_dhcp_enp.rb: -------------------------------------------------------------------------------- 1 | network_interface 'ovsbr0' do 2 | bootproto 'none' 3 | devicetype 'ovs' 4 | hotplug false 5 | arpcheck false 6 | ipv6init false 7 | nm_controlled false 8 | ovsdhcpinterfaces ['enp0s5'] 9 | ovsbootproto 'dhcp' 10 | type 'OVSBridge' 11 | userctl false 12 | end 13 | network_interface 'enp0s5' do 14 | bootproto 'none' 15 | type 'OVSPort' 16 | ipv6init false 17 | devicetype 'ovs' 18 | ovs_bridge 'ovsbr0' 19 | end 20 | # interfaces as string, not array of string 21 | network_interface 'ovsbr1' do 22 | bootproto 'none' 23 | devicetype 'ovs' 24 | hotplug false 25 | arpcheck false 26 | ipv6init false 27 | nm_controlled false 28 | ovsdhcpinterfaces 'enp0s6' 29 | ovsbootproto 'dhcp' 30 | type 'OVSBridge' 31 | userctl false 32 | end 33 | network_interface 'enp0s6' do 34 | bootproto 'none' 35 | type 'OVSPort' 36 | ipv6init false 37 | devicetype 'ovs' 38 | ovs_bridge 'ovsbr1' 39 | end 40 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/_ovs_dhcp_eth.rb: -------------------------------------------------------------------------------- 1 | network_interface 'ovsbr0' do 2 | bootproto 'none' 3 | devicetype 'ovs' 4 | hotplug false 5 | arpcheck false 6 | ipv6init false 7 | nm_controlled false 8 | ovsdhcpinterfaces ['eth5'] 9 | ovsbootproto 'dhcp' 10 | type 'OVSBridge' 11 | userctl false 12 | end 13 | network_interface 'eth5' do 14 | bootproto 'none' 15 | type 'OVSPort' 16 | ipv6init false 17 | devicetype 'ovs' 18 | ovs_bridge 'ovsbr0' 19 | end 20 | # as String, not Array of String 21 | network_interface 'ovsbr1' do 22 | bootproto 'none' 23 | devicetype 'ovs' 24 | hotplug false 25 | arpcheck false 26 | ipv6init false 27 | nm_controlled false 28 | ovsdhcpinterfaces 'eth6' 29 | ovsbootproto 'dhcp' 30 | type 'OVSBridge' 31 | userctl false 32 | end 33 | network_interface 'eth6' do 34 | bootproto 'none' 35 | type 'OVSPort' 36 | ipv6init false 37 | devicetype 'ovs' 38 | ovs_bridge 'ovsbr1' 39 | end 40 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/bonding.rb: -------------------------------------------------------------------------------- 1 | int5 = 'eth5' 2 | int6 = 'eth6' 3 | 4 | # RHEL/CentOS 7+ or Ubuntu 16.04+ 5 | if (%w(rhel fedora).include?(node['platform_family']) && node['platform_version'].to_i > 6) || 6 | (%w(debian ubuntu).include?(node['platform_family']) && node['platform_version'] >= '16.04') 7 | int5 = 'enp0s5' 8 | int6 = 'enp0s6' 9 | end 10 | 11 | case node['platform_family'] 12 | when 'rhel', 'fedora' 13 | network_interface int5 do 14 | bootproto 'none' 15 | bond_master 'bond0' 16 | end 17 | 18 | network_interface int6 do 19 | bootproto 'none' 20 | bond_master 'bond0' 21 | end 22 | 23 | network_interface 'bond0' do 24 | bootproto 'static' 25 | address '12.12.12.10' 26 | netmask '255.255.255.0' 27 | bond_mode 'mode=1 miimon=100' 28 | end 29 | when 'debian' 30 | network_interface 'bond0' do 31 | bootproto 'static' 32 | address '12.12.12.10' 33 | netmask '255.255.255.0' 34 | bond_slaves [int5, int6] 35 | bond_mode '0' 36 | end 37 | 38 | network_interface int5 do 39 | bootproto 'manual' 40 | bond_master 'bond0' 41 | end 42 | 43 | network_interface int6 do 44 | bootproto 'manual' 45 | bond_master 'bond0' 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/bridge.rb: -------------------------------------------------------------------------------- 1 | int7 = 'eth7' 2 | 3 | # RHEL/CentOS 7+ or Ubuntu 16.04+ 4 | if (%w(rhel fedora).include?(node['platform_family']) && node['platform_version'].to_i > 6) || 5 | (%w(debian ubuntu).include?(node['platform_family']) && node['platform_version'] >= '16.04') 6 | int7 = 'enp0s7' 7 | end 8 | 9 | case node['platform_family'] 10 | when 'rhel', 'fedora' 11 | rhel_network_interface int7 do 12 | bootproto 'none' 13 | bridge_device 'br0' 14 | end 15 | 16 | network_interface 'br0' do 17 | bootproto 'static' 18 | address '13.13.13.10' 19 | netmask '255.255.255.0' 20 | end 21 | when 'debian' 22 | debian_network_interface 'br0' do 23 | bootproto 'static' 24 | address '13.13.13.10' 25 | netmask '255.255.255.0' 26 | bridge_ports [int7] 27 | bridge_stp false 28 | end 29 | 30 | network_interface int7 do 31 | bootproto 'manual' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/core.rb: -------------------------------------------------------------------------------- 1 | if %w(rhel fedora).include? node['platform_family'] 2 | if node['platform_version'].to_i <= 6 3 | include_recipe 'fake::_core_eth' 4 | else 5 | include_recipe 'fake::_core_enp' 6 | end 7 | end 8 | 9 | if %w(debian ubuntu).include? node['platform_family'] 10 | if node['platform_version'] < '16.04' 11 | include_recipe 'fake::_core_eth' 12 | else 13 | include_recipe 'fake::_core_enp' 14 | end 15 | end 16 | 17 | include_recipe 'fake::_core_win' if node['os'] == 'windows' 18 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/default.rb: -------------------------------------------------------------------------------- 1 | include_recipe 'fake::core' 2 | include_recipe 'fake::bonding' 3 | include_recipe 'fake::bridge' 4 | include_recipe 'fake::vlan' 5 | include_recipe 'fake::multiple_int_defs' if %w(debian ubuntu).include?(node['platform_family']) 6 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/dhcp.rb: -------------------------------------------------------------------------------- 1 | network_interface 'eth1' 2 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/dns.rb: -------------------------------------------------------------------------------- 1 | network_interface 'eth1' do 2 | dns ['14.14.13.13', '14.14.14.13'] 3 | end 4 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/metrics.rb: -------------------------------------------------------------------------------- 1 | debian_network_interface 'eth2' do 2 | metric 25 3 | end 4 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/multiple_int_defs.rb: -------------------------------------------------------------------------------- 1 | int9 = 'eth9' 2 | if node['platform_version'] >= '16.04' 3 | int9 = 'enp0s9' 4 | end 5 | 6 | network_interface "#{int9}_inet4" do 7 | device int9 8 | bootproto 'static' if node['platform_family'] == 'debian' 9 | address '10.12.10.19' 10 | gateway node['network']['default_gateway'] 11 | metric 101 12 | netmask '255.255.255.0' 13 | post_up 'sleep 1' 14 | end 15 | 16 | network_interface "#{int9}_inet6" do 17 | ipv6 true 18 | device int9 19 | bootproto 'static' 20 | address 'fe80::202:b3ff:fe1e:8329' 21 | gateway 'fe80::0202:b3ff:fe1e:0' 22 | netmask '64' 23 | post_up 'sleep 1' 24 | end 25 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/override.rb: -------------------------------------------------------------------------------- 1 | case node['platform_family'] 2 | when 'rhel', 'fedora' 3 | rhel_network_interface 'eth2' do 4 | address '12.12.12.12' 5 | network '12.12.12.0' 6 | netmask '255.255.255.0' 7 | broadcast '12.12.12.255' 8 | gateway '12.12.12.1' 9 | bootproto 'static' 10 | type 'IPsec' 11 | bond_master 'eth0' 12 | bond_mode 'test opts' 13 | mac_address '12-12-12-12-12-12' 14 | hw_address '13-13-13-13-13-13' 15 | bridge_device 'eth0' 16 | bridge_stp false 17 | mtu 1501 18 | nm_controlled true 19 | ipv6init false 20 | nozeroconf true 21 | userctl false 22 | peerdns true 23 | dns_domain 'example.domain.com' 24 | end 25 | when 'debian' 26 | debian_network_interface 'eth2' do 27 | address '12.12.12.12' 28 | netmask '255.255.255.0' 29 | broadcast '12.12.12.255' 30 | gateway '12.12.12.1' 31 | bootproto 'static' 32 | ipv6 true 33 | bond_slaves ['eth0', 'eth1'] 34 | bond_mode 'test mode' 35 | bridge_ports ['eth3', 'eth4'] 36 | bridge_stp false 37 | mtu 1501 38 | pre_up ['1st pre up code', '2nd pre up code'] 39 | up 'code for up' 40 | post_up 'post up it' 41 | pre_down 'pre down plz' 42 | down 'coming down' 43 | post_down 'im down' 44 | custom 'custom_attr' => 'custom_command', 45 | 'abc' => '123' 46 | end 47 | end 48 | 49 | network_interface 'eth1' do 50 | address '12.12.12.12' 51 | bootproto 'static' 52 | netmask '255.255.255.0' 53 | broadcast '12.12.12.255' 54 | gateway '12.12.12.1' 55 | bond_mode 'test opts' 56 | bridge_stp false 57 | mtu 1501 58 | end 59 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/ovs_dhcp.rb: -------------------------------------------------------------------------------- 1 | if %(rhel fedora).include? node['platform_family'] 2 | if node['platform_version'].to_i <= 6 3 | include_recipe 'fake::_ovs_dhcp_eth' 4 | else 5 | include_recipe 'fake::_ovs_dhcp_enp' 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/fake/recipes/vlan.rb: -------------------------------------------------------------------------------- 1 | int8 = 'eth8' 2 | 3 | # RHEL/CentOS 7+ or Ubuntu 16.04+ 4 | if (%w(rhel fedora).include?(node['platform_family']) && node['platform_version'].to_i > 6) || 5 | (%w(debian ubuntu).include?(node['platform_family']) && node['platform_version'] >= '16.04') 6 | int8 = 'enp0s8' 7 | end 8 | 9 | case node['platform_family'] 10 | when 'rhel', 'fedora' 11 | rhel_network_interface int8 do 12 | bootproto 'none' 13 | end 14 | 15 | rhel_network_interface "#{int8}.12" do 16 | bootproto 'static' 17 | address '12.12.12.12' 18 | netmask '255.255.255.0' 19 | vlan true 20 | end 21 | when 'debian' 22 | debian_network_interface int8 do 23 | bootproto 'manual' 24 | end 25 | 26 | debian_network_interface "#{int8}.12" do 27 | bootproto 'static' 28 | address '12.12.12.12' 29 | netmask '255.255.255.0' 30 | vlan int8 31 | end 32 | when 'windows' 33 | win_network_interface 'vlan12' do 34 | hw_address '00-25-B5-5B-00-35' 35 | bootproto 'static' 36 | address '12.12.12.14' 37 | netmask '255.255.255.0' 38 | dns ['4.2.2.4', '4.2.2.8'] 39 | vlan 12 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/net_setup/metadata.rb: -------------------------------------------------------------------------------- 1 | name 'net_setup' 2 | maintainer 'Jacob McCann' 3 | maintainer_email 'jacob.mccann2@target.com' 4 | license 'All rights reserved' 5 | description 'Setup additional dummy interfaces' 6 | long_description 'Setup additional dummy interfaces' 7 | version '0.1.0' 8 | -------------------------------------------------------------------------------- /test/fixtures/cookbooks/net_setup/recipes/default.rb: -------------------------------------------------------------------------------- 1 | prefix='eth' 2 | prefix='enp0s' if %w(rhel fedora).include?(node['platform_family']) && node['platform_version'].to_i >= 7 3 | prefix='enp0s' if %w(debian ubuntu).include?(node['platform_family']) && node['platform_version'] >= '16.04' 4 | 5 | (4..9).to_a.each do |n| 6 | execute "add dummy interface #{prefix}#{n}" do 7 | command "ip link add dev #{prefix}#{n} type dummy" 8 | not_if "ip a show dev #{prefix}#{n}" 9 | end 10 | 11 | execute "online #{prefix}#{n}" do 12 | command "ip link set dev #{prefix}#{n} up" 13 | not_if "ip a show dev #{prefix}#{n} | grep UP" 14 | not_if { node['platform_family'] == 'rhel' && node['platform_version'].to_i >= 7 } 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'wmi-lite', platforms: [:mswin, :mingw] 4 | gem 'wmi-lite' if RUBY_PLATFORM =~ /mingw32/ # rubocop:disable Bundler/DuplicatedGem 5 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/bonding_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | unless windows? 4 | describe 'Interface "bond0"' do 5 | it 'should exist' do 6 | expect(bond('bond0')).to exist 7 | end 8 | 9 | it "should include #{int['5']} as a slave" do 10 | expect(bond('bond0').has_interface?(int['5'])).to eq true 11 | end 12 | 13 | it "should include #{int['6']} as a slave" do 14 | expect(bond('bond0').has_interface?(int['6'])).to eq true 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/bridge_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | unless windows? 3 | describe 'Interface "br0"' do 4 | it 'should exist' do 5 | expect(interface('br0')).to exist 6 | end 7 | 8 | it "should include #{int['7']} as an interface" do 9 | expect(command("brctl show br0 | egrep #{int['7']}$").exit_status).to eq 0 10 | end 11 | 12 | it 'should have an address set' do 13 | expect(interface('br0').has_ipv4_address?('13.13.13.10')).to eq true 14 | end 15 | 16 | it 'should have netmask set' do 17 | expect(command('ip addr show dev br0').stdout).to contain '/24 brd ' 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/config_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | if rhel? 4 | describe file("/etc/sysconfig/network-scripts/ifcfg-#{int['4']}") do 5 | it { should be_file } 6 | its(:content) { should eq File.read File.join(File.dirname(__FILE__), 'fixtures', "ifcfg-#{int['4']}") } 7 | end 8 | end 9 | 10 | if debian? 11 | describe file("/etc/network/interfaces.d/#{int['4']}") do 12 | it { should be_file } 13 | its(:content) { should eq File.read File.join(File.dirname(__FILE__), 'fixtures', int['4']) } 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/enp0s4: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | auto enp0s4 4 | iface enp0s4 inet static 5 | address 10.12.10.11 6 | netmask 255.255.255.0 7 | gateway 10.0.2.2 8 | metric 100 9 | pre-up sleep 2 10 | post-up sleep 1 11 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/eth0: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | auto eth0 4 | iface eth0 inet dhcp 5 | pre-up sleep 2 6 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/eth4: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | auto eth4 4 | iface eth4 inet static 5 | address 10.12.10.11 6 | netmask 255.255.255.0 7 | gateway 10.0.2.2 8 | pre-up sleep 2 9 | post-up sleep 1 10 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/ifcfg-enp0s3: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | DEVICE="enp0s3" 4 | TYPE="Ethernet" 5 | ONBOOT="yes" 6 | BOOTPROTO="dhcp" 7 | NM_CONTROLLED="no" 8 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/ifcfg-enp0s4: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | DEVICE="enp0s4" 4 | TYPE="OVSBridge" 5 | ONBOOT="yes" 6 | BOOTPROTO="none" 7 | IPADDR="10.12.10.11" 8 | PREFIX=24 9 | NETMASK="255.255.255.0" 10 | GATEWAY="10.0.2.2" 11 | NM_CONTROLLED="no" 12 | DEVICETYPE="ovs" 13 | ZONE="trusted" 14 | ARPCHECK="yes" 15 | HOTPLUG="no" 16 | METRIC=100 17 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/ifcfg-eth0: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | DEVICE="eth0" 4 | TYPE="Ethernet" 5 | ONBOOT="yes" 6 | BOOTPROTO="dhcp" 7 | NM_CONTROLLED="no" 8 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/fixtures/ifcfg-eth4: -------------------------------------------------------------------------------- 1 | # This file maintained by Chef. DO NOT EDIT! 2 | 3 | DEVICE="eth4" 4 | TYPE="OVSBridge" 5 | ONBOOT="yes" 6 | BOOTPROTO="none" 7 | IPADDR="10.12.10.11" 8 | PREFIX=24 9 | NETMASK="255.255.255.0" 10 | GATEWAY="10.0.2.2" 11 | NM_CONTROLLED="no" 12 | DEVICETYPE="ovs" 13 | DEFROUTE="no" 14 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/interfaces_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | unless windows? 4 | describe "Interface '#{int['0']}'" do 5 | it 'should exist' do 6 | expect(interface(int['0'])).to exist 7 | end 8 | 9 | it 'should have DHCP enabled' do 10 | expect(command('ps -ef | grep dhclient | grep -v grep').stdout).to contain(/[-\.]#{int['0']}./) 11 | end 12 | end 13 | 14 | describe "Interface '#{int['4']}'" do 15 | it 'should exist' do 16 | expect(interface(int['4'])).to exist 17 | end 18 | 19 | it 'should have DHCP disabled' do 20 | expect(command('ps -ef | grep dhclient | grep -v grep').stdout).not_to contain(/[-\.]#{int['4']}./) 21 | end 22 | 23 | it 'should have an address' do 24 | expect(interface(int['4']).has_ipv4_address?('10.12.10.11')).to eq true 25 | end 26 | 27 | it 'should have netmask "255.255.255.0"' do 28 | expect(command("ip addr show dev #{int['4']}").stdout).to contain '/24 brd ' 29 | end 30 | end 31 | 32 | if debian? 33 | describe "Interface '#{int['9']}'" do 34 | it 'should have an ipv4 address' do 35 | expect(interface(int['9']).has_ipv4_address?('10.12.10.19')).to eq true 36 | end 37 | 38 | it 'should have ipv4 netmask' do 39 | expect(command("ip addr show dev #{int['9']}").stdout).to contain '/24 brd ' 40 | end 41 | 42 | it 'should have an ipv6 address' do 43 | expect(interface(int['9']).has_ipv6_address?('fe80::202:b3ff:fe1e:8329')).to eq true 44 | end 45 | 46 | it 'should have ipv6 netmask' do 47 | expect(command("ip addr show dev #{int['9']}").stdout).to contain 'fe80::202:b3ff:fe1e:8329/64 scope' 48 | end 49 | end 50 | end 51 | end 52 | 53 | if windows? 54 | describe 'Interface "eth1"' do 55 | it 'should exist' do 56 | expect(win_interface('eth1')).not_to be_nil 57 | end 58 | 59 | it 'should have DHCP disabled' do 60 | expect(win_interface_config('eth1')['dhcpenabled']).to eq false 61 | end 62 | 63 | # Get index in array of our found IP ... so we can match proper subnet later 64 | addr_indx = win_interface_config('eth1')['ipaddress'].index('10.12.10.13') 65 | 66 | it 'should have address "10.12.10.13"' do 67 | expect(win_interface_config('eth1')['ipaddress']).to include '10.12.10.13' 68 | end 69 | 70 | it 'should have netmask "255.255.255.0"' do 71 | subnet_ip = nil 72 | subnet_ip = win_interface_config('eth1')['ipsubnet'][addr_indx] unless addr_indx.nil? 73 | expect(subnet_ip).to eq '255.255.255.0' 74 | end 75 | 76 | it 'should have gateway "10.12.10.1"' do 77 | expect(win_interface_config('eth1')['defaultipgateway'].first).to eq '10.12.10.1' 78 | end 79 | 80 | it 'should have NetBIOS disabled' do 81 | expect(win_interface_config('eth1')['tcpipnetbiosoptions']).to eq 2 82 | end 83 | end 84 | 85 | describe 'Interface "eth2"' do 86 | it 'should exist' do 87 | expect(win_interface('eth2')).not_to be_nil 88 | end 89 | 90 | it 'should have DHCP enabled' do 91 | expect(win_interface_config('eth2')['dhcpenabled']).to eq true 92 | end 93 | 94 | it 'should have DNS servers assigned' do 95 | expect(win_interface_config('eth2')['dnsserversearchorder']).to eq ['14.13.13.13', '14.13.13.12'] 96 | end 97 | 98 | it 'should have DNS domain set' do 99 | expect(win_interface_config('eth2')['dnsdomain']).to eq 'test.it.com' 100 | end 101 | 102 | it 'should have NetBIOS enabled' do 103 | expect(win_interface_config('eth2')['tcpipnetbiosoptions']).to eq 1 104 | end 105 | end 106 | 107 | describe 'Interface "Ethernet 4"' do 108 | it 'should have DHCP disabled' do 109 | expect(win_interface_config('Ethernet 4')['dhcpenabled']).to eq false 110 | end 111 | 112 | it 'should have an address' do 113 | expect(win_interface_config('Ethernet 4')['ipaddress'].first).to match(/172.28.128.[0-9]+/) 114 | end 115 | 116 | it 'should have netmask "255.255.255.0"' do 117 | expect(win_interface_config('Ethernet 4')['ipsubnet'].first).to eq '255.255.255.0' 118 | end 119 | end 120 | end 121 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | 3 | def windows? 4 | !(RUBY_PLATFORM =~ /mswin|mingw32|windows/).nil? 5 | end 6 | 7 | def wmi 8 | @wmi ||= WmiLite::Wmi.new 9 | end 10 | 11 | def net_adapters 12 | @adapters ||= wmi.instances_of('Win32_NetworkAdapter') 13 | end 14 | 15 | def adapter_configs 16 | @adapter_configs ||= wmi.instances_of('Win32_NetworkAdapterConfiguration') 17 | end 18 | 19 | def debian? 20 | File.exist? '/etc/debian_version' 21 | end 22 | 23 | def rhel? 24 | File.exist? '/etc/redhat-release' 25 | end 26 | 27 | def rhel_version 28 | File.read('/etc/redhat-release').gsub(/.* ([\.0-9]+).*/, '\1').chomp 29 | end 30 | 31 | def ubuntu_version 32 | `lsb_release -r -s` 33 | end 34 | 35 | def win_interface(name) 36 | net_adapters.find { |n| n['netconnectionid'] == name } 37 | end 38 | 39 | def win_interface_config(name) 40 | adapter_configs.find { |n| n['interfaceindex'] == win_interface(name)['interfaceindex'] } 41 | end 42 | 43 | def prefix 44 | return 'enp0s' if rhel? && rhel_version.split('.').first.to_i > 6 45 | return 'enp0s' if !rhel? && ubuntu_version.to_s >= '16.04' 46 | 'eth' 47 | end 48 | 49 | def int 50 | @int ||= begin 51 | int = {} 52 | int['0'] = 'eth0' 53 | int['0'] = 'enp0s3' if rhel? && rhel_version.split('.').first.to_i > 6 54 | int['0'] = 'enp0s3' if !rhel? && ubuntu_version.to_s >= '16.04' 55 | (4..9).each do |n| 56 | int[n.to_s] = "#{prefix}#{n}" 57 | end 58 | int 59 | end 60 | end 61 | 62 | # NIX? 63 | set :backend, :exec unless windows? 64 | 65 | # Windows 66 | require 'wmi-lite' if windows? 67 | set :backend, :cmd if windows? 68 | set :os, family: 'windows' if windows? 69 | -------------------------------------------------------------------------------- /test/integration/default/serverspec/vlan_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | unless windows? 4 | describe "Interface '#{int['8']}'" do 5 | it 'should exist' do 6 | expect(interface(int['8'])).to exist 7 | end 8 | 9 | it 'should have DHCP disabled' do 10 | expect(command('ps -ef | grep dhclient | grep -v grep').stdout).not_to contain(/[-\.]#{int['8']}\./) 11 | end 12 | end 13 | 14 | describe "Interface '#{int['8']}.12'" do 15 | it 'should exist' do 16 | expect(interface("#{int['8']}.12")).to exist 17 | end 18 | 19 | it 'should have DHCP disabled' do 20 | expect(command('ps -ef | grep dhclient | grep -v grep').stdout).not_to contain(/[-\.]#{int['8']}\.12\./) 21 | end 22 | 23 | it 'should have an address' do 24 | expect(interface("#{int['8']}.12").has_ipv4_address?('12.12.12.12')).to eq true 25 | end 26 | 27 | it 'should have netmask "255.255.255.0"' do 28 | expect(command("ip addr show dev #{int['8']}.12").stdout).to contain '/24 brd ' 29 | end 30 | end 31 | end 32 | 33 | if windows? 34 | describe 'Interface "vlan12"' do 35 | it 'should exist' do 36 | expect(win_interface('vlan12')).not_to be_nil 37 | end 38 | 39 | it 'should have DHCP disabled' do 40 | expect(win_interface_config('vlan12')['dhcpenabled']).to eq false 41 | end 42 | 43 | it 'should have VLAN set' do 44 | expect(command("(Get-NetLbfoTeamNic -name 'vlan12').VlanID").stdout.chomp).to eq '12' 45 | end 46 | 47 | it 'should have address "12.12.12.14"' do 48 | expect(win_interface_config('vlan12')['ipaddress'].first).to eq '12.12.12.14' 49 | end 50 | 51 | it 'should have netmask "255.255.255.0"' do 52 | expect(win_interface_config('vlan12')['ipsubnet'].first).to eq '255.255.255.0' 53 | end 54 | 55 | it 'should have DNS servers assigned' do 56 | expect(win_interface_config('vlan12')['dnsserversearchorder']).to eq ['4.2.2.4', '4.2.2.8'] 57 | end 58 | end 59 | end 60 | --------------------------------------------------------------------------------