Skip to content

Commit 9bfab8e

Browse files
author
“dsoper2”
committed
1.5.0 collection with modules for vnic order, profile associate, and vlan groups
Fixes #14
1 parent a9f4591 commit 9bfab8e

8 files changed

+748
-1
lines changed

galaxy.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace: cisco
99
name: ucs
1010

1111
# The version of the collection. Must be compatible with semantic versioning
12-
version: 1.4.0
12+
version: 1.5.0
1313

1414
# The path to the Markdown (.md) readme file. This path is relative to the root of the collection
1515
readme: README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
---
2+
# Example Playbook: cisco.ucs.ucs_ucs_service_profile_association
3+
- hosts: ucs
4+
connection: local
5+
gather_facts: false
6+
7+
tasks:
8+
- name: Test that we have a UCS hostname, UCS username, and UCS password
9+
fail:
10+
msg: 'Please define the following variables: ucs_hostname, ucs_username and ucs_password.'
11+
when: ucs_hostname is not defined or ucs_username is not defined or ucs_password is not defined
12+
vars:
13+
# use "<<: *login_info" to substite the information below in each task
14+
# this is not required, however it makes the playbook shorter.
15+
login_info: &login_info
16+
hostname: "{{ ucs_hostname }}"
17+
username: "{{ ucs_username }}"
18+
password: "{{ ucs_password }}"
19+
20+
- name: Change Service Profile Association to Existing Server
21+
cisco.ucs.ucs_service_profile_association:
22+
<<: *login_info
23+
service_profile_name: auto-profile-2
24+
server_assignment: server
25+
server_dn: sys/chassis-6/blade-1
26+
delegate_to: localhost
27+
register: result
28+
until: result.assign_state == 'assigned' and result.assoc_state == 'associated'
29+
retries: 10
30+
delay: 60
31+
32+
- name: Change Service Profile Association to Pool
33+
cisco.ucs.ucs_service_profile_association:
34+
<<: *login_info
35+
service_profile_name: auto-profile-2
36+
server_assignment: pool
37+
server_pool_name: default
38+
delegate_to: localhost
39+
register: result
40+
until: result.assign_state == 'assigned' and result.assoc_state == 'associated'
41+
retries: 10
42+
delay: 60
43+
44+
- name: Disassociate Service Profile
45+
cisco.ucs.ucs_service_profile_association:
46+
<<: *login_info
47+
service_profile_name: auto-profile-2
48+
state: absent
49+
delegate_to: localhost
50+
register: result
51+
until: result.assign_state == 'unassigned' and result.assoc_state == 'unassociated'
52+
retries: 10
53+
delay: 60

playbooks/ucs_sp_vnic_order.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
# Example Playbook: cisco.ucs.ucs_sp_vnic_order
3+
- hosts: ucs
4+
connection: local
5+
gather_facts: false
6+
7+
tasks:
8+
- name: Test that we have a UCS hostname, UCS username, and UCS password
9+
fail:
10+
msg: 'Please define the following variables: ucs_hostname, ucs_username and ucs_password.'
11+
when: ucs_hostname is not defined or ucs_username is not defined or ucs_password is not defined
12+
vars:
13+
# use "<<: *login_info" to substite the information below in each task
14+
# this is not required, however it makes the playbook shorter.
15+
login_info: &login_info
16+
hostname: "{{ ucs_hostname }}"
17+
username: "{{ ucs_username }}"
18+
password: "{{ ucs_password }}"
19+
20+
- name: Configure vnic order
21+
cisco.ucs.ucs_sp_vnic_order:
22+
<<: *login_info
23+
sp_name: DEE-Ctrl-02
24+
vnics:
25+
- name: eno1
26+
admin_vcon: '1'
27+
order: '1'
28+
transport: ethernet
29+
delegate_to: localhost

