From 4b5fae3e4e24adfa7286cb863e31bf7a6dd362e3 Mon Sep 17 00:00:00 2001
From: Olaf Bohlen <olbohlen@eenfach.de>
Date: Mon, 24 Aug 2020 22:32:30 +0200
Subject: [PATCH] added housekeeping, ssh-key provisioning, local inventory, etc

---
 tasks/main.yml       |  257 ++++++++++++++++-----------
 templates/sysding.j2 |   15 +
 defaults/main.yml    |   63 -------
 meta/main.yml        |    2 
 README.md            |  151 ++++++++++++++++
 5 files changed, 305 insertions(+), 183 deletions(-)

diff --git a/README.md b/README.md
index 79249fa..2145644 100644
--- a/README.md
+++ b/README.md
@@ -1,22 +1,144 @@
 Role Name
 =========
 
-This role is supposed to deploy a new OpenIndiana Zone on a yada...
+This role is supposed to deploy a new OpenIndiana Zone, with different settings. It will also allow to provision (multiple) ZFS filesystems,
+vnics and other related resources.
 
 Requirements
 ------------
 
-Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
+This role obiously requires an OpenIndiana host system and following ansible modules:
+- solaris_zone
+- zfs
+- dladm_vnic
 
 Role Variables
 --------------
 
-A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
+You need to create a data structure called "oizone". The mandatory minimum is shown here:
+``
+oizone:
+  name: myzone
+  zoneroot: /export/zones/
+  filesystems:
+    - path: rpool/export/zones/myzone
+      type: zoneroot
+      zfscreate: true
+      zfs_extra_properties:
+        mountpoint: /export/zones/myzone
+  nics:
+    - physical: ixgbe0
+      logical: myzone0
+      address: 10.23.42.23/24
+      addrsuffix: v4
+  sysding:
+    timezone: UTC
+    locale: C
+    ip:
+      routes:
+        - target: default # can be a CIDR or a host ip or "default"
+          router: 10.23.42.1 # IP of the router
+      dns:
+        nameservers:
+          - 1.1.1.1
+          - 8.8.8.8
+        search:
+          - example.com
+          - openindiana.org
+        domain: example.com
+    users:
+      - name: root
+        hashedpassword: "$5$foobar...."
+      - name: localadm
+        uid: 100
+        gid: 10
+        shell: /usr/bin/bash
+        gecos: "Local Admin Account"
+        home: /export/home/localadm
+        hashedpassword: "$5$barfoo...."
+``
+
+A set of all possible attributes is here:
+
+``
+oizone:
+  name: oizone
+  updateinventory: true # adds zone on top of your inventory
+  zoneroot: /export/zones/
+  autoboot: "true"
+  bootargs: # -v
+  iptype: exclusive
+  cpus: dedicated # dedicated or capped-cpu
+  ncpus: 1
+  mem: capped-memory # or nil
+  ram: 1G
+  swap: 1G
+  locked: 1G
+  brand: ipkg
+  filesystems:
+    - path: rpool/export/zones/oizone
+      type: zoneroot
+      zfscreate: true
+      zfs_extra_properties:
+        refquota: 10G
+	mountpoint: /export/zones/oizone
+    - path: apppool/oizone/datavol1
+      type: volume
+      zfscreate: true
+      zfs_extra_properties:
+        volsize: 5G
+    - path: apppool/oizone/dataset1
+      type: dataset
+      zfscreate: true
+      zfs_extra_properties:
+        quota: 2G
+    - path: /disk1
+      type: lofs
+      mountpoint: /hostdisks/disk1
+      zfscreate: false
+      options:
+        - ro
+        - nodevices
+  nics:
+    - physical: ixgbe0
+      logical: oizoneint0
+      vlan: 100
+      address: dhcp  # can be "dhcp" or a regular IP address
+      addrsuffix: v4 # can be a string, interface0/suffix will be the ipadm create-addr
+  kvm:
+    vnc: "on"
+    bootorder: cd
+  sysding:
+    timezone: UTC
+    locale: C
+    ip:
+      routes:
+        - target: default # can be a CIDR or a host ip or "default"
+          router: 172.18.0.200 # IP of the router
+      dns:
+        nameservers:
+          - 1.1.1.1
+          - 8.8.8.8
+        search:
+          - example.com
+          - openindiana.org
+        domain: example.com
+    users:
+      - name: root
+        hashedpassword: "$5$foobar...."
+      - name: localadm
+        uid: 100
+        gid: 10
+        shell: /usr/bin/bash
+        gecos: "Local Admin Account"
+        home: /export/home/localadm
+        hashedpassword: "$5$barfoo...."
+``
 
 Dependencies
 ------------
 
