|
| 1 | +fb_networkmanager Cookbook |
| 2 | +============================ |
| 3 | +An attribute-driven API to configure Network Manager |
| 4 | + |
| 5 | +Requirements |
| 6 | +------------ |
| 7 | + |
| 8 | +Attributes |
| 9 | +---------- |
| 10 | +* node['fb_networkmanager']['config'] |
| 11 | +* node['fb_networkmanager']['enable'] |
| 12 | +* node['fb_networkmanager']['system_connections'] |
| 13 | +* node['fb_networkmanager']['system_connections'][$NAME]['_defaults'] |
| 14 | +* node['fb_networkmanager']['system_connections'][$NAME]['_migrate_from'] |
| 15 | +* node['fb_networkmanater']['extra_packages'] |
| 16 | +* node['fb_networkmanater']['manage_packages'] |
| 17 | + |
| 18 | +Usage |
| 19 | +----- |
| 20 | +### Packages |
| 21 | + |
| 22 | +By default this cookbook will install the network-manager package for your |
| 23 | +platform. If you intend to make connections that require optional packages, |
| 24 | +such as VPN connections, you can add the necessary packages to the array in |
| 25 | +`node['fb_networkmanater']['extra_packages']` so that they will be installed |
| 26 | +early enough. |
| 27 | + |
| 28 | +If you'd prefer to manage packages yourself you may set |
| 29 | +`node['fb_networkmanater']['manage_packages']` to `false`. |
| 30 | + |
| 31 | +### Config |
| 32 | + |
| 33 | +The global config (`/etc/NetworkManager/NetworkManager.conf`), is controlled |
| 34 | +by the `config` hash. It's a two-level hash where the top-level is INI section |
| 35 | +names and the second level is key-value pairs for the options in that section. |
| 36 | + |
| 37 | +For example: |
| 38 | + |
| 39 | +```ruby |
| 40 | +node.default['fb_networkmanager']['config']['main']['foo'] = 'bar' |
| 41 | +``` |
| 42 | + |
| 43 | +would render as: |
| 44 | + |
| 45 | +```text |
| 46 | +[main] |
| 47 | +foo=bar |
| 48 | +``` |
| 49 | + |
| 50 | +The default config is based on the Ubuntu config but should be safe for all |
| 51 | +distros. |
| 52 | + |
| 53 | +### System Connections |
| 54 | + |
| 55 | +Network Manager unfortunately uses the files in the `system-connections` folder |
| 56 | +as a data store about those networks. This means they can change out from under |
| 57 | +you as it addds its own information. For example, for WiFi entries, it can add |
| 58 | +BSSIDs it has seen to the file. |
| 59 | + |
| 60 | +As such using the desired config to populate a template is not sufficient - this |
| 61 | +would both lose data that Network Manager wants and also cause a lot of |
| 62 | +unnecessary resource firing. |
| 63 | + |
| 64 | +To work around this scenario, this cookbook loads in the existing file, merges |
| 65 | +in the desired config, and then checks to see if the resulting contents are |
| 66 | +different from just the loaded file. If the values would not change, then we do |
| 67 | +not write out the new config. If the values are different, then we write out |
| 68 | +the merged config. Since Network Manager can write out values in a different |
| 69 | +order or with different spacing, we dont' compare the actual files, but instead |
| 70 | +the parsed data. We leverage IniParse for reading and writing INI files since |
| 71 | +it is bundled with Chef. |
| 72 | + |
| 73 | +All that said, the system_connections hash works a lot like the `config` hash, |
| 74 | +except there's an extra level for each connection. For example: |
| 75 | + |
| 76 | +```ruby |
| 77 | +node.default['fb_networkmanager']['system-connections']['mywifi'] = { |
| 78 | + 'connection' => { |
| 79 | + 'type' => 'wifi', |
| 80 | + 'id' => 'Cool Wifi', |
| 81 | + 'uuid' => '...', |
| 82 | + }, |
| 83 | + 'wifi' => { |
| 84 | + 'mode' => 'infrastructure', |
| 85 | + 'ssid' => 'Cool Wifi', |
| 86 | + }, |
| 87 | + 'wifi-security' => { |
| 88 | + 'auth-alg' => 'open', |
| 89 | + 'key-mgmt' => 'wpa-psk', |
| 90 | + 'psk' => 'SuperS3kr1t', |
| 91 | + }, |
| 92 | +} |
| 93 | +``` |
| 94 | + |
| 95 | +Would create `/etc/NetworkManager/system-connections/fb_networkmanager_mywifi` |
| 96 | +with this content: |
| 97 | + |
| 98 | +```text |
| 99 | +[connection] |
| 100 | +id=Cool Wifi |
| 101 | +uuid=... |
| 102 | +type=wifi |
| 103 | +
|
| 104 | +[wifi] |
| 105 | +mode=infrastructure |
| 106 | +ssid=Cool Wifi |
| 107 | +
|
| 108 | +[wifi-security] |
| 109 | +auth-alg=open |
| 110 | +key-mgmt=wpa-psk |
| 111 | +psk=SuperS3kr1t |
| 112 | +``` |
| 113 | + |
| 114 | +Note that all files we make are prefixed with `fb_networkmanager`, so that we |
| 115 | +can cleanup files we created that are no longer in the config. |
| 116 | + |
| 117 | +### A note on booleans |
| 118 | + |
| 119 | +It is worth noting that various plugins and parts of the config expect |
| 120 | +different kinds of booleans - some `true` and `false`, others `yes` and `no`. |
| 121 | +Normally, an FB Attribute API cookbook would take a true ruby boolean and |
| 122 | +convert it to the appropriate string for a system, but since it's not |
| 123 | +consistent across NM, we leave it to the user to specify the right one for the |
| 124 | +right value. This is true both in `config` and in `system_connections`. |
| 125 | + |
| 126 | +### A note on UUIDs |
| 127 | + |
| 128 | +We generally recommend coming up with a static UUID per connection you want |
| 129 | +to rollout. For example, generate a UUID (for example using `uuidgen`, or |
| 130 | +by `cat /proc/sys/kernel/random/uuid`), and then associate that with given |
| 131 | +connection, statically in your config. You must use a different UUID for each |
| 132 | +connection (obviously), but using the same UUID for the same connection across |
| 133 | +machines makes debugging easier. |
| 134 | + |
| 135 | +However, if you want truly unique UUIDs, one option is to just not specify a |
| 136 | +UUID and let Network Manager fill one in. However, not all versions of NM |
| 137 | +support this, and some will just ignore that connections. |
| 138 | + |
| 139 | +You can't just generate UUIDs in the recipe, as they'll change on every run. So |
| 140 | +here's one way to solve that problem: build each UUID seeded with the hostname |
| 141 | +and the connection name so they stay the same across runs: |
| 142 | + |
| 143 | +```ruby |
| 144 | +node.default['fb_networkmanager']['system-connections']['mywifi'] = { |
| 145 | + 'connection' => { |
| 146 | + 'type' => 'wifi', |
| 147 | + 'id' => 'Cool Wifi', |
| 148 | + 'uuid' => UUIDTools::UUID.sha1_create( |
| 149 | + UUIDTools::UUID_DNS_NAMESPACE, |
| 150 | + "#{node['fqdn']}/Cool Wifi", |
| 151 | + ), |
| 152 | + }, |
| 153 | + ... |
| 154 | +} |
| 155 | +``` |
| 156 | + |
| 157 | +#### Migrating from existing configs |
| 158 | + |
| 159 | +Migrating to this cookbook could potentially pose a problem: you want all the |
| 160 | +information from the existing connection, but you don't want a duplicate |
| 161 | +connection. |
| 162 | + |
| 163 | +We provide a `_migrate_from` key. When populated, we'll use that as our base |
| 164 | +config the first time, merge any data provided in the node, and then delete |
| 165 | +the old config. |
| 166 | + |
| 167 | +This provides seemless transition - it will preserve the UUID, which will |
| 168 | +keep network manager from thinking any connections went away, and ensure |
| 169 | +in-use connections don't drop. |
| 170 | + |
| 171 | +For example, let's say you had droped a file |
| 172 | +`/etc/NetworkManager/system-connections/OurCorpWifi` that you had dropped off |
| 173 | +with `cookbook_file`, or a script, or even that you had was built through |
| 174 | +manually setting it up in the NM GUI. You could then do: |
| 175 | + |
| 176 | +```ruby |
| 177 | +node.default['fb_networkmanager']['system-connections']['our_corp_wifi'] = { |
| 178 | + '_migrate_from' => 'OurCorpWifi', |
| 179 | + 'connection' => { |
| 180 | + 'type' => 'wifi', |
| 181 | + 'id' => 'OurCorpWifi', |
| 182 | + }, |
| 183 | + 'wifi' => { |
| 184 | + 'mode' => 'infrastructure', |
| 185 | + 'ssid' => 'OurCorpWifi', |
| 186 | + }, |
| 187 | + 'wifi-security' => { |
| 188 | + 'auth-alg' => 'open', |
| 189 | + 'key-mgmt' => 'wpa-psk', |
| 190 | + 'psk' => 'SuperS3kr1t', |
| 191 | + }, |
| 192 | +} |
| 193 | +``` |
| 194 | + |
| 195 | +Then anything not specified here will be pulled in from the existing |
| 196 | +`OurCorpWifi` file. Note that any settings that you care about should be |
| 197 | +specified in the node to ensure that on new setups, you're not missing critical |
| 198 | +configuration. |
| 199 | + |
| 200 | +Note that if the original service file isn't there, Chef will just create a new |
| 201 | +connection file (though it will warn). Also note that once Chef has created one, |
| 202 | +it stop pulling in the old file (and will remove it). |
| 203 | + |
| 204 | +#### Providing defaults |
| 205 | + |
| 206 | +In general, the Chef config wins over the user config as described above. |
| 207 | +However it is often desirable to specify a default config in case the user does |
| 208 | +not specify anything. In that case you can use the `_defaults`. For example: |
| 209 | + |
| 210 | +```ruby |
| 211 | +node.default['fb_networkmanager']['system-connections']['our_corp_wifi'] = { |
| 212 | + '_migrate_from' => 'OurCorpWifi', |
| 213 | + '_defaults' => { |
| 214 | + 'connection' => { |
| 215 | + 'autoconnect-priority' => '100', |
| 216 | + } |
| 217 | + }, |
| 218 | + 'connection' => { |
| 219 | + 'type' => 'wifi', |
| 220 | + 'id' => 'OurCorpWifi', |
| 221 | + }, |
| 222 | + 'wifi' => { |
| 223 | + 'mode' => 'infrastructure', |
| 224 | + 'ssid' => 'OurCorpWifi', |
| 225 | + }, |
| 226 | + 'wifi-security' => { |
| 227 | + 'auth-alg' => 'open', |
| 228 | + 'key-mgmt' => 'wpa-psk', |
| 229 | + 'psk' => 'SuperS3kr1t', |
| 230 | + }, |
| 231 | +} |
| 232 | +``` |
| 233 | + |
| 234 | +The rendered config here will set `connection.autoconnect-priority` to 100 |
| 235 | +if there is no value for it found in the existing file, but will use the value |
| 236 | +in the file if it exists. The logic here is quite simple: |
| 237 | + |
| 238 | + defaults < user config < chef config |
0 commit comments