1********************************** 2Packet.net Guide 3********************************** 4 5Introduction 6============ 7 8`Packet.net <https://packet.net>`_ is a bare metal infrastructure host that's supported by Ansible (>=2.3) via a dynamic inventory script and two cloud modules. The two modules are: 9 10- packet_sshkey: adds a public SSH key from file or value to the Packet infrastructure. Every subsequently-created device will have this public key installed in .ssh/authorized_keys. 11- packet_device: manages servers on Packet. You can use this module to create, restart and delete devices. 12 13Note, this guide assumes you are familiar with Ansible and how it works. If you're not, have a look at their :ref:`docs <ansible_documentation>` before getting started. 14 15Requirements 16============ 17 18The Packet modules and inventory script connect to the Packet API using the packet-python package. You can install it with pip: 19 20.. code-block:: bash 21 22 $ pip install packet-python 23 24In order to check the state of devices created by Ansible on Packet, it's a good idea to install one of the `Packet CLI clients <https://www.packet.net/developers/integrations/>`_. Otherwise you can check them via the `Packet portal <https://app.packet.net/portal>`_. 25 26To use the modules and inventory script you'll need a Packet API token. You can generate an API token via the Packet portal `here <https://app.packet.net/portal#/api-keys>`__. The simplest way to authenticate yourself is to set the Packet API token in an environment variable: 27 28.. code-block:: bash 29 30 $ export PACKET_API_TOKEN=Bfse9F24SFtfs423Gsd3ifGsd43sSdfs 31 32If you're not comfortable exporting your API token, you can pass it as a parameter to the modules. 33 34On Packet, devices and reserved IP addresses belong to `projects <https://www.packet.com/developers/api/#projects>`_. In order to use the packet_device module, you need to specify the UUID of the project in which you want to create or manage devices. You can find a project's UUID in the Packet portal `here <https://app.packet.net/portal#/projects/list/table/>`_ (it's just under the project table) or via one of the available `CLIs <https://www.packet.net/developers/integrations/>`_. 35 36 37If you want to use a new SSH keypair in this tutorial, you can generate it to ``./id_rsa`` and ``./id_rsa.pub`` as: 38 39.. code-block:: bash 40 41 $ ssh-keygen -t rsa -f ./id_rsa 42 43If you want to use an existing keypair, just copy the private and public key over to the playbook directory. 44 45 46Device Creation 47=============== 48 49The following code block is a simple playbook that creates one `Type 0 <https://www.packet.com/cloud/servers/t1-small/>`_ server (the 'plan' parameter). You have to supply 'plan' and 'operating_system'. 'location' defaults to 'ewr1' (Parsippany, NJ). You can find all the possible values for the parameters via a `CLI client <https://www.packet.net/developers/integrations/>`_. 50 51.. code-block:: yaml 52 53 # playbook_create.yml 54 55 - name: create ubuntu device 56 hosts: localhost 57 tasks: 58 59 - packet_sshkey: 60 key_file: ./id_rsa.pub 61 label: tutorial key 62 63 - packet_device: 64 project_id: <your_project_id> 65 hostnames: myserver 66 operating_system: ubuntu_16_04 67 plan: baremetal_0 68 facility: sjc1 69 70After running ``ansible-playbook playbook_create.yml``, you should have a server provisioned on Packet. You can verify via a CLI or in the `Packet portal <https://app.packet.net/portal#/projects/list/table>`__. 71 72If you get an error with the message "failed to set machine state present, error: Error 404: Not Found", please verify your project UUID. 73 74 75Updating Devices 76================ 77 78The two parameters used to uniquely identify Packet devices are: "device_ids" and "hostnames". Both parameters accept either a single string (later converted to a one-element list), or a list of strings. 79 80The 'device_ids' and 'hostnames' parameters are mutually exclusive. The following values are all acceptable: 81 82- device_ids: a27b7a83-fc93-435b-a128-47a5b04f2dcf 83 84- hostnames: mydev1 85 86- device_ids: [a27b7a83-fc93-435b-a128-47a5b04f2dcf, 4887130f-0ccd-49a0-99b0-323c1ceb527b] 87 88- hostnames: [mydev1, mydev2] 89 90In addition, hostnames can contain a special '%d' formatter along with a 'count' parameter that lets you easily expand hostnames that follow a simple name and number pattern; in other words, ``hostnames: "mydev%d", count: 2`` will expand to [mydev1, mydev2]. 91 92If your playbook acts on existing Packet devices, you can only pass the 'hostname' and 'device_ids' parameters. The following playbook shows how you can reboot a specific Packet device by setting the 'hostname' parameter: 93 94.. code-block:: yaml 95 96 # playbook_reboot.yml 97 98 - name: reboot myserver 99 hosts: localhost 100 tasks: 101 102 - packet_device: 103 project_id: <your_project_id> 104 hostnames: myserver 105 state: rebooted 106 107You can also identify specific Packet devices with the 'device_ids' parameter. The device's UUID can be found in the `Packet Portal <https://app.packet.net/portal>`_ or by using a `CLI <https://www.packet.net/developers/integrations/>`_. The following playbook removes a Packet device using the 'device_ids' field: 108 109.. code-block:: yaml 110 111 # playbook_remove.yml 112 113 - name: remove a device 114 hosts: localhost 115 tasks: 116 117 - packet_device: 118 project_id: <your_project_id> 119 device_ids: <myserver_device_id> 120 state: absent 121 122 123More Complex Playbooks 124====================== 125 126In this example, we'll create a CoreOS cluster with `user data <https://packet.com/developers/docs/servers/key-features/user-data/>`_. 127 128 129The CoreOS cluster will use `etcd <https://etcd.io/>`_ for discovery of other servers in the cluster. Before provisioning your servers, you'll need to generate a discovery token for your cluster: 130 131.. code-block:: bash 132 133 $ curl -w "\n" 'https://discovery.etcd.io/new?size=3' 134 135The following playbook will create an SSH key, 3 Packet servers, and then wait until SSH is ready (or until 5 minutes passed). Make sure to substitute the discovery token URL in 'user_data', and the 'project_id' before running ``ansible-playbook``. Also, feel free to change 'plan' and 'facility'. 136 137.. code-block:: yaml 138 139 # playbook_coreos.yml 140 141 - name: Start 3 CoreOS nodes in Packet and wait until SSH is ready 142 hosts: localhost 143 tasks: 144 145 - packet_sshkey: 146 key_file: ./id_rsa.pub 147 label: new 148 149 - packet_device: 150 hostnames: [coreos-one, coreos-two, coreos-three] 151 operating_system: coreos_beta 152 plan: baremetal_0 153 facility: ewr1 154 project_id: <your_project_id> 155 wait_for_public_IPv: 4 156 user_data: | 157 #cloud-config 158 coreos: 159 etcd2: 160 discovery: https://discovery.etcd.io/<token> 161 advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001 162 initial-advertise-peer-urls: http://$private_ipv4:2380 163 listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001 164 listen-peer-urls: http://$private_ipv4:2380 165 fleet: 166 public-ip: $private_ipv4 167 units: 168 - name: etcd2.service 169 command: start 170 - name: fleet.service 171 command: start 172 register: newhosts 173 174 - name: wait for ssh 175 wait_for: 176 delay: 1 177 host: "{{ item.public_ipv4 }}" 178 port: 22 179 state: started 180 timeout: 500 181 loop: "{{ newhosts.results[0].devices }}" 182 183 184As with most Ansible modules, the default states of the Packet modules are idempotent, meaning the resources in your project will remain the same after re-runs of a playbook. Thus, we can keep the ``packet_sshkey`` module call in our playbook. If the public key is already in your Packet account, the call will have no effect. 185 186The second module call provisions 3 Packet Type 0 (specified using the 'plan' parameter) servers in the project identified via the 'project_id' parameter. The servers are all provisioned with CoreOS beta (the 'operating_system' parameter) and are customized with cloud-config user data passed to the 'user_data' parameter. 187 188The ``packet_device`` module has a ``wait_for_public_IPv`` that is used to specify the version of the IP address to wait for (valid values are ``4`` or ``6`` for IPv4 or IPv6). If specified, Ansible will wait until the GET API call for a device contains an Internet-routeable IP address of the specified version. When referring to an IP address of a created device in subsequent module calls, it's wise to use the ``wait_for_public_IPv`` parameter, or ``state: active`` in the packet_device module call. 189 190Run the playbook: 191 192.. code-block:: bash 193 194 $ ansible-playbook playbook_coreos.yml 195 196Once the playbook quits, your new devices should be reachable via SSH. Try to connect to one and check if etcd has started properly: 197 198.. code-block:: bash 199 200 tomk@work $ ssh -i id_rsa core@$one_of_the_servers_ip 201 core@coreos-one ~ $ etcdctl cluster-health 202 203Once you create a couple of devices, you might appreciate the dynamic inventory script... 204 205 206Dynamic Inventory Script 207======================== 208 209The dynamic inventory script queries the Packet API for a list of hosts, and exposes it to Ansible so you can easily identify and act on Packet devices. 210 211You can find it in Ansible Community General Collection's git repo at `scripts/inventory/packet_net.py <https://raw.githubusercontent.com/ansible-community/contrib-scripts/main/inventory/packet_net.py>`_. 212 213The inventory script is configurable via a `ini file <https://raw.githubusercontent.com/ansible-community/contrib-scripts/main/inventory/packet_net.ini>`_. 214 215If you want to use the inventory script, you must first export your Packet API token to a PACKET_API_TOKEN environment variable. 216 217You can either copy the inventory and ini config out from the cloned git repo, or you can download it to your working directory like so: 218 219.. code-block:: bash 220 221 $ wget https://raw.githubusercontent.com/ansible-community/contrib-scripts/main/inventory/packet_net.py 222 $ chmod +x packet_net.py 223 $ wget https://raw.githubusercontent.com/ansible-community/contrib-scripts/main/inventory/packet_net.ini 224 225In order to understand what the inventory script gives to Ansible you can run: 226 227.. code-block:: bash 228 229 $ ./packet_net.py --list 230 231It should print a JSON document looking similar to following trimmed dictionary: 232 233.. code-block:: json 234 235 { 236 "_meta": { 237 "hostvars": { 238 "147.75.64.169": { 239 "packet_billing_cycle": "hourly", 240 "packet_created_at": "2017-02-09T17:11:26Z", 241 "packet_facility": "ewr1", 242 "packet_hostname": "coreos-two", 243 "packet_href": "/devices/d0ab8972-54a8-4bff-832b-28549d1bec96", 244 "packet_id": "d0ab8972-54a8-4bff-832b-28549d1bec96", 245 "packet_locked": false, 246 "packet_operating_system": "coreos_beta", 247 "packet_plan": "baremetal_0", 248 "packet_state": "active", 249 "packet_updated_at": "2017-02-09T17:16:35Z", 250 "packet_user": "core", 251 "packet_userdata": "#cloud-config\ncoreos:\n etcd2:\n discovery: https://discovery.etcd.io/e0c8a4a9b8fe61acd51ec599e2a4f68e\n advertise-client-urls: http://$private_ipv4:2379,http://$private_ipv4:4001\n initial-advertise-peer-urls: http://$private_ipv4:2380\n listen-client-urls: http://0.0.0.0:2379,http://0.0.0.0:4001\n listen-peer-urls: http://$private_ipv4:2380\n fleet:\n public-ip: $private_ipv4\n units:\n - name: etcd2.service\n command: start\n - name: fleet.service\n command: start" 252 } 253 } 254 }, 255 "baremetal_0": [ 256 "147.75.202.255", 257 "147.75.202.251", 258 "147.75.202.249", 259 "147.75.64.129", 260 "147.75.192.51", 261 "147.75.64.169" 262 ], 263 "coreos_beta": [ 264 "147.75.202.255", 265 "147.75.202.251", 266 "147.75.202.249", 267 "147.75.64.129", 268 "147.75.192.51", 269 "147.75.64.169" 270 ], 271 "ewr1": [ 272 "147.75.64.129", 273 "147.75.192.51", 274 "147.75.64.169" 275 ], 276 "sjc1": [ 277 "147.75.202.255", 278 "147.75.202.251", 279 "147.75.202.249" 280 ], 281 "coreos-two": [ 282 "147.75.64.169" 283 ], 284 "d0ab8972-54a8-4bff-832b-28549d1bec96": [ 285 "147.75.64.169" 286 ] 287 } 288 289In the ``['_meta']['hostvars']`` key, there is a list of devices (uniquely identified by their public IPv4 address) with their parameters. The other keys under ``['_meta']`` are lists of devices grouped by some parameter. Here, it is type (all devices are of type baremetal_0), operating system, and facility (ewr1 and sjc1). 290 291In addition to the parameter groups, there are also one-item groups with the UUID or hostname of the device. 292 293You can now target groups in playbooks! The following playbook will install a role that supplies resources for an Ansible target into all devices in the "coreos_beta" group: 294 295.. code-block:: yaml 296 297 # playbook_bootstrap.yml 298 299 - hosts: coreos_beta 300 gather_facts: false 301 roles: 302 - defunctzombie.coreos-boostrap 303 304Don't forget to supply the dynamic inventory in the ``-i`` argument! 305 306.. code-block:: bash 307 308 $ ansible-playbook -u core -i packet_net.py playbook_bootstrap.yml 309 310 311If you have any questions or comments let us know! help@packet.net 312