-A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles.
+No dependencies to others roles so far.
 
 Example Playbook
 ----------------
@@ -24,15 +146,30 @@
 Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
 
     - hosts: servers
+      vars:
+        - oizone:
+	    [... see above ..]
       roles:
-         - { role: username.rolename, x: 42 }
+         - role: oi-zone
 
 License
 -------
 
-BSD
+BSD 3-Clause
+
+Copyright 2020 Olaf Bohlen
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 Author Information
 ------------------
 
-An optional section for the role authors to include contact information, or a website (HTML is not allowed).
+Olaf Bohlen <olbohlen@eenfach.de>
diff --git a/defaults/main.yml b/defaults/main.yml
index 7fcda8a..b7b6cb2 100644
--- a/defaults/main.yml
+++ b/defaults/main.yml
@@ -1,72 +1,9 @@
 ---
 # defaults file for oi-zone
 oizone:
-  name: oizone
-  zoneroot: /export/zones/
   autoboot: "true"
-  bootargs: # -v
   iptype: exclusive
-  cpus: dedicated # dedicated or capped-cpu
-  ncpus: 1
-  mem: capped-memory # or nil
-  ram: 1G
-  swap: 1G
-  locked: 1G
   brand: ipkg
-  filesystems:
-    - path: /export/zones/oizone
-      type: zoneroot
-      zfscreate: true
-      zfs_extra_properties:
-        refquota: 10G
-    - path: apppool/oizone/datavol1
-      type: volume
-      zfscreate: true
-      zfs_extra_properties:
-        volsize: 5G
-    - path: apppool/oizone/dataset1
-      type: dataset
-      zfscreate: true
-      zfs_extra_properties:
-        quota: 2G
-    - path: /disk1
-      type: lofs
-      mountpoint: /hostdisks/disk1
-      zfscreate: false
-      options:
-        - ro
-        - nodevices
-  nics:
-    - physical: ixgbe0
-      logical: oizoneint0
-      vlan: 100
-      address: dhcp  # can be "dhcp" or a regular IP address
-      addrsuffix: v4 # can be a string, interface0/suffix will be the ipadm create-addr
-  kvm:
-    vnc: "on"
-    bootorder: cd
   sysding:
     timezone: UTC
     locale: C
-    ip:
-      routes:
-        - target: default # can be a CIDR or a host ip or "default"
-          router: 172.18.0.200 # IP of the router
-      dns:
-        nameservers:
-          - 1.1.1.1
-          - 8.8.8.8
-        search:
-          - example.com
-          - openindiana.org
-        domain: example.com
-    users:
-      - name: root
-        hashedpassword: "$5$foobar...."
-      - name: localadm
-        uid: 100
-        gid: 10
-        shell: /usr/bin/bash
-        gecos: "Local Admin Account"
-        home: /export/home/localadm
-        hashedpassword: "$5$barfoo...."
diff --git a/meta/main.yml b/meta/main.yml
index c8148b0..bc07d0e 100644
--- a/meta/main.yml
+++ b/meta/main.yml
@@ -1,5 +1,5 @@
 galaxy_info:
-  author: Olaf Bohlen
+  author: Olaf Bohlen <olbohlen@eenfach.de>
   description: create zones on OpenIndiana
   company: eenfach.de
 
diff --git a/tasks/main.yml b/tasks/main.yml
index fd4045c..244a684 100644
--- a/tasks/main.yml
+++ b/tasks/main.yml
@@ -1,112 +1,155 @@
 ---
 # tasks file for oi-zone
