Initial commit
[ta/infra-ansible.git] / roles / baremetal_provision / tasks / ironic_nodes_deploy.yml
diff --git a/roles/baremetal_provision/tasks/ironic_nodes_deploy.yml b/roles/baremetal_provision/tasks/ironic_nodes_deploy.yml
new file mode 100644 (file)
index 0000000..cb5ba95
--- /dev/null
@@ -0,0 +1,338 @@
+---
+
+# Copyright 2019 Nokia
+
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Block traffic during nodes power on/off so that possible old deployment
+# clients cannot connect new deployment services (like mysql)  and ruin
+# the installation.
+- name: Block traffic on infra_internal
+  iptables:
+    state: present
+    action: insert
+    chain: INPUT
+    jump: REJECT
+    in_interface: "{{ networking['infra_internal']['interface'] }}"
+  when:
+    - installation_phase == "provisioning-started"
+
+- name: Power off nodes
+  environment:
+    OS_AUTH_TOKEN: "fake-token"
+    IRONIC_URL: "{{ ironic_service_adminurl }}"
+  command: "/usr/bin/ironic node-set-power-state {{item.uuid}} off"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  when:
+    - not virtual_env
+    - installation_phase == "provisioning-started"
+  retries: 5
+  delay: 10
+  loop_control:
+    label: "{{ item.name }}"
+
+- name: Power off nodes
+  command: "openstack --os-cloud default baremetal node power off {{item.uuid}}"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  when:
+    - not virtual_env
+    - installation_phase != "provisioning-started"
+  retries: 5
+  delay: 10
+  loop_control:
+    label: "{{ item.name }}"
+
+- name: Ensure nodes are powered off
+  environment:
+    OS_AUTH_TOKEN: "fake-token"
+    IRONIC_URL: "{{ ironic_service_adminurl }}"
+  os_node_power_check:
+    auth:
+    auth_type: 'None'
+    ironic_url: "{{ ironic_service_adminurl }}"
+    nodes_details: "{{ baremetal_ironic_nodes_ids }}"
+    power_state: 'power off'
+  until: power_pending_list | length == 0
+  retries: 30
+  delay: 6
+  when:
+    - not virtual_env and baremetal_ironic_nodes_ids | length > 0
+    - installation_phase == "provisioning-started"
+  no_log: True
+
+- name: Ensure nodes are powered off
+  os_node_power_check:
+    cloud: default
+    auth_type: password
+    ironic_url: "{{ ironic_service_adminurl }}"
+    nodes_details: "{{ baremetal_ironic_nodes_ids }}"
+    power_state: 'power off'
+    endpoint_type: internal
+  until: power_pending_list | length == 0
+  retries: 30
+  delay: 6
+  when:
+    - not virtual_env and baremetal_ironic_nodes_ids | length > 0
+    - installation_phase != "provisioning-started"
+  no_log: True
+
+# Sleep to make sure power is off
+- name: Sleep for 15 seconds
+  pause:
+    seconds: 15
+  when: not virtual_env and baremetal_ironic_nodes_ids | length > 0
+
+- name: Create config-drive directories for all nodes
+  file:
+    path: "/var/lib/ironic/confdrive/{{item.name}}/openstack/latest/"
+    state: "directory"
+    owner: "ironic"
+    group: "ironic"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  loop_control:
+    label: "{{ item.name }}"
+
+- name: Generate config-drive files
+  config_template:
+    src: "{{ item[1].src }}"
+    dest: "/var/lib/ironic/confdrive/{{item[0].name}}/openstack/latest/{{ item[1].dest }}"
+    owner: "ironic"
+    group: "ironic"
+    mode: "0644"
+    config_type: "{{ item[1].config_type }}"
+  with_nested: 
+    - "{{ baremetal_ironic_nodes_ids }}"
+    - "{{ config_drive_templates }}"
+  loop_control:
+    label: "{{ item[0].name }}"
+
+- name: Stat config-drive files to check if they exists
+  stat:
+    path: "/var/lib/ironic/confdrive/{{ item.name }}.base64"
+  register: confdrive_stat
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+
+- name: Prepare Config-drive ISO file
+  shell: |
+    # Generated ISO
+    genisoimage -o /var/lib/ironic/confdrive/{{ item.item.name }}.iso -ldots -allow-lowercase -allow-multidot -l -publisher 'ironicclient-configdrive 0.1' -quiet -J -r -V config-2 /var/lib/ironic/confdrive/{{ item.item.name }}
+    # Zip it!
+    gzip /var/lib/ironic/confdrive/{{ item.item.name }}.iso
+    # Encode it to base64
+    base64 -w 0 /var/lib/ironic/confdrive/{{ item.item.name }}.iso.gz > /var/lib/ironic/confdrive/{{ item.item.name }}.base64
+  when: not item.stat.exists
+  with_items: "{{confdrive_stat.results}}"
+
+- name: Remove os_net_config temp files
+  file:
+    dest: "/tmp/{{item.name}}_config.yaml"
+    state: absent
+  with_items: "{{ baremetal_ironic_nodes }}"
+  loop_control:
+    label: "{{ item.name }}"
+
+- name: Calculate md5sum of Golden image
+  stat:
+    path: "/opt/images/guest-image.img"
+    get_md5: yes
+  register: golden_img_md5sum
+  when: baremetal_ironic_nodes_ids | length > 0
+
+- name: Enable traffic on infra_internal
+  iptables:
+    state: absent
+    chain: INPUT
+    jump: REJECT
+    in_interface: "{{ networking['infra_internal']['interface'] }}"
+  when:
+    - installation_phase == "provisioning-started"
+
+- name: Configure Baremetal deployment
+  environment:
+    OS_AUTH_TOKEN: "fake-token"
+    IRONIC_URL: "{{ ironic_service_adminurl }}"
+  os_ironic_node:
+    auth:
+    auth_type: 'None'
+    ironic_url: "{{ ironic_service_adminurl }}"
+    uuid: "{{item.uuid}}"
+    deploy: False
+    state: present
+    power: absent
+    maintenance: False
+    instance_info:
+      root_gb: 10
+      image_source: "http://{{ansible_host}}:{{golden_image_http_port}}/guest-image.img"
+      image_checksum: "{{golden_img_md5sum.stat.md5}}"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  loop_control:
+    label: "{{ item.name }}"
+  when:
+    - installation_phase == "provisioning-started"
+
+- name: Configure Baremetal deployment
+  os_ironic_node:
+    cloud: default
+    endpoint_type: internal
+    auth_type: password
+    uuid: "{{item.uuid}}"
+    deploy: False
+    state: present
+    power: absent
+    maintenance: False
+    instance_info:
+      root_gb: 10
+      image_source: "http://{{ansible_host}}:{{golden_image_http_port}}/guest-image.img"
+      image_checksum: "{{golden_img_md5sum.stat.md5}}"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  loop_control:
+    label: "{{ item.name }}"
+  when:
+    - installation_phase != "provisioning-started"
+
+- name: Start Baremetal deployment
+  environment:
+    OS_AUTH_TOKEN: "fake-token"
+    IRONIC_URL: "{{ ironic_service_adminurl }}"
+  os_ironic_node:
+    auth:
+    auth_type: 'None'
+    ironic_url: "{{ ironic_service_adminurl }}"
+    deploy: True
+    power: present
+    config_drive: "{{lookup('file', '/var/lib/ironic/confdrive/{{ item.name }}.base64')}}"
+    uuid: "{{item.uuid}}"
+    instance_info:
+      root_gb: 10
+      image_source: "http://{{ansible_host}}:{{golden_image_http_port}}/guest-image.img"
+      image_checksum: "{{golden_img_md5sum.stat.md5}}"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  loop_control:
+    label: "{{ item.name }}"
+  when:
+    - installation_phase == "provisioning-started"
+
+- name: Start Baremetal deployment
+  os_ironic_node:
+    cloud: default
+    endpoint_type: internal
+    auth_type: password
+    deploy: True
+    power: present
+    config_drive: "{{lookup('file', '/var/lib/ironic/confdrive/{{ item.name }}.base64')}}"
+    uuid: "{{item.uuid}}"
+    instance_info:
+      root_gb: 10
+      image_source: "http://{{ansible_host}}:{{golden_image_http_port}}/guest-image.img"
+      image_checksum: "{{golden_img_md5sum.stat.md5}}"
+  with_items: "{{ baremetal_ironic_nodes_ids }}"
+  loop_control:
+    label: "{{ item.name }}"
+  when:
+    - installation_phase != "provisioning-started"
+
+- name: Verify node provisioning state. Waiting for 60mins max.
+  environment:
+    OS_AUTH_TOKEN: "fake-token"
+    IRONIC_URL: "{{ ironic_service_adminurl }}"
+  os_node_provision_check:
+    auth:
+    auth_type: 'None'
+    ironic_url: "{{ ironic_service_adminurl }}"
+    nodes_details: "{{baremetal_ironic_nodes_ids}}"
+  register: baremetal_ironic_node_provisionin_results
+  until: provision_pending_list | length == 0
+  retries: 360
+  delay: 10
+  when:
+    - installation_phase == "provisioning-started"
+
+- name: Checking for any deployment failures
+  fail:
+    msg: "One or more nodes failed in deployment. {{baremetal_ironic_node_provisionin_results['ansible_facts']['provision_failed_list'] }}"
+  when:
+    - installation_phase == "provisioning-started"
+    - baremetal_ironic_node_provisionin_results['ansible_facts']['provision_failed_list'] | length > 0
+
+- name: Verify node provisioning state. Waiting for 60mins max.
+  os_node_provision_check:
+    cloud: default
+    endpoint_type: internal
+    auth_type: password
+    nodes_details: "{{baremetal_ironic_nodes_ids}}"
+  register: baremetal_ironic_node_provisionin_results
+  until: provision_pending_list | length == 0
+  retries: 360
+  delay: 10
+  when:
+    - installation_phase != "provisioning-started"
+
+- name: Checking for any deployment failures
+  fail:
+    msg: "One or more nodes failed in deployment. {{baremetal_ironic_node_provisionin_results['ansible_facts']['provision_failed_list'] }}"
+  when:
+    - installation_phase != "provisioning-started"
+    - baremetal_ironic_node_provisionin_results['ansible_facts']['provision_failed_list'] | length > 0
+
+# JanneS: until looping is a fix for the problem in wait_for module; it does not catch socket error in recv if peer closes the connection.
+- name: Verify remote node ssh ports active. Waiting for 60mins max.
+  wait_for:
+     host: "{{ item.node_ip[0] }}"
+     port: 22
+     search_regex: OpenSSH
+     sleep: 5
+     timeout: 3600
+  register: remote_success
+  until: remote_success | success
+  retries: 3
+  with_items: "{{net_conn_details}}"
+
+- name: Wait for remote node ssh login. Waiting for 10mins max.
+  become: "{{ ansible_env.SUDO_USER }}"
+  local_action: shell ssh -oBatchMode=yes -4 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null {{ item.node_ip[0] }} "echo success"
+  register: user_enabled
+  with_items: "{{net_conn_details}}"
+  until: user_enabled.stdout.find("success") != -1
+  retries: 90
+  delay: 10
+
+- name: Set Ironic maintenance mode to all nodes.
+  os_ironic_node:
+    cloud: default
+    endpoint_type: internal
+    auth_type: password
+    uuid: "{{item.name}}"
+    maintenance: True
+    deploy: False
+  with_items: "{{ baremetal_ironic_nodes }}"
+  loop_control:
+    label: "{{ item.name }}"
+  when:
+    - installation_phase != "provisioning-started"
+
+- name: Set Ironic maintenance mode to all nodes.
+  environment:
+    OS_AUTH_TOKEN: "fake-token"
+    IRONIC_URL: "{{ ironic_service_adminurl }}"
+  os_ironic_node:
+    auth:
+    auth_type: 'None'
+    ironic_url: "{{ ironic_service_adminurl }}"
+    uuid: "{{item.name}}"
+    maintenance: True
+    deploy: False
+  with_items: "{{ baremetal_ironic_nodes }}"
+  loop_control:
+    label: "{{ item.name }}"
+  when:
+    - installation_phase == "provisioning-started"