playbooks/ucs_vlan_to_group.yml

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
---
2+
# Example Playbook: cisco.ucs.ucs_vlan_to_group
3+
- hosts: ucs
4+
connection: local
5+
gather_facts: false
6+
7+
tasks:
8+
- name: Test that we have a UCS hostname, UCS username, and UCS password
9+
fail:
10+
msg: 'Please define the following variables: ucs_hostname, ucs_username and ucs_password.'
11+
when: ucs_hostname is not defined or ucs_username is not defined or ucs_password is not defined
12+
vars:
13+
# use "<<: *login_info" to substite the information below in each task
14+
# this is not required, however it makes the playbook shorter.
15+
login_info: &login_info
16+
hostname: "{{ ucs_hostname }}"
17+
username: "{{ ucs_username }}"
18+
password: "{{ ucs_password }}"
19+
20+
- name: Add VLAN to existing VLAN group
21+
cisco.ucs.ucs_vlan_to_group:
22+
<<: *login_info
23+
vlangroup: inband
24+
vlanname: vlan244
25+
delegate_to: localhost
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
4+
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
5+
6+
from __future__ import absolute_import, division, print_function
7+
__metaclass__ = type
8+
9+
ANSIBLE_METADATA = {'metadata_version': '1.1',
10+
'status': ['preview'],
11+
'supported_by': 'community'}
12+
13+
DOCUMENTATION = r'''
14+
---
15+
module: ucs_service_profile_association
16+
short_description: Configures Service Profile Association on Cisco UCS Manager
17+
description:
18+
- Configures Service Profile Association (change association or disassociate) on Cisco UCS Manager.
19+
extends_documentation_fragment: cisco.ucs.ucs
20+
options:
21+
state:
22+
description:
23+
- If C(present), will verify service profile association and associate with specified server or server pool if needed.
24+
- If C(absent), will verify service profile is not associated and will disassociate if needed. This is the same as specifying Assign Later in the webUI.
25+
choices: [present, absent]
26+
default: present
27+
service_profile_name:
28+
description:
29+
- The name of the Service Profile being associated or disassociated.
30+
required: yes
31+
server_assignment:
32+
description:
33+
- "Specifies how to associate servers with this service profile using the following choices:"
34+
- "server - Use to pre-provision a slot or select an existing server. Slot or server is specified by the server_dn option."
35+
- "pool - Use to select from a server pool. The server_pool option specifies the name of the server pool to use."
36+
- Option is not valid if the service profile is bound to a template.
37+
- Optional if the state is absent.
38+
choices: [server, pool]
39+
required: yes
40+
server_dn:
41+
description:
42+
- The Distinguished Name (dn) of the server object used for pre-provisioning or selecting an existing server.
43+
- Required if the server_assignment option is server.
44+
- Optional if the state is absent.
45+
server_pool_name:
46+
description:
47+
- Name of the server pool used for server pool based assignment.
48+
- Required if the server_assignment option is pool.
49+
- Optional if the state is absent.
50+
restrict_migration:
51+
description:
52+
- Restricts the migration of the service profile after it has been associated with a server.
53+
- If set to no, Cisco UCS Manager does not perform any compatibility checks on the new server before migrating the existing service profile.
54+
- If set to no and the hardware of both servers used in migration are not similar, the association might fail.
55+
choices: ['yes', 'no']
56+
default: 'no'
57+
org_dn:
58+
description:
59+
- The distinguished name (dn) of the organization where the resource is assigned.
60+
default: org-root
61+
requirements:
62+
- ucsmsdk
63+
author:
64+
- David Soper (@dsoper2)
65+
- CiscoUcs (@CiscoUcs)
66+
version_added: 2.10
67+
'''
68+
69+
EXAMPLES = r'''
70+
- name: Change Service Profile Association to server pool Container-Pool and restrict migration
71+
cisco.ucs.ucs_service_profile_association:
72+
hostname: 172.16.143.150
73+
username: admin
74+
password: password
75+
service_profile_name: test-sp
76+
server_assignment: pool
77+
server_pool_name: Container-Pool
78+
restrict_migration: 'yes'
79+
80+
- name: Attempt to change association once a minute for up to 10 minutes
81+
cisco.ucs.ucs_service_profile_association:
82+
hostname: 172.16.143.150
83+
username: admin
84+
password: password
85+
service_profile_name: test-sp
86+
server_assignment: server
87+
server_dn: sys/chassis-2/blade-1
88+
register: result
89+
until: result.assign_state == 'assigned' and result.assoc_state == 'associated'
90+
retries: 10
91+
delay: 60
92+
93+
- name: Disassociate Service Profile
94+
cisco.ucs.ucs_service_profile_association:
95+
hostname: 172.16.143.150
96+
username: admin
97+
password: password
98+
service_profile_name: test-sp
99+
state: absent
100+
'''
101+
102+
RETURN = r'''
103+
assign_state:
104+
description: The logical server Assigned State (assigned, unassigned, or failed).
105+
returned: success
106+
type: string
107+
sample: assigned
108+
assoc_state:
109+
description: The logical server Association State (associated or unassociated).
110+
returned: success
111+
type: string
112+
sample: associated
113+
'''
114+
115+
from ansible.module_utils.basic import AnsibleModule
116+
from ansible_collections.cisco.ucs.plugins.module_utils.ucs import UCSModule, ucs_argument_spec
117+
118+
119+
def main():
120+
argument_spec = ucs_argument_spec
121+
argument_spec.update(
122+
org_dn=dict(type='str', default='org-root'),
123+
service_profile_name=dict(type='str', required=True),
124+
server_assignment=dict(type='str', choices=['server', 'pool']),
125+
server_dn=dict(type='str'),
126+
server_pool_name=dict(type='str'),
127+
restrict_migration=dict(type='str', default='no', choices=['yes', 'no']),
128+
state=dict(default='present', choices=['present', 'absent'], type='str'),
129+
)
130+
module = AnsibleModule(
131+
argument_spec,
132+
supports_check_mode=True,
133+
required_if=[
134+
['state', 'present', ['server_assignment']],
135+
['server_assignment', 'server', ['server_dn']],
136+
['server_assignment', 'pool', ['server_pool_name']],
137+
],
138+
mutually_exclusive=[
139+
['server_dn', 'server_pool_name'],
140+
],
141+
)
142+
# UCSModule verifies ucsmsdk is present and exits on failure. Imports are below ucs object creation.
143+
ucs = UCSModule(module)
144+
145+
err = False
146+
147+
from ucsmsdk.mometa.ls.LsRequirement import LsRequirement
148+
from ucsmsdk.mometa.ls.LsBinding import LsBinding
149+
from ucsmsdk.mometa.ls.LsServer import LsServer
150+
151+
changed = False
152+
ucs.result['assign_state'] = 'unassigned'
153+
ucs.result['assoc_state'] = 'unassociated'
154+
try:
155+
ls_mo_exists = False
156+
pn_mo_exists = False
157+
pn_req_mo_exists = False
158+
props_match = False
159+
160+
# logical server distinguished name is <org>/ls-<name> and physical node dn appends 'pn' or 'pn-req'
161+
ls_dn = module.params['org_dn'] + '/ls-' + module.params['service_profile_name']
162+
ls_mo = ucs.login_handle.query_dn(ls_dn)
163+
if ls_mo:
164+
ls_mo_exists = True
165+
pn_dn = ls_dn + '/pn'
166+
pn_mo = ucs.login_handle.query_dn(pn_dn)
167+
if pn_mo:
168+
pn_mo_exists = True
169+
170+
pn_req_dn = ls_dn + '/pn-req'
171+
pn_req_mo = ucs.login_handle.query_dn(pn_req_dn)
172+
if pn_req_mo:
173+
pn_req_mo_exists = True
174+
175+
if module.params['state'] == 'absent':
176+
if ls_mo_exists and ls_mo.assign_state != 'unassigned':
177+
if pn_mo_exists:
178+
if not module.check_mode:
179+
ucs.login_handle.remove_mo(pn_mo)
180+
ucs.login_handle.commit()
181+
changed = True
182+
elif pn_req_mo_exists:
183+
if not module.check_mode:
184+
ucs.login_handle.remove_mo(pn_req_mo)
185+
ucs.login_handle.commit()
186+
changed = True
187+
elif ls_mo_exists:
188+
# check if logical server is assigned and associated
189+
ucs.result['assign_state'] = ls_mo.assign_state
190+
ucs.result['assoc_state'] = ls_mo.assoc_state
191+
if module.params['server_assignment'] == 'pool' and pn_req_mo_exists:
192+
# check the current pool
193+
kwargs = dict(name=module.params['server_pool_name'])
194+
kwargs['restrict_migration'] = module.params['restrict_migration']
195+
if pn_req_mo.check_prop_match(**kwargs):
196+
props_match = True
197+
elif pn_mo_exists:
198+
kwargs = dict(pn_dn=module.params['server_dn'])
199+
kwargs['restrict_migration'] = module.params['restrict_migration']
200+
if pn_mo.check_prop_match(**kwargs):
201+
props_match = True
202+
203+
if not props_match:
204+
if not module.check_mode:
205+
# create if mo does not already exist in desired state
206+
mo = LsServer(
207+
parent_mo_or_dn=module.params['org_dn'],
208+
name=module.params['service_profile_name'],
209+
)
210+
if module.params['server_assignment'] == 'pool':
211+
if pn_mo_exists:
212+
ucs.login_handle.remove_mo(pn_mo)
213+
214+
mo_1 = LsRequirement(
215+
parent_mo_or_dn=mo,
216+
name=module.params['server_pool_name'],
217+
restrict_migration=module.params['restrict_migration'],
218+
)
219+
else:
220+
mo_1 = LsBinding(
221+
parent_mo_or_dn=mo,
222+
pn_dn=module.params['server_dn'],
223+
restrict_migration=module.params['restrict_migration'],
224+
)
225+
ucs.login_handle.add_mo(mo_1, True)
226+
ucs.login_handle.commit()
227+
228+
pn_req_mo = ucs.login_handle.query_dn(pn_req_dn)
229+
if pn_req_mo:
230+
# profiles from templates will add a server pool, so remove and add the server again
231+
ucs.login_handle.remove_mo(pn_req_mo)
232+
233+
ucs.login_handle.add_mo(mo_1, True)
234+
ucs.login_handle.commit()
235+
ls_mo = ucs.login_handle.query_dn(ls_dn)
236+
if ls_mo:
237+
ucs.result['assign_state'] = ls_mo.assign_state
238+
ucs.result['assoc_state'] = ls_mo.assoc_state
239+
changed = True
240+
241+
except Exception as e:
242+
err = True
243+
ucs.result['msg'] = "setup error: %s " % str(e)
244+
245+
ucs.result['changed'] = changed
246+
if err:
247+
module.fail_json(**ucs.result)
248+
module.exit_json(**ucs.result)
249+
250+
251+
if __name__ == '__main__':
252+
main()

0 commit comments

Comments
 (0)