-- name: create VNICs
-  dladm_vnic:
-    name: "{{ item['logical'] }}"
-    link: "{{ item['physical'] }}"
-    vlan: "{{ item['vlan'] }}"
-  loop: "{{ oizone['nics'] }}"
+- name: creating zone for you
+  block:
+    - name: create VNICs with VLAN
+      dladm_vnic:
+        name: "{{ item['logical'] }}"
+        link: "{{ item['physical'] }}"
+        vlan: "{{ item['vlan'] }}"
+      loop: "{{ oizone['nics'] }}"
+      when: item['vlan'] is defined
 
-- name: create filesystems
-  zfs:
-    name: "{{ item['path'] }}"
-    state: present
-    zfs_extra_properties: "{{ item['zfs_extra_properties'] }}"
-  loop: "{{ oizone['filesystems'] }}"
-  when: zfscreate
+    - name: create VNICs without VLAN
+      dladm_vnic:
+        name: "{{ item['logical'] }}"
+        link: "{{ item['physical'] }}"
+      loop: "{{ oizone['nics'] }}"
+      when: item['vlan'] is not defined
+
+    - name: create filesystems
+      zfs:
+        name: "{{ item['path'] }}"
+        state: present
+        extra_zfs_properties: "{{ item['extra_zfs_properties'] }}"
+      loop: "{{ oizone['filesystems'] }}"
+      when: item['zfscreate']
   
