VCF 4.0 on VxRail – externalize vCenter with Ansible

In the previous post I showed how to automate initial VxRail cluster configuration and deployment with Ansible. In this post, which is the next of a number of posts on VCF 4 on VxRail I will show you how to externalize embedded vCenter.

As you know, by default, VMware vCenter server is internal to the VxRail cluster. But as per the VVD guidelines, it needs to be external for VCF 4.0.0 on VxRail (starting with Cloud Foundation 4.0.1, externalization of VMware vCenter server is automated during the bring-up process).

So let’s automate this step. We will use ‘rest/vxm/v1/vc/mode’ and /v1/requests’ APIs.

Vars used in the role task:

externalizeVcenterApiUrl: rest/vxm/v1/vc/mode
checkRequestStatusApiUrl: /v1/requests
vCenterUsername: administrator@vsphere.local
vCenterPassword: SoM3Pa$$w0Rd

As a first step, let’s check what is the current vCenter mode:

- name: Get current vCenter mode
  uri:
    url: "{{ vxmUrl }}/{{ externalizeVcenterApiUrl }}"
    method: GET
    headers:
      Content-Type: application/json
      # Authorization: Basic {{ auth }}
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    validate_certs: no
    return_content: yes
  register: getVcenterMode
  
- name : Debug - Get current vCenter mode
  debug:
   msg: "{{ getVcenterMode.json.vc_mode }}"

As you can see above, it’s EMBEDDED. So let’s use this as a condition for next step- externalize vCenter. As a response we will get a request ID.

- name: Externalize vCenter
  uri:
    url: "{{ vxmUrl }}/{{ externalizeVcenterApiUrl }}"
    method: PATCH
    headers:
      Content-Type: application/json
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    validate_certs: no
    return_content: yes
    body_format: json
    status_code: 202
    body:
      psc_mode: EMBEDDED
      vc_admin_user:
        password: "{{ vCenterPassword }}"
        username: "{{ vCenterUsername }}"
      vc_mode: EXTERNAL
  register: externalizeVcenter
  when: "getVcenterMode.json.vc_mode == 'EMBEDDED'"

- name : Debug - Externalize vCenter
  debug:
   msg: "{{ externalizeVcenter.json.request_id }}"

If you switch to vSphere Client, you should see two completed tasks: ‘Run VC Conversion’ and Initiate guest OS reboot’.

And let’s use Request ID ‘externalizeVcenter.json.request_id’ (in my case it’s ‘SBI_2’) to check externalize vCenter task status. The task will finish when the status is COMPLETED. And as a last step we will check vCenter mode after convertion.

- name: Check request status
  uri:
    url: "{{ vxmUrl }}/{{ checkRequestStatusApiUrl }}/{{ externalizeVcenter.json.request_id }}"
    method: GET
    headers:
      Content-Type: application/json
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    timeout: 300
    validate_certs: no
    return_content: yes
  register: checkRequestStatus
  until: checkRequestStatus.json.state == "COMPLETED"
  retries: 100
  delay: 20
  
- name : Debug - Check request status
  debug:
   msg: "{{ checkRequestStatus.json.state }}"

Quick check in Postman as a proof that all is fine:

And once again, all in one file:

---
- name: Get current vCenter mode
  uri:
    url: "{{ vxmUrl }}/{{ externalizeVcenterApiUrl }}"
    method: GET
    headers:
      Content-Type: application/json
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    validate_certs: no
    return_content: yes
  register: getVcenterMode
  
- name : Debug - Get current vCenter mode
  debug:
   msg: "{{ getVcenterMode.json.vc_mode }}"
   
- name: Externalize vCenter
  uri:
    url: "{{ vxmUrl }}/{{ externalizeVcenterApiUrl }}"
    method: PATCH
    headers:
      Content-Type: application/json
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    validate_certs: no
    return_content: yes
    body_format: json
    status_code: 202
    body:
      psc_mode: EMBEDDED
      vc_admin_user:
        password: "{{ vCenterPassword }}"
        username: "{{ vCenterUsername }}"
      vc_mode: EXTERNAL
  register: externalizeVcenter
  when: "getVcenterMode.json.vc_mode == 'EMBEDDED'"

- name : Debug - Externalize vCenter
  debug:
   msg: "{{ externalizeVcenter.json.request_id }}"
   
- name: Check request status
  uri:
    url: "{{ vxmUrl }}/{{ checkRequestStatusApiUrl }}/{{ externalizeVcenter.json.request_id }}"
    method: GET
    headers:
      Content-Type: application/json
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    timeout: 300
    validate_certs: no
    return_content: yes
  register: checkRequestStatus
  until: checkRequestStatus.json.state == "COMPLETED"
  retries: 100
  delay: 20
  
- name : Debug - Check request status
  debug:
   msg: "{{ checkRequestStatus.json.state }}"
   
- name: Get vCenter mode after conversion
  uri:
    url: "{{ vxmUrl }}/{{ externalizeVcenterApiUrl }}"
    method: GET
    headers:
      Content-Type: application/json
      # Authorization: Basic {{ auth }}
    force_basic_auth: yes
    user: "{{ vCenterUsername }}"
    password: "{{ vCenterPassword }}"
    validate_certs: no
    return_content: yes
  register: getNewVcenterMode
  
- name : Debug - Get current vCenter mode
  debug:
   msg: "Current vCenter mode is:{{ getNewVcenterMode.json.vc_mode }}"
   
- name: "vCenter externalize task completed"
  debug:
    msg: "vCenter externalize task completed."
  when: "checkRequestStatus.json.state == 'COMPLETED'"

And pretty much that’s it. In next post i will show you how to automate changing vCenter components names: DC, cluster, vDS and vSAN datastore before VCF bring-up.