Fixed k8s: Deleting\adding a node in some cases applies to all cluster worker groups. ViNS: Mechanism for connecting several virtual network segments has been improved. Changed the mechanism for assigning an IP address for connecting via SSH. Add examples for usage Vault
This commit is contained in:
14
examples/hashivault_create_engine.yaml
Normal file
14
examples/hashivault_create_engine.yaml
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
#
|
||||||
|
# This playbook create engine "test".
|
||||||
|
#
|
||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- hashivault_secret_engine:
|
||||||
|
url: "https://vault.domain.local"
|
||||||
|
authtype: ldap
|
||||||
|
username: "user"
|
||||||
|
password: "p@ssword"
|
||||||
|
state: present
|
||||||
|
name: test
|
||||||
|
backend: generic
|
||||||
17
examples/hashivault_create_secret.yaml
Normal file
17
examples/hashivault_create_secret.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
---
|
||||||
|
#
|
||||||
|
# This playbook create secret "secret" with data foo:foe. If secret "secret" exists - add data foo:foe.
|
||||||
|
#
|
||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- hashivault_secret:
|
||||||
|
url: "https://vault.domain.local"
|
||||||
|
authtype: ldap
|
||||||
|
username: "user"
|
||||||
|
password: "p@ssword"
|
||||||
|
mount_point: "kv"
|
||||||
|
state: present
|
||||||
|
permanent: true
|
||||||
|
secret: secret
|
||||||
|
data:
|
||||||
|
foo: foe
|
||||||
35
examples/hashivault_example.yaml
Normal file
35
examples/hashivault_example.yaml
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
|
||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- hashivault_read:
|
||||||
|
url: "https://vault.domain.local"
|
||||||
|
authtype: ldap
|
||||||
|
username: "user"
|
||||||
|
password: "p@ssword"
|
||||||
|
mount_point: kv
|
||||||
|
secret: secrets/myaccount
|
||||||
|
key: app_secret
|
||||||
|
version: 2
|
||||||
|
register: key
|
||||||
|
|
||||||
|
- name: create a VM using app_secret from hashicorp vault
|
||||||
|
decort_kvmvm:
|
||||||
|
annotation: "VM managed by decort_kvmvm module"
|
||||||
|
authenticator: oauth2
|
||||||
|
app_id: "" # Application id from SSO Digital Energy
|
||||||
|
app_secret: "{{ key }}" # API key from SSO Digital Energy
|
||||||
|
controller_url: "https://cloud.digitalenergy.online"
|
||||||
|
name: hashivault_read_example
|
||||||
|
cpu: 2
|
||||||
|
ram: 2048
|
||||||
|
boot_disk: 10
|
||||||
|
image_name: "DECS Ubuntu 18.04 v1.2.3" #Name of OS image
|
||||||
|
networks:
|
||||||
|
- type: VINS
|
||||||
|
id: 99 #VINS id
|
||||||
|
tags: "Ansible hashivault_read example"
|
||||||
|
state: present
|
||||||
|
rg_id: 99 #Resource group id
|
||||||
|
delegate_to: localhost
|
||||||
|
register: simple_vm
|
||||||
31
examples/hashivault_plugin_example.yaml
Normal file
31
examples/hashivault_plugin_example.yaml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Read a kv2 secret with kv mount point
|
||||||
|
vars:
|
||||||
|
ansible_hashi_vault_auth_method: ldap
|
||||||
|
ansible_hashi_vault_username: username
|
||||||
|
ansible_hashi_vault_password: pwd
|
||||||
|
ansible_hashi_vault_engine_mount_point: kv
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
response: "{{ lookup('community.hashi_vault.vault_kv2_get', 'secret', url='https://vault.domain.local') }}"
|
||||||
|
|
||||||
|
- name: create a VM using app_secret from hashicorp vault
|
||||||
|
decort_kvmvm:
|
||||||
|
annotation: "VM managed by decort_kvmvm module"
|
||||||
|
authenticator: oauth2
|
||||||
|
app_id: "" # Application id from SSO Digital Energy
|
||||||
|
app_secret: "{{ response.data.password }}" # API key from SSO Digital Energy
|
||||||
|
controller_url: "https://cloud.digitalenergy.online"
|
||||||
|
name: hashivault_read_example
|
||||||
|
cpu: 2
|
||||||
|
ram: 2048
|
||||||
|
boot_disk: 10
|
||||||
|
image_name: "DECS Ubuntu 18.04 v1.2.3" #Name of OS image
|
||||||
|
networks:
|
||||||
|
- type: VINS
|
||||||
|
id: 99 #VINS id
|
||||||
|
tags: "Ansible hashivault_read example"
|
||||||
|
state: present
|
||||||
|
rg_id: 99 #Resource group id
|
||||||
|
delegate_to: localhost
|
||||||
|
register: simple_vm
|
||||||
16
examples/hashivault_plugin_login.yaml
Normal file
16
examples/hashivault_plugin_login.yaml
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Get auth token from vault
|
||||||
|
set_fact:
|
||||||
|
login_data: "{{ lookup('community.hashi_vault.vault_login', url='https://vault.domain.local', auth_method='ldap', username='username', password='pwd') }}"
|
||||||
|
|
||||||
|
- name: Perform multiple kv2 reads with a single Vault login, showing the secrets
|
||||||
|
vars:
|
||||||
|
ansible_hashi_vault_auth_method: token
|
||||||
|
ansible_hashi_vault_token: '{{ login_data | community.hashi_vault.vault_login_token }}'
|
||||||
|
ansible_hashi_vault_engine_mount_point: kv
|
||||||
|
paths:
|
||||||
|
- secret
|
||||||
|
- secret2
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg: "{{ lookup('community.hashi_vault.vault_kv2_get', *paths, auth_method='token', url='https://vault.domain.local') }}"
|
||||||
18
examples/hashivault_plugin_read_secret.yaml
Normal file
18
examples/hashivault_plugin_read_secret.yaml
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- name: Read a kv2 secret with the default mount point
|
||||||
|
vars:
|
||||||
|
ansible_hashi_vault_auth_method: ldap
|
||||||
|
ansible_hashi_vault_username: username
|
||||||
|
ansible_hashi_vault_password: pwd
|
||||||
|
ansible_hashi_vault_engine_mount_point: kv
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
response: "{{ lookup('community.hashi_vault.vault_kv2_get', 'secret', url='https://vault.domain.local') }}"
|
||||||
|
|
||||||
|
- name: Display the results
|
||||||
|
ansible.builtin.debug:
|
||||||
|
msg:
|
||||||
|
- "Secret: {{ response.secret }}"
|
||||||
|
- "Data: {{ response.data }} (contains secret data & metadata in kv2)"
|
||||||
|
- "Metadata: {{ response.metadata }}"
|
||||||
|
- "Full response: {{ response.raw }}"
|
||||||
13
examples/hashivault_read_secret.yaml
Normal file
13
examples/hashivault_read_secret.yaml
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
---
|
||||||
|
- hosts: localhost
|
||||||
|
tasks:
|
||||||
|
- hashivault_read:
|
||||||
|
url: "https://vault.domain.local"
|
||||||
|
authtype: ldap
|
||||||
|
username: "uset"
|
||||||
|
password: "p@ssword"
|
||||||
|
mount_point: kv
|
||||||
|
secret: secret
|
||||||
|
key: foo
|
||||||
|
version: 2
|
||||||
|
register: key
|
||||||
@@ -114,10 +114,10 @@ class decort_k8s(DecortController):
|
|||||||
return ret_dict
|
return ret_dict
|
||||||
|
|
||||||
def nop(self):
|
def nop(self):
|
||||||
"""No operation (NOP) handler for Compute management by decort_kvmvm module.
|
"""No operation (NOP) handler for k8s cluster management by decort_k8s module.
|
||||||
This function is intended to be called from the main switch construct of the module
|
This function is intended to be called from the main switch construct of the module
|
||||||
when current state -> desired state change logic does not require any changes to
|
when current state -> desired state change logic does not require any changes to
|
||||||
the actual Compute state.
|
the actual k8s cluster state.
|
||||||
"""
|
"""
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
self.result['changed'] = False
|
self.result['changed'] = False
|
||||||
|
|||||||
@@ -242,17 +242,185 @@ facts:
|
|||||||
|
|
||||||
from ansible.module_utils.basic import AnsibleModule
|
from ansible.module_utils.basic import AnsibleModule
|
||||||
from ansible.module_utils.basic import env_fallback
|
from ansible.module_utils.basic import env_fallback
|
||||||
import paramiko
|
|
||||||
|
|
||||||
from ansible.module_utils.decort_utils import *
|
from ansible.module_utils.decort_utils import *
|
||||||
|
|
||||||
|
class decort_vins(DecortController):
|
||||||
|
def __init__(self,arg_amodule):
|
||||||
|
super(decort_vins, self).__init__(arg_amodule)
|
||||||
|
|
||||||
def decort_vins_package_facts(arg_vins_facts, arg_check_mode=False):
|
vins_id = 0
|
||||||
|
vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level
|
||||||
|
vins_facts = None # will hold ViNS facts
|
||||||
|
validated_rg_id = 0
|
||||||
|
rg_facts = None # will hold RG facts
|
||||||
|
validated_acc_id = 0
|
||||||
|
acc_facts = None # will hold Account facts
|
||||||
|
|
||||||
|
if arg_amodule.params['vins_id']:
|
||||||
|
# expect existing ViNS with the specified ID
|
||||||
|
# This call to vins_find will abort the module if no ViNS with such ID is present
|
||||||
|
self.vins_id, self.vins_facts = self.vins_find(arg_amodule.params['vins_id'])
|
||||||
|
if not vins_id:
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['msg'] = "Specified ViNS ID {} not found.".format(arg_amodule.params['vins_id'])
|
||||||
|
self.fail_json(**self.result)
|
||||||
|
vins_level = "ID"
|
||||||
|
validated_acc_id = vins_facts['accountId']
|
||||||
|
validated_rg_id = vins_facts['rgId']
|
||||||
|
|
||||||
|
elif arg_amodule.params['rg_id']:
|
||||||
|
# expect ViNS @ RG level in the RG with specified ID
|
||||||
|
vins_level = "RG"
|
||||||
|
# This call to rg_find will abort the module if no RG with such ID is present
|
||||||
|
validated_rg_id, rg_facts = self.rg_find(0, # account ID set to 0 as we search for RG by RG ID
|
||||||
|
arg_amodule.params['rg_id'], arg_rg_name="")
|
||||||
|
|
||||||
|
# This call to vins_find may return vins_id=0 if no ViNS found
|
||||||
|
self.vins_id, self.vins_facts = self.vins_find(vins_id=0, vins_name=arg_amodule.params['vins_name'],
|
||||||
|
account_id=0,
|
||||||
|
rg_id=arg_amodule.params['rg_id'],
|
||||||
|
rg_facts=rg_facts,
|
||||||
|
check_state=False)
|
||||||
|
# TODO: add checks and setup ViNS presence flags accordingly
|
||||||
|
pass
|
||||||
|
elif arg_amodule.params['account_id'] or arg_amodule.params['account_name'] != "":
|
||||||
|
# Specified account must be present and accessible by the user, otherwise abort the module
|
||||||
|
validated_acc_id, acc_facts = self.account_find(arg_amodule.params['account_name'], arg_amodule.params['account_id'])
|
||||||
|
if not validated_acc_id:
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['msg'] = ("Current user does not have access to the requested account "
|
||||||
|
"or non-existent account specified.")
|
||||||
|
self.fail_json(**self.result)
|
||||||
|
if arg_amodule.params['rg_name'] != "": # at this point we know that rg_id=0
|
||||||
|
# expect ViNS @ RG level in the RG with specified name under specified account
|
||||||
|
# RG with the specified name must be present under the account, otherwise abort the module
|
||||||
|
validated_rg_id, rg_facts = self.rg_find(validated_acc_id, 0, arg_amodule.params['rg_name'])
|
||||||
|
if (not validated_rg_id or
|
||||||
|
rg_facts['status'] in ["DESTROYING", "DESTROYED", "DELETING", "DELETED", "DISABLING", "ENABLING"]):
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['msg'] = "RG name '{}' not found or has invalid state.".format(arg_amodule.params['rg_name'])
|
||||||
|
self.fail_json(**self.result)
|
||||||
|
# This call to vins_find may return vins_id=0 if no ViNS with this name found under specified RG
|
||||||
|
self.vins_id, self.vins_facts = self.vins_find(vins_id=0, vins_name=arg_amodule.params['vins_name'],
|
||||||
|
account_id=0, # set to 0, as we are looking for ViNS under RG
|
||||||
|
rg_id=validated_rg_id,
|
||||||
|
rg_facts=rg_facts,
|
||||||
|
check_state=False)
|
||||||
|
vins_level = "RG"
|
||||||
|
# TODO: add checks and setup ViNS presence flags accordingly
|
||||||
|
else: # At this point we know for sure that rg_name="" and rg_id=0
|
||||||
|
# So we expect ViNS @ account level
|
||||||
|
# This call to vins_find may return vins_id=0 if no ViNS found
|
||||||
|
self.vins_id, self.vins_facts = self.vins_find(vins_id=0, vins_name=arg_amodule.params['vins_name'],
|
||||||
|
account_id=validated_acc_id,
|
||||||
|
rg_id=0,
|
||||||
|
rg_facts=rg_facts,
|
||||||
|
check_state=False)
|
||||||
|
vins_level = "ACC"
|
||||||
|
# TODO: add checks and setup ViNS presence flags accordingly
|
||||||
|
else:
|
||||||
|
# this is "invalid arguments combination" sink
|
||||||
|
# if we end up here, it means that module was invoked with vins_id=0 and rg_id=0
|
||||||
|
self.result['failed'] = True
|
||||||
|
if arg_amodule.params['account_id'] == 0 and arg_amodule.params['account_name'] == "":
|
||||||
|
self.result['msg'] = "Cannot find ViNS by name when account name is empty and account ID is 0."
|
||||||
|
if arg_amodule.params['rg_name'] == "":
|
||||||
|
# rg_name without account specified
|
||||||
|
self.result['msg'] = "Cannot find ViNS by name when RG name is empty and RG ID is 0."
|
||||||
|
self.fail_json(**self.result)
|
||||||
|
|
||||||
|
return
|
||||||
|
self.rg_id = validated_rg_id
|
||||||
|
self.acc_id = validated_acc_id
|
||||||
|
return
|
||||||
|
def create(self):
|
||||||
|
self.vins_id = self.vins_provision(self.amodule.params['vins_name'],
|
||||||
|
self.acc_id, self.rg_id,
|
||||||
|
self.amodule.params['ipcidr'],
|
||||||
|
self.amodule.params['ext_net_id'], self.amodule.params['ext_ip_addr'],
|
||||||
|
self.amodule.params['annotation'])
|
||||||
|
|
||||||
|
if self.amodule.params['mgmtaddr'] or self.amodule.params['connect_to']:
|
||||||
|
_, self.vins_facts = self.vins_find(self.vins_id)
|
||||||
|
if self.amodule.params['connect_to']:
|
||||||
|
self.vins_update_ifaces(self.vins_facts,self.amodule.params['connect_to'],)
|
||||||
|
if self.amodule.params['mgmtaddr']:
|
||||||
|
self.vins_update_mgmt(self.vins_facts,self.amodule.params['mgmtaddr'])
|
||||||
|
|
||||||
|
return
|
||||||
|
def action(self,d_state='',restore=False):
|
||||||
|
if restore == True:
|
||||||
|
self.vins_restore(arg_vins_id=self.vins_id)
|
||||||
|
self.vins_state(self.vins_facts, 'enabled')
|
||||||
|
self.vins_facts['status'] = "ENABLED"
|
||||||
|
self.vins_facts['VNFDev']['techStatus'] = "STARTED"
|
||||||
|
|
||||||
|
self.vins_update_extnet(self.vins_facts,
|
||||||
|
self.amodule.params['ext_net_id'],
|
||||||
|
self.amodule.params['ext_ip_addr'],
|
||||||
|
)
|
||||||
|
|
||||||
|
if d_state == 'enabled' and self.vins_facts['status'] == "DISABLED":
|
||||||
|
self.vins_state(self.vins_facts, d_state)
|
||||||
|
self.vins_facts['status'] = "ENABLED"
|
||||||
|
self.vins_facts['VNFDev']['techStatus'] = "STARTED"
|
||||||
|
d_state = ''
|
||||||
|
|
||||||
|
if self.vins_facts['status'] == "ENABLED" and self.vins_facts['VNFDev']['techStatus'] == "STARTED":
|
||||||
|
self.vins_update_ifaces(self.vins_facts,
|
||||||
|
self.amodule.params['connect_to'],
|
||||||
|
)
|
||||||
|
if self.result['changed']:
|
||||||
|
_, self.vins_facts = self.vins_find(self.vins_id)
|
||||||
|
self.vins_update_mgmt(self.vins_facts,
|
||||||
|
self.amodule.params['mgmtaddr'],
|
||||||
|
)
|
||||||
|
|
||||||
|
if d_state != '':
|
||||||
|
self.vins_state(self.vins_facts, d_state)
|
||||||
|
return
|
||||||
|
def delete(self):
|
||||||
|
self.vins_delete(self.vins_id, permanently=True)
|
||||||
|
self.vins_facts['status'] = 'DESTROYED'
|
||||||
|
return
|
||||||
|
def nop(self):
|
||||||
|
"""No operation (NOP) handler for ViNS management by decort_vins module.
|
||||||
|
This function is intended to be called from the main switch construct of the module
|
||||||
|
when current state -> desired state change logic does not require any changes to
|
||||||
|
the actual ViNS state.
|
||||||
|
"""
|
||||||
|
self.result['failed'] = False
|
||||||
|
self.result['changed'] = False
|
||||||
|
if self.vins_id:
|
||||||
|
self.result['msg'] = ("No state change required for ViNS ID {} because of its "
|
||||||
|
"current status '{}'.").format(self.vins_id, self.vins_facts['status'])
|
||||||
|
else:
|
||||||
|
self.result['msg'] = ("No state change to '{}' can be done for "
|
||||||
|
"non-existent ViNS instance.").format(self.amodule.params['state'])
|
||||||
|
return
|
||||||
|
def error(self):
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['changed'] = False
|
||||||
|
if self.vins_id:
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['changed'] = False
|
||||||
|
self.result['msg'] = ("Invalid target state '{}' requested for ViNS ID {} in the "
|
||||||
|
"current status '{}'").format(self.vins_id,
|
||||||
|
self.amodule.params['state'],
|
||||||
|
self.vins_facts['status'])
|
||||||
|
else:
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['changed'] = False
|
||||||
|
self.result['msg'] = ("Invalid target state '{}' requested for non-existent "
|
||||||
|
"ViNS name '{}'").format(self.amodule.params['state'],
|
||||||
|
self.amodule.params['vins_name'])
|
||||||
|
return
|
||||||
|
def package_facts(self, arg_check_mode=False):
|
||||||
"""Package a dictionary of ViNS facts according to the decort_vins module specification.
|
"""Package a dictionary of ViNS facts according to the decort_vins module specification.
|
||||||
This dictionary will be returned to the upstream Ansible engine at the completion of
|
This dictionary will be returned to the upstream Ansible engine at the completion of
|
||||||
the module run.
|
the module run.
|
||||||
|
|
||||||
@param arg_vins_facts: dictionary with viNS facts as returned by API call to .../vins/get
|
|
||||||
@param arg_check_mode: boolean that tells if this Ansible module is run in check mode
|
@param arg_check_mode: boolean that tells if this Ansible module is run in check mode
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -265,21 +433,32 @@ def decort_vins_package_facts(arg_vins_facts, arg_check_mode=False):
|
|||||||
# in check mode return immediately with the default values
|
# in check mode return immediately with the default values
|
||||||
return ret_dict
|
return ret_dict
|
||||||
|
|
||||||
if arg_vins_facts is None:
|
if self.vins_facts is None:
|
||||||
# if void facts provided - change state value to ABSENT and return
|
# if void facts provided - change state value to ABSENT and return
|
||||||
ret_dict['state'] = "ABSENT"
|
ret_dict['state'] = "ABSENT"
|
||||||
return ret_dict
|
return ret_dict
|
||||||
|
|
||||||
ret_dict['id'] = arg_vins_facts['id']
|
ret_dict['id'] = self.vins_facts['id']
|
||||||
ret_dict['name'] = arg_vins_facts['name']
|
ret_dict['name'] = self.vins_facts['name']
|
||||||
ret_dict['state'] = arg_vins_facts['status']
|
ret_dict['state'] = self.vins_facts['status']
|
||||||
ret_dict['account_id'] = arg_vins_facts['accountId']
|
ret_dict['account_id'] = self.vins_facts['accountId']
|
||||||
ret_dict['rg_id'] = arg_vins_facts['rgId']
|
ret_dict['rg_id'] = self.vins_facts['rgId']
|
||||||
ret_dict['int_net_addr'] = arg_vins_facts['network']
|
ret_dict['int_net_addr'] = self.vins_facts['network']
|
||||||
ret_dict['gid'] = arg_vins_facts['gid']
|
ret_dict['gid'] = self.vins_facts['gid']
|
||||||
|
custom_interfaces = list(filter(lambda i: i['type']=="CUSTOM",self.vins_facts['VNFDev']['interfaces']))
|
||||||
if arg_vins_facts['vnfs'].get('GW'):
|
if custom_interfaces:
|
||||||
gw_config = arg_vins_facts['vnfs']['GW']['config']
|
ret_dict['custom_net_addr'] = []
|
||||||
|
for runner in custom_interfaces:
|
||||||
|
ret_dict['custom_net_addr'].append(runner['ipAddress'])
|
||||||
|
mgmt_interfaces = list(filter(lambda i: i['listenSsh'] and i['name']!="ens9",self.vins_facts['VNFDev']['interfaces']))
|
||||||
|
if mgmt_interfaces:
|
||||||
|
ret_dict['ssh_ipaddr'] = []
|
||||||
|
for runner in mgmt_interfaces:
|
||||||
|
ret_dict['ssh_ipaddr'].append(runner['ipAddress'])
|
||||||
|
ret_dict['ssh_password'] = self.vins_facts['VNFDev']['config']['mgmt']['password']
|
||||||
|
ret_dict['ssh_port'] = 9022
|
||||||
|
if self.vins_facts['vnfs'].get('GW'):
|
||||||
|
gw_config = self.vins_facts['vnfs']['GW']['config']
|
||||||
ret_dict['ext_ip_addr'] = gw_config['ext_net_ip']
|
ret_dict['ext_ip_addr'] = gw_config['ext_net_ip']
|
||||||
ret_dict['ext_net_id'] = gw_config['ext_net_id']
|
ret_dict['ext_net_id'] = gw_config['ext_net_id']
|
||||||
else:
|
else:
|
||||||
@@ -293,8 +472,8 @@ def decort_vins_package_facts(arg_vins_facts, arg_check_mode=False):
|
|||||||
|
|
||||||
return ret_dict
|
return ret_dict
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
def decort_vins_parameters():
|
def build_parameters():
|
||||||
"""Build and return a dictionary of parameters expected by decort_vins module in a form accepted
|
"""Build and return a dictionary of parameters expected by decort_vins module in a form accepted
|
||||||
by AnsibleModule utility class."""
|
by AnsibleModule utility class."""
|
||||||
|
|
||||||
@@ -317,7 +496,7 @@ def decort_vins_parameters():
|
|||||||
ext_net_id=dict(type='int', required=False, default=-1),
|
ext_net_id=dict(type='int', required=False, default=-1),
|
||||||
ext_ip_addr=dict(type='str', required=False, default=''),
|
ext_ip_addr=dict(type='str', required=False, default=''),
|
||||||
ipcidr=dict(type='str', required=False, default=''),
|
ipcidr=dict(type='str', required=False, default=''),
|
||||||
mgmtaddr=dict(type='str',required=False, default=''),
|
mgmtaddr=dict(type='list',required=False, default=[]),
|
||||||
custom_config=dict(type='bool',required=False, default=False),
|
custom_config=dict(type='bool',required=False, default=False),
|
||||||
config_save=dict(type='bool',required=False, default=False),
|
config_save=dict(type='bool',required=False, default=False),
|
||||||
connect_to=dict(type='list', default=[], required=False),
|
connect_to=dict(type='list', default=[], required=False),
|
||||||
@@ -356,7 +535,7 @@ def decort_vins_parameters():
|
|||||||
# 5) report result to Ansible
|
# 5) report result to Ansible
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
module_parameters = decort_vins_parameters()
|
module_parameters = decort_vins.build_parameters()
|
||||||
|
|
||||||
amodule = AnsibleModule(argument_spec=module_parameters,
|
amodule = AnsibleModule(argument_spec=module_parameters,
|
||||||
supports_check_mode=True,
|
supports_check_mode=True,
|
||||||
@@ -371,84 +550,7 @@ def main():
|
|||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
decon = DecortController(amodule)
|
decon = decort_vins(amodule)
|
||||||
|
|
||||||
vins_id = 0
|
|
||||||
vins_level = "" # "ID" if specified by ID, "RG" - at resource group, "ACC" - at account level
|
|
||||||
vins_facts = None # will hold ViNS facts
|
|
||||||
validated_rg_id = 0
|
|
||||||
rg_facts = None # will hold RG facts
|
|
||||||
validated_acc_id = 0
|
|
||||||
acc_facts = None # will hold Account facts
|
|
||||||
|
|
||||||
if amodule.params['vins_id']:
|
|
||||||
# expect existing ViNS with the specified ID
|
|
||||||
# This call to vins_find will abort the module if no ViNS with such ID is present
|
|
||||||
vins_id, vins_facts = decon.vins_find(amodule.params['vins_id'])
|
|
||||||
if not vins_id:
|
|
||||||
decon.result['failed'] = True
|
|
||||||
decon.result['msg'] = "Specified ViNS ID {} not found.".format(amodule.params['vins_id'])
|
|
||||||
decon.fail_json(**decon.result)
|
|
||||||
vins_level = "ID"
|
|
||||||
validated_acc_id = vins_facts['accountId']
|
|
||||||
validated_rg_id = vins_facts['rgId']
|
|
||||||
|
|
||||||
elif amodule.params['rg_id']:
|
|
||||||
# expect ViNS @ RG level in the RG with specified ID
|
|
||||||
vins_level = "RG"
|
|
||||||
# This call to rg_find will abort the module if no RG with such ID is present
|
|
||||||
validated_rg_id, rg_facts = decon.rg_find(0, # account ID set to 0 as we search for RG by RG ID
|
|
||||||
amodule.params['rg_id'], arg_rg_name="")
|
|
||||||
# This call to vins_find may return vins_id=0 if no ViNS found
|
|
||||||
vins_id, vins_facts = decon.vins_find(vins_id=0, vins_name=amodule.params['vins_name'],
|
|
||||||
account_id=0,
|
|
||||||
rg_id=amodule.params['rg_id'],
|
|
||||||
check_state=False)
|
|
||||||
# TODO: add checks and setup ViNS presence flags accordingly
|
|
||||||
pass
|
|
||||||
elif amodule.params['account_id'] or amodule.params['account_name'] != "":
|
|
||||||
# Specified account must be present and accessible by the user, otherwise abort the module
|
|
||||||
validated_acc_id, acc_facts = decon.account_find(amodule.params['account_name'], amodule.params['account_id'])
|
|
||||||
if not validated_acc_id:
|
|
||||||
decon.result['failed'] = True
|
|
||||||
decon.result['msg'] = ("Current user does not have access to the requested account "
|
|
||||||
"or non-existent account specified.")
|
|
||||||
decon.fail_json(**decon.result)
|
|
||||||
if amodule.params['rg_name'] != "": # at this point we know that rg_id=0
|
|
||||||
# expect ViNS @ RG level in the RG with specified name under specified account
|
|
||||||
# RG with the specified name must be present under the account, otherwise abort the module
|
|
||||||
validated_rg_id, rg_facts = decon.rg_find(validated_acc_id, 0, amodule.params['rg_name'])
|
|
||||||
if (not validated_rg_id or
|
|
||||||
rg_facts['status'] in ["DESTROYING", "DESTROYED", "DELETING", "DELETED", "DISABLING", "ENABLING"]):
|
|
||||||
decon.result['failed'] = True
|
|
||||||
decon.result['msg'] = "RG name '{}' not found or has invalid state.".format(amodule.params['rg_name'])
|
|
||||||
decon.fail_json(**decon.result)
|
|
||||||
# This call to vins_find may return vins_id=0 if no ViNS with this name found under specified RG
|
|
||||||
vins_id, vins_facts = decon.vins_find(vins_id=0, vins_name=amodule.params['vins_name'],
|
|
||||||
account_id=0, # set to 0, as we are looking for ViNS under RG
|
|
||||||
rg_id=validated_rg_id,
|
|
||||||
check_state=False)
|
|
||||||
vins_level = "RG"
|
|
||||||
# TODO: add checks and setup ViNS presence flags accordingly
|
|
||||||
else: # At this point we know for sure that rg_name="" and rg_id=0
|
|
||||||
# So we expect ViNS @ account level
|
|
||||||
# This call to vins_find may return vins_id=0 if no ViNS found
|
|
||||||
vins_id, vins_facts = decon.vins_find(vins_id=0, vins_name=amodule.params['vins_name'],
|
|
||||||
account_id=validated_acc_id,
|
|
||||||
rg_id=0,
|
|
||||||
check_state=False)
|
|
||||||
vins_level = "ACC"
|
|
||||||
# TODO: add checks and setup ViNS presence flags accordingly
|
|
||||||
else:
|
|
||||||
# this is "invalid arguments combination" sink
|
|
||||||
# if we end up here, it means that module was invoked with vins_id=0 and rg_id=0
|
|
||||||
decon.result['failed'] = True
|
|
||||||
if amodule.params['account_id'] == 0 and amodule.params['account_name'] == "":
|
|
||||||
decon.result['msg'] = "Cannot find ViNS by name when account name is empty and account ID is 0."
|
|
||||||
if amodule.params['rg_name'] == "":
|
|
||||||
# rg_name without account specified
|
|
||||||
decon.result['msg'] = "Cannot find ViNS by name when RG name is empty and RG ID is 0."
|
|
||||||
decon.fail_json(**decon.result)
|
|
||||||
#
|
#
|
||||||
# Initial validation of module arguments is complete
|
# Initial validation of module arguments is complete
|
||||||
#
|
#
|
||||||
@@ -465,127 +567,70 @@ def main():
|
|||||||
# if cconfig_save is true, only config save without other updates
|
# if cconfig_save is true, only config save without other updates
|
||||||
vins_should_exist = False
|
vins_should_exist = False
|
||||||
|
|
||||||
if vins_id:
|
if decon.vins_id:
|
||||||
vins_should_exist = True
|
vins_should_exist = True
|
||||||
if vins_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING", "DESTROYING"]:
|
if decon.vins_facts['status'] in ["MODELED", "DISABLING", "ENABLING", "DELETING", "DESTROYING"]:
|
||||||
# error: nothing can be done to existing ViNS in the listed statii regardless of
|
# error: nothing can be done to existing ViNS in the listed statii regardless of
|
||||||
# the requested state
|
# the requested state
|
||||||
decon.result['failed'] = True
|
decon.result['failed'] = True
|
||||||
decon.result['changed'] = False
|
decon.result['changed'] = False
|
||||||
decon.result['msg'] = ("No change can be done for existing ViNS ID {} because of its current "
|
decon.result['msg'] = ("No change can be done for existing ViNS ID {} because of its current "
|
||||||
"status '{}'").format(vins_id, vins_facts['status'])
|
"status '{}'").format(decon.vins_id, decon.vins_facts['status'])
|
||||||
elif vins_facts['status'] == "DISABLED":
|
elif decon.vins_facts['status'] == "DISABLED":
|
||||||
if amodule.params['state'] == 'absent':
|
if amodule.params['state'] == 'absent':
|
||||||
decon.vins_delete(vins_id, permanently=True)
|
decon.delete()
|
||||||
vins_facts['status'] = 'DESTROYED'
|
|
||||||
vins_should_exist = False
|
vins_should_exist = False
|
||||||
elif amodule.params['state'] in ('present', 'disabled'):
|
elif amodule.params['state'] in ('present', 'disabled'):
|
||||||
# update ViNS, leave in disabled state
|
# update ViNS, leave in disabled state
|
||||||
decon.vins_update(vins_facts,
|
decon.action()
|
||||||
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'])
|
|
||||||
elif amodule.params['state'] == 'enabled':
|
elif amodule.params['state'] == 'enabled':
|
||||||
# update ViNS and enable
|
# update ViNS and enable
|
||||||
decon.vins_update(vins_facts,
|
decon.action('enabled')
|
||||||
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'])
|
elif decon.vins_facts['status'] in ["CREATED", "ENABLED"]:
|
||||||
decon.vins_state(vins_facts, 'enabled')
|
|
||||||
elif vins_facts['status'] in ["CREATED", "ENABLED"]:
|
|
||||||
if amodule.params['state'] == 'absent':
|
if amodule.params['state'] == 'absent':
|
||||||
decon.vins_delete(vins_id, permanently=True)
|
decon.delete()
|
||||||
vins_facts['status'] = 'DESTROYED'
|
|
||||||
vins_should_exist = False
|
vins_should_exist = False
|
||||||
elif amodule.params['state'] in ('present', 'enabled'):
|
elif amodule.params['state'] in ('present', 'enabled'):
|
||||||
# update ViNS
|
# update ViNS
|
||||||
decon.vins_update(vins_facts,
|
decon.action()
|
||||||
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
|
|
||||||
|
|
||||||
)
|
|
||||||
decon.vins_update_mgmt(
|
|
||||||
vins_facts,
|
|
||||||
amodule.params['mgmtaddr'],
|
|
||||||
)
|
|
||||||
decon.vins_update_ifaces(
|
|
||||||
vins_facts,
|
|
||||||
amodule.params['connect_to'],
|
|
||||||
)
|
|
||||||
elif amodule.params['state'] == 'disabled':
|
elif amodule.params['state'] == 'disabled':
|
||||||
# disable and update ViNS
|
# disable and update ViNS
|
||||||
decon.vins_state(vins_facts, 'disabled')
|
decon.action('disabled')
|
||||||
decon.vins_update(vins_facts,
|
elif decon.vins_facts['status'] == "DELETED":
|
||||||
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'])
|
|
||||||
elif vins_facts['status'] == "DELETED":
|
|
||||||
if amodule.params['state'] in ['present', 'enabled']:
|
if amodule.params['state'] in ['present', 'enabled']:
|
||||||
# restore and enable
|
# restore and enable
|
||||||
decon.vins_restore(arg_vins_id=vins_id)
|
decon.action(restore=True)
|
||||||
decon.vins_state(vins_facts, 'enabled')
|
|
||||||
vins_should_exist = True
|
vins_should_exist = True
|
||||||
elif amodule.params['state'] == 'absent':
|
elif amodule.params['state'] == 'absent':
|
||||||
# destroy permanently
|
# destroy permanently
|
||||||
decon.vins_delete(vins_id, permanently=True)
|
decon.delete()
|
||||||
vins_facts['status'] = 'DESTROYED'
|
|
||||||
vins_should_exist = False
|
vins_should_exist = False
|
||||||
elif amodule.params['state'] == 'disabled':
|
elif amodule.params['state'] == 'disabled':
|
||||||
# error
|
decon.error()
|
||||||
decon.result['failed'] = True
|
|
||||||
decon.result['changed'] = False
|
|
||||||
decon.result['msg'] = ("Invalid target state '{}' requested for ViNS ID {} in the "
|
|
||||||
"current status '{}'").format(vins_id,
|
|
||||||
amodule.params['state'],
|
|
||||||
vins_facts['status'])
|
|
||||||
vins_should_exist = False
|
vins_should_exist = False
|
||||||
elif vins_facts['status'] == "DESTROYED":
|
elif decon.vins_facts['status'] == "DESTROYED":
|
||||||
if amodule.params['state'] in ('present', 'enabled'):
|
if amodule.params['state'] in ('present', 'enabled'):
|
||||||
# need to re-provision ViNS; some attributes may be changed, some stay the same.
|
# need to re-provision ViNS;
|
||||||
# account and RG - stays the same
|
decon.create()
|
||||||
# vins_name - stays the same
|
|
||||||
# IPcidr - take from module arguments
|
|
||||||
# ext IP address - take from module arguments
|
|
||||||
# annotation - take from module arguments
|
|
||||||
vins_id = decon.vins_provision(vins_facts['name'],
|
|
||||||
validated_acc_id, validated_rg_id,
|
|
||||||
amodule.params['ipcidr'],
|
|
||||||
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
|
|
||||||
amodule.params['annotation'])
|
|
||||||
vins_should_exist = True
|
vins_should_exist = True
|
||||||
elif amodule.params['state'] == 'absent':
|
elif amodule.params['state'] == 'absent':
|
||||||
# nop
|
decon.nop()
|
||||||
decon.result['failed'] = False
|
|
||||||
decon.result['changed'] = False
|
|
||||||
decon.result['msg'] = ("No state change required for ViNS ID {} because of its "
|
|
||||||
"current status '{}'").format(vins_id,
|
|
||||||
vins_facts['status'])
|
|
||||||
vins_should_exist = False
|
vins_should_exist = False
|
||||||
elif amodule.params['state'] == 'disabled':
|
elif amodule.params['state'] == 'disabled':
|
||||||
# error
|
decon.error()
|
||||||
decon.result['failed'] = True
|
|
||||||
decon.result['changed'] = False
|
|
||||||
decon.result['msg'] = ("Invalid target state '{}' requested for ViNS ID {} in the "
|
|
||||||
"current status '{}'").format(vins_id,
|
|
||||||
amodule.params['state'],
|
|
||||||
vins_facts['status'])
|
|
||||||
else:
|
else:
|
||||||
# Preexisting ViNS was not found.
|
# Preexisting ViNS was not found.
|
||||||
vins_should_exist = False # we will change it back to True if ViNS is created or restored
|
vins_should_exist = False # we will change it back to True if ViNS is created or restored
|
||||||
# If requested state is 'absent' - nothing to do
|
# If requested state is 'absent' - nothing to do
|
||||||
if amodule.params['state'] == 'absent':
|
if amodule.params['state'] == 'absent':
|
||||||
decon.result['failed'] = False
|
decon.nop()
|
||||||
decon.result['changed'] = False
|
|
||||||
decon.result['msg'] = ("Nothing to do as target state 'absent' was requested for "
|
|
||||||
"non-existent ViNS name '{}'").format(amodule.params['vins_name'])
|
|
||||||
elif amodule.params['state'] in ('present', 'enabled'):
|
elif amodule.params['state'] in ('present', 'enabled'):
|
||||||
decon.check_amodule_argument('vins_name')
|
decon.check_amodule_argument('vins_name')
|
||||||
# as we already have account ID and RG ID we can create ViNS and get vins_id on success
|
# as we already have account ID and RG ID we can create ViNS and get vins_id on success
|
||||||
vins_id = decon.vins_provision(amodule.params['vins_name'],
|
decon.create()
|
||||||
validated_acc_id, validated_rg_id,
|
|
||||||
amodule.params['ipcidr'],
|
|
||||||
amodule.params['ext_net_id'], amodule.params['ext_ip_addr'],
|
|
||||||
amodule.params['annotation'])
|
|
||||||
vins_should_exist = True
|
vins_should_exist = True
|
||||||
elif amodule.params['state'] == 'disabled':
|
elif amodule.params['state'] == 'disabled':
|
||||||
decon.result['failed'] = True
|
decon.error()
|
||||||
decon.result['changed'] = False
|
|
||||||
decon.result['msg'] = ("Invalid target state '{}' requested for non-existent "
|
|
||||||
"ViNS name '{}'").format(amodule.params['state'],
|
|
||||||
amodule.params['vins_name'])
|
|
||||||
#
|
#
|
||||||
# conditional switch end - complete module run
|
# conditional switch end - complete module run
|
||||||
#
|
#
|
||||||
@@ -593,18 +638,9 @@ def main():
|
|||||||
amodule.fail_json(**decon.result)
|
amodule.fail_json(**decon.result)
|
||||||
else:
|
else:
|
||||||
# prepare ViNS facts to be returned as part of decon.result and then call exit_json(...)
|
# prepare ViNS facts to be returned as part of decon.result and then call exit_json(...)
|
||||||
if vins_should_exist:
|
|
||||||
if decon.result['changed']:
|
if decon.result['changed']:
|
||||||
# If we arrive here, there is a good chance that the ViNS is present - get fresh ViNS
|
_, decon.vins_facts = decon.vins_find(decon.vins_id)
|
||||||
# facts from # the cloud by ViNS ID.
|
decon.result['facts'] = decon.package_facts(amodule.check_mode)
|
||||||
# Otherwise, ViNS facts from previous call (when the ViNS was still in existence) will
|
|
||||||
# be returned.
|
|
||||||
_, vins_facts = decon.vins_find(vins_id)
|
|
||||||
decon.result['facts'] = decort_vins_package_facts(vins_facts, amodule.check_mode)
|
|
||||||
# add password to facts if mgmtaddr is present
|
|
||||||
# need reworking
|
|
||||||
if amodule.params['mgmtaddr'] != "":
|
|
||||||
decon.result['facts'].update({'password': vins_facts['VNFDev']['config']['mgmt']['password']})
|
|
||||||
amodule.exit_json(**decon.result)
|
amodule.exit_json(**decon.result)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2051,8 +2051,27 @@ class DecortController(object):
|
|||||||
"response {}.").format(vins_id, api_resp.status_code, api_resp.reason)
|
"response {}.").format(vins_id, api_resp.status_code, api_resp.reason)
|
||||||
|
|
||||||
return ret_vins_id, ret_vins_dict
|
return ret_vins_id, ret_vins_dict
|
||||||
|
def _rg_listvins(self,rg_id):
|
||||||
|
"""List all ViNS in the resource group
|
||||||
|
@param (int) rg_id: id onr resource group
|
||||||
|
"""
|
||||||
|
if not rg_id:
|
||||||
|
self.result['failed'] = True
|
||||||
|
self.result['msg'] = "_rg_listvins(): zero RG ID specified."
|
||||||
|
self.amodule.fail_json(**self.result)
|
||||||
|
|
||||||
def vins_find(self, vins_id, vins_name="", account_id=0, rg_id=0, check_state=True):
|
api_params = dict(rgId=rg_id, )
|
||||||
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/rg/listVins", api_params)
|
||||||
|
if api_resp.status_code == 200:
|
||||||
|
ret_rg_vins_list = json.loads(api_resp.content.decode('utf8'))
|
||||||
|
else:
|
||||||
|
self.result['warning'] = ("rg_listvins(): failed to get RG by ID {}. HTTP code {}, "
|
||||||
|
"response {}.").format(rg_id, api_resp.status_code, api_resp.reason)
|
||||||
|
return []
|
||||||
|
|
||||||
|
return ret_rg_vins_list
|
||||||
|
|
||||||
|
def vins_find(self, vins_id, vins_name="", account_id=0, rg_id=0, rg_facts="", check_state=True):
|
||||||
"""Find specified ViNS.
|
"""Find specified ViNS.
|
||||||
|
|
||||||
@param (int) vins_id: ID of the ViNS. If non-zero vins_id is specified, all other arguments
|
@param (int) vins_id: ID of the ViNS. If non-zero vins_id is specified, all other arguments
|
||||||
@@ -2093,29 +2112,29 @@ class DecortController(object):
|
|||||||
elif vins_name != "":
|
elif vins_name != "":
|
||||||
if rg_id > 0:
|
if rg_id > 0:
|
||||||
# search for ViNS at RG level
|
# search for ViNS at RG level
|
||||||
validated_id, validated_facts = self._rg_get_by_id(rg_id)
|
# validated_id, validated_facts = self._rg_get_by_id(rg_id)
|
||||||
if not validated_id:
|
# if not validated_id:
|
||||||
self.result['failed'] = True
|
# self.result['failed'] = True
|
||||||
self.result['msg'] = "vins_find(): cannot find RG ID {}.".format(rg_id)
|
# self.result['msg'] = "vins_find(): cannot find RG ID {}.".format(rg_id)
|
||||||
self.amodule.fail_json(**self.result)
|
# self.amodule.fail_json(**self.result)
|
||||||
# NOTE: RG's 'vins' attribute does not list destroyed ViNSes!
|
# # NOTE: RG's 'vins' attribute does not list destroyed ViNSes!
|
||||||
for runner in validated_facts['vins']:
|
list_vins = self._rg_listvins(rg_id)
|
||||||
# api_params['vinsId'] = runner
|
for vins in list_vins:
|
||||||
ret_vins_id, ret_vins_facts = self._vins_get_by_id(runner)
|
if vins['name'] == vins_name:
|
||||||
if ret_vins_id and ret_vins_facts['name'] == vins_name:
|
ret_vins_id, ret_vins_facts = self._vins_get_by_id(vins['id'])
|
||||||
if not check_state or ret_vins_facts['status'] not in VINS_INVALID_STATES:
|
if not check_state or ret_vins_facts['status'] not in VINS_INVALID_STATES:
|
||||||
return ret_vins_id, ret_vins_facts
|
return ret_vins_id, ret_vins_facts
|
||||||
else:
|
else:
|
||||||
return 0, None
|
return 0, None
|
||||||
elif account_id > 0:
|
elif account_id > 0:
|
||||||
# search for ViNS at account level
|
# search for ViNS at account level
|
||||||
validated_id, validated_facts = self.account_find("", account_id)
|
# validated_id, validated_facts = self.account_find("", account_id)
|
||||||
if not validated_id:
|
# if not validated_id:
|
||||||
self.result['failed'] = True
|
# self.result['failed'] = True
|
||||||
self.result['msg'] = "vins_find(): cannot find Account ID {}.".format(account_id)
|
# self.result['msg'] = "vins_find(): cannot find Account ID {}.".format(account_id)
|
||||||
self.amodule.fail_json(**self.result)
|
# self.amodule.fail_json(**self.result)
|
||||||
# NOTE: account's 'vins' attribute does not list destroyed ViNSes!
|
# NOTE: account's 'vins' attribute does not list destroyed ViNSes!
|
||||||
for runner in validated_facts['vins']:
|
for runner in rg_facts['vins']:
|
||||||
# api_params['vinsId'] = runner
|
# api_params['vinsId'] = runner
|
||||||
ret_vins_id, ret_vins_facts = self._vins_get_by_id(runner)
|
ret_vins_id, ret_vins_facts = self._vins_get_by_id(runner)
|
||||||
if ret_vins_id and ret_vins_facts['name'] == vins_name:
|
if ret_vins_id and ret_vins_facts['name'] == vins_name:
|
||||||
@@ -2296,7 +2315,7 @@ class DecortController(object):
|
|||||||
desired_state)
|
desired_state)
|
||||||
return
|
return
|
||||||
|
|
||||||
def vins_update(self, vins_dict, ext_net_id, ext_ip_addr=""):
|
def vins_update_extnet(self, vins_dict, ext_net_id, ext_ip_addr=""):
|
||||||
"""Update ViNS. Currently only updates to the external network connection settings and
|
"""Update ViNS. Currently only updates to the external network connection settings and
|
||||||
external IP address assignment are implemented.
|
external IP address assignment are implemented.
|
||||||
Note that as ViNS created at account level cannot have external connections, attempt
|
Note that as ViNS created at account level cannot have external connections, attempt
|
||||||
@@ -2318,7 +2337,7 @@ class DecortController(object):
|
|||||||
|
|
||||||
if self.amodule.check_mode:
|
if self.amodule.check_mode:
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
self.result['msg'] = ("vins_update() in check mode: updating ViNS ID {}, name '{}' "
|
self.result['msg'] = ("vins_update_extnet() in check mode: updating ViNS ID {}, name '{}' "
|
||||||
"was requested.").format(vins_dict['id'], vins_dict['name'])
|
"was requested.").format(vins_dict['id'], vins_dict['name'])
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -2373,10 +2392,16 @@ class DecortController(object):
|
|||||||
gw_config[
|
gw_config[
|
||||||
'ext_net_id'])
|
'ext_net_id'])
|
||||||
return
|
return
|
||||||
def vins_update_mgmt(self, vins_dict, mgmtaddr=""):
|
def vins_update_mgmt(self, vins_dict, mgmtaddr=[]):
|
||||||
|
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_update_mgmt")
|
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_update_mgmt")
|
||||||
|
|
||||||
|
if self.amodule.check_mode:
|
||||||
|
self.result['failed'] = False
|
||||||
|
self.result['msg'] = ("vins_update_mgmt() in check mode: updating ViNS ID {}, name '{}' "
|
||||||
|
"was requested.").format(vins_dict['id'], vins_dict['name'])
|
||||||
|
return
|
||||||
|
|
||||||
if self.amodule.params['config_save'] and vins_dict['VNFDev']['customPrecfg']:
|
if self.amodule.params['config_save'] and vins_dict['VNFDev']['customPrecfg']:
|
||||||
# only save config,no other modifictaion
|
# only save config,no other modifictaion
|
||||||
self.result['changed'] = True
|
self.result['changed'] = True
|
||||||
@@ -2386,13 +2411,12 @@ class DecortController(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
for iface in vins_dict['VNFDev']['interfaces']:
|
for iface in vins_dict['VNFDev']['interfaces']:
|
||||||
if iface['ipAddress'] == mgmtaddr:
|
if iface['ipAddress'] in mgmtaddr and not iface['listenSsh']:
|
||||||
if not iface['listenSsh']:
|
self._vins_vnf_addmgmtaddr(vins_dict['VNFDev']['id'],iface['ipAddress'])
|
||||||
self._vins_vnf_addmgmtaddr(vins_dict['VNFDev']['id'],mgmtaddr)
|
|
||||||
self.result['changed'] = True
|
self.result['changed'] = True
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
elif mgmtaddr =="":
|
elif iface['ipAddress'] not in mgmtaddr and iface['listenSsh']:
|
||||||
if iface['listenSsh'] and iface['name'] != "ens9":
|
if iface['name'] != "ens9":
|
||||||
self._vins_vnf_delmgmtaddr(vins_dict['VNFDev']['id'],iface['ipAddress'])
|
self._vins_vnf_delmgmtaddr(vins_dict['VNFDev']['id'],iface['ipAddress'])
|
||||||
self.result['changed'] = True
|
self.result['changed'] = True
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
@@ -2411,13 +2435,15 @@ class DecortController(object):
|
|||||||
|
|
||||||
def vins_update_ifaces(self,vins_dict,vinses=""):
|
def vins_update_ifaces(self,vins_dict,vinses=""):
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_update_ifaces")
|
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_update_ifaces")
|
||||||
existed_conn_ip = []
|
|
||||||
#vnf_dict = self._get_vnf_by_id(vins_dict['VNFDev']['id'])
|
if self.amodule.check_mode:
|
||||||
list_account_vins = self._get_all_account_vinses(vins_dict['VNFDev']['accountId'])
|
self.result['failed'] = False
|
||||||
list_account_vinsid = [rec['id'] for rec in list_account_vins]
|
self.result['msg'] = ("vins_update_iface() in check mode: updating ViNS ID {}, name '{}' "
|
||||||
|
"was requested.").format(vins_dict['id'], vins_dict['name'])
|
||||||
|
return
|
||||||
|
|
||||||
list_ifaces_ip = [rec['ipaddr'] for rec in vinses]
|
list_ifaces_ip = [rec['ipaddr'] for rec in vinses]
|
||||||
vins_inner = [rec['id'] for rec in vinses]
|
vinsid_not_existed = []
|
||||||
vins_outer = [rec['id'] for rec in list_account_vins]
|
|
||||||
for iface in vins_dict['VNFDev']['interfaces']:
|
for iface in vins_dict['VNFDev']['interfaces']:
|
||||||
if iface['connType'] == "VXLAN" and iface['type'] == "CUSTOM":
|
if iface['connType'] == "VXLAN" and iface['type'] == "CUSTOM":
|
||||||
if iface['ipAddress'] not in list_ifaces_ip:
|
if iface['ipAddress'] not in list_ifaces_ip:
|
||||||
@@ -2425,19 +2451,30 @@ class DecortController(object):
|
|||||||
self.result['changed'] = True
|
self.result['changed'] = True
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
else:
|
else:
|
||||||
existed_conn_ip.append(iface['ipAddress'])
|
#existed_conn_ip.append(iface['ipAddress'])
|
||||||
|
vinses = list(filter(lambda i: i['ipaddr']!=iface['ipAddress'],vinses))
|
||||||
|
|
||||||
|
if not vinses:
|
||||||
|
return
|
||||||
|
list_account_vins = self._get_all_account_vinses(vins_dict['VNFDev']['accountId'])
|
||||||
|
list_account_vinsid = [rec['id'] for rec in list_account_vins]
|
||||||
for vins in vinses:
|
for vins in vinses:
|
||||||
if vins['id'] in list_account_vinsid:
|
if vins['id'] in list_account_vinsid:
|
||||||
_,v_dict = self._vins_get_by_id(vins['id'])
|
_,v_dict = self._vins_get_by_id(vins['id'])
|
||||||
if vins['ipaddr'] not in existed_conn_ip:
|
#TODO: vins reservation
|
||||||
self._vnf_iface_add(vins_dict['VNFDev']['id'],v_dict['vxlanId'],vins['ipaddr'],vins['netmask'])
|
self._vnf_iface_add(vins_dict['VNFDev']['id'],v_dict['vxlanId'],vins['ipaddr'],vins['netmask'])
|
||||||
self.result['changed'] = True
|
self.result['changed'] = True
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
|
else:
|
||||||
|
vinsid_not_existed.append(vins['id'])
|
||||||
|
if vinsid_not_existed:
|
||||||
|
self.result['warning'] = ("List ViNS id: {} that not created on account id: {}").format(
|
||||||
|
vinsid_not_existed,
|
||||||
|
vins_dict['VNFDev']['accountId']
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
def _vnf_iface_add(self,arg_devid,arg_vxlanid,arg_ipaddr,arg_netmask="24",arg_defgw=""):
|
def _vnf_iface_add(self,arg_devid,arg_vxlanid,arg_ipaddr,arg_netmask="24",arg_defgw=""):
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "_vnf_iface_add")
|
|
||||||
api_params = dict(
|
api_params = dict(
|
||||||
devId=arg_devid,
|
devId=arg_devid,
|
||||||
ifType="CUSTOM",
|
ifType="CUSTOM",
|
||||||
@@ -2473,7 +2510,6 @@ class DecortController(object):
|
|||||||
return ret_vnf_dict
|
return ret_vnf_dict
|
||||||
|
|
||||||
def _get_all_account_vinses(self,acc_id):
|
def _get_all_account_vinses(self,acc_id):
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "get_all_account_vinses")
|
|
||||||
api_params = dict(accountId=acc_id)
|
api_params = dict(accountId=acc_id)
|
||||||
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/listVins", api_params)
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/account/listVins", api_params)
|
||||||
if api_resp.status_code == 200:
|
if api_resp.status_code == 200:
|
||||||
@@ -2484,8 +2520,6 @@ class DecortController(object):
|
|||||||
return ret_listvins_dict
|
return ret_listvins_dict
|
||||||
|
|
||||||
def _vins_vnf_addmgmtaddr(self,dev_id,mgmtip):
|
def _vins_vnf_addmgmtaddr(self,dev_id,mgmtip):
|
||||||
|
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_vnf_addmgmtaddr")
|
|
||||||
api_params = dict(devId=dev_id,ip=mgmtip)
|
api_params = dict(devId=dev_id,ip=mgmtip)
|
||||||
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/addMgmtAddr", api_params)
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/addMgmtAddr", api_params)
|
||||||
if api_resp.status_code == 200:
|
if api_resp.status_code == 200:
|
||||||
@@ -2497,8 +2531,6 @@ class DecortController(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def _vins_vnf_delmgmtaddr(self,dev_id,mgmtip):
|
def _vins_vnf_delmgmtaddr(self,dev_id,mgmtip):
|
||||||
|
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_vnf_delmgmtaddr")
|
|
||||||
api_params = dict(devId=dev_id,ip=mgmtip)
|
api_params = dict(devId=dev_id,ip=mgmtip)
|
||||||
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/delMgmtAddr", api_params)
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/delMgmtAddr", api_params)
|
||||||
if api_resp.status_code == 200:
|
if api_resp.status_code == 200:
|
||||||
@@ -2510,7 +2542,6 @@ class DecortController(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def _vins_vnf_customconfig_set(self,dev_id,arg_mode=True):
|
def _vins_vnf_customconfig_set(self,dev_id,arg_mode=True):
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_vnf_customconfig_set")
|
|
||||||
api_params = dict(devId=dev_id,mode=arg_mode)
|
api_params = dict(devId=dev_id,mode=arg_mode)
|
||||||
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/customSet", api_params)
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/customSet", api_params)
|
||||||
if api_resp.status_code == 200:
|
if api_resp.status_code == 200:
|
||||||
@@ -2522,7 +2553,6 @@ class DecortController(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
def _vins_vnf_config_save(self,dev_id):
|
def _vins_vnf_config_save(self,dev_id):
|
||||||
self.result['waypoints'] = "{} -> {}".format(self.result['waypoints'], "vins_vnf_config_save")
|
|
||||||
api_params = dict(devId=dev_id)
|
api_params = dict(devId=dev_id)
|
||||||
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/configSave", api_params)
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudbroker/vnfdev/configSave", api_params)
|
||||||
if api_resp.status_code == 200:
|
if api_resp.status_code == 200:
|
||||||
@@ -2533,12 +2563,6 @@ class DecortController(object):
|
|||||||
"response {}.").format(dev_id,api_resp.status_code, api_resp.reason)
|
"response {}.").format(dev_id,api_resp.status_code, api_resp.reason)
|
||||||
return
|
return
|
||||||
|
|
||||||
def vins_vnf_ifaceadd(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
def vins_vnf_ifaceremove(self):
|
|
||||||
return
|
|
||||||
|
|
||||||
##############################
|
##############################
|
||||||
#
|
#
|
||||||
# Disk management
|
# Disk management
|
||||||
@@ -3146,7 +3170,7 @@ class DecortController(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
api_params = dict(k8sId=k8s_id,
|
api_params = dict(k8sId=k8s_id,
|
||||||
permanently=False,
|
permanently=permanently,
|
||||||
)
|
)
|
||||||
self.decort_api_call(requests.post, "/restmachine/cloudapi/k8s/delete", api_params)
|
self.decort_api_call(requests.post, "/restmachine/cloudapi/k8s/delete", api_params)
|
||||||
# On success the above call will return here. On error it will abort execution by calling fail_json.
|
# On success the above call will return here. On error it will abort execution by calling fail_json.
|
||||||
@@ -3238,9 +3262,11 @@ class DecortController(object):
|
|||||||
ret_info = json.loads(api_get_resp.content.decode('utf8'))
|
ret_info = json.loads(api_get_resp.content.decode('utf8'))
|
||||||
if api_get_resp.status_code == 200:
|
if api_get_resp.status_code == 200:
|
||||||
if ret_info['status'] in ["PROCESSING", "SCHEDULED"]:
|
if ret_info['status'] in ["PROCESSING", "SCHEDULED"]:
|
||||||
|
self.result['msg'] = ("k8s_provision(): Can't create cluster")
|
||||||
self.result['failed'] = False
|
self.result['failed'] = False
|
||||||
time.sleep(30)
|
time.sleep(30)
|
||||||
elif ret_info['status'] == "ERROR":
|
elif ret_info['status'] == "ERROR":
|
||||||
|
self.result['msg'] = ("k8s_provision(): Can't create cluster")
|
||||||
self.result['failed'] = True
|
self.result['failed'] = True
|
||||||
return
|
return
|
||||||
elif ret_info['status'] == "OK":
|
elif ret_info['status'] == "OK":
|
||||||
@@ -3250,10 +3276,13 @@ class DecortController(object):
|
|||||||
else:
|
else:
|
||||||
k8s_id = ret_info['status']
|
k8s_id = ret_info['status']
|
||||||
else:
|
else:
|
||||||
|
self.result['msg'] = ("k8s_provision(): Can't create cluster")
|
||||||
self.result['failed'] = True
|
self.result['failed'] = True
|
||||||
# Timeout
|
# Timeout
|
||||||
|
self.result['msg'] = ("k8s_provision(): Can't create cluster")
|
||||||
self.result['failed'] = True
|
self.result['failed'] = True
|
||||||
else:
|
else:
|
||||||
|
self.result['msg'] = ("k8s_provision(): Can't create cluster")
|
||||||
self.result['failed'] = True
|
self.result['failed'] = True
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -3283,11 +3312,12 @@ class DecortController(object):
|
|||||||
|
|
||||||
for rec_inn in arg_k8swg['k8sGroups']['workers']:
|
for rec_inn in arg_k8swg['k8sGroups']['workers']:
|
||||||
for rec_out in arg_modwg:
|
for rec_out in arg_modwg:
|
||||||
|
if rec_inn['name'] == rec_out['name']:
|
||||||
if rec_inn['num'] != rec_out['num'] and rec_out['num'] != 0:
|
if rec_inn['num'] != rec_out['num'] and rec_out['num'] != 0:
|
||||||
count = rec_inn['num']-rec_out['num']
|
count = rec_inn['num']-rec_out['num']
|
||||||
cmp_list = []
|
cmp_list = []
|
||||||
if count > 0:
|
if count > 0:
|
||||||
for cmp in rec_inn['detailedInfo'][:count]:
|
for cmp in rec_inn['detailedInfo'][-count:]:
|
||||||
cmp_list.append(cmp['id'])
|
cmp_list.append(cmp['id'])
|
||||||
wg_moddel_list.append({rec_inn['id']:cmp_list})
|
wg_moddel_list.append({rec_inn['id']:cmp_list})
|
||||||
if count < 0:
|
if count < 0:
|
||||||
@@ -3335,15 +3365,17 @@ class DecortController(object):
|
|||||||
api_params = dict(includeDisabled=False)
|
api_params = dict(includeDisabled=False)
|
||||||
|
|
||||||
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/k8ci/list", api_params)
|
api_resp = self.decort_api_call(requests.post, "/restmachine/cloudapi/k8ci/list", api_params)
|
||||||
|
k8ci_id_present = False
|
||||||
if api_resp.status_code == 200:
|
if api_resp.status_code == 200:
|
||||||
ret_k8ci_list = json.loads(api_resp.content.decode('utf8'))
|
ret_k8ci_list = json.loads(api_resp.content.decode('utf8'))
|
||||||
for k8ci_item in ret_k8ci_list:
|
for k8ci_item in ret_k8ci_list:
|
||||||
if k8ci_item['id'] == arg_k8ci_id:
|
if k8ci_item['id'] == arg_k8ci_id:
|
||||||
|
k8ci_id_present = True
|
||||||
break
|
break
|
||||||
else:
|
|
||||||
|
if k8ci_id_present == False:
|
||||||
self.result['failed'] = True
|
self.result['failed'] = True
|
||||||
self.result['msg'] = "k8s_k8ci_find(): cannot find ID."
|
self.result['msg'] = ("Cannot find k8ci id: {}.").format(arg_k8ci_id)
|
||||||
self.amodule.fail_json(**self.result)
|
self.amodule.fail_json(**self.result)
|
||||||
else:
|
else:
|
||||||
self.result['failed'] = True
|
self.result['failed'] = True
|
||||||
|
|||||||
Reference in New Issue
Block a user