-- name: set up VM zones for master
-  solaris_zone:
-    name: "{{ oizone['name'] }}"
-    state: installed
-    path: "{{ oizone['zoneroot'] }}/{{ oizone['name'] }}"
-    config: >
-      set brand={{ oizone['brand'] }};
-      set autoboot={{ oizone['autoboot'] }};
-      {% if oizone['bootargs'] %}
-      set bootargs={{ oizone['bootargs'] }};
-      {% endif %}
-      set ip-type={{ oizone['iptype'] }};
-      {% for nic in oizone['nics'] %}
-      add net;
-      set physical={{ nic['logical'] }};
-      {% if {{ oizone['iptype'] == "shared" %}
-      set address={{ nic['address'] }};
-      {% endif %}
-      end;
-      {% endfor %}
-      {% for disk in vmconfig[outer_item]['disks'] %}
-      add device;
-      set match="/dev/zvol/rdsk/localstripe/vm/{{ outer_item }}d{{ disk['instance'] }}";
-      end;
-      add attr;
-      set name="{{ disk['label'] }}";
-      set type="string";
-      set value="localstripe/vm/{{ outer_item }}d{{ disk['instance'] }}";
-      end;
-      {% endfor %}
-      {% if oizone['cpus'] == "dedicated" %}
-      add dedicated-cpu;
-      set ncpus={{ oizone['ncpus'] }};
-      end;
-      {% endif %}
-      {% if oizone['cpus'] == "capped-cpu" %}
-      add capped-cpu;
-      set ncpus={{ oizone['ncpus'] }};
-      end;
-      {% endif %}
-      {% if oizone['mem'] == "capped-memory" %}
-      add capped-memory;
-      set physical={{ oizone['ram'] }};
-      set swap={{ oizone['swap'] }};
-      set locked={{ oizone['locked'] }};
-      end;
-      {% endif %}
-      {% for dataset in oizone['filesystems'] %}
-      {% if dataset['type'] == "dataset" %}
-      add dataset;
-      set name={{ dataset['path'] }};
-      end;
-      {% endif %}
-      {% if dataset['type'] == "lofs" %}
-      add fs;
-      set special={{ dataset['path'] }};
-      set dir={{ dataset['mountpoint'] }};
-      set type="lofs";
-      {% for option in database['options'] %}
-      add options {{ option }};
-      {% endfor %}
-      end;
-      {% endif %}
-      {% if dataset['type'] == "volume" %}
-      add device;
-      set match=/dev/zvol/rdsk/{{ dataset['path'] }};
-      end;
-      {% endif %}
-      {% endfor %}
-      {% if oizone['brand'] == "kvm" %}
-      add attr;
-      set name="bootorder";
-      set type="string";
-      set value="{{ oizone['kvm']['bootorder'] }}";
-      add attr;
-      set name="vnc";
-      set type="string";
-      set value="{{ oizone['kvm']['vnc'] }}";
-      end;
-      add attr;
-      set name="vcpus";
-      set type="string";
-      set value="{{ oizone['ncpus'] }}";
-      end;
-      add attr;
-      set name="ram";
-      set type="string";
-      set value="{{ oizone['ram'] }}";
-      end;
-      {% endif %}
+    - name: set up VM zones for master
+      solaris_zone:
+        name: "{{ oizone['name'] }}"
+        state: installed
+        path: "{{ oizone['zoneroot'] }}/{{ oizone['name'] }}"
+        config: >
+          set brand={{ oizone['brand'] }};
+          set autoboot={{ oizone['autoboot'] }};
+          {% if oizone['bootargs'] is defined and oizone['bootargs'] | length %}
+          set bootargs={{ oizone['bootargs'] }};
+          {% endif %}
+          set ip-type={{ oizone['iptype'] }};
+          {% for nic in oizone['nics'] %}
+          add net;
+          set physical={{ nic['logical'] }};
+          {% if oizone['iptype'] == "shared" %}
+          set address={{ nic['address'] }};
+          {% endif %}
+          end;
+          {% endfor %}
+          {% if oizone['cpus'] is defined and oizone['cpus'] == "dedicated" %}
+          add dedicated-cpu;
+          set ncpus={{ oizone['ncpus'] }};
+          end;
+          {% endif %}
+          {% if oizone['cpus'] is defined and oizone['cpus'] == "capped-cpu" %}
+          add capped-cpu;
+          set ncpus={{ oizone['ncpus'] }};
+          end;
+          {% endif %}
+          {% if oizone['mem'] is defined and oizone['mem'] == "capped-memory" %}
+          add capped-memory;
+          set physical={{ oizone['ram'] }};
+          set swap={{ oizone['swap'] }};
+          set locked={{ oizone['locked'] }};
+          end;
+          {% endif %}
+          {% for dataset in oizone['filesystems'] %}
+          {% if dataset['type'] == "dataset" %}
+          add dataset;
+          set name={{ dataset['path'] }};
+          end;
+          {% endif %}
+          {% if dataset['type'] == "lofs" %}
+          add fs;
+          set special={{ dataset['path'] }};
+          set dir={{ dataset['mountpoint'] }};
+          set type="lofs";
+          {% for option in database['options'] %}
+          add options {{ option }};
+          {% endfor %}
+          end;
+          {% endif %}
+          {% if dataset['type'] == "volume" %}
+          add device;
+          set match=/dev/zvol/rdsk/{{ dataset['path'] }};
+          end;
+          {% endif %}
+          {% endfor %}
+          {% if oizone['brand'] == "kvm" %}
+          add attr;
+          set name="bootorder";
+          set type="string";
+          set value="{{ oizone['kvm']['bootorder'] }}";
+          add attr;
+          set name="vnc";
+          set type="string";
+          set value="{{ oizone['kvm']['vnc'] }}";
+          end;
+          add attr;
+          set name="vcpus";
+          set type="string";
+          set value="{{ oizone['ncpus'] }}";
+          end;
+          add attr;
+          set name="ram";
+          set type="string";
+          set value="{{ oizone['ram'] }}";
+          end;
+          {% endif %}
 
-- name: create a sysding.conf
-  template:
-    dest: "{{ oizone['zoneroot'] }}/{{ oizone['name'] }}/root/etc/sysding.conf"
-    src: sysding.j2
+    - name: create a sysding.conf
+      template:
+        dest: "{{ oizone['zoneroot'] }}/{{ oizone['name'] }}/root/etc/sysding.conf"
+        src: sysding.j2
+        mode: 0400
+
+    - name: boot zone
+      solaris_zone:
+        name: "{{ oizone['name'] }}"
+        state: running
+        path: "{{ oizone['zoneroot'] }}/{{ oizone['name'] }}"
+
+    - name: add zone to inventory
+      local_action:
+        module: lineinfile
+        path: "{{ inventory_file }}"
+        insertbefore: "BOF"
+        line: "{{ oizone['name'] }}.{{ oizone['sysding']['ip']['dns']['domain'] }}"
+      when:
+        - oizone['updateinventory'] is defined
+        - oizone['updateinventory']
+      
+  rescue:   # in case something wents wrong above, we do housekeeping here
+    - name: ATTENTION
+      debug:
+        msg: "failed to install {{ oizone['name'] }}, rolling back"
+    - name: delete zone
+      solaris_zone:
+        name: "{{ oizone['name'] }}"
+        state: absent
+        path: "{{ oizone['zoneroot'] }}/{{ oizone['name'] }}"
+
+    - name: delete VNICs
+      dladm_vnic:
+        name: "{{ item['logical'] }}"
+        link: "{{ item['physical'] }}"
+        state: absent
+      loop: "{{ oizone['nics'] }}"
+        
+    - name: delete filesystems
+      zfs:
+        name: "{{ item['path'] }}"
+        state: absent
+        extra_zfs_properties: "{{ item['extra_zfs_properties'] }}"
+      loop: "{{ oizone['filesystems'] }}"
+      when: item['zfscreate']
+        
diff --git a/templates/sysding.j2 b/templates/sysding.j2
index c3afcc7..b2416ad 100644
--- a/templates/sysding.j2
+++ b/templates/sysding.j2
@@ -1,20 +1,25 @@
+# created by oi-zone ansible role
 setup_timezone {{ oizone['sysding']['timezone'] }}
 setup_locale {{ oizone['sysding']['locale'] }}
 
-{% if oizone['sysding']['nfs4domain'] %}
+{% if oizone['sysding']['nfs4domain'] is defined and oizone['sysding']['nfs4domain'] | length %}
 setup_nfs4domain "{{ oizone['sysding']['nfs4domain'] }}"
 {% endif %}
 
 {% for user in oizone['sysding']['users'] %}
 {% if user['name'] != "root" %}
-setup_user_account {{ user['name'] }} {{ user['uid'] }} {{ user['gid'] }} {{ user['gecos'] }} {{ user['home'] }} {{ user['shell'] }}
+setup_user_account {{ user['name'] }} {{ user['uid'] }} {{ user['gid'] }} "{{ user['gecos'] }}" "{{ user['home'] }}" "{{ user['shell'] }}"
 mkdir -p {{ user['home'] }}
-chmod {{ user['name'] }}:{{ user['gid'] }} {{ user['home'] }}
+{% if user['authorized_key'] is defined %}
+mkdir -p "{{ user['home'] }}/.ssh"
+echo "{{ user['authorized_key'] }}" > "{{ user['home'] }}/.ssh/authorized_keys"
+{% endif %}
+chown -R {{ user['name'] }}:{{ user['gid'] }} {{ user['home'] }}
 {% endif %}
 setup_user_password {{ user['name'] }} '{{ user["hashedpassword"] }}'
 {% endfor %}
 
-{% if oizone['iptype'] == "exclusive-ip" %}
+{% if oizone['iptype'] == "exclusive" %}
 {% for nic in oizone['nics'] %}
 setup_interface {{ nic['logical'] }} {{ nic['addrsuffix'] }} {{ nic['address'] }}
 {% endfor %}
@@ -24,6 +29,6 @@
 setup_route {{ route['target'] }} {{ route['router'] }}
 {% endfor %}
 
-{% if oizone['sysding']['ip']['dns'] %}
+{% if oizone['sysding']['ip']['dns'] is defined and oizone['sysding']['ip']['dns'] | length %}
 setup_ns_dns "{{ oizone['sysding']['ip']['dns']['domain'] }}" "{{ oizone['sysding']['ip']['dns']['search'] | join(' ') }}" "{{ oizone['sysding']['ip']['dns']['nameservers'] | join(' ') }}"
 {% endif %}

--
Gitblit v1.9.3