Init: mediaserver

This commit is contained in:
2023-02-08 12:13:28 +01:00
parent 848bc9739c
commit f7c23d4ba9
31914 changed files with 6175775 additions and 0 deletions

View File

@@ -0,0 +1,26 @@
# cisco.intersight Collection Development Notes
### Current Development Status
| Configuration Category | Configuration Task | Module Name |
| ---------------------- | ------------------ | ----------- |
| General purpose resource config | Any (with user provided data) | intersight_rest_api |
| Resource data collection/inventory | GET servers information | intersight_facts |
### Ansible Development Notes
Modules in development follow processes documented at http://docs.ansible.com/ansible/latest/dev_guide/developing_modules_general.html. The modules support ansible-doc and should eventually have integration tests.
When developing modules in this repository, here are a few helpful commands to sanity check the code and documentation (replace module_name with your module (e.g., intersight_objects)). Ansible modules won't generally be pylint or pycodestyle (PEP8) clean without disabling several of the checks:
```
pylint --disable=invalid-name,no-member,too-many-nested-blocks,redefined-variable-type,too-many-statements,too-many-branches,broad-except,line-too-long,missing-docstring,wrong-import-position,too-many-locals,import-error <module_name>.py
pycodestyle --max-line-length 160 --config /dev/null --ignore E402 <module_name>.py
ansible-doc <module_name>
```
# Community:
* We are on Slack (https://ciscoucs.slack.com/) - Slack requires registration, but the ucspython team is open invitation to
anyone. Click [here](https://ucspython.herokuapp.com) to register

View File

@@ -0,0 +1,971 @@
{
"files": [
{
"name": ".",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "misc",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "misc/CL2020 EMEAR DEVWKS-1542 Intersight Ansible Lab Guide.pdf",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "5b15d28312a255524c6da61ce4ba75a4fa8b4f92d89d66edead1e163dbad143c",
"format": 1
},
{
"name": "misc/README.md",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "e61dd07deb821f7d7de15f2667c7b8c0a636efab8ad63484badfeb37ad6d7796",
"format": 1
},
{
"name": ".DS_Store",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "98f367559ce36735eed68c5cad1a6e62490c7c8637ece60e843e6d29ecf908be",
"format": 1
},
{
"name": "plugins",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "plugins/doc_fragments",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "plugins/doc_fragments/intersight.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "131b654e295475ebb9368b7277e3717722f6dd5276ee85be62baa71cd6103605",
"format": 1
},
{
"name": "plugins/README.md",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "c82ee692702ec1dd604cdbc38ff252114e5204e1b0627045a66c9451e7a918ac",
"format": 1
},
{
"name": "plugins/module_utils",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "plugins/module_utils/intersight.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "1470e423372daaebd10c6043b9cfb3687b6fc1e7e5d995d95c1256cfe14d3988",
"format": 1
},
{
"name": "plugins/modules",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "plugins/modules/intersight_virtual_media_policy.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "29dfdf3c35b0d3cd692ffac445b4f98aaf0b45ee75ae25f014cf23597cf876bc",
"format": 1
},
{
"name": "plugins/modules/intersight_server_profile.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "d601ebdea78364043ec2e0b0e88ac8eeebb6c48245e486cd26029dae983daf6e",
"format": 1
},
{
"name": "plugins/modules/intersight_imc_access_policy.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6da42e68f533b023db27b503d77493085bde53ed79eafe0f4654d7f449c6f593",
"format": 1
},
{
"name": "plugins/modules/intersight_rest_api.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "82311182b1b9183ada2e566f71691594b1ca62ce9039acf7180a82ee90045ee8",
"format": 1
},
{
"name": "plugins/modules/intersight_boot_order_policy.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "99fa19496735e97f4f4a30fa8ee042aad8a6f3dd6943ea7ef0c6c6d1be69a3fc",
"format": 1
},
{
"name": "plugins/modules/intersight_target_claim.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a52ba154c829af3e592145b84028ead62029a9c7bbf3090dce7e83b4fffac0b1",
"format": 1
},
{
"name": "plugins/modules/intersight_local_user_policy.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "8e76ce64c8aefd7ff4f7e511094cde15abbb3a0e7e7776618d62f3f09d972da1",
"format": 1
},
{
"name": "plugins/modules/intersight_info.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "83f0ef20ef237b449e8e140deaa300a18feb35b7abf6658722eb916259b5520c",
"format": 1
},
{
"name": "plugins/modules/intersight_ntp_policy.py",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "31913fec08680f6858fc25a713162a4b49a8c6b251e289a8c01f2bdeb708f423",
"format": 1
},
{
"name": "meta",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "meta/runtime.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "aa2e34142e05cac25ebdf95790050adccca8011fdeb0aec65425c2547fd80f39",
"format": 1
},
{
"name": "roles",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/profile_with_buckets.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f4f4017efbaccffae4a91f1baa157b988eb165b0eb76982daa6e4d38dba942c6",
"format": 1
},
{
"name": "playbooks/intersight_local_user_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "b3ab3e57a87f9f87203227bc94e02cde60fd9aab84bc643b808dc8361d171f40",
"format": 1
},
{
"name": "playbooks/firmware_direct_download.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "c92736b0cc04d2076d9fb0ac81596213636081c82a9d5b81b67d60134d2318ef",
"format": 1
},
{
"name": "playbooks/vault_intersight_server_profile.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "564d431fe088c2d0edfb90087f013180dc0e3b6ea0326ab1b619b7b5c4876388",
"format": 1
},
{
"name": "playbooks/intersight_server_profile.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "1e717fa8cd3cc8a08412fd72f5ff97095f89f3f818966c870dc3614817b1495a",
"format": 1
},
{
"name": "playbooks/only_new_server_profiles.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "862327ef411dbeecac16f0bedeaed6f75623acb8ecd935beed559322003c0fad",
"format": 1
},
{
"name": "playbooks/intersight_imc_access_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "0e1c127f93c3a40ce65c745d3a6dbf40b12d019875e99e83f642247872d751c4",
"format": 1
},
{
"name": "playbooks/server_actions.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a5f3b79c9d1d8117f855da5be12d7d2a7c12853aa3268c1756a9ebd639ac186a",
"format": 1
},
{
"name": "playbooks/intersight_port_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "d23dfdd7d29aa214ab6dedf2948bc8f1965759f310278fd5c78ad3c4c95829d7",
"format": 1
},
{
"name": "playbooks/intersight_lan_connectivity_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "ae907dd2252ad0cb6a9ec9359e1fc8275bca6c7c98f326678a982ed8d62aa52f",
"format": 1
},
{
"name": "playbooks/os_install.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "42ac577dacc72a9a09a73212d8537f3c91b64ed76b3fb972f98eb5e36b1ee79c",
"format": 1
},
{
"name": "playbooks/intersight_virtual_media_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "90b06235d14f5f8deb0442a6ce0d344b708c0291802a5bc2b6db3ae5f65c7175",
"format": 1
},
{
"name": "playbooks/devnet_inventory",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "052d485b54ba98f650030c8191229576f085e8d8566242af2067fb5d165a5a34",
"format": 1
},
{
"name": "playbooks/example_imm_inventory",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "53bc1620b17898948e5ddcc05bdc10d29ca52992747a5105d9ee0ae308e46906",
"format": 1
},
{
"name": "playbooks/profile_inventory",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "7c2c5a08115b656eb0cefca6ba606233b8c8e5ea9ead6f1138ad7da31b317ac7",
"format": 1
},
{
"name": "playbooks/roles",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/server_policies",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/server_policies/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/server_policies/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "2a3c6a4c4090856ccb26687d29585cccd5d766a1303b9c0848d39d531432d5c9",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/iscsi",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/iscsi/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/iscsi/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "34f73a5da07d4f9c964ce03c54a72a5bc6263a039ff118fb79268b6f619ee2f6",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_storage",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_storage/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_storage/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "19e6401ea717d1764cd1a4ca15ae5c2d3939e6971e9505cfeda97475e2d849f0",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/vcenter",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/vcenter/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/vcenter/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "917fbf014db777725f748bf325643d48f4fb8de32391e0bfd4e2aa97c027d00c",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_storage",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_storage/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_storage/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "5633998510bf093629c279e719ea60a4da5ba053c426e5d1f8e039c59e5e6c72",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_network",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_network/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_network/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "94f4d6f684732cda931e2cfb6debed9d54141817fd7445a55d988dedb114db98",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/proxy",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/proxy/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/proxy/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "856289b787b9f208808fbfb45220ec4c8cf0374c3b6f12495066908fd6d9282d",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/local_credential",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/local_credential/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/local_credential/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "0bf9787cef676282a4e920a04e7f33877d67fff4a68661eaa2380ad30bd43c19",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_network",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_network/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_network/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "d7a0c5952ce35a42e9157935f0457d3c1ea53a92e8250f3d43b44afdc6fbd4e2",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/deploy",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/deploy/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/deploy/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "06d41f41438fd7adfa8cb1be4004f4648fee274949762144919c21f100a4b394",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/intersight_org",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/intersight_org/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/intersight_org/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "cdfd9e4c8dd76d3e4ac4e4e7a3616ca27d55e475eb52c869cfea026686b46397",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/fc",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/fc/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/fc/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "4b46a867defd0891d82ffb4077c597251e91026fc040c144f10ce7d80f8483f1",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/software_version",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/software_version/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/software_version/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "588264a162d57bd5f0941a8fb72c9e9b6b511e1cc9654eafffd79d8ba79d75e0",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_software_version",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_software_version/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_software_version/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "3a0cfcbc4fcf6f7b6208d9020c50432a5226375f451852cf73cf077dffc0902f",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/node_config",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/node_config/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/node_config/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "401598a86d13dd54ba1eedc70417da00d386132bde1ec11c9f8478d41f4d26d7",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/auto_support",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/auto_support/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/auto_support/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "29d365d1f005c9205be3aaa78cfd10a99fc61d8d9cde354eef2d63409f2e9eda",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/node_profiles",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/node_profiles/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/node_profiles/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "6277ab0904e90cce7d59bae2872923313b48053504393cabb3ccc3e42fd45f90",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/sys_config",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/sys_config/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/sys_config/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "764a361479fb7b7fe1b0ba55c106d417eba9cb6cef9c6dceb8cd68cd96584aee",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_profile",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_profile/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_profile/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "367d755ab35fba5415974ee384426900a027def8da0ea319d6d0f72b021f0c0e",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_profile/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/cluster_profile/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "23c89ecd9631f2818d72f1826ab77db383e0c17af4aab1e9174256a1050c5a6b",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_profile",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_profile/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_profile/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "fa9bc3adc9f616f86031d34cedc765a97ff70e5d894c60118929c0e885b9f9fb",
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_profile/defaults",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/policies/hyperflex_policies/edge_cluster_profile/defaults/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "71993244f86f68dff3fbf58ef5d374291feac0734d78665e4aa3b4fe225d3b4e",
"format": 1
},
{
"name": "playbooks/roles/servers",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/servers/actions",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/servers/actions/tasks",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "playbooks/roles/servers/actions/tasks/main.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "b5089d72e2bf05c709233ed1bd0e14b7772df213085bf8004a504259dedcf473",
"format": 1
},
{
"name": "playbooks/ova_workflow.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "5726b9c6f974584f7fc25ac424682c52fd99aa4bd42e1b3c03db7387d4371e83",
"format": 1
},
{
"name": "playbooks/servers_to_file.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "9f689aa6fee3cf915934f5b8682060fba10672a31ef18e3abb26cedbad286c52",
"format": 1
},
{
"name": "playbooks/example_inventory",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "be93920afe1f6a8e2faf1aebc34473f1ec4773dac2de865bd4a7343002cba0fa",
"format": 1
},
{
"name": "playbooks/intersight_domain_profile.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "9abaa16f3b04ecb406c8377d0c72786ce9f72ddf2fbcf99eaf64bd5b9463c6c9",
"format": 1
},
{
"name": "playbooks/intersight_server_profile_template.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "70764578d27d3fd0d032aee8eacbe719f9f8ace6cbf5ec331ffbdadd73e91c01",
"format": 1
},
{
"name": "playbooks/server_firmware.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "979245318dc158b5d98a555ce52d92a9801065a2b8619efc29969f6904460660",
"format": 1
},
{
"name": "playbooks/deploy_server_profiles.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "14ff599fea45fe43a5a30e731c6d300120bbc306f78f4627df28643e59b2c027",
"format": 1
},
{
"name": "playbooks/intersight_boot_order_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "35450777e023766769892bc39adfc31e8b7e0ce435d27490955c46d68315cb25",
"format": 1
},
{
"name": "playbooks/cos_server_policies_and_profiles.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "edbf6afccb77a998c8e1ba000e5abd66a5153cf587054c167e9b91799eda1962",
"format": 1
},
{
"name": "playbooks/claim_device.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "45e7d0b8463e5528b064b41e2cec84a82b84c25c4c19e191cf09ce3ae84228bd",
"format": 1
},
{
"name": "playbooks/example_hx_host_vars",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "a8df99fe5c8977bffaa4a13112b4f761fc7fa3733838c75f6050b9e249063962",
"format": 1
},
{
"name": "playbooks/update_hx_edge_inventory.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "3231ee15076dadb159d89d10c15e432acf70157eb5a0311035e15988bd365fb1",
"format": 1
},
{
"name": "playbooks/update_standalone_inventory.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "dbf92e7526cebe08b36fd5979b0e99dfdb63079b5ba80677ee96c4e4ed13ecfa",
"format": 1
},
{
"name": "playbooks/update_hx_inventory.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "2bef43ab2074db7f42695e33fdefc4e33c9494ac59f97f696edb51f176b11ace",
"format": 1
},
{
"name": "playbooks/update_all_inventory.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "1194dfdc2f241861ad8a94af09927b27337a7c9be61977cfe8f84d9f97d53b03",
"format": 1
},
{
"name": "playbooks/derive_profiles.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "bef73bbcaa3a11b14138e724c437d74f0c5b2be10e05671920ab7c6a1c008172",
"format": 1
},
{
"name": "playbooks/hyperflex_cluster_profiles.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "f9f9469cb6a00a04a5ea13de088d80c5ec63aa0eda3dda37e7ba7742f2c384c7",
"format": 1
},
{
"name": "playbooks/hyperflex_edge_cluster_profiles.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "4022dd1b6ca98b6028957c658986882154e2959bf8e2698576429375a21a3332",
"format": 1
},
{
"name": "playbooks/intersight_ntp_policy.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "5e5fb746cb087b54777417b29ff999782cef2f733ea6f2ebecb6ad6d0d11790d",
"format": 1
},
{
"name": "playbooks/hcl_status.yml",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "36426be67e3cc9f09ff1265f296ee7107854cd19d7ae1dafdae230df070df990",
"format": 1
},
{
"name": "docs",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": "README.md",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "8e96532088333339cdfdae188a75f6dd92558319b65b6aeff8657ec52fa753c1",
"format": 1
},
{
"name": ".gitignore",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "daf9a841d96fd66c3358a7ba3a3524dd09c309097d71438f7280d987a6a5080c",
"format": 1
},
{
"name": "LICENSE.txt",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "30cd47435d09af02a38c1f286279009584f2a88ce02f05c34da23e617131f268",
"format": 1
},
{
"name": ".vscode",
"ftype": "dir",
"chksum_type": null,
"chksum_sha256": null,
"format": 1
},
{
"name": ".vscode/settings.json",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "be935285d998e568e5039a0960a20e001b938299ab81d44789211d6b13abc3d1",
"format": 1
},
{
"name": "Development.md",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "c928aeefe50d3eb2016604a8b6c78bcdf2bd8cd4065178dfbb9e9b09dbd42a3f",
"format": 1
}
],
"format": 1
}

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Cisco Systems, Inc. and/or its affiliates
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,33 @@
{
"collection_info": {
"namespace": "cisco",
"name": "intersight",
"version": "1.0.23",
"authors": [
"David Soper (@dsoper2)"
],
"readme": "README.md",
"tags": [
"cisco",
"intersight"
],
"description": "modules for Cisco Intersight",
"license": [
"GPL-3.0-or-later"
],
"license_file": null,
"dependencies": {},
"repository": "https://github.com/CiscoDevNet/intersight-ansible",
"documentation": "https://intersight.com/apidocs",
"homepage": "https://github.com/CiscoDevNet/intersight-ansible",
"issues": "https://github.com/CiscoDevNet/intersight-ansible"
},
"file_manifest_file": {
"name": "FILES.json",
"ftype": "file",
"chksum_type": "sha256",
"chksum_sha256": "258f351bba4dadba59e3c60f0d6486f1c3602d714b956035edab0c23af60fa26",
"format": 1
},
"format": 1
}

View File

@@ -0,0 +1,88 @@
# cisco.intersight Ansible Collection
Ansible collection for managing and automating Cisco Intersight environments. Modules and roles are provided for common Cisco Intersight tasks. Detailed installation and usage examples are included in a lab guide in the misc directory of this collection at https://github.com/CiscoDevNet/intersight-ansible/blob/master/misc/CL2020%20EMEAR%20DEVWKS-1542%20Intersight%20Ansible%20Lab%20Guide.pdf
* Note: This collection is not compatible with versions of Ansible before v2.8.
## Requirements
- Ansible v2.8 or newer
## Install
- ansible must be installed
```
sudo pip install ansible
```
## Usage
Authentication with the Intersight API requires the use of API keys that should be generated within the Intersight UI. See (https://intersight.com/help) or (https://communities.cisco.com/docs/DOC-76947) for more information on generating and using API keys.
If you do not have an Intersight account, you can create one and claim devices in Intersight using the DevNet Intersight Sandbox at https://devnetsandbox.cisco.com/RM/Diagram/Index/a63216d2-e891-4856-9f27-309ca61ec862?diagramType=Topology
Because Intersight has a single API endpoint, minimal setup is required in playbooks or variables to access the API. Here's an example playbook:
```
---
- hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Configure Boot Policy
cisco.intersight.intersight_rest_api:
api_private_key: <path to your private key>
api_key_id: <your public key id>
resource_path: /boot/PrecisionPolicies
api_body: {
```
localhost (the Ansible controller) can be used without the need to specify any hosts or inventory. Hosts can be specified to perform parallel actions. An example of Server Firmware Update on multiple servers is provided by the server_firmware.yml playbook.
If you're using playbooks in this repo, you will need to provide your own inventory file and cusomtize any variables used in playbooks with settings for your environment. This repo includes an example_inventory file with host groups for HX Clusters (Intersight_HX) and Servers (Intersight_Servers) and API key variables shared for Intersight host groups:
```
[Intersight_HX]
sjc07-r13-501
sjc07-r13-503
[Intersight_Servers]
[Intersight:children]
Intersight_HX
Intersight_Servers
[Intersight:vars]
api_private_key=~/Downloads/SecretKey.txt
api_key_id=...
```
For demo purposes, you can copy the example_inventory file to a new file named inventory. Then, edit the inventory file to provide your own api_private_key location and api_key_id for use in playbooks. If you're are using the Intersight Virtual Appliance, your inventory file can also specify the appliance URI and use of local certificates:
```
api_uri=https://tme-appliance2.intersightdemo.cisco.com/api/v1
validate_certs=false
```
Once you've provided API key information, the inventory file can be automatically updated with data from your Intersight account using one of the following playbooks:
- update_all_inventory.yml (if you'd like all Servers in the inventory)
- update_standalone_inventory.yml (if you'd like only Standalone C-Series Servers that can be managed through Server Policies/Profiles)
Here are example command lines for creating your own inventory and running the update_standalone_inventory.yml playbook:
```
cp example_inventory inventory
edit inventory with your api_private_key and api_key_id
ansible-playbook -i inventory update_standalone_inventory.yml
```
With an inventory for your Intersight account, you can now run playbooks to configure profiles/policies, and perform other server actions in Intersight:
```
ansible-playbook -i inventory cos_server_policies_and_profiles.yml --list-tasks --list-hosts (will show the tasks and their tags along with the hosts that will be configured)
ansible-playbook -i inventory cos_server_policies_and_profiles.yml (will configure policies and profiles in Intersight)
ansible-playbook -i inventory deploy_server_profiles.yml (note: this will deploy settings, run with --check to see what would change 1st)
ansible-playbook -i inventory server_actions.yml (note: by default this will PowerOn all servers, view the playbook to see other options)
```
Here are example command lines for creating an inventory with all Servers:
```
cp example_inventory inventory
edit inventory with your api_private_key and api_key_id
ansible-playbook -i inventory update_all_inventory.yml
```
# Community:
* We are on Slack (https://ciscoucs.slack.com/) - Slack requires registration, but the ucspython team is open invitation to
anyone. Click [here](https://ucspython.herokuapp.com) to register

View File

@@ -0,0 +1 @@
requires_ansible: ">=2.9"

View File

@@ -0,0 +1,3 @@
# Miscellaneous Items
This folder contains miscellaneous items related to the collection. Trainings, DevNet Workshop giudes, etc.

View File

@@ -0,0 +1,31 @@
---
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
tasks:
# Claim device
- name: Claim device
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: /asset/DeviceClaims
api_body: {
"SecurityToken": "{{ SecurityToken }}",
"SerialNumber": "{{ SerialNumber }}"
}
update_method: post
delegate_to: localhost
run_once: true

View File

@@ -0,0 +1,353 @@
---
#
# Configure Server Profiles and Policies
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Server Profile name default
profile_name: "SP-{{ inventory_hostname }}"
# Organization name
org_name: DevNet
tasks:
# Get the Organization Moid used by all profiles and policies
- name: "Get Organization {{ org_name }} Moid"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: org_resp
delegate_to: localhost
tags: always
#
# Configure profiles specific to server (run for each server in the inventory)
# Server Profiles role will register a profile_resp and profile_resp list (from all hosts) can be used by policy tasks
#
- name: "Configure {{ profile_name }} Server Profile"
intersight_rest_api:
<<: *api_info
resource_path: /server/Profiles
query_params:
$filter: "Name eq '{{ profile_name }}'"
api_body: {
"Name": "{{ profile_name }}",
"AssignedServer": {
"Moid": "{{ server_moid }}",
"ObjectType": "compute.RackUnit"
},
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: profile_resp
when: server_moid is defined
delegate_to: localhost
tags: server_profiles
#
# Enclose policy tasks in a block that runs once
# Policy API body is specified in a role specific vars section for each role import
# See https://intersight.com/apidocs/ or https://intersight.com/mobrowser/ for information on setting resource_path and api_body
#
- block:
# Boot Order policy
- import_role:
name: policies/server_policies
vars:
resource_path: /boot/PrecisionPolicies
api_body: {
"Name": "COS-Boot",
"ConfiguredBootMode": "Legacy",
"BootDevices": [
{
"ObjectType": "boot.LocalDisk",
"Enabled": true,
"Name": "Disk",
"Slot": "MRAID"
},
{
"ObjectType": "boot.VirtualMedia",
"Enabled": true,
"Name": "VM",
"Subtype": "cimc-mapped-dvd"
}
],
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
tags: boot_order
# Adapter Configuration policy
- import_role:
name: policies/server_policies
vars:
resource_path: /adapter/ConfigPolicies
api_body: {
"Name":"COS-Adapter",
"Settings":[
{
"SlotId":"MLOM",
"EthSettings":{
"LldpEnabled":true
},
"FcSettings":{
"FipEnabled":false
}
}
],
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
tags: adapter_configuration
# LAN Connectivity and related policies
- block:
# Ethernet Adapter
- name: "Configure Ethernet Adapter Policy"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthAdapterPolicies
query_params:
$filter: "Name eq 'COS-EthernetAdapter'"
api_body: {
"Name": "COS-EthernetAdapter",
"InterruptSettings": {
"Count": 32,
"Mode": "MSIx",
"CoalescingTime": 125,
"CoalescingType": "MIN"
},
"RxQueueSettings": {
"Count": 8,
"RingSize": 4096
},
"TxQueueSettings": {
"Count": 8,
"RingSize": 4096
},
"CompletionQueueSettings": {
"Count": 16
},
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: eth_adapter_resp
# Ethernet Network
- name: "Configure Ethernet Network Policy"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthNetworkPolicies
query_params:
$filter: "Name eq 'COS-EthernetNetwork'"
api_body: {
"Name": "COS-EthernetNetwork",
"VlanSettings": {
"Mode": "TRUNK",
"DefaultVlan": 10
},
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: eth_network_resp
# Ethernet QoS
- name: "Configure Ethernet QoS Policy"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthQosPolicies
query_params:
$filter: "Name eq 'COS-QoS'"
api_body: {
"Name": "COS-QoS",
"Mtu": 9000,
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: eth_qos_resp
# Import role for LAN Connectivity will register a policy_resp
- import_role:
name: policies/server_policies
vars:
resource_path: /vnic/LanConnectivityPolicies
api_body: {
"Name": "COS-LAN",
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
# vNIC configuration
# Ideally this would be in a loop, but Uplink is converted to a string (instead of the required int) when in a loop
- name: "Configure eth0"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthIfs
query_params:
$filter: "LanConnectivityPolicy.Moid eq '{{ policy_resp.api_response.Moid }}' and Name eq 'eth0'"
api_body: {
"Name": "eth0",
"Placement": {
"Id": "MLOM",
"Uplink": 0
},
"Order": 0,
"EthAdapterPolicy": {
"Moid": "{{ eth_adapter_resp.api_response.Moid }}"
},
"EthNetworkPolicy": {
"Moid": "{{ eth_network_resp.api_response.Moid }}"
},
"EthQosPolicy": {
"Moid": "{{ eth_qos_resp.api_response.Moid }}"
},
"LanConnectivityPolicy": {
"Moid": "{{ policy_resp.api_response.Moid }}"
},
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
- name: "Configure eth1"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthIfs
query_params:
$filter: "LanConnectivityPolicy.Moid eq '{{ policy_resp.api_response.Moid }}' and Name eq 'eth1'"
api_body: {
"Name": "eth1",
"Placement": {
"Id": "MLOM",
"Uplink": 1
},
"Order": 1,
"EthAdapterPolicy": {
"Moid": "{{ eth_adapter_resp.api_response.Moid }}"
},
"EthNetworkPolicy": {
"Moid": "{{ eth_network_resp.api_response.Moid }}"
},
"EthQosPolicy": {
"Moid": "{{ eth_qos_resp.api_response.Moid }}"
},
"LanConnectivityPolicy": {
"Moid": "{{ policy_resp.api_response.Moid }}"
},
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
tags: lan_connectivity
# NTP policy config
- import_role:
name: policies/server_policies
vars:
resource_path: /ntp/Policies
api_body: {
"Name": "COS-NTP",
"Enabled": true,
"NtpServers": [
"173.38.201.115"
],
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
tags: ntp
# Storage and related policies
- block:
# Disk Group policy
- name: "Configure Disk Group Policy"
intersight_rest_api:
<<: *api_info
resource_path: /storage/DiskGroupPolicies
query_params:
$filter: "Name eq 'COS-Disk'"
api_body: {
"Name":"COS-Disk",
"RaidLevel":"Raid1",
"SpanGroups":[
{
"Disks":[
{
"SlotNumber":13
},
{
"SlotNumber":14
}
]
}
],
"UseJbods":true,
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: disk_group_resp
# Storage policy
- import_role:
name: policies/server_policies
vars:
resource_path: /storage/StoragePolicies
api_body: {
"Name": "COS-Storage",
"RetainPolicyVirtualDrives": true,
"UnusedDisksState": "Jbod",
"VirtualDrives": [
{
"Name": "Boot",
"DiskGroupPolicy": "{{ disk_group_resp.api_response.Moid }}",
"AccessPolicy": "ReadWrite",
"ReadPolicy": "Default",
"WritePolicy": "WriteBackGoodBbu",
"IoPolicy": "Default",
"DriveCache": "Default",
"ExpandToAvailable": true,
"BootDrive": true
}
],
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
tags: storage
# Virtual Media policy config
- import_role:
name: policies/server_policies
vars:
resource_path: /vmedia/Policies
api_body: {
"Name": "COS-VM",
"Mappings": [
{
"MountProtocol": "http",
"VolumeName": "COS.3.13.6",
"DeviceType": "cdd",
"HostName": "sjc02dmz-rhel.sjc02dmz.net",
"RemotePath": "ibm",
"RemoteFile": "clevos-3.13.6.33-allinone-usbiso.iso"
}
],
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
tags: virtual_media
# Policies are common, so only run this block once and not for every host
run_once: true
delegate_to: localhost

View File

@@ -0,0 +1,38 @@
---
#
# Deploy Server Profiles
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Server Profile name default
profile_name: "SP-{{ inventory_hostname }}"
tasks:
# Deploy (or perform other action)
# action can be given on the command line if needed, e.g., ansible-playbook ... -e action=Unassign
# to delete a profile (profile must 1st be unassigned): ansible-playbook ... -e state=absent -e action=No-op
- name: Deploy (or user defined action) Server Profile
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: /server/Profiles
query_params:
$filter: "Name eq '{{ profile_name }}'"
api_body: {
"Action": "{{ profile_action | default('Deploy') }}"
}
delegate_to: localhost

View File

@@ -0,0 +1,72 @@
---
#
# include_tasks for deriving profiles from a template
#
# Get the Organization Moid
- name: "Get {{ template_name }}_DERIVED-{{ item }} Profile Moid"
intersight_rest_api:
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
resource_path: /server/Profiles
query_params:
$filter: "Name eq '{{ template_name }}_DERIVED-{{ item }}'"
register: profile_resp
# Derive profiles from template (if profiles don't already exist)
- name: "POST to derive {{ template_name }}_DERIVED-{{ item }}"
intersight_rest_api:
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
resource_path: /bulk/MoCloners
update_method: post
api_body: {
"Sources": [
{
"ClassId": "mo.MoRef",
"ObjectType": "server.ProfileTemplate",
"Moid": "{{ template_resp.api_response.Moid }}"
}
],
"Targets": [
{
"Name": "{{ template_name }}_DERIVED-{{ item }}",
"ObjectType": "server.Profile",
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
},
"ClassId": "server.Profile"
}
]
}
when: profile_resp.api_response is not defined or not profile_resp.api_response
# POST updates to derived profiles if template was changed
- name: "POST to update {{ template_name }}_DERIVED-{{ item }}"
intersight_rest_api:
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
resource_path: /bulk/MoMergers
update_method: post
api_body: {
"Sources": [
{
"ObjectType": "server.ProfileTemplate",
"Moid": "{{ template_resp.api_response.Moid }}"
}
],
"Targets": [
{
"ObjectType": "server.Profile",
"Moid": "{{ profile_resp.api_response.Moid }}"
}
],
"MergeAction":"Replace"
}
when: profile_resp.api_response and template_resp.changed

View File

@@ -0,0 +1,23 @@
[Intersight_HX]
# Note: at least one host (e.g., sjc07-r13-501) must be present for update_*_inventory.yml to work
sjc07-r13-501
sjc07-r13-503
[Intersight_Servers]
C220M5-WZP23230LJ6 server_moid=5f0736dc6176752d37dbe9f4 model=UCSC-C220-M5SX
C220M5-WZP23230LJC server_moid=5ec59a786176752d377205f1 model=UCSC-C220-M5SX
C240M4-FCH1906V37P server_moid=5e8c974d6176752d332f44c9 model=UCSC-C240-M4S2
C220-FCH2050V0LB server_moid=5dee9ce46176752d332eb867 model=UCSC-C220-M4L
[Intersight:children]
Intersight_HX
Intersight_Servers
[all:vars]
api_private_key=~/Downloads/DevNetSecretKey.txt
api_key_id=596cc79e5d91b400010d15ad/5db71f977564612d30cc3860/5f0f42d47564612d3363b87b
organization=DevNet
boot_order_policy=COS-Boot
local_user_policy=devnet-guest-admin
ntp_policy=lab-ntp
virtual_media_policy=COS-VM

View File

@@ -0,0 +1,91 @@
# HX Cluster Profile Settings
intersight_org_name: Test-Org
hx_cluster_name: M5-Hybrid
hx_mgmt_platform: FI
hx_hypervisor_type: ESXi
hxdp_version: 4.5(1a)
ucs_firmware_version: 4.2(1a)
hx_mgmt_mac_prefix: 00:25:B5:7F
#hx_replication_factor: 3
#hx_vdi_optimization: false
hx_disk_cleanup: true
#hx_laz_autoconfig: false
# VCenter Settings
hx_vcenter_hostname: vcenter.hx.lab.cisco.com
hx_vcenter_username: administrator@vsphere.local
hx_vcenter_datacenter: Datacenter
# HX Credentials
hx_hypervisor_admin: root
hx_hypervisor_factory_password: true
#hx_hypervisor_password:
#hx_dp_root_password:
#hx_vcenter_password:
# HX Network Services Settings
hx_sys_config_timezone: America/Los_Angeles
hx_sys_config_dns_servers:
- 10.29.133.110
hx_sys_config_ntp_servers:
- ntp1.hx.lab.cisco.com
- ntp2.hx.lab.cisco.com
hx_sys_config_dns_domain: hx.lab.cisco.com
# HX Networking Settings
hx_mgmt_ip: 10.29.133.237
hx_mgmt_vm_ip_start: 10.29.133.238
hx_mgmt_vm_ip_end: 10.29.133.241
hx_mgmt_netmask: 255.255.255.0
hx_mgmt_gateway: 10.29.133.1
hx_jumbo_frames: true
hx_mgmt_vlan_name: hx-mgmt-133
hx_mgmt_vlan_id: 133
hx_migration_vlan_name: vmotion-200
hx_migration_vlan_id: 200
hx_data_vlan_name: storage-51
hx_data_vlan_id: 51
#hx_vm_vlan_name: vm-network-100
#hx_vm_vlan: 100
hx_guest_vm_vlans:
- {"Name": vm-network-100, "VlanId": 100}
- {"Name": vm-network-101, "VlanId": 101}
# HX Auto Support Settings
#hx_auto_support_enable: false
hx_auto_support_receipient: beveritt@cisco.com
# HX Proxy Settings
hx_proxy_setting_hostname: proxy-wsa.esl.cisco.com
hx_proxy_setting_port: 80
# FC Settings
hx_vsan_a_name: vsan-10
hx_vsan_a_id: 10
hx_vsan_b_name: vsan-20
hx_vsan_b_id: 20
hx_fc_wwxn_range_start: 20:00:00:25:B5:7F
hx_fc_wwxn_range_end: 20:00:00:25:B5:7F
# iSCSI Settings
hx_iscsi_vlan_a_name: iscsi-110
hx_iscsi_vlan_a_id: 110
hx_iscsi_vlan_b_name: iscsi-111
hx_iscsi_vlan_b_id: 111
# HX Node Settings
hx_node_profile_prefix: hx220m5
esx_mgmt_ip_start: 10.29.133.246
esx_mgmt_ip_end: 10.29.133.249
ucs_kvm_start_ip: 10.29.133.242
ucs_kvm_end_ip: 10.29.133.245
ucs_kvm_gateway: 10.29.133.1
ucs_kvm_netmask: 255.255.255.0
hx_mac_start: 00:25:B5:7F
hx_mac_end: 00:25:B5:7F
hx_servers:
- SJC2-151-K27-6332-9
- SJC2-151-K27-6332-10
- SJC2-151-K27-6332-11
- SJC2-151-K27-6332-12

View File

@@ -0,0 +1,15 @@
[Intersight_Servers]
SJC07-R14-FI-1-1-7
SJC07-R14-FI-1-1-8
# Examples can use Intersight or Intersight_Servers host group
[Intersight:children]
Intersight_Servers
# For examples that use localhost, all:vars allows key lookup
[all:vars]
api_key_id=596cc79e5d91b400010d15ad/5db71f977564612d30cc3860/5e9217a57564612d302f475b
# Policies to use with profiles
boot_order_policy=tf-module-boot-policy
imc_access_policy=tf-module-SJC07-R14-15-access
lan_connectivity_policy=tf-module-lan-connectivity-policy

View File

@@ -0,0 +1,14 @@
[Intersight_HX]
# Note: at least one host (e.g., sjc07-r13-501) must be present for update_*_inventory.yml to work
sjc07-r13-501
sjc07-r13-503
[Intersight_Servers]
[Intersight:children]
Intersight_HX
Intersight_Servers
[all:vars]
api_private_key=~/Downloads/SecretKey.txt
api_key_id=596cc79e5d91b400010d15ad/5f0ce0ad7564612d3311a1f3/5f0ea8eb7564612d334ccb5a

View File

@@ -0,0 +1,85 @@
---
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
# Firmware Version
fw_version: 4.2(2d)
tasks:
# Set the distributable type based on the management mode and server type
- set_fact:
dist_type: IMMHOST
when: mode == 'Intersight' or mode == 'IntersightStandalone'
- set_fact:
dist_type: UMMBLADE
when: mode == 'UCSM' and object_type == 'Blade'
- set_fact:
dist_type: UMMRACK
when: mode == 'UCSM' and object_type == 'RackUnit'
# Get a user defined FW version
- name: Get Moid of user defined FW version
intersight_rest_api:
<<: *api_info
resource_path: /firmware/Distributables
query_params:
$filter: "SupportedModels eq '{{ model }}' and Version eq '{{ fw_version }}' and Tags.Key eq 'cisco.meta.distributabletype' and Tags.Value eq '{{ dist_type }}' and Tags.Key eq 'cisco.meta.repositorytype' and Tags.Value eq 'IntersightCloud'"
delegate_to: localhost
register: fw_resp
# Update server firmware with a post based on server moid
- name: Update server firmware
intersight_rest_api:
<<: *api_info
resource_path: /firmware/Upgrades
query_params:
$filter: "Server.Moid eq '{{ server_moid }}'"
update_method: post
api_body: {
"DirectDownload": {
"Upgradeoption": "upgrade_mount_only"
},
"Distributable": {
"Moid": "{{ fw_resp.api_response.Moid }}"
},
"Server": {
"Moid": "{{ server_moid }}",
"ObjectType": "compute.{{ object_type }}"
},
"UpgradeType": "direct_upgrade",
"SkipEstimateImpact": true
}
delegate_to: localhost
register: update_resp
when:
- server_moid is defined
- fw_resp.api_response.Moid is defined
# Wait for download/update to complete
- name: Check firmware download/update status
intersight_rest_api:
<<: *api_info
resource_path: /firmware/UpgradeStatuses
query_params:
$filter: "Moid eq '{{ update_resp.api_response.UpgradeStatus.Moid }}'"
delegate_to: localhost
register: status_resp
until: status_resp.api_response.Overallstatus == 'pending' or status_resp.api_response.Overallstatus == 'success'
# 60 minutes to allow download/update to complete
retries: 60
delay: 60
when:
- update_resp.api_response is defined

View File

@@ -0,0 +1,46 @@
---
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
collections:
- cisco.intersight
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
tasks:
# Get HclStatus
- name: Get HCL Status for Server
intersight_rest_api:
<<: *api_info
resource_path: /cond/HclStatuses
query_params:
$filter: "ManagedObject.Moid eq '{{ server_moid }}'"
delegate_to: localhost
register: hcl_resp
when:
- server_moid is defined
# Create .csv file with version and status information
- copy:
content: |
Name, FW version, OS vendor, OS version, HW status, SW status, Overall Status
{% for host in hostvars %}
{% set vars = hostvars[host|string] %}
{% if vars.hcl_resp.api_response is defined %}
{{ vars.inventory_hostname }}, {{ vars.hcl_resp.api_response.HclFirmwareVersion }}, {{ vars.hcl_resp.api_response.HclOsVendor }}, {{ vars.hcl_resp.api_response.HclOsVersion }}, {{ vars.hcl_resp.api_response.HardwareStatus }}, {{ vars.hcl_resp.api_response.SoftwareStatus }}, {{ vars.hcl_resp.api_response.Status }} {{ vars.hcl_resp.api_response.ServerReason }}
{% endif %}
{% endfor %}
dest: /tmp/hcl_status.csv
backup: false
run_once: true
delegate_to: localhost

View File

@@ -0,0 +1,172 @@
---
#
# Configure HyperFlex Cluster Profiles
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_HX'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_HX') }}"
connection: local
gather_facts: false
vars:
# If your inventory or host/group_vars don't specify required api key information, you can set directly below:
# api_private_key: ~/Downloads/SecretKey.txt
# api_key_id: 5a3404ac3768393836093cab/5b02fa7e6d6c356772394170/5b02fad36d6c356772394449
vars_prompt:
- name: "hx_vcenter_password"
prompt: "Enter the vCenter administrative password"
private: yes
confirm: yes
unsafe: yes
- name: "hx_hypervisor_password"
prompt: "Enter the new ESXi nodes' administrative password"
private: yes
confirm: yes
unsafe: yes
- name: "hx_dp_root_password"
prompt: "Enter the HyperFlex administrative password"
private: yes
confirm: yes
unsafe: yes
- name: "execute_auto_support"
prompt: "Do you need to enable Auto Support settings? (yes/no)"
private: no
- name: "execute_proxy"
prompt: "Do you need to configure proxy settings? (yes/no)"
private: no
- name: "execute_iscsi"
prompt: "Do you need to configure additional vNICs for iSCSI settings? (yes/no)"
private: no
- name: "execute_fc"
prompt: "Do you need to configure additional vHBAs for FC settings? (yes/no)"
private: no
tasks:
# Intersight Org
- import_role:
name: policies/hyperflex_policies/intersight_org
vars:
org_name: "{{ intersight_org_name }}"
tags: ['org']
# Cluster Profile
- import_role:
name: policies/hyperflex_policies/cluster_profile
vars:
hx_cluster_profile: "{{ hx_cluster_name }}"
tags: ['cluster_profile']
# Software Version
- import_role:
name: policies/hyperflex_policies/software_version
vars:
hx_software_policy: "{{ hx_cluster_name }}-software-version-policy"
tags: ['software']
# DNS
- import_role:
name: policies/hyperflex_policies/sys_config
vars:
hx_sys_config_policy: "{{ hx_cluster_name }}-sys-config-policy"
tags: ['dns']
# Security
- import_role:
name: policies/hyperflex_policies/local_credential
vars:
hx_local_credential_policy: "{{ hx_cluster_name }}-local-credential-policy"
tags: ['security']
# vCenter
- import_role:
name: policies/hyperflex_policies/vcenter
vars:
hx_vcenter_config_policy: "{{ hx_cluster_name }}-vcenter-config-policy"
tags: ['vcenter']
# Storage Config
- import_role:
name: policies/hyperflex_policies/cluster_storage
vars:
hx_cluster_storage_policy: "{{ hx_cluster_name }}-cluster-storage-policy"
tags: ['storage']
# Auto Support
- import_role:
name: policies/hyperflex_policies/auto_support
vars:
hx_auto_support_policy: "{{ hx_cluster_name }}-auto-support-policy"
hx_auto_support_enable: true
when: execute_auto_support|bool
tags: ['autosupport']
# Proxy
- import_role:
name: policies/hyperflex_policies/proxy
vars:
hx_proxy_setting_policy: "{{ hx_cluster_name }}-proxy-setting-policy"
when: execute_proxy|bool
tags: ['proxy']
# FC
- import_role:
name: policies/hyperflex_policies/fc
vars:
hx_fc_setting_policy: "{{ hx_cluster_name }}-ext-fc-storage-policy"
hx_fc_setting_enable: true
when: execute_fc|bool
tags: ['fc']
# iSCSI
- import_role:
name: policies/hyperflex_policies/iscsi
vars:
hx_iscsi_setting_policy: "{{ hx_cluster_name }}-ext-iscsi-storage-policy"
hx_iscsi_setting_enable: true
when: execute_iscsi|bool
tags: ['iscsi']
# Network Config
- import_role:
name: policies/hyperflex_policies/cluster_network
vars:
hx_cluster_network_policy: "{{ hx_cluster_name }}-cluster-network-policy"
tags: ['network']
# Node IP and Hostname
- import_role:
name: policies/hyperflex_policies/node_config
vars:
hx_node_config_policy: "{{ hx_cluster_name }}-node-config-policy"
tags: ['nodes']
- debug:
msg: "All policies and the HyperFlex cluster profile have been created."
- name: "Prompt to assign"
pause:
prompt: "Proceed with physical node assignment? (yes/no)"
echo: yes
register: assign_response
run_once: true
tags: ['prompt_assign']
# Assign servers to cluster profile and set deployment action
- import_role:
name: policies/hyperflex_policies/node_profiles
tags: ['assign']
when: assign_response.user_input|bool
- name: "Prompt to deploy"
pause:
prompt: "Proceed with cluster deployment? (yes/no)"
echo: yes
register: deploy_response
run_once: true
tags: ['prompt_deploy']
# Set cluster profile deployment action
- import_role:
name: policies/hyperflex_policies/deploy
tags: ['deploy']
when: deploy_response.user_input|bool
- debug:
msg: "HyperFlex cluster creation is complete."

View File

@@ -0,0 +1,148 @@
---
#
# Configure HyperFlex Edge Cluster Profiles
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_HX'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_HX') }}"
connection: local
gather_facts: false
vars:
# If your inventory or host/group_vars don't specify required api key information, you can set directly below:
# api_private_key: ~/Downloads/SecretKey.txt
# api_key_id: 5a3404ac3768393836093cab/5b02fa7e6d6c356772394170/5b02fad36d6c356772394449
vars_prompt:
- name: "hx_vcenter_password"
prompt: "Enter the vCenter administrative password"
private: yes
confirm: yes
unsafe: yes
- name: "hx_hypervisor_password"
prompt: "Enter the new ESXi nodes' administrative password"
private: yes
confirm: yes
unsafe: yes
- name: "hx_dp_root_password"
prompt: "Enter the HyperFlex administrative password"
private: yes
confirm: yes
unsafe: yes
- name: "execute_auto_support"
prompt: "Do you need to enable Auto Support settings? (yes/no)"
private: no
- name: "execute_proxy"
prompt: "Do you need to configure proxy settings? (yes/no)"
private: no
tasks:
# Intersight Org
- import_role:
name: policies/hyperflex_policies/intersight_org
vars:
org_name: "{{ intersight_org_name }}"
tags: ['org']
# Cluster Profile
- import_role:
name: policies/hyperflex_policies/edge_cluster_profile
vars:
hx_cluster_profile: "{{ hx_cluster_name }}"
tags: ['cluster_profile']
# Software Version
- import_role:
name: policies/hyperflex_policies/edge_software_version
vars:
hx_software_policy: "{{ hx_cluster_name }}-software-version-policy"
tags: ['software']
# DNS
- import_role:
name: policies/hyperflex_policies/sys_config
vars:
hx_sys_config_policy: "{{ hx_cluster_name }}-sys-config-policy"
tags: ['dns']
# Security
- import_role:
name: policies/hyperflex_policies/local_credential
vars:
hx_local_credential_policy: "{{ hx_cluster_name }}-local-credential-policy"
tags: ['security']
# vCenter
- import_role:
name: policies/hyperflex_policies/vcenter
vars:
hx_vcenter_config_policy: "{{ hx_cluster_name }}-vcenter-config-policy"
tags: ['vcenter']
# Storage Config
- import_role:
name: policies/hyperflex_policies/edge_cluster_storage
vars:
hx_cluster_storage_policy: "{{ hx_cluster_name }}-cluster-storage-policy"
tags: ['storage']
# Auto Support
- import_role:
name: policies/hyperflex_policies/auto_support
vars:
hx_auto_support_policy: "{{ hx_cluster_name }}-auto-support-policy"
hx_auto_support_enable: true
when: execute_auto_support|bool
tags: ['autosupport']
# Proxy
- import_role:
name: policies/hyperflex_policies/proxy
vars:
hx_proxy_setting_policy: "{{ hx_cluster_name }}-proxy-setting-policy"
when: execute_proxy|bool
tags: ['proxy']
# Network Config
- import_role:
name: policies/hyperflex_policies/edge_cluster_network
vars:
hx_cluster_network_policy: "{{ hx_cluster_name }}-cluster-network-policy"
tags: ['network']
# Node IP and Hostname
- import_role:
name: policies/hyperflex_policies/node_config
vars:
hx_node_config_policy: "{{ hx_cluster_name }}-node-config-policy"
tags: ['nodes']
- debug:
msg: "All policies and the HyperFlex cluster profile have been created."
- name: "Prompt to assign"
pause:
prompt: "Proceed with physical node assignment? (yes/no)"
echo: yes
register: assign_response
run_once: true
tags: ['prompt_assign']
# Assign servers to cluster profile and set deployment action
- import_role:
name: policies/hyperflex_policies/node_profiles
tags: ['assign']
when: assign_response.user_input|bool
- name: "Prompt to deploy"
pause:
prompt: "Proceed with cluster deployment? (yes/no)"
echo: yes
register: deploy_response
run_once: true
tags: ['prompt_deploy']
# Set cluster profile deployment action
- import_role:
name: policies/hyperflex_policies/deploy
tags: ['deploy']
when: deploy_response.user_input|bool
- debug:
msg: "HyperFlex Edge cluster creation is complete."

View File

@@ -0,0 +1,32 @@
---
# Example Playbook: cisco.intersight.intersight_boot_order_policy
# Runs on localhost since policies are only configured once
# Author: Tse Kai "Kevin" Chan (@BrightScale)
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
tasks:
- name: Configure Boot Order Policy
intersight_boot_order_policy:
<<: *api_info
organization: "{{ organization | default(omit) }}"
name: COS-Boot
description: Boot Order policy for lab use
tags:
- Key: Site
Value: RCDN
configured_boot_mode: Legacy
boot_devices:
- device_type: Local Disk
device_name: Boot-Lun
controller_slot: MRAID
- device_type: Virtual Media
device_name: vmedia

View File

@@ -0,0 +1,140 @@
---
#
# Configure UCS Domain Profiles
#
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
# Domain Profile name
profile_name: emulator
org_name: dsoper-DevNet
port_policy: server-1-6-eth-pc-47-48
qos_policy: required-qos
# Fabric Intersight A and B Serial Numbers
fia_sn: FDO23021WJ6
fib_sn: FDO23070UA2
tasks:
# Get the Organization Moid
- name: "Get {{ org_name }} Organization Moid"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: org_resp
# Get the Port Policy
- name: "Get {{ port_policy }} Port Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/PortPolicies
query_params:
$filter: "Name eq '{{ port_policy }}'"
register: port_resp
# Get the QoS Policy
- name: "Get {{ qos_policy }} Qos Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/SystemQosPolicies
query_params:
$filter: "Name eq '{{ qos_policy }}'"
register: qos_resp
# Get FI A Moid
- name: "Get FI A {{ fia_sn }} Moid"
intersight_rest_api:
<<: *api_info
resource_path: /network/Elements
query_params:
$filter: "Serial eq '{{ fia_sn }}'"
register: fia_resp
# Get FI B Moid
- name: "Get FI B {{ fib_sn }} Moid"
intersight_rest_api:
<<: *api_info
resource_path: /network/Elements
query_params:
$filter: "Serial eq '{{ fib_sn }}'"
register: fib_resp
# Config Domain (SwitchCluster) Profile
- name: "Configure {{ profile_name }} Domain Profile"
intersight_rest_api:
<<: *api_info
state: "{{ state | default('present') }}"
resource_path: /fabric/SwitchClusterProfiles
query_params:
$filter: "Name eq '{{ profile_name }}'"
api_body: {
"Name": "{{ profile_name }}",
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: profile_resp
# Config Switch Profile A with Policy Bucket
# Command line arg -e profile_action=Unassign can be used to unassign the profile
# Command line arg -e profile_action=Deploy can be used to deploy the profile
- name: "Configure {{ profile_name }}-A Switch Profile"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/SwitchProfiles
query_params:
$filter: "Name eq '{{ profile_name }}-A'"
api_body: {
"Name": "{{ profile_name }}-A",
"SwitchClusterProfile": {
"Moid": "{{ profile_resp.api_response.Moid }}"
},
"PolicyBucket": [
{
"Moid": "{{ port_resp.api_response.Moid }}",
"ObjectType": "fabric.PortPolicy"
},
{
"Moid": "{{ qos_resp.api_response.Moid }}",
"ObjectType": "fabric.SystemQosPolicy"
}
],
"AssignedSwitch": {
"Moid": "{{ fia_resp.api_response.Moid }}"
},
"Action": "{{ profile_action | default('No-op') }}"
}
when: profile_resp.api_response is defined and profile_resp.api_response
# Config Switch Profile B with Policy Bucket
- name: "Configure {{ profile_name }}-B Switch Profile"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/SwitchProfiles
query_params:
$filter: "Name eq '{{ profile_name }}-B'"
api_body: {
"Name": "{{ profile_name }}-B",
"SwitchClusterProfile": {
"Moid": "{{ profile_resp.api_response.Moid }}"
},
"PolicyBucket": [
{
"Moid": "{{ port_resp.api_response.Moid }}",
"ObjectType": "fabric.PortPolicy"
},
{
"Moid": "{{ qos_resp.api_response.Moid }}",
"ObjectType": "fabric.SystemQosPolicy"
}
],
"AssignedSwitch": {
"Moid": "{{ fib_resp.api_response.Moid }}"
},
"Action": "{{ profile_action | default('No-op') }}"
}
when: profile_resp.api_response is defined and profile_resp.api_response

View File

@@ -0,0 +1,25 @@
---
# Example Playbook: cisco.intersight.intersight_..._policy
# Runs on localhost since policies are only configured once
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
tasks:
- name: Configure IMC Access policy
intersight_imc_access_policy:
<<: *api_info
name: "{{ imc_access_name | default('sjc02-d23-access') }}"
tags:
- Key: Site
Value: SJC02
description: Updated IMC access for SJC labs
vlan_id: "{{ imc_access_vlan | default(131) }}"
ip_pool: "{{ ip_pool | default('sjc02-d23-ext-mgmt') }}"

View File

@@ -0,0 +1,134 @@
---
#
# Configure LAN Connectivity Policy
#
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
# LAN Connectivity Policy name
lcp_name: SJC07-R14-R15-lan-conn
eth_net_group: sjc07-248-net-group
eth_net_control: default-eth-net-control
eth_qos: default-eth-qos
eth_adapter: eth-adapter
mac_pool: sjc07-de31-mac
vnic_name: eth0
org_name: dsoper-DevNet
tasks:
# Get the Organization Moid
- name: "Get {{ org_name }} Organization Moid"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: org_resp
# Get the Ethernet Network Group Policy
- name: "Get {{ eth_net_group }} Ethernet Network Group Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/EthNetworkGroupPolicies
query_params:
$filter: "Name eq '{{ eth_net_group }}'"
register: eth_net_group_resp
# Get the Ethernet Network Control Policy
- name: "Get {{ eth_net_control }} Ethernet Network Control Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/EthNetworkControlPolicies
query_params:
$filter: "Name eq '{{ eth_net_control }}'"
register: eth_net_control_resp
# Get the Ethernet QoS Policy
- name: "Get {{ eth_qos }} Ethernet QoS Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthQosPolicies
query_params:
$filter: "Name eq '{{ eth_qos }}'"
register: eth_qos_resp
# Get the Ethernet Network Group Policy
- name: "Get {{ eth_adapter }} Ethernet Adapter Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthAdapterPolicies
query_params:
$filter: "Name eq '{{ eth_adapter }}'"
register: eth_adapter_resp
# Get MAC Address Pool
- name: "Get {{ mac_pool }} MAC Address Pool Moid"
intersight_rest_api:
<<: *api_info
resource_path: /macpool/Pools
query_params:
$filter: "Name eq '{{ mac_pool }}'"
register: mac_resp
# Config LAN Connectivity Policy
- name: "Configure {{ lcp_name }} LAN Connectivity Policy"
intersight_rest_api:
<<: *api_info
state: "{{ state | default('present') }}"
resource_path: /vnic/LanConnectivityPolicies
query_params:
$filter: "Name eq '{{ lcp_name }}'"
api_body: {
"Name": "{{ lcp_name }}",
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
},
"PlacementMode": "auto",
"TargetPlatform": "FIAttached"
}
register: lcp_resp
# Config vNIC with LAN Connectivity Policy
- name: "Configure {{ vnic_name }} vNIC"
intersight_rest_api:
<<: *api_info
resource_path: /vnic/EthIfs
query_params:
$filter: "Name eq '{{ vnic_name }}'"
api_body: {
"Name": "{{ vnic_name }}",
"MacAddressType": "POOL",
"MacPool": {
"Moid": "{{ mac_resp.api_response.Moid }}",
},
"Placement": {
"SwitchId": "A",
"AutoSlotId": false,
"AutoPciLink": false
},
"Cdn": {
"Source": "vnic"
},
"FailoverEnabled": true,
"FabricEthNetworkGroupPolicy": [
{
"Moid": "{{ eth_net_group_resp.api_response.Moid }}"
}
],
"FabricEthNetworkControlPolicy": {
"Moid": "{{ eth_net_control_resp.api_response.Moid }}"
},
"EthQosPolicy": {
"Moid": "{{ eth_qos_resp.api_response.Moid }}"
},
"EthAdapterPolicy": {
"Moid": "{{ eth_adapter_resp.api_response.Moid }}"
},
"LanConnectivityPolicy": {
"Moid": "{{ lcp_resp.api_response.Moid }}"
}
}
when: lcp_resp.api_response is defined and lcp_resp.api_response

View File

@@ -0,0 +1,55 @@
---
# Example Playbook: cisco.intersight.intersight_..._policy
# Runs on localhost since policies are only configured once
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
#
# Example using vault:
# 1. Place the vault password into a plain text file (this is the password for vault access - do not check this into any repos!)
# $ cat vault_password_file
# ...
# 2. Encrypt a string (e.g., 'notagoodpassword'). You will later decrypt using your vault password file
# $ ansible-vault encrypt_string --vault-id tme@vault_password_file 'notagoodpassword' --name 'vault_password'
# (response is the encrypting string)
# 3. Place the vault variable in your playbook (example below):
# 4. Run the playbook and supply the vault password file (used to decrypt the vaulted password in the playbook)
# $ ansible-playbook -i inventory --vault-id tme@vault_password_file intersight_local_user_policy.yml
#
vault_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;tme
36656264656638646566313633353832396138616264313032303433656636643638363864653936
6532646363303435633965383432633630306566323838640a363566376234303366313064306162
39326331373231643333616335393232353633393834653161633032383539383537656336666639
3635306535366233660a356235393664653538386136626439646137626531663135363636326131
3538
tasks:
- name: Configure Local User policy
intersight_local_user_policy:
<<: *api_info
name: "{{ local_user_policy | default('guest-admin') }}"
tags:
- Key: username
Value: guest
description: Username guest with admin role
enforce_strong_password: true
enable_password_expiry: false
password_history: 5
purge: true
always_update_password: true
local_users:
- username: guest
role: admin
password: "{{ vault_password }}"

View File

@@ -0,0 +1,27 @@
---
# Example Playbook: cisco.intersight.intersight_ntp_policy
# Runs on localhost since policies are only configured once
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
tasks:
- name: Configure NTP Policy
intersight_ntp_policy:
<<: *api_info
organization: "{{ organization | default(omit) }}"
name: lab-ntp
description: NTP policy for lab use
tags:
- Key: Site
Value: RCDN
ntp_servers:
- ntp.esl.cisco.com
timezone: America/Chicago

View File

@@ -0,0 +1,88 @@
---
#
# Configure Fabric Port Policies
#
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
# Port Policy name
port_name: server-1-6-eth-pc-47-48
org_name: dsoper-DevNet
tasks:
# Get the Organization Moid
- name: "Get {{ org_name }} Organization Moid"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: org_resp
# Config Port Policy
- name: "Configure {{ port_name }} Port Policy"
intersight_rest_api:
<<: *api_info
state: "{{ state | default('present') }}"
resource_path: /fabric/PortPolicies
query_params:
$filter: "Name eq '{{ port_name }}'"
api_body: {
"Name": "{{ port_name }}",
"DeviceModel": "UCS-FI-6454",
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
register: port_resp
# Config Server Roles
- name: "Configure Server Roles"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/ServerRoles
query_params:
$filter: "PortPolicy.Moid eq '{{ port_resp.api_response.Moid }}' and PortId eq {{ item }}"
api_body: {
"Fec": "Auto",
"PortId": "{{ item }}",
"PortPolicy": {
"Moid": "{{ port_resp.api_response.Moid }}"
},
"SlotId": 1
}
loop: "{{ range(1, 6+1) | list }}"
when: port_resp.api_response is defined and port_resp.api_response
# Config Uplink Port Channel Roles
- name: "Configure Uplink Port Channel Roles"
intersight_rest_api:
<<: *api_info
resource_path: /fabric/UplinkPcRoles
query_params:
$filter: "PortPolicy.Moid eq '{{ port_resp.api_response.Moid }}'"
api_body: {
"AdminSpeed": "Auto",
"PcId": 47,
"PortPolicy": {
"Moid": "{{ port_resp.api_response.Moid }}"
},
"Ports": [
{
"PortId": 47,
"SlotId": 1
},
{
"PortId": 48,
"SlotId": 1
}
]
}
when: port_resp.api_response is defined and port_resp.api_response

View File

@@ -0,0 +1,51 @@
---
#
# Configure Server Profiles
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Server Profile name default
profile_name: "SP-{{ inventory_hostname }}"
tasks:
#
# Configure profiles specific to server (run for each server in the inventory)
#
- set_fact:
mode: Standalone
when: mode is not defined or mode == 'IntersightStandalone'
- set_fact:
mode: FIAttached
when: mode == 'Intersight'
- name: "Configure {{ profile_name }} Server Profile"
intersight_server_profile:
<<: *api_info
organization: "{{ organization | default(omit) }}"
name: "{{ profile_name }}"
target_platform: "{{ mode | default(omit) }}"
description: "Updated Profile for server name {{ inventory_hostname }}"
assigned_server: "{{ server_moid | default(omit) }}"
boot_order_policy: "{{ boot_order_policy | default(omit) }}"
imc_access_policy: "{{ imc_access_policy | default(omit) }}"
lan_connectivity_policy: "{{ lan_connectivity_policy | default(omit) }}"
local_user_policy: "{{ local_user_policy | default(omit) }}"
ntp_policy: "{{ ntp_policy | default(omit) }}"
virtual_media_policy: "{{ virtual_media_policy | default(omit) }}"
delegate_to: localhost

View File

@@ -0,0 +1,94 @@
---
#
# Configure Server Profile Templates
#
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Server Profile Template name
template_name: sp-devnet
org_name: dsoper-DevNet
imc_access_policy: access-devnet
ntp_policy: LabNTP
uuid_pool: uuid-devnet
num_profiles: 3
tasks:
# Get the Organization Moid
- name: "Get {{ org_name }} Organization Moid"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: org_resp
# Get the Access Policy
- name: "Get {{ imc_access_policy }} Access Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /access/Policies
query_params:
$filter: "Name eq '{{ imc_access_policy }}'"
register: access_resp
# Get the NTP Policy
- name: "Get {{ ntp_policy }} NTP Policy Moid"
intersight_rest_api:
<<: *api_info
resource_path: /ntp/Policies
query_params:
$filter: "Name eq '{{ ntp_policy }}'"
register: ntp_resp
# Get the UUID Pool
- name: "Get {{ uuid_pool }} UUID Pool Moid"
intersight_rest_api:
<<: *api_info
resource_path: /uuidpool/Pools
query_params:
$filter: "Name eq '{{ uuid_pool }}'"
register: uuid_resp
# Config SP Template using Policy Buckets
- name: "Configure {{ template_name }} Server Profile Template"
intersight_rest_api:
<<: *api_info
resource_path: /server/ProfileTemplates
query_params:
$filter: "Name eq '{{ template_name }}'"
api_body: {
"Name": "{{ template_name }}",
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
},
"PolicyBucket": [
{
"Moid": "{{ ntp_resp.api_response.Moid }}",
"ObjectType": "ntp.Policy"
},
{
"Moid": "{{ access_resp.api_response.Moid }}",
"ObjectType": "access.Policy"
}
],
"Tags": [],
"TargetPlatform": "FIAttached",
"UuidAddressType": "POOL",
"UuidPool": {
"Moid": "{{ uuid_resp.api_response.Moid }}",
"ObjectType": "uuidpool.Pool"
}
}
register: template_resp
# Derive profiles from template (if profiles don't already exist)
- name: "Derive Profiles from {{ template_name}}"
include_tasks: derive_profiles.yml
loop: "{{ range(1, num_profiles+1) | list }}"

View File

@@ -0,0 +1,30 @@
---
# Example Playbook: cisco.intersight.intersight_virtual_media_policy
# Runs on localhost since policies are only configured once
- hosts: localhost
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
tasks:
- name: Configure Virtual Media Policy
intersight_virtual_media_policy:
<<: *api_info
organization: DevNet
name: COS-VM
description: Virtual Media policy for lab use
tags:
- Key: Site
Value: RCDN
cdd_virtual_media:
mount_type: nfs
volume: nfs-cdd
remote_hostname: 172.28.224.77
remote_path: /mnt/SHARE/ISOS/CENTOS
remote_file: CentOS7.iso

View File

@@ -0,0 +1,72 @@
---
#
# Configure Server Profiles
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# Key can be directly specified, and vault should be used to encrypt:
# Ex. ansible-vault encrypt_string --vault-id tme@/Users/dsoper/Documents/vault_password_file '-----BEGIN EC PRIVATE KEY-----
# <your private key data>
# -----END EC PRIVATE KEY-----'
# To use with vault:
# ansible-playbook -i inventory --vault-id tme@vault_password_file intersight_server_profile.yml
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Server Profile name default
profile_name: "{{ inventory_hostname | regex_replace('-r$', '') }}"
tasks:
#
# Configure profiles specific to server (run for each server in the inventory)
#
- set_fact:
mode: Standalone
when: mode is not defined or mode == 'IntersightStandalone'
- set_fact:
mode: FIAttached
when: mode == 'Intersight'
# Get server moid when not defined in inventory
- block:
- name: "Get {{ inventory_hostname }} Server Moid"
intersight_info:
<<: *api_info
server_names: "{{ inventory_hostname }}"
register: server
- set_fact:
server_moid: "{{ server.intersight_servers[0].Moid }}"
when: server_moid is not defined
delegate_to: localhost
- name: "Get current profile assignment"
intersight_rest_api:
<<: *api_info
resource_path: /server/Profiles
query_params:
$filter: "AssignedServer.Moid eq '{{ server_moid }}' or AssociatedServer.Moid eq '{{ server_moid }}'"
when: server_moid is defined
register: profile
delegate_to: localhost
- name: "Configure {{ profile_name }} Server Profile"
intersight_server_profile:
<<: *api_info
organization: "{{ organization | default(omit) }}"
name: "{{ profile_name }}"
target_platform: "{{ mode | default(omit) }}"
description: "Updated Profile for server name {{ inventory_hostname }}"
assigned_server: "{{ server_moid }}"
when:
- server_moid is defined
- profile is not defined or profile.api_response.Moid is not defined
delegate_to: localhost

View File

@@ -0,0 +1,142 @@
---
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
# OS and SCU Versions
os_version: ESXi 7.0 U3
os_config: ESXi7.0ConfigFile
scu_version: 6.2.2a
org_name: default
#
# Example using vault:
# 1. Place the vault password into a plain text file (this is the password for vault access - do not check this into any repos!)
# $ cat vault_password_file
# ...
# 2. Encrypt a string (e.g., 'notagoodpassword'). You will later decrypt using your vault password file
# $ ansible-vault encrypt_string --vault-id tme@vault_password_file 'notagoodpassword' --name 'vault_password'
# (response is the encrypting string)
# 3. Place the vault variable in your playbook (example below):
# 4. Run the playbook and supply the vault password file (used to decrypt the vaulted password in the playbook)
# $ ansible-playbook -i inventory --vault-id tme@vault_password_file os_install.yml
#
vault_password: !vault |
$ANSIBLE_VAULT;1.2;AES256;tme
36656264656638646566313633353832396138616264313032303433656636643638363864653936
6532646363303435633965383432633630306566323838640a363566376234303366313064306162
39326331373231643333616335393232353633393834653161633032383539383537656336666639
3635306535366233660a356235393664653538386136626439646137626531663135363636326131
3538
tasks:
# Get the Organization Moid
- name: "Get {{ org_name }} Organization Moid"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: org_resp
delegate_to: localhost
# Get the OS File Moid
- name: "Get {{ os_version }} OS File Moid"
intersight_rest_api:
<<: *api_info
resource_path: /softwarerepository/OperatingSystemFiles
query_params:
$filter: "Version eq '{{ os_version }}' and PermissionResources.Moid eq '{{ org_resp.api_response.Moid }}'"
register: os_resp
delegate_to: localhost
# Get the SCU File Moid
- name: "Get {{ scu_version }} SCU File Moid"
intersight_rest_api:
<<: *api_info
resource_path: /firmware/ServerConfigurationUtilityDistributables
query_params:
$filter: "Version eq '{{ scu_version }}' and PermissionResources.Moid eq '{{ org_resp.api_response.Moid }}'"
register: scu_resp
delegate_to: localhost
# Get the OS Config File Moid
- name: "Get {{ os_config }} OS Config File Moid"
intersight_rest_api:
<<: *api_info
resource_path: /os/ConfigurationFiles
query_params:
$filter: "Name eq '{{ os_config }}'"
register: os_config_resp
delegate_to: localhost
# Install OS
- name: Install OS
intersight_rest_api:
<<: *api_info
resource_path: /bulk/Requests
update_method: post
api_body: {
"Verb": "POST",
"Uri": "/v1/os/Installs",
"Requests": [
{
"ObjectType": "bulk.RestSubRequest",
"Body": {
"InstallMethod": "vMedia",
"Image": {
"Moid": "{{ os_resp.api_response.Moid }}",
"ObjectType": "softwarerepository.OperatingSystemFile"
},
"OsduImage": {
"ObjectType": "firmware.ServerConfigurationUtilityDistributable",
"Moid": "{{ scu_resp.api_response.Moid }}"
},
"OverrideSecureBoot": true,
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
},
"Answers": {
"Hostname": "sjc07-r14-1-1-6",
"IpConfigType": "DHCP",
"RootPassword": "{{ vault_password }}",
"IsRootPasswordCrypted": false,
"Source": "Template",
"IpConfiguration": {
"ObjectType": "os.Ipv4Configuration"
}
},
"ConfigurationFile": {
"Moid": "{{ os_config_resp.api_response.Moid }}",
"ObjectType": "os.ConfigurationFile"
},
"AdditionalParameters": null,
"InstallTarget": {
"ObjectType": "os.PhysicalDisk",
"Name": "Disk 1",
"StorageControllerSlotId": "1",
"SerialNumber": "99B0A05NFJXF"
},
"Server": {
"ObjectType": "compute.{{ object_type }}",
"Moid": "{{ server_moid }}"
}
}
}
],
"Organization": {
"Moid": "{{ org_resp.api_response.Moid }}"
}
}
delegate_to: localhost
register: install_resp

View File

@@ -0,0 +1,72 @@
---
# Execute Orchestration Workflow
- hosts: localhost
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
image_url: "{{ image_url | default('http://172.28.224.62/UCSPE_4.0.4e.ova') }}"
vm_name: "{{ vm_name | default('ucspe-4-0-4e-orch') }}"
tasks:
- name: Get vCenter Moid
intersight_rest_api:
<<: *api_info
resource_path: /asset/DeviceRegistrations
query_params:
$filter: DeviceIpAddress eq '172.28.225.220'
register: vcenter
- name: Execute OVA deploy workflow
intersight_rest_api:
<<: *api_info
resource_path: /workflow/WorkflowInfos
update_method: post
api_body: {
"Name": "ucspe_vm",
"Organization": {
# "Selector": "Name eq 'default'",
# "ObjectType": "organization.Organization"
"Moid": "5dde9f116972652d33539d39"
},
"Action": "Start",
"Input": {
"Vcenter": {
"Moid": "{{ vcenter.api_response.Moid }}",
"ObjectType":"asset.DeviceRegistration"
},
"Datastore": "Atlanta Data",
"Image": "{{ image_url }}",
"VmName": "{{ vm_name }}",
"PowerOn": false,
"Datacenter": "SJC07",
"Cluster": "Atlanta"
},
"WorkflowDefinition": {
"Selector": "Name eq 'ucspe_vm'",
"ObjectType":"workflow.WorkflowDefinition"
},
"WorkflowCtx": {
"InitiatorCtx": {
"InitiatorName":"ucspe_vm",
"InitiatorType":"workflow.WorkflowDefinition"
}
}
}
register: workflow
- name: Get status of OVA deploy workflow
intersight_rest_api:
<<: *api_info
resource_path: /workflow/WorkflowInfos
query_params:
$expand: ParentTaskInfo($select=WorkflowInfo;$expand=WorkflowInfo($select=WorkflowDefinition))
$filter: "Moid eq '{{ workflow.api_response.Moid }}'"
register: status
until: status.api_response.Status != 'RUNNING' and status.api_response.Status != 'WAITING'
retries: 10
delay: 60
ignore_errors: true
- debug:
msg: "Final workflow status: {{ status.api_response.Status }}"

View File

@@ -0,0 +1,4 @@
# example group to create profiles with no server assignment
[Intersight_Servers]
demo1 mode=Intersight
demo2 mode=Intersight

View File

@@ -0,0 +1,28 @@
---
# Server profile config using policy buckets
- hosts: localhost
gather_facts: false
vars:
profile_name: SP-SJC07-R14-FI-1-1-6
tasks:
- name: "Get {{ profile_name }}"
cisco.intersight.intersight_rest_api:
resource_path: /server/Profiles
query_params:
$filter: "Name eq '{{ profile_name }}'"
register: results
- debug:
msg: "{{ results.api_response.PolicyBucket | selectattr('ObjectType', 'eq', 'access.Policy') }}"
- name: "Config {{ profile_name }}"
cisco.intersight.intersight_rest_api:
resource_path: "/server/Profiles/{{ results.api_response.Moid }}/PolicyBucket"
# should be moid for tf-k8s-SJC07-R14-15-access
list_body:
[
{
"Moid": "60a6e26f6275722d31f8e278",
"ObjectType": "access.Policy",
},
]
update_method: post
when: not (results.api_response.PolicyBucket | selectattr('ObjectType', 'eq', 'access.Policy') | selectattr('Moid', 'eq', '60a6e26f6275722d31f8e278'))

View File

@@ -0,0 +1,31 @@
---
- name: "Configure Auto Support Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/AutoSupportPolicies
query_params:
$filter: "Name eq '{{ hx_auto_support_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name": "{{ hx_auto_support_policy }}",
"AdminState":"{{ hx_auto_support_enable }}",
"ServiceTicketReceipient":"{{ hx_auto_support_receipient }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: auto_support_policy
- debug: msg="HyperFlex Autosupport Policy named {{ hx_auto_support_policy }} has been created successfully."

View File

@@ -0,0 +1,50 @@
---
- name: "Configure Cluster Network Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterNetworkPolicies
query_params:
$filter: "Name eq '{{ hx_cluster_network_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_cluster_network_policy }}",
"JumboFrame":"{{ hx_jumbo_frames }}",
"KvmIpRange":{
"StartAddr":"{{ ucs_kvm_start_ip }}",
"EndAddr":"{{ ucs_kvm_end_ip }}",
"Gateway":"{{ ucs_kvm_gateway }}",
"Netmask":"{{ ucs_kvm_netmask }}"
},
"MacPrefixRange":{
"StartAddr":"{{ hx_mac_start }}",
"EndAddr":"{{ hx_mac_end }}"
},
"MgmtVlan":{
"Name":"{{ hx_mgmt_vlan_name }}",
"VlanId":"{{ hx_mgmt_vlan_id }}"
},
"VmMigrationVlan":{
"Name":"{{ hx_migration_vlan_name }}",
"VlanId":"{{ hx_migration_vlan_id }}"
},
"VmNetworkVlans":"{{ hx_guest_vm_vlans }}",
"UplinkSpeed": "default",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: cluster_network
- debug: msg="HyperFlex Cluster Network Policy named {{ hx_cluster_network_policy }} has been created successfully."

View File

@@ -0,0 +1,8 @@
---
# Default variable values for HyperFlex Cluster Profiles
hx_mgmt_platform: FI
hx_hypervisor_type: ESXi
hx_replication_factor: 3
hx_vdi_optimization: false
hx_disk_cleanup: false
hx_laz_autoconfig: false

View File

@@ -0,0 +1,33 @@
---
- name: "Configure Cluster Profile"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterProfiles
query_params:
$filter: "Name eq '{{ hx_cluster_profile }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_cluster_profile }}",
"MgmtPlatform":"{{ hx_mgmt_platform }}",
"HypervisorType":"{{ hx_hypervisor_type }}",
"MgmtIpAddress":"{{ hx_mgmt_ip }}",
"MacAddressPrefix":"{{ hx_mgmt_mac_prefix }}",
"Replication":"{{ hx_replication_factor }}",
"StorageDataVlan":{
"Name":"{{ hx_data_vlan_name }}",
"VlanId":"{{ hx_data_vlan_id }}"
}
}
register: cluster_profile
- debug: msg="HyperFlex Cluster Profile named {{ hx_cluster_profile }} has been created successfully."

View File

@@ -0,0 +1,34 @@
---
- name: "Configure Cluster Storage Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterStoragePolicies
query_params:
$filter: "Name eq '{{ hx_cluster_storage_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_cluster_storage_policy }}",
"VdiOptimization":"{{ hx_vdi_optimization }}",
"DiskPartitionCleanup":"{{ hx_disk_cleanup }}",
"LogicalAvalabilityZoneConfig":{
"AutoConfig":"{{ hx_laz_autoconfig }}"
},
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: storage_setting
- debug: msg="HyperFlex Cluster Storage Policy named {{ hx_cluster_storage_policy }} has been created successfully."

View File

@@ -0,0 +1,43 @@
---
# Get cluster profile
- name: Get Cluster Profile
vars:
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterProfiles
query_params:
$filter: "Name eq '{{ hx_cluster_name }}'"
register: profile
# Prompt for cluster deployment action
- name: "Prompt for deployment action"
pause:
prompt: "Set the deployment action. Valid choices are Validate, Deploy, Continue or Retry."
echo: yes
register: hx_action
run_once: true
# Set cluster deployment action
- name: Set Cluster Action
vars:
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterProfiles
query_params:
$filter: "Name eq '{{ hx_cluster_name }}'"
api_body: {
"Action": "{{ hx_action.user_input }}"
}
when:
- profile.api_response.ConfigContext.ConfigState != 'Configuring'
- profile.api_response.ConfigContext.ConfigState != 'Associated'
# Can optionally wait for subsequent tasks if needed
# register: result
# until: result.api_response.config_context.config_state == 'Associated'
# retries: 20
# delay: 30
- debug: msg="HyperFlex Cluster Profile deployment action has been triggered successfully."

View File

@@ -0,0 +1,38 @@
---
- name: "Configure Cluster Network Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterNetworkPolicies
query_params:
$filter: "Name eq '{{ hx_cluster_network_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_cluster_network_policy }}",
"JumboFrame":"{{ hx_jumbo_frames }}",
"MacPrefixRange":{
"StartAddr":"{{ hx_mac_start }}",
"EndAddr":"{{ hx_mac_end }}"
},
"MgmtVlan":{
"VlanId":"{{ hx_mgmt_vlan_id }}"
},
"UplinkSpeed":"{{ hx_uplink_speed }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: cluster_network
- debug: msg="HyperFlex Cluster Network Policy named {{ hx_cluster_network_policy }} has been created successfully."

View File

@@ -0,0 +1,6 @@
---
# Default variable values for HyperFlex Cluster Profiles
hx_mgmt_platform: EDGE
hx_hypervisor_type: ESXi
hx_vdi_optimization: false
hx_disk_cleanup: false

View File

@@ -0,0 +1,31 @@
---
- name: "Configure Cluster Profile"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterProfiles
query_params:
$filter: "Name eq '{{ hx_cluster_profile }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_cluster_profile }}",
"MgmtPlatform":"{{ hx_mgmt_platform }}",
"HypervisorType":"{{ hx_hypervisor_type }}",
"MgmtIpAddress":"{{ hx_mgmt_ip }}",
"MacAddressPrefix":"{{ hx_mgmt_mac_prefix }}",
"StorageDataVlan":{
"VlanId":"{{ hx_data_vlan_id }}"
}
}
register: cluster_profile
- debug: msg="HyperFlex Cluster Profile named {{ hx_cluster_profile }} has been created successfully."

View File

@@ -0,0 +1,31 @@
---
- name: "Configure Cluster Storage Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterStoragePolicies
query_params:
$filter: "Name eq '{{ hx_cluster_storage_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_cluster_storage_policy }}",
"VdiOptimization":"{{ hx_vdi_optimization }}",
"DiskPartitionCleanup":"{{ hx_disk_cleanup }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: storage_setting
- debug: msg="HyperFlex Cluster Storage Policy named {{ hx_cluster_storage_policy }} has been created successfully."

View File

@@ -0,0 +1,30 @@
---
- name: "Configure Software Version Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/SoftwareVersionPolicies
query_params:
$filter: "Name eq '{{ hx_software_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_software_policy }}",
"HxdpVersion":"{{ hxdp_version }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: software_policy
- debug: msg="HyperFlex Software Version Policy named {{ hx_software_policy }} has been created successfully."

View File

@@ -0,0 +1,52 @@
---
- name: "Configure External FC Storage Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ExtFcStoragePolicies
query_params:
$filter: "Name eq '{{ hx_fc_setting_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"AdminState":"{{ hx_fc_setting_enable }}",
"Name":"{{ hx_fc_setting_policy }}",
"ExtaTraffic":{
"Name":"{{ hx_vsan_a_name }}",
"VsanId":"{{ hx_vsan_a_id }}"
},
"ExtbTraffic":{
"Name":"{{ hx_vsan_b_name }}",
"VsanId":"{{ hx_vsan_b_id }}"
},
"WwxnPrefixRange":{
"StartAddr":"{{ hx_fc_wwxn_range_start }}",
"EndAddr":"{{ hx_fc_wwxn_range_end }}"
},
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: fc_settings
# Set WWXN prefix for the cluster profile when additional FC HBAs are configured
- name: "Perform Action on {{ hx_profile_name }} Profile"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterProfiles
query_params:
$filter: "Name eq '{{ hx_cluster_name }}'"
api_body: {
"WwxnPrefix": "{{ hx_fc_wwxn_range_start }}"
}
- debug: msg="HyperFlex External FC Storage Policy named {{ hx_fc_setting_policy }} has been created successfully."

View File

@@ -0,0 +1,17 @@
---
- name: "Retrieve Intersight Org"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /organization/Organizations
query_params:
$filter: "Name eq '{{ org_name }}'"
register: intersight_org

View File

@@ -0,0 +1,38 @@
---
- name: "Configure External iSCSI Storage Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ExtIscsiStoragePolicies
query_params:
$filter: "Name eq '{{ hx_iscsi_setting_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"AdminState":"{{ hx_iscsi_setting_enable }}",
"Name":"{{ hx_iscsi_setting_policy }}",
"ExtaTraffic":{
"Name":"{{ hx_iscsi_vlan_a_name }}",
"VlanId":"{{ hx_iscsi_vlan_a_id }}"
},
"ExtbTraffic":{
"Name":"{{ hx_iscsi_vlan_b_name }}",
"VlanId":"{{ hx_iscsi_vlan_b_id }}"
},
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: iscsi_settings
- debug: msg="HyperFlex External iSCSI Storage Policy named {{ hx_iscsi_setting_policy }} has been created successfully."

View File

@@ -0,0 +1,33 @@
---
- name: "Configure Local Credential Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/LocalCredentialPolicies
query_params:
$filter: "Name eq '{{ hx_local_credential_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name": "{{ hx_local_credential_policy }}",
"HypervisorAdmin":"{{ hx_hypervisor_admin }}",
"FactoryHypervisorPassword":"{{ hx_hypervisor_factory_password }}",
"HypervisorAdminPwd":"{{ hx_hypervisor_password | default(omit) }}",
"HxdpRootPwd":"{{ hx_dp_root_password | default(omit) }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: local_credential
- debug: msg="HyperFlex Local Credential Policy named {{ hx_local_credential_policy }} has been created successfully."

View File

@@ -0,0 +1,42 @@
---
- name: "Configure Node Configuration Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/NodeConfigPolicies
query_params:
$filter: "Name eq '{{ hx_node_config_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_node_config_policy }}",
"NodeNamePrefix":"{{ hx_node_profile_prefix }}",
"MgmtIpRange":{
"StartAddr":"{{ esx_mgmt_ip_start }}",
"EndAddr":"{{ esx_mgmt_ip_end }}",
"Netmask":"{{ hx_mgmt_netmask }}",
"Gateway":"{{ hx_mgmt_gateway }}"
},
"HxdpIpRange":{
"StartAddr":"{{ hx_mgmt_vm_ip_start }}",
"EndAddr":"{{ hx_mgmt_vm_ip_end }}",
"Netmask":"{{ hx_mgmt_netmask }}",
"Gateway":"{{ hx_mgmt_gateway }}"
},
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: node_config
- debug: msg="HyperFlex Node Configuration Policy named {{ hx_node_config_policy }} has been created successfully."

View File

@@ -0,0 +1,49 @@
---
# Get server Moids
- name: Get server Moid
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
cisco.intersight.intersight_info:
<<: *api_info
server_names:
- "{{ item }}"
loop: "{{ hx_servers }}"
register: inventory
# Get Cluster Profile Attributes
- name: "Get HyperFlex Cluster Profile"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ClusterProfiles
query_params:
$filter: "Name eq '{{ hx_cluster_name }}'"
register: profile
# Assign servers and profile to node profile
- name: "Configure Node Profile"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/NodeProfiles
query_params:
$filter: "Name eq '{{ hx_node_profile_prefix }}-{{ '%02d' % (idx + 1) }}'"
api_body: {
"Name":"{{ hx_node_profile_prefix }}-{{ '%02d' % (idx + 1) }}",
"AssignedServer": {
"Moid": "{{ item.intersight_servers[0].Moid }}",
"ObjectType": "compute.RackUnit"
},
"ClusterProfile": {
"Moid": "{{ profile.api_response.Moid }}"
}
}
when: item.intersight_servers is not none
loop: "{{ inventory.results }}"
loop_control:
index_var: idx
label: "{{ item.intersight_servers[0].Name }}"
- debug: msg="HyperFlex Node Profiles have been created successfully."

View File

@@ -0,0 +1,31 @@
---
- name: "Configure Proxy Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/ProxySettingPolicies
query_params:
$filter: "Name eq '{{ hx_proxy_setting_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_proxy_setting_policy }}",
"Hostname":"{{ hx_proxy_setting_hostname }}",
"Port":"{{ hx_proxy_setting_port }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: proxy_setting
- debug: msg="HyperFlex Proxy Policy named {{ hx_proxy_setting_policy }} has been created successfully."

View File

@@ -0,0 +1,31 @@
---
- name: "Configure Software Version Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/SoftwareVersionPolicies
query_params:
$filter: "Name eq '{{ hx_software_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_software_policy }}",
"HxdpVersion":"{{ hxdp_version }}",
"ServerFirmwareVersion":"{{ ucs_firmware_version }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: software_policy
- debug: msg="HyperFlex Software Version Policy named {{ hx_software_policy }} has been created successfully."

View File

@@ -0,0 +1,33 @@
---
- name: "Configure System Config Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/SysConfigPolicies
query_params:
$filter: "Name eq '{{ hx_sys_config_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name": "{{ hx_sys_config_policy }}",
"Timezone":"{{ hx_sys_config_timezone }}",
"DnsServers":"{{ hx_sys_config_dns_servers }}",
"NtpServers":"{{ hx_sys_config_ntp_servers }}",
"DnsDomainName":"{{ hx_sys_config_dns_domain }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: sys_config
- debug: msg="HyperFlex System Config Policy named {{ hx_sys_config_policy }} has been created successfully."

View File

@@ -0,0 +1,33 @@
---
- name: "Configure vCenter Config Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
intersight_rest_api:
<<: *api_info
resource_path: /hyperflex/VcenterConfigPolicies
query_params:
$filter: "Name eq '{{ hx_vcenter_config_policy }}'"
api_body: {
"Organization": {
"Moid": "{{ intersight_org.api_response.Moid }}"
},
"Name":"{{ hx_vcenter_config_policy }}",
"Hostname":"{{ hx_vcenter_hostname }}",
"Username":"{{ hx_vcenter_username }}",
"Password":"{{ hx_vcenter_password | default(omit) }}",
"DataCenter":"{{ hx_vcenter_datacenter }}",
"ClusterProfiles": [
{
"Moid": "{{ cluster_profile.api_response.Moid }}"
}
]
}
register: vcenter
- debug: msg="HyperFlex vCenter Config Policy named {{ hx_vcenter_config_policy }} has been created successfully."

View File

@@ -0,0 +1,40 @@
---
- name: "Configure {{ api_body.Name }} Server Policy"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: "{{ resource_path }}"
query_params:
$filter: "Name eq '{{ api_body.Name }}'"
api_body: "{{ api_body }}"
register: policy_resp
# Append profile_resp list to policy
- block:
# Create a list of all host's profile Moids
- set_fact:
# See the Ansible docs on json_query for info on how the Moid data is being extracted
profile_list: "{{ ansible_play_hosts | map('extract', hostvars, 'profile_resp') | list | json_query(moid_query) }}"
vars:
moid_query: "[*].api_response.{Moid: Moid, ObjectType: 'server.Profile'}"
- name: "Update Server Profiles used by {{ api_body.Name }} Server Policy (change may always be reported)"
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: "{{ resource_path }}"
query_params:
$filter: "Name eq '{{ api_body.Name }}'"
api_body: {
"Profiles": "{{ profile_list + policy_resp.api_response.Profiles }}"
}
# Do not update if the profile isn't available
when:
- profile_resp is defined
- profile_resp.api_response.Moid is defined
- policy_resp is defined
- policy_resp.api_response.Profiles is defined

View File

@@ -0,0 +1,30 @@
---
- name: "Configure {{ inventory_hostname }} power state"
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: /compute/ServerSettings
query_params:
$filter: "Server.Moid eq '{{ server_moid }}'"
api_body: {
"AdminPowerState": "{{ power_state }}"
}
when: power_state is defined
# Configure LED locator state
- name: "Configure {{ inventory_hostname }} locator state"
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: /compute/ServerSettings
query_params:
$filter: "Server.Moid eq '{{ server_moid }}'"
api_body: {
"AdminLocatorLedState": "{{ locator_state }}"
}
when: locator_state is defined

View File

@@ -0,0 +1,23 @@
---
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
gather_facts: false
tasks:
- import_role:
name: servers/actions
vars:
# power and reset state
# options: Policy, PowerOn, PowerOff, PowerCycle, HardReset, Shutdown, Reboot
# Can override on the command line: ansible-playbook ... -e power_state=PowerCycle
power_state: PowerOn
# led locator state
# options: On, Off, None
# Can override on the command line: ansible-playbook ... -e locator_state=Off
# locator_state: On
delegate_to: localhost

View File

@@ -0,0 +1,115 @@
---
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
fw_version: 4.1(2b)
file_share: 172.28.224.77/mnt/SHARE/ISOS/HUU
tasks:
# Edit FW to be used as needed for server type below
- set_fact:
file_name: "ucs-c220m4-huu-{{ fw_version | replace('(','.') | replace(')','') }}.iso"
supported_models:
- UCSC-C220-M4L
- UCSC-C220-M4S
when: model is search("UCSC-C220-M4.*")
- set_fact:
file_name: "ucs-c240m4-huu-{{ fw_version | replace('(','.') | replace(')','') }}.iso"
supported_models:
- UCSC-C240-M4L
- UCSC-C240-M4S
- UCSC-C240-M4SX
- UCSC-C240-M4SNEBS
- UCSC-C240-M4S2
when: model is search("UCSC-C240-M4.*")
- set_fact:
file_name: "ucs-c240m5-huu-{{ fw_version | replace('(','.') | replace(')','') }}.iso"
supported_models:
- UCSC-C240-M5S
- UCSC-C240-M5L
- UCSC-C240-M5SX
- UCSC-C240-M5SN
- UCSC-C240-M5SD
- HX240C-M5SX
- HXAF240C-M5SX
- HX240C-M5L
- HX240C-M5SD
- HXAF240C-M5SD
when: model is search("UCSC-C240-M5.*")
- set_fact:
file_name: "ucs-c220m5-huu-{{ fw_version | replace('(','.') | replace(')','') }}.iso"
supported_models:
- UCSC-C220-M5SX
- UCSC-C220-M5L
- UCSC-C220-M5SN
- HX220C-M5SX
- HXAF220C-M5SX
when: model is search("UCSC-C220-M5.*")
- set_fact:
file_location: "{{ file_share }}/{{ file_name }}"
# Set the distributable type based on the management mode and server type
- set_fact:
dist_type: STANDALONE
when: mode == 'Intersight' or mode == 'IntersightStandalone'
# Get a user defined FW version
- name: Get Moid of user defined FW version
intersight_rest_api:
<<: *api_info
resource_path: /firmware/Distributables
query_params:
$filter: "FileLocation eq '{{ file_location }}'"
update_method: post
api_body: {
"Catalog": {
"Moid": "5cd993686567612d30aaa762"
},
"ImportAction": "None",
"Name": "{{ file_name }}",
"Origin": "User",
"Source": {
"ObjectType": "softwarerepository.NfsServer",
"FileLocation": "{{ file_location }}"
},
"SupportedModels": "{{ supported_models }}",
"Version": "{{ fw_version }}"
}
delegate_to: localhost
register: fw_resp
- name: Update server firmware
cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: /firmware/Upgrades
query_params:
$filter: "Server.Moid eq '{{ server_moid }}'"
update_method: post
# nw_upgrade_full supported in UI, nw_upgrade_mount_only has partial API support
api_body: {
"UpgradeType": "network_upgrade",
"Distributable": {
"Moid": "{{ fw_resp.api_response.Moid }}"
},
"DirectDownload": {},
"NetworkShare": {
"Upgradeoption": "nw_upgrade_mount_only",
"MapType":"nfs"
},
"Server": {
"ObjectType": "compute.{{ object_type }}",
"Moid": "{{ server_moid }}"
}
}
delegate_to: localhost
when: server_moid is defined

View File

@@ -0,0 +1,14 @@
---
# Update standalone servers (IMC) in the file
- lineinfile:
path: "{{ filepath }}"
insertafter: "^\\[{{ host_group }}\\]"
regexp: "^{{ item.Name }} "
# Each line of the inventory has the following:
# Name server_moid=<Moid value> model=<Model value> ...
line: "{{ item.Name }} server_moid={{ item.Moid }} model={{ item.Model }}"
create: true
loop: "{{ outer_item.api_response }}"
loop_control:
label: "{{ item.Name }}"
when: outer_item.api_response is defined and outer_item.api_response

View File

@@ -0,0 +1,57 @@
---
#
# Summary: Auto generate (or update) the Ansible inventory file with all servers (Name and Moid or each discovered server)
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
# This playbook only runs once (and not for each server in the inventory), but the hosts group is used to get API key info
#
- hosts: "{{ group | default('Intersight') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Change filepath if you want to update a different inventory file
filepath: "{{ inventory_file }}"
# Change host_group if you want to use another group name for your servers in the created inventory
host_group: Intersight_Servers
tasks:
# Enclose tasks in a block that is only run once
- block:
# Find all servers
- cisco.intersight.intersight_info:
<<: *api_info
server_names:
register: all_results
# Place the servers in a group in the file
- debug:
msg: Inventory filepath "{{ filepath }}"
- lineinfile:
path: "{{ filepath }}"
line: "[{{ host_group }}]"
create: true
# Update servers in the file
- lineinfile:
path: "{{ filepath }}"
insertafter: "^\\[{{ host_group }}\\]"
regexp: "^{{ item.Name }} serial={{ item.Serial }} "
# Each line of the inventory has the following:
line: "{{ item.Name }} serial={{ item.Serial }} server_moid={{ item.Moid }} model={{ item.Model }} mode={{ item.ManagementMode }} object_type={{ item.SourceObjectType | regex_replace('compute.')}}"
create: true
loop: "{{ all_results.intersight_servers }}"
loop_control:
label: "{{ item.Name }}"
when: all_results.intersight_servers is defined
delegate_to: localhost
run_once: true

View File

@@ -0,0 +1,61 @@
---
#
# Summary: Auto generate (or update) the Ansible inventory file with all servers (Name and Moid or each discovered server)
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
# This playbook only runs once (and not for each server in the inventory), but the hosts group is used to get API key info
#
- hosts: "{{ group | default('Intersight') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Change filepath if you want to update a different inventory file
filepath: "{{ inventory_file }}"
# Change host_group if you want to use another group name for your servers in the created inventory
host_group: Intersight_Servers
tasks:
# Enclose tasks in a block that is only run once
- block:
# Find all servers
- cisco.intersight.intersight_info:
<<: *api_info
server_names:
register: all_results
# Place the servers in a group in the file
- debug:
msg: Inventory filepath "{{ filepath }}"
- lineinfile:
path: "{{ filepath }}"
line: "[{{ host_group }}]"
create: true
# Update servers in the file
- lineinfile:
path: "{{ filepath }}"
insertafter: "^\\[{{ host_group }}\\]"
regexp: "^{{ item.Name }} serial={{ item.Serial }} "
# Each line of the inventory has the following:
# Name server_moid=<Moid value> model=<Model value> boot_policy=<policy from tag> | 'na'
line: "{{ item.Name }} serial={{ item.Serial }} server_moid={{ item.Moid }} model={{ item.Model }}"
create: true
# Ansible and jmespath contains have type differences, so to/from_json used
loop: "{{ all_results.intersight_servers | json_query(platform_query) | to_json | from_json | json_query(model_query) }}"
loop_control:
label: "{{ item.Name }}"
vars:
# Filter for IMC and C-Series only (no HX)
platform_query: "[?PlatformType=='IMC']"
model_query: "[?contains(Model, 'HX')]"
when: all_results.intersight_servers is defined
delegate_to: localhost
run_once: true

View File

@@ -0,0 +1,61 @@
---
#
# Summary: Auto generate (or update) the Ansible inventory file with all servers (Name and Moid or each discovered server)
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
# This playbook only runs once (and not for each server in the inventory), but the hosts group is used to get API key info
#
- hosts: "{{ group | default('Intersight') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Change filepath if you want to update a different inventory file
filepath: "{{ inventory_file }}"
# Change host_group if you want to use another group name for your servers in the created inventory
host_group: Intersight_Servers
tasks:
# Enclose tasks in a block that is only run once
- block:
# Find all servers
- cisco.intersight.intersight_info:
<<: *api_info
server_names:
register: all_results
# Place the servers in a group in the file
- debug:
msg: Inventory filepath "{{ filepath }}"
- lineinfile:
path: "{{ filepath }}"
line: "[{{ host_group }}]"
create: true
# Update servers in the file
- lineinfile:
path: "{{ filepath }}"
insertafter: "^\\[{{ host_group }}\\]"
regexp: "^{{ item.Name }} serial={{ item.Serial }} "
# Each line of the inventory has the following:
# Name server_moid=<Moid value> model=<Model value> boot_policy=<policy from tag> | 'na'
line: "{{ item.Name }} serial={{ item.Serial }} server_moid={{ item.Moid }} model={{ item.Model }}"
create: true
# Ansible and jmespath contains have type differences, so to/from_json used
loop: "{{ all_results.intersight_servers | json_query(platform_query) | to_json | from_json | json_query(model_query) }}"
loop_control:
label: "{{ item.Name }}"
vars:
# Filter for IMC and C-Series only (no HX)
platform_query: "[?PlatformType=='UCSFI']"
model_query: "[?contains(Model, 'HX')]"
when: all_results.intersight_servers is defined
delegate_to: localhost
run_once: true

View File

@@ -0,0 +1,67 @@
---
#
# Summary: Auto generate (or update) the Ansible inventory file with Standalone C-Series servers (Name and Moid or each discovered server)
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
# This playbook only runs once (and not for each server in the inventory), but the hosts group is used to get API key info
#
- hosts: "{{ group | default('Intersight') }}"
connection: local
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# if api_key vars are omitted, INTERSIGHT_API_KEY_ID, INTERSIGHT_API_PRIVATE_KEY,
# and INTERSIGHT_API_URI environment variables used for API key data
api_private_key: "{{ api_private_key | default(omit) }}"
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# How many results to return per inventory file
per_page: 500
# Total servers to query
max_servers: 15000
# Change filepath if you want to update a different inventory file
filepath: "{{ inventory_file }}"
# Change host_group if you want to use another group name for your servers in the created inventory
host_group: Intersight_Servers
tasks:
# Enclose tasks in a block that is only run once
- block:
# Set an api response for the 1st loop iteration
- set_fact:
servers:
api_response:
- Moid: fake
run_once: true
# Find all servers
- cisco.intersight.intersight_rest_api:
<<: *api_info
resource_path: /compute/PhysicalSummaries
query_params:
$filter: "ManagementMode eq 'IntersightStandalone' and contains(Model, 'UCSC-C')"
$select: Name,Model,Serial
$top: "{{ per_page }}"
$skip: "{{ item }}"
return_list: true
loop: "{{ range(0, max_servers|int, per_page|int) | list }}"
register: servers
when: servers.api_response
# Place the servers in a group in the file
- debug:
msg: Inventory filepath "{{ filepath }}"
- lineinfile:
path: "{{ filepath }}"
line: "[{{ host_group }}]"
create: true
- include_tasks: servers_to_file.yml
loop: "{{ servers.results }}"
loop_control:
loop_var: outer_item
delegate_to: localhost
run_once: true

View File

@@ -0,0 +1,88 @@
---
#
# Configure Server Profiles
#
# The hosts group used is provided by the group variable or defaulted to 'Intersight_Servers'.
# You can specify a specific host (or host group) on the command line:
# ansible-playbook ... -e group=<your host group>
# e.g., ansible-playbook server_profiles.yml -e group=TME_Demo
#
- hosts: "{{ group | default('Intersight_Servers') }}"
connection: local
collections:
- cisco.intersight
gather_facts: false
vars:
# Create an anchor for api_info that can be used throughout the file
api_info: &api_info
# Key can be directly specified, and vault should be used to encrypt:
# Ex. ansible-vault encrypt_string --vault-id tme@/Users/dsoper/Documents/vault_password_file '-----BEGIN EC PRIVATE KEY-----
# <your private key data>
# -----END EC PRIVATE KEY-----'
# To use with vault:
# ansible-playbook -i inventory --vault-id tme@vault_password_file intersight_server_profile.yml
api_private_key: !vault |
$ANSIBLE_VAULT;1.2;AES256;tme
34376535353966373536386366646435643735636364373163343365623465343466393338386331
3135633161333861386265393631616237623236643263620a613363396362386631613863643364
65376635316232613561373761363633633034346138366165356561666462333562643065393332
6631363239333332640a376632376434366461393039663530386161313864633265353839636337
39393939363535376566333565666537666137366537396639623633643665363066646161633833
35656430366665336334383435326239316333323631306237626432636361356166383466656362
36626566643637366264393933353038653062373035306338663730383739336530313664646162
30623337383832306665356433346331656164366638633563396532313463643032366537666639
32383230633135373764623733653261326536626561656462343565613535386331643365343738
62623631383135623539393538396435623064306636323165623661633466373664326130396663
31333163643763616263623566353565363030383761366566613036616163343530663362313131
32643737653063383330356436303437383966366163383461376236363563313264303833653631
62613432303536386630646166346262636566303563646337653166303937333134356537656630
39303363383262376237366565346638336139346363383634623333356639616538303366616634
35666439356634353530363566313864333966386263623566323564656366356264313166353038
66643566313361636231616338633939323131643061646664396264366538386230366364326633
3831
api_key_id: "{{ api_key_id | default(omit) }}"
api_uri: "{{ api_uri | default(omit) }}"
validate_certs: "{{ validate_certs | default(omit) }}"
state: "{{ state | default(omit) }}"
# Server Profile name default
profile_name: "SP-{{ inventory_hostname }}"
tasks:
#
# Configure profiles specific to server (run for each server in the inventory)
#
- set_fact:
mode: Standalone
when: mode is not defined or mode == 'IntersightStandalone'
- set_fact:
mode: FIAttached
when: mode == 'Intersight'
# Get server moid when not defined in inventory
- block:
- name: "Get {{ inventory_hostname }} Server Moid"
cisco.intersight.intersight_info:
<<: *api_info
server_names: "{{ inventory_hostname }}"
register: server
- set_fact:
server_moid: "{{ server.intersight_servers[0].Moid }}"
when: server_moid is not defined
delegate_to: localhost
- name: "Configure {{ profile_name }} Server Profile"
intersight_server_profile:
<<: *api_info
organization: "{{ organization | default(omit) }}"
name: "{{ profile_name }}"
target_platform: "{{ mode | default(omit) }}"
tags:
- Key: Site
Value: SJC02
description: "Updated Profile for server name {{ inventory_hostname }}"
assigned_server: "{{ server_moid }}"
boot_order_policy: "{{ boot_order_policy | default(omit) }}"
imc_access_policy: "{{ imc_access_policy | default(omit) }}"
lan_connectivity_policy: "{{ lan_connectivity_policy | default(omit) }}"
local_user_policy: "{{ local_user_policy | default(omit) }}"
ntp_policy: "{{ ntp_policy | default(omit) }}"
virtual_media_policy: "{{ virtual_media_policy | default(omit) }}"
when: server_moid is defined
delegate_to: localhost

View File

@@ -0,0 +1,31 @@
# Collections Plugins Directory
This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that
is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that
would contain module utils and modules respectively.
Here is an example directory of the majority of plugins currently supported by Ansible:
```
└── plugins
├── action
├── become
├── cache
├── callback
├── cliconf
├── connection
├── filter
├── httpapi
├── inventory
├── lookup
├── module_utils
├── modules
├── netconf
├── shell
├── strategy
├── terminal
├── test
└── vars
```
A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible/2.9/plugins/plugins.html).

View File

@@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# (c) 2016 Red Hat Inc.
# (c) 2017 Cisco Systems Inc.
#
# Simplified BSD License (see licenses/simplified_bsd.txt or https://opensource.org/licenses/BSD-2-Clause)
#
class ModuleDocFragment(object):
# Cisco Intersight doc fragment
DOCUMENTATION = '''
options:
api_private_key:
description:
- 'Filename (absolute path) or string of PEM formatted private key data to be used for Intersight API authentication.'
- If a string is used, Ansible vault should be used to encrypt string data.
- "Ex. ansible-vault encrypt_string --vault-id tme@/Users/dsoper/Documents/vault_password_file '-----BEGIN EC PRIVATE KEY-----"
- " <your private key data>"
- " -----END EC PRIVATE KEY-----'"
- If not set, the value of the INTERSIGHT_API_PRIVATE_KEY environment variable is used.
type: str
required: yes
api_uri:
description:
- URI used to access the Intersight API.
- If not set, the value of the INTERSIGHT_API_URI environment variable is used.
type: str
default: https://intersight.com/api/v1
api_key_id:
description:
- Public API Key ID associated with the private key.
- If not set, the value of the INTERSIGHT_API_KEY_ID environment variable is used.
type: str
required: yes
validate_certs:
description:
- Boolean control for verifying the api_uri TLS certificate
type: bool
default: yes
use_proxy:
description:
- If C(no), it will not use a proxy, even if one is defined in an environment variable on the target hosts.
type: bool
default: yes
'''

View File

@@ -0,0 +1,471 @@
# This code is part of Ansible, but is an independent component.
# This particular file snippet, and this file snippet only, is BSD licensed.
# Modules you write using this snippet, which is embedded dynamically by Ansible
# still belong to the author of the module, and may assign their own license
# to the complete work.
#
# (c) 2016 Red Hat Inc.
# (c) 2020 Cisco Systems Inc.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * 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.
#
# 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.
#
# Intersight REST API Module
# Author: Matthew Garrett
# Contributors: David Soper, Chris Gascoigne, John McDonough
from base64 import b64encode
from email.utils import formatdate
import re
import json
import hashlib
from ansible.module_utils.six import iteritems
from ansible.module_utils.six.moves.urllib.parse import urlparse, urlencode
from ansible.module_utils.urls import fetch_url
from ansible.module_utils.basic import env_fallback
try:
from cryptography.hazmat.primitives import serialization, hashes
from cryptography.hazmat.primitives.asymmetric import padding, ec
from cryptography.hazmat.backends import default_backend
HAS_CRYPTOGRAPHY = True
except ImportError:
HAS_CRYPTOGRAPHY = False
intersight_argument_spec = dict(
api_private_key=dict(fallback=(env_fallback, ['INTERSIGHT_API_PRIVATE_KEY']), type='path', required=True, no_log=True),
api_uri=dict(fallback=(env_fallback, ['INTERSIGHT_API_URI']), type='str', default='https://intersight.com/api/v1'),
api_key_id=dict(fallback=(env_fallback, ['INTERSIGHT_API_KEY_ID']), type='str', required=True),
validate_certs=dict(type='bool', default=True),
use_proxy=dict(type='bool', default=True),
)
def get_sha256_digest(data):
"""
Generates a SHA256 digest from a String.
:param data: data string set by user
:return: instance of digest object
"""
digest = hashlib.sha256()
digest.update(data.encode())
return digest
def prepare_str_to_sign(req_tgt, hdrs):
"""
Concatenates Intersight headers in preparation to be signed
:param req_tgt : http method plus endpoint
:param hdrs: dict with header keys
:return: concatenated header authorization string
"""
ss = ""
ss = ss + "(request-target): " + req_tgt + "\n"
length = len(hdrs.items())
i = 0
for key, value in hdrs.items():
ss = ss + key.lower() + ": " + value
if i < length - 1:
ss = ss + "\n"
i += 1
return ss
def get_gmt_date():
"""
Generated a GMT formatted Date
:return: current date
"""
return formatdate(timeval=None, localtime=False, usegmt=True)
def compare_lists(expected_list, actual_list):
if len(expected_list) != len(actual_list):
# mismatch if list lengths aren't equal
return False
for expected, actual in zip(expected_list, actual_list):
# if compare_values returns False, stop the loop and return
if not compare_values(expected, actual):
return False
# loop complete with all items matching
return True
def compare_values(expected, actual):
try:
if isinstance(expected, list) and isinstance(actual, list):
return compare_lists(expected, actual)
for (key, value) in iteritems(expected):
if re.search(r'P(ass)?w(or)?d', key) or key not in actual:
# do not compare any password related attributes or attributes that are not in the actual resource
continue
if not compare_values(value, actual[key]):
return False
# loop complete with all items matching
return True
except (AttributeError, TypeError):
# if expected and actual != expected:
if actual != expected:
return False
return True
class IntersightModule():
def __init__(self, module):
self.module = module
self.result = dict(changed=False)
if not HAS_CRYPTOGRAPHY:
self.module.fail_json(msg='cryptography is required for this module')
self.host = self.module.params['api_uri']
self.public_key = self.module.params['api_key_id']
try:
with open(self.module.params['api_private_key'], 'r') as f:
self.private_key = f.read()
except (FileNotFoundError, OSError):
self.private_key = self.module.params['api_private_key']
self.digest_algorithm = ''
self.response_list = []
def get_sig_b64encode(self, data):
"""
Generates a signed digest from a String
:param digest: string to be signed & hashed
:return: instance of digest object
"""
# Python SDK code: Verify PEM Pre-Encapsulation Boundary
r = re.compile(r"\s*-----BEGIN (.*)-----\s+")
m = r.match(self.private_key)
if not m:
raise ValueError("Not a valid PEM pre boundary")
pem_header = m.group(1)
key = serialization.load_pem_private_key(self.private_key.encode(), None, default_backend())
if pem_header == 'RSA PRIVATE KEY':
sign = key.sign(data.encode(), padding.PKCS1v15(), hashes.SHA256())
self.digest_algorithm = 'rsa-sha256'
elif pem_header == 'EC PRIVATE KEY':
sign = key.sign(data.encode(), ec.ECDSA(hashes.SHA256()))
self.digest_algorithm = 'hs2019'
else:
raise Exception("Unsupported key: {0}".format(pem_header))
return b64encode(sign)
def get_auth_header(self, hdrs, signed_msg):
"""
Assmebled an Intersight formatted authorization header
:param hdrs : object with header keys
:param signed_msg: base64 encoded sha256 hashed body
:return: concatenated authorization header
"""
auth_str = "Signature"
auth_str = auth_str + " " + "keyId=\"" + self.public_key + "\"," + "algorithm=\"" + self.digest_algorithm + "\","
auth_str = auth_str + "headers=\"(request-target)"
for key, dummy in hdrs.items():
auth_str = auth_str + " " + key.lower()
auth_str = auth_str + "\""
auth_str = auth_str + "," + "signature=\"" + signed_msg.decode('ascii') + "\""
return auth_str
def get_moid_by_name(self, resource_path, target_name):
"""
Retrieve an Intersight object moid by name
:param resource_path: intersight resource path e.g. '/ntp/Policies'
:param target_name: intersight object name
:return: json http response object
"""
query_params = {
"$filter": "Name eq '{0}'".format(target_name)
}
options = {
"http_method": "GET",
"resource_path": resource_path,
"query_params": query_params
}
get_moid = self.intersight_call(**options)
if get_moid.json()['Results'] is not None:
located_moid = get_moid.json()['Results'][0]['Moid']
else:
raise KeyError('Intersight object with name "{0}" not found!'.format(target_name))
return located_moid
def call_api(self, **options):
"""
Call the Intersight API and check for success status
:param options: options dict with method and other params for API call
:return: json http response object
"""
try:
response, info = self.intersight_call(**options)
if not re.match(r'2..', str(info['status'])):
raise RuntimeError(info['status'], info['msg'], info['body'])
except Exception as e:
self.module.fail_json(msg="API error: %s " % str(e))
response_data = response.read()
if len(response_data) > 0:
resp_json = json.loads(response_data)
resp_json['trace_id'] = info.get('x-starship-traceid')
return resp_json
return {}
def intersight_call(self, http_method="", resource_path="", query_params=None, body=None, moid=None, name=None):
"""
Invoke the Intersight API
:param resource_path: intersight resource path e.g. '/ntp/Policies'
:param query_params: dictionary object with query string parameters as key/value pairs
:param body: dictionary object with intersight data
:param moid: intersight object moid
:param name: intersight object name
:return: json http response object
"""
target_host = urlparse(self.host).netloc
target_path = urlparse(self.host).path
query_path = ""
method = http_method.upper()
bodyString = ""
# Verify an accepted HTTP verb was chosen
if(method not in ['GET', 'POST', 'PATCH', 'DELETE']):
raise ValueError('Please select a valid HTTP verb (GET/POST/PATCH/DELETE)')
# Verify the resource path isn't empy & is a valid <str> object
if(resource_path != "" and not (resource_path, str)):
raise TypeError('The *resource_path* value is required and must be of type "<str>"')
# Verify the query parameters isn't empy & is a valid <dict> object
if(query_params is not None and not isinstance(query_params, dict)):
raise TypeError('The *query_params* value must be of type "<dict>"')
# Verify the MOID is not null & of proper length
if(moid is not None and len(moid.encode('utf-8')) != 24):
raise ValueError('Invalid *moid* value!')
# Check for query_params, encode, and concatenate onto URL
if query_params:
query_path = "?" + urlencode(query_params)
# Handle PATCH/DELETE by Object "name" instead of "moid"
if method in ('PATCH', 'DELETE'):
if moid is None:
if name is not None:
if isinstance(name, str):
moid = self.get_moid_by_name(resource_path, name)
else:
raise TypeError('The *name* value must be of type "<str>"')
else:
raise ValueError('Must set either *moid* or *name* with "PATCH/DELETE!"')
# Check for moid and concatenate onto URL
if moid is not None:
resource_path += "/" + moid
# Check for GET request to properly form body
if method != "GET":
bodyString = json.dumps(body)
# Concatenate URLs for headers
target_url = self.host + resource_path + query_path
request_target = method.lower() + " " + target_path + resource_path + query_path
# Get the current GMT Date/Time
cdate = get_gmt_date()
# Generate the body digest
body_digest = get_sha256_digest(bodyString)
b64_body_digest = b64encode(body_digest.digest())
# Generate the authorization header
auth_header = {
'Host': target_host,
'Date': cdate,
'Digest': "SHA-256=" + b64_body_digest.decode('ascii'),
}
string_to_sign = prepare_str_to_sign(request_target, auth_header)
b64_signed_msg = self.get_sig_b64encode(string_to_sign)
auth_header = self.get_auth_header(auth_header, b64_signed_msg)
# Generate the HTTP requests header
request_header = {
'Accept': 'application/json',
'Content-Type': 'application/json',
'Host': '{0}'.format(target_host),
'Date': '{0}'.format(cdate),
'Digest': 'SHA-256={0}'.format(b64_body_digest.decode('ascii')),
'Authorization': '{0}'.format(auth_header),
}
response, info = fetch_url(self.module, target_url, data=bodyString, headers=request_header, method=method, use_proxy=self.module.params['use_proxy'])
return response, info
def get_resource(self, resource_path, query_params, return_list=False):
'''
GET a resource and return the 1st element found or the full Results list
'''
options = {
'http_method': 'get',
'resource_path': resource_path,
'query_params': query_params,
}
response = self.call_api(**options)
if response.get('Results'):
if return_list:
self.result['api_response'] = response['Results']
else:
# return the 1st list element
self.result['api_response'] = response['Results'][0]
self.result['trace_id'] = response.get('trace_id')
def configure_resource(self, moid, resource_path, body, query_params, update_method=''):
if not self.module.check_mode:
if moid and update_method != 'post':
# update the resource - user has to specify all the props they want updated
options = {
'http_method': 'patch',
'resource_path': resource_path,
'body': body,
'moid': moid,
}
response_dict = self.call_api(**options)
if response_dict.get('Results'):
# return the 1st element in the results list
self.result['api_response'] = response_dict['Results'][0]
self.result['trace_id'] = response_dict.get('trace_id')
else:
# create the resource
options = {
'http_method': 'post',
'resource_path': resource_path,
'body': body,
}
response_dict = self.call_api(**options)
if response_dict:
self.result['api_response'] = response_dict
self.result['trace_id'] = response_dict.get('trace_id')
elif query_params:
# POSTs may not return any data.
# Get the current state of the resource if query_params.
self.get_resource(
resource_path=resource_path,
query_params=query_params,
)
self.result['changed'] = True
def delete_resource(self, moid, resource_path):
# delete resource and create empty api_response
if not self.module.check_mode:
options = {
'http_method': 'delete',
'resource_path': resource_path,
'moid': moid,
}
resp = self.call_api(**options)
self.result['api_response'] = {}
self.result['trace_id'] = resp.get('trace_id')
self.result['changed'] = True
def configure_policy_or_profile(self, resource_path):
# Configure (create, update, or delete) the policy or profile
organization_moid = None
# GET Organization Moid
self.get_resource(
resource_path='/organization/Organizations',
query_params={
'$filter': "Name eq '" + self.module.params['organization'] + "'",
'$select': 'Moid',
},
)
if self.result['api_response'].get('Moid'):
# resource exists and moid was returned
organization_moid = self.result['api_response']['Moid']
self.result['api_response'] = {}
# Get the current state of the resource
filter_str = "Name eq '" + self.module.params['name'] + "'"
filter_str += "and Organization.Moid eq '" + organization_moid + "'"
self.get_resource(
resource_path=resource_path,
query_params={
'$filter': filter_str,
'$expand': 'Organization',
}
)
moid = None
resource_values_match = False
if self.result['api_response'].get('Moid'):
# resource exists and moid was returned
moid = self.result['api_response']['Moid']
if self.module.params['state'] == 'present':
resource_values_match = compare_values(self.api_body, self.result['api_response'])
else: # state == 'absent'
self.delete_resource(
moid=moid,
resource_path=resource_path,
)
moid = None
if self.module.params['state'] == 'present' and not resource_values_match:
# remove read-only Organization key
self.api_body.pop('Organization')
if not moid:
# Organization must be set, but can't be changed after initial POST
self.api_body['Organization'] = {
'Moid': organization_moid,
}
self.configure_resource(
moid=moid,
resource_path=resource_path,
body=self.api_body,
query_params={
'$filter': filter_str
}
)
if self.result['api_response'].get('Moid'):
# resource exists and moid was returned
moid = self.result['api_response']['Moid']
return moid

View File

@@ -0,0 +1,495 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_boot_order_policy
short_description: Boot Order policy configuration for Cisco Intersight
description:
- Boot Order policy configuration for Cisco Intersight.
- Used to configure Boot Order servers and timezone settings on Cisco Intersight managed devices.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
organization:
description:
- The name of the Organization this resource is assigned to.
- Profiles and Policies that are created within a Custom Organization are applicable only to devices in the same Organization.
default: default
name:
description:
- The name assigned to the Boot Order policy.
- The name must be between 1 and 62 alphanumeric characters, allowing special characters :-_.
required: true
tags:
description:
- List of tags in Key:<user-defined key> Value:<user-defined value> format.
type: list
description:
description:
- The user-defined description of the Boot Order policy.
- Description can contain letters(a-z, A-Z), numbers(0-9), hyphen(-), period(.), colon(:), or an underscore(_).
aliases: [descr]
configured_boot_mode:
description:
- Sets the BIOS boot mode.
- UEFI uses the GUID Partition Table (GPT) whereas Legacy mode uses the Master Boot Record (MBR) partitioning scheme.
choices: [Legacy, Uefi]
default: Legacy
uefi_enable_secure_boot:
description:
- Secure boot enforces that device boots using only software that is trusted by the Original Equipment Manufacturer (OEM).
- Option is only used if configured_boot_mode is set to Uefi.
type: bool
default: false
boot_devices:
description:
- List of Boot Devices configured on the endpoint.
type: list
suboptions:
enabled:
description:
- Specifies if the boot device is enabled or disabled.
type: bool
default: true
device_type:
description:
- Device type used with this boot option.
- Choices are based on each device title in the API schema.
choices: [iSCSI, Local CDD, Local Disk, NVMe, PCH Storage, PXE, SAN, SD Card, UEFI Shell, USB, Virtual Media]
required: true
device_name:
description:
- A name that helps identify a boot device.
- It can be any string that adheres to the following constraints.
- It should start and end with an alphanumeric character.
- It can have underscores and hyphens.
- It cannot be more than 30 characters.
required: true
network_slot:
description:
- The slot id of the controller for the iscsi and pxe device.
- Option is used when device_type is iscsi and pxe.
choices: [1 - 255, MLOM, L, L1, L2, OCP]
port:
description:
- The port id of the controller for the iscsi and pxe device.
- Option is used when device_type is iscsi and pxe.
- The port id need to be an integer from 0 to 255.
controller_slot:
description:
- The slot id of the controller for the local disk device.
- Option is used when device_type is local_disk.
choices: [1-255, M, HBA, SAS, RAID, MRAID, MSTOR-RAID]
bootloader_name:
description:
- Details of the bootloader to be used during boot from local disk.
- Option is used when device_type is local_disk and configured_boot_mode is Uefi.
bootloader_description:
description:
- Details of the bootloader to be used during boot from local disk.
- Option is used when device_type is local_disk and configured_boot_mode is Uefi.
bootloader_path:
description:
- Details of the bootloader to be used during boot from local disk.
- Option is used when device_type is local_disk and configured_boot_mode is Uefi.
ip_type:
description:
- The IP Address family type to use during the PXE Boot process.
- Option is used when device_type is pxe.
choices: [None, IPv4, IPv6]
default: None
interface_source:
description:
- Lists the supported Interface Source for PXE device.
- Option is used when device_type is pxe.
choices: [name, mac, port]
default: name
intefrace_name:
description:
- The name of the underlying virtual ethernet interface used by the PXE boot device.
- Option is used when device_type is pxe and interface_source is name.
mac_address:
description:
- The MAC Address of the underlying virtual ethernet interface used by the PXE boot device.
- Option is used when device_type is pxe and interface_source is mac.
sd_card_subtype:
description:
- The subtype for the selected device type.
- Option is used when device_type is sd_card.
choices: [None, flex-util, flex-flash, SDCARD]
default: None
lun:
description:
- The Logical Unit Number (LUN) of the device.
- Option is used when device_type is pch, san and sd_card.
- The LUN need to be an integer from 0 to 255.
usb_subtype:
description:
- The subtype for the selected device type.
- Option is used when device_type is usb.
choices: [None, usb-cd, usb-fdd, usb-hdd]
default: None
virtual_media_subtype:
description:
- The subtype for the selected device type.
- Option is used when device_type is virtual_media.
choices: [None, cimc-mapped-dvd, cimc-mapped-hdd, kvm-mapped-dvd, kvm-mapped-hdd, kvm-mapped-fdd]
default: None
author:
- Tse Kai "Kevin" Chan (@BrightScale)
version_added: '2.10'
'''
EXAMPLES = r'''
- name: Configure Boot Order Policy
cisco.intersight.intersight_boot_order_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
organization: DevNet
name: COS-Boot
description: Boot Order policy for COS
tags:
- Key: Site
Value: RCDN
configured_boot_mode: legacy
boot_devices:
- device_type: Local Disk
device_name: Boot-Lun
controller_slot: MRAID
- name: Delete Boot Order Policy
cisco.intersight.intersight_boot_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
organization: DevNet
name: COS-Boot
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"Name": "COS-Boot",
"ObjectType": "boot.Policy",
"Tags": [
{
"Key": "Site",
"Value": "RCDN"
}
]
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec
def main():
boot_device = dict(
enabled=dict(type='bool', default=True),
device_type=dict(
type='str',
choices=[
'iSCSI',
'Local CDD',
'Local Disk',
'NVMe',
'PCH Storage',
'PXE',
'SAN',
'SD Card',
'UEFI Shell',
'USB',
'Virtual Media',
],
required=True,
),
device_name=dict(type='str', required=True),
# iscsi and pxe options
network_slot=dict(type='str', default=''),
port=dict(type='int', default=0),
# local disk options
controller_slot=dict(type='str', default=''),
# bootloader options
bootloader_name=dict(type='str', default=''),
bootloader_description=dict(type='str', default=''),
bootloader_path=dict(type='str', default=''),
# pxe only options
ip_type=dict(
type='str',
choices=[
'None',
'IPv4',
'IPv6'
],
default='None'
),
interface_source=dict(
type='str',
choices=[
'name',
'mac',
'port'
],
default='name'
),
interface_name=dict(type='str', default=''),
mac_address=dict(type='str', defualt=''),
# sd card options
sd_card_subtype=dict(
type='str',
choices=[
'None',
'flex-util',
'flex-flash',
'SDCARD'
],
default='None',
),
# lun for pch, san, sd_card
lun=dict(type='int', default=0),
# usb options
usb_subtype=dict(
type='str',
choices=[
'None',
'usb-cd',
'usb-fdd',
'usb-hdd'
],
default='None',
),
# virtual media options
virtual_media_subtype=dict(
type='str',
choices=[
'None',
'cimc-mapped-dvd',
'cimc-mapped-hdd',
'kvm-mapped-dvd',
'kvm-mapped-hdd',
'kvm-mapped-fdd'
],
default='None',
),
)
argument_spec = intersight_argument_spec
argument_spec.update(
state=dict(type='str', choices=['present', 'absent'], default='present'),
organization=dict(type='str', default='default'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
tags=dict(type='list', default=[]),
configured_boot_mode=dict(type='str', choices=['Legacy', 'Uefi'], default='Legacy'),
uefi_enable_secure_boot=dict(type='bool', default=False),
boot_devices=dict(type='list', elements='dict', options=boot_device),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
#
# Argument spec above, resource path, and API body should be the only code changed in each policy module
#
# Resource path used to configure policy
resource_path = '/boot/PrecisionPolicies'
# Define API body used in compares or create
intersight.api_body = {
'Organization': {
'Name': intersight.module.params['organization'],
},
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
'ConfiguredBootMode': intersight.module.params['configured_boot_mode'],
"EnforceUefiSecureBoot": intersight.module.params['uefi_enable_secure_boot'],
'BootDevices': [],
}
if intersight.module.params.get('boot_devices'):
for device in intersight.module.params['boot_devices']:
if device['device_type'] == 'iSCSI':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.Iscsi",
"ObjectType": "boot.Iscsi",
"Enabled": device['enabled'],
"Name": device['device_name'],
"Slot": device['network_slot'],
"Port": device['port'],
}
)
elif device['device_type'] == 'Local CDD':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.LocalCDD",
"ObjectType": "boot.LocalCDD",
"Enabled": device['enabled'],
"Name": device['device_name'],
}
)
elif device['device_type'] == 'Local Disk':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.LocalDisk",
"ObjectType": "boot.LocalDisk",
"Enabled": device['enabled'],
"Name": device['device_name'],
"Slot": device['controller_slot'],
"Bootloader": {
"ClassId": "boot.Bootloader",
"ObjectType": "boot.Bootloader",
"Description": device['bootloader_description'],
"Name": device['bootloader_name'],
"Path": device['bootloader_path'],
},
}
)
elif device['device_type'] == 'NVMe':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.NVMe",
"ObjectType": "boot.NVMe",
"Enabled": device['enabled'],
"Name": device['device_name'],
"Bootloader": {
"ClassId": "boot.Bootloader",
"ObjectType": "boot.Bootloader",
"Description": device['bootloader_description'],
"Name": device['bootloader_name'],
"Path": device['bootloader_path'],
},
}
)
elif device['device_type'] == 'PCH Storage':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.PchStorage",
"ObjectType": "boot.PchStorage",
"Enabled": device['enabled'],
"Name": device['device_name'],
"Bootloader": {
"ClassId": "boot.Bootloader",
"ObjectType": "boot.Bootloader",
"Description": device['bootloader_description'],
"Name": device['bootloader_name'],
"Path": device['bootloader_path'],
},
"Lun": device['lun'],
}
)
elif device['device_type'] == 'PXE':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.Pxe",
"ObjectType": "boot.Pxe",
"Enabled": device['enabled'],
"Name": device['device_name'],
"IpType": device['ip_type'],
"InterfaceSource": device['interface_source'],
"Slot": device['network_slot'],
"InterfaceName": device['interface_name'],
"Port": device['port'],
"MacAddress": device['mac_address'],
}
)
elif device['device_type'] == 'SAN':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.San",
"ObjectType": "boot.San",
"Enabled": device['enabled'],
"Name": device['device_name'],
"Lun": device['lun'],
"Slot": device['network_slot'],
"Bootloader": {
"ClassId": "boot.Bootloader",
"ObjectType": "boot.Bootloader",
"Description": device['bootloader_description'],
"Name": device['bootloader_name'],
"Path": device['bootloader_path'],
},
}
)
elif device['device_type'] == 'SD Card':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.SdCard",
"ObjectType": "boot.SdCard",
"Enabled": device['enabled'],
"Name": device['device_name'],
"Lun": device['lun'],
"SubType": device['sd_card_subtype'],
"Bootloader": {
"ClassId": "boot.Bootloader",
"ObjectType": "boot.Bootloader",
"Description": device['bootloader_description'],
"Name": device['bootloader_name'],
"Path": device['bootloader_path'],
},
}
)
elif device['device_type'] == 'UEFI Shell':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.UefiShell",
"ObjectType": "boot.UefiShell",
"Enabled": device['enabled'],
"Name": device['device_name'],
}
)
elif device['device_type'] == 'USB':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.Usb",
"ObjectType": "boot.Usb",
"Enabled": device['enabled'],
"Name": device['device_name'],
"SubType": device['usb_subtype'],
}
)
elif device['device_type'] == 'Virtual Media':
intersight.api_body['BootDevices'].append(
{
"ClassId": "boot.VirtualMedia",
"ObjectType": "boot.VirtualMedia",
"Enabled": device['enabled'],
"Name": device['device_name'],
"SubType": device['virtual_media_subtype'],
}
)
#
# Code below should be common across all policy modules
#
intersight.configure_policy_or_profile(resource_path=resource_path)
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,200 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_imc_access_policy
short_description: IMC Access Policy configuration for Cisco Intersight
description:
- IMC Access Policy configuration for Cisco Intersight.
- Used to configure IP addresses and VLAN used for external connectivity to Cisco IMC.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
organization:
description:
- The name of the Organization this resource is assigned to.
- Profiles and Policies that are created within a Custom Organization are applicable only to devices in the same Organization.
default: default
name:
description:
- The name assigned to the IMC Access Policy.
- The name must be between 1 and 62 alphanumeric characters, allowing special characters :-_.
required: true
tags:
description:
- List of tags in Key:<user-defined key> Value:<user-defined value> format.
descrption:
description:
- The user-defined description of the IMC access policy.
- Description can contain letters(a-z, A-Z), numbers(0-9), hyphen(-), period(.), colon(:), or an underscore(_).
aliases: [descr]
vlan_id:
description:
- VLAN to be used for server access over Inband network.
required: true
type: int
ip_pool:
description:
- IP Pool used to assign IP address and other required network settings.
required: true
author:
- David Soper (@dsoper2)
version_added: '2.10'
'''
EXAMPLES = r'''
- name: Configure IMC Access policy
intersight_imc_access_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
name: sjc02-d23-access
description: IMC access for SJC02 rack D23
tags:
- Site: D23
vlan_id: 131
ip_pool: sjc02-d23-ext-mgmt
- name: Delete IMC Access policy
intersight_imc_access_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
name: sjc02-d23-access
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"Name": "sjc02-d23-access",
"ObjectType": "access.Policy",
"Profiles": [
{
"Moid": "5e4ec7ae77696e2d30840cfc",
"ObjectType": "server.Profile",
},
{
"Moid": "5e84d78777696e2d302ec195",
"ObjectType": "server.Profile",
}
],
"Tags": [
{
"Key": "Site",
"Value": "SJC02"
}
]
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec, compare_values
def main():
argument_spec = intersight_argument_spec
argument_spec.update(
state=dict(type='str', choices=['present', 'absent'], default='present'),
organization=dict(type='str', default='default'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
tags=dict(type='list', default=[]),
vlan_id=dict(type='int', required=True),
ip_pool=dict(type='str', required=True),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
intersight.api_body = {
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
'InbandVlan': intersight.module.params['vlan_id'],
'Organization': {
'Name': intersight.module.params['organization'],
},
}
# get the current state of the resource
intersight.get_resource(
resource_path='/access/Policies',
query_params={
'$filter': "Name eq '" + intersight.module.params['name'] + "'",
'$expand': 'Organization',
},
)
moid = None
resource_values_match = False
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
moid = intersight.result['api_response']['Moid']
if module.params['state'] == 'present':
resource_values_match = compare_values(intersight.api_body, intersight.result['api_response'])
else: # state == 'absent'
intersight.delete_resource(
moid=moid,
resource_path='/access/Policies',
)
moid = None
if module.params['state'] == 'present' and not resource_values_match:
# remove read-only Organization key
intersight.api_body.pop('Organization')
if not moid:
# GET Organization Moid
intersight.get_resource(
resource_path='/organization/Organizations',
query_params={
'$filter': "Name eq '" + intersight.module.params['organization'] + "'",
'$select': 'Moid',
},
)
organization_moid = None
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
organization_moid = intersight.result['api_response']['Moid']
# Organization must be set, but can't be changed after initial POST
intersight.api_body['Organization'] = {
'Moid': organization_moid,
}
intersight.configure_resource(
moid=moid,
resource_path='/access/Policies',
body=intersight.api_body,
query_params={
'$filter': "Name eq '" + intersight.module.params['name'] + "'",
},
)
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,117 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_info
short_description: Gather information about Intersight
description:
- Gathers information about servers in L(Cisco Intersight,https://intersight.com).
- This module was called C(intersight_facts) before Ansible 2.9. The usage did not change.
extends_documentation_fragment: intersight
options:
server_names:
description:
- Server names to retrieve information from.
- An empty list will return all servers.
type: list
required: yes
author:
- David Soper (@dsoper2)
- CiscoUcs (@CiscoUcs)
version_added: '2.8'
'''
EXAMPLES = r'''
- name: Get info for all servers
intersight_info:
api_private_key: ~/Downloads/SecretKey.txt
api_key_id: 64612d300d0982/64612d300d0b00/64612d300d3650
server_names:
- debug:
msg: "server name {{ item.Name }}, moid {{ item.Moid }}"
loop: "{{ intersight_servers }}"
when: intersight_servers is defined
- name: Get info for servers by name
intersight_info:
api_private_key: ~/Downloads/SecretKey.txt
api_key_id: 64612d300d0982/64612d300d0b00/64612d300d3650
server_names:
- SJC18-L14-UCS1-1
- debug:
msg: "server moid {{ intersight_servers[0].Moid }}"
when: intersight_servers[0] is defined
'''
RETURN = r'''
intersight_servers:
description: A list of Intersight Servers. See L(Cisco Intersight,https://intersight.com/apidocs) for details.
returned: always
type: complex
contains:
Name:
description: The name of the server.
returned: always
type: str
sample: SJC18-L14-UCS1-1
Moid:
description: The unique identifier of this Managed Object instance.
returned: always
type: str
sample: 5978bea36ad4b000018d63dc
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec
def get_servers(module, intersight):
query_list = []
if module.params['server_names']:
for server in module.params['server_names']:
query_list.append("Name eq '%s'" % server)
query_str = ' or '.join(query_list)
options = {
'http_method': 'get',
'resource_path': '/compute/PhysicalSummaries',
'query_params': {
'$filter': query_str,
'$top': 1000,
}
}
response_dict = intersight.call_api(**options)
return response_dict.get('Results')
def main():
argument_spec = intersight_argument_spec
argument_spec.update(
server_names=dict(type='list', required=True),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
if module._name == 'intersight_facts':
module.deprecate("The 'intersight_facts' module has been renamed to 'intersight_info'", version='2.13')
intersight = IntersightModule(module)
# one API call returning all requested servers
module.exit_json(intersight_servers=get_servers(module, intersight))
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,363 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_local_user_policy
short_description: Local User Policy configuration for Cisco Intersight
description:
- Local User Policy configuration for Cisco Intersight.
- Used to configure local users on endpoint devices.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
organization:
description:
- The name of the Organization this resource is assigned to.
- Profiles and Policies that are created within a Custom Organization are applicable only to devices in the same Organization.
default: default
name:
description:
- The name assigned to the Local User Policy.
- The name must be between 1 and 62 alphanumeric characters, allowing special characters :-_.
required: true
tags:
description:
- List of tags in Key:<user-defined key> Value:<user-defined value> format.
description:
description:
- The user-defined description of the Local User policy.
- Description can contain letters(a-z, A-Z), numbers(0-9), hyphen(-), period(.), colon(:), or an underscore(_).
aliases: [descr]
enforce_strong_password:
description:
- If true, enables a strong password policy.
- Strong password requirements:.
- A. The password must have a minimum of 8 and a maximum of 20 characters.
- B. The password must not contain the User's Name.
- C. The password must contain characters from three of the following four categories.
- 1) English uppercase characters (A through Z).
- 2) English lowercase characters (a through z).
- 3) Base 10 digits (0 through 9).
- 4) Non-alphabetic characters (! , @, '#', $, %, ^, &, *, -, _, +, =).
type: bool
default: true
enable_password_expiry:
description:
- Enables password expiry on the endpoint.
type: bool
default: false
password_history:
description:
- Specifies number of times a password cannot repeat when changed (value between 0 and 5).
- Entering 0 disables this option.
type: int
default: 5
local_users:
description:
- List of local users on the endpoint.
- An admin user already exists on the endpoint.
- Add the admin user here only if you want to change the password, or enable or disable the user.
- To add admin user, provide a username as 'admin', select the admin user role, and then proceed.
suboptions:
username:
description:
- Name of the user created on the endpoint.
required: true
enable:
description:
- Enable or disable the user.
type: bool
default: true
role:
description:
- Roles associated with the user on the endpoint.
choices: [admin, readonly, user]
required: true
password:
description:
- Valid login password of the user.
required: true
purge:
description:
- The purge argument instructs the module to consider the resource definition absolute.
- If true, any previously configured usernames will be removed from the policy with the exception of the `admin` user which cannot be deleted.
default: false
always_update_password:
description:
- Since passwords are not returned by the API and are encrypted on the endpoint, this option will instruct the module when to change the password.
- If true, the password for each user will always be updated in the policy.
- If false, the password will be updated only if the user is created.
default: false
author:
- David Soper (@dsoper2)
version_added: '2.10'
'''
EXAMPLES = r'''
- name: Configure Local User policy
intersight_local_user_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
name: guest-admin
tags:
- Key: username
Value: guest
description: User named guest with admin role
local_users:
- username: guest
role: admin
password: vault_guest_password
- username: reader
role: readonly
password: vault_reader_password
- name: Delete Local User policy
intersight_local_user_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
name: guest-admin
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"Description": "User named guest with admin role",
"EndPointUserRoles": [
{
"ChangePassword": true,
"Enabled": true
}
]
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec, compare_values
def main():
local_user = dict(
username=dict(type='str', required=True),
enable=dict(type='bool', default=True),
role=dict(type='str', choices=['admin', 'readonly', 'user'], required=True),
password=dict(type='str', required=True, no_log=True),
)
argument_spec = intersight_argument_spec
argument_spec.update(
state=dict(type='str', choices=['present', 'absent'], default='present'),
organization=dict(type='str', default='default'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
tags=dict(type='list', default=[]),
enforce_strong_password=dict(type='bool', default=True, no_log=False),
enable_password_expiry=dict(type='bool', default=False, no_log=False),
password_history=dict(type='int', default=5, no_log=False),
local_users=dict(type='list', elements='dict', options=local_user, default=[]),
purge=dict(type='bool', default=False),
always_update_password=dict(type='bool', default=False, no_log=False),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
# get the current state of the resource
intersight.get_resource(
resource_path='/iam/EndPointUserPolicies',
query_params={
'$filter': "Name eq '" + intersight.module.params['name'] + "'",
'$expand': 'EndPointUserRoles($expand=EndPointRole,EndPointUser),Organization',
},
)
user_policy_moid = None
resource_values_match = False
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
user_policy_moid = intersight.result['api_response']['Moid']
#
# always_update_password
# false: compare expected vs. actual (won't check passwords)
# true: no compare
#
if module.params['state'] == 'present' and not module.params['always_update_password']:
# Create api body used to check current state
end_point_user_roles = []
for user in intersight.module.params['local_users']:
end_point_user_roles.append(
{
'Enabled': user['enable'],
'EndPointRole': [
{
'Name': user['role'],
'Type': 'IMC',
},
],
'EndPointUser': {
'Name': user['username'],
},
}
)
intersight.api_body = {
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
'PasswordProperties': {
'EnforceStrongPassword': intersight.module.params['enforce_strong_password'],
'EnablePasswordExpiry': intersight.module.params['enable_password_expiry'],
'PasswordHistory': intersight.module.params['password_history'],
},
'EndPointUserRoles': end_point_user_roles,
'Organization': {
'Name': intersight.module.params['organization'],
},
}
resource_values_match = compare_values(intersight.api_body, intersight.result['api_response'])
elif module.params['state'] == 'absent':
intersight.delete_resource(
moid=user_policy_moid,
resource_path='/iam/EndPointUserPolicies',
)
user_policy_moid = None
if module.params['state'] == 'present' and not resource_values_match:
intersight.api_body = {
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
'PasswordProperties': {
'EnforceStrongPassword': intersight.module.params['enforce_strong_password'],
'EnablePasswordExpiry': intersight.module.params['enable_password_expiry'],
'PasswordHistory': intersight.module.params['password_history'],
},
}
organization_moid = None
if not user_policy_moid or module.params['purge']:
# get Organization Moid which is needed when resources are created
saved_response = intersight.result['api_response']
intersight.get_resource(
resource_path='/organization/Organizations',
query_params={
'$filter': "Name eq '" + intersight.module.params['organization'] + "'",
'$select': 'Moid',
},
)
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
organization_moid = intersight.result['api_response']['Moid']
intersight.result['api_response'] = saved_response
if not user_policy_moid:
# Initial create: Organization must be set, but can't be changed after initial POST
intersight.api_body['Organization'] = {
'Moid': organization_moid,
}
elif module.params['purge']:
# update existing resource and purge any existing users
for end_point_user_role in intersight.result['api_response']['EndPointUserRoles']:
intersight.delete_resource(
moid=end_point_user_role['Moid'],
resource_path='/iam/EndPointUserRoles',
)
# configure the top-level policy resource
intersight.result['api_response'] = {}
intersight.configure_resource(
moid=user_policy_moid,
resource_path='/iam/EndPointUserPolicies',
body=intersight.api_body,
query_params={
'$filter': "Name eq '" + intersight.module.params['name'] + "'",
},
)
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
user_policy_moid = intersight.result['api_response']['Moid']
# EndPointUser local_users list config
for user in intersight.module.params['local_users']:
intersight.api_body = {
'Name': user['username'],
}
if organization_moid:
intersight.api_body['Organization'] = {
'Moid': organization_moid,
}
intersight.configure_resource(
moid=None,
resource_path='/iam/EndPointUsers',
body=intersight.api_body,
query_params={
'$filter': "Name eq '" + user['username'] + "'",
},
)
user_moid = None
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
user_moid = intersight.result['api_response']['Moid']
# GET EndPointRole Moid
intersight.get_resource(
resource_path='/iam/EndPointRoles',
query_params={
'$filter': "Name eq '" + user['role'] + "' and Type eq 'IMC'",
},
)
end_point_role_moid = None
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
end_point_role_moid = intersight.result['api_response']['Moid']
# EndPointUserRole config
intersight.api_body = {
'EndPointUser': {
'Moid': user_moid,
},
'EndPointRole': [
{
'Moid': end_point_role_moid,
}
],
'Password': user['password'],
'Enabled': user['enable'],
'EndPointUserPolicy': {
'Moid': user_policy_moid,
},
}
intersight.configure_resource(
moid=None,
resource_path='/iam/EndPointUserRoles',
body=intersight.api_body,
query_params={
'$filter': "EndPointUserPolicy.Moid eq '" + user_policy_moid + "'",
},
)
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,160 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_ntp_policy
short_description: NTP policy configuration for Cisco Intersight
description:
- NTP policy configuration for Cisco Intersight.
- Used to configure NTP servers and timezone settings on Cisco Intersight managed devices.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
organization:
description:
- The name of the Organization this resource is assigned to.
- Profiles and Policies that are created within a Custom Organization are applicable only to devices in the same Organization.
default: default
name:
description:
- The name assigned to the NTP policy.
- The name must be between 1 and 62 alphanumeric characters, allowing special characters :-_.
required: true
tags:
description:
- List of tags in Key:<user-defined key> Value:<user-defined value> format.
type: list
description:
description:
- The user-defined description of the NTP policy.
- Description can contain letters(a-z, A-Z), numbers(0-9), hyphen(-), period(.), colon(:), or an underscore(_).
aliases: [descr]
enable:
description:
- Enable or disable NTP.
type: bool
default: true
ntp_servers:
description:
- List of NTP servers configured on the endpoint.
type: list
timezone:
description:
- Timezone of services on the endpoint.
author:
- David Soper (@dsoper2)
version_added: '2.10'
'''
EXAMPLES = r'''
- name: Configure NTP Policy
cisco.intersight.intersight_ntp_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
organization: DevNet
name: lab-ntp
description: NTP policy for lab use
tags:
- Key: Site
Value: RCDN
ntp_servers:
- ntp.esl.cisco.com
timezone: America/Chicago
- name: Delete NTP Policy
cisco.intersight.intersight_ntp_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
organization: DevNet
name: lab-ntp
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"Name": "lab-ntp",
"ObjectType": "ntp.Policy",
"Tags": [
{
"Key": "Site",
"Value": "RCDN"
}
]
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec
def main():
argument_spec = intersight_argument_spec
argument_spec.update(
state=dict(type='str', choices=['present', 'absent'], default='present'),
organization=dict(type='str', default='default'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
tags=dict(type='list', default=[]),
enable=dict(type='bool', default=True),
ntp_servers=dict(type='list', default=[]),
timezone=dict(type='str', default=''),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
#
# Argument spec above, resource path, and API body should be the only code changed in each policy module
#
# Resource path used to configure policy
resource_path = '/ntp/Policies'
# Define API body used in compares or create
intersight.api_body = {
'Organization': {
'Name': intersight.module.params['organization'],
},
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
'Enabled': intersight.module.params['enable'],
'NtpServers': intersight.module.params['ntp_servers'],
'Timezone': intersight.module.params['timezone'],
}
#
# Code below should be common across all policy modules
#
intersight.configure_policy_or_profile(resource_path=resource_path)
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,216 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec, compare_values
from ansible.module_utils.basic import AnsibleModule
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_rest_api
short_description: REST API configuration for Cisco Intersight
description:
- Direct REST API configuration for Cisco Intersight.
- All REST API resources and properties must be specified.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
resource_path:
description:
- Resource URI being configured related to api_uri.
type: str
required: yes
query_params:
description:
- Query parameters for the Intersight API query languange.
type: dict
update_method:
description:
- The HTTP method used for update operations.
- Some Intersight resources require POST operations for modifications.
type: str
choices: [ patch, post ]
default: patch
api_body:
description:
- The paylod for API requests used to modify resources.
type: dict
list_body:
description:
- The paylod for API requests used to modify resources.
- Should be used instead of api_body if a list is required in the API payload.
type: list
return_list:
description:
- If C(yes), will return a list of API results in the api_response.
- By default only the 1st element of the API Results list is returned.
- Can only be used with GET operations.
type: bool
default: no
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
author:
- David Soper (@dsoper2)
- CiscoUcs (@CiscoUcs)
version_added: '2.8'
'''
EXAMPLES = r'''
- name: Configure Boot Policy
intersight_rest_api:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_key_uri: "{{ api_key_uri }}"
validate_certs: "{{ validate_certs }}"
resource_path: /boot/PrecisionPolicies
query_params:
$filter: "Name eq 'vmedia-localdisk'"
api_body: {
"Name": "vmedia-localdisk",
"ConfiguredBootMode": "Legacy",
"BootDevices": [
{
"ObjectType": "boot.VirtualMedia",
"Enabled": true,
"Name": "remote-vmedia",
"Subtype": "cimc-mapped-dvd"
},
{
"ObjectType": "boot.LocalDisk",
"Enabled": true,
"Name": "localdisk",
"Slot": "MRAID",
"Bootloader": null
}
],
}
state: present
- name: Delete Boot Policy
intersight_rest_api:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
api_key_uri: "{{ api_key_uri }}"
validate_certs: "{{ validate_certs }}"
resource_path: /boot/PrecisionPolicies
query_params:
$filter: "Name eq 'vmedia-localdisk'"
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"BootDevices": [
{
"Enabled": true,
"Name": "remote-vmedia",
"ObjectType": "boot.VirtualMedia",
"Subtype": "cimc-mapped-dvd"
},
{
"Bootloader": null,
"Enabled": true,
"Name": "boot-lun",
"ObjectType": "boot.LocalDisk",
"Slot": "MRAID"
}
],
"ConfiguredBootMode": "Legacy",
"Name": "vmedia-localdisk",
"ObjectType": "boot.PrecisionPolicy",
}
'''
def main():
argument_spec = intersight_argument_spec
argument_spec.update(
resource_path=dict(type='str', required=True),
query_params=dict(type='dict', default={}),
update_method=dict(type='str', choices=['patch', 'post'], default='patch'),
api_body=dict(type='dict', default={}),
list_body=dict(type='list', default=[]),
return_list=dict(type='bool', default=False),
state=dict(type='str', choices=['absent', 'present'], default='present'),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
mutually_exclusive=[
['return_list', 'api_body'],
['return_list', 'state'],
['api_body', 'list_body'],
],
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
if module.params['list_body']:
module.params['api_body'] = module.params['list_body']
if module.params['update_method'] != 'post' or module.params['query_params']:
# get the current state of the resource
# skip if this is a post to /asset/DeviceClaims or similar resource without GET
intersight.get_resource(
resource_path=module.params['resource_path'],
query_params=module.params['query_params'],
return_list=module.params['return_list'],
)
# determine requested operation (config, delete, or neither (get resource only))
if module.params['state'] == 'present':
request_delete = False
# api_body implies resource configuration through post/patch
request_config = bool(module.params['api_body'])
else: # state == 'absent'
request_delete = True
request_config = False
moid = None
resource_values_match = False
if (request_config or request_delete) and intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
moid = intersight.result['api_response']['Moid']
if request_config:
resource_values_match = compare_values(module.params['api_body'], intersight.result['api_response'])
else: # request_delete
intersight.delete_resource(
moid=moid,
resource_path=module.params['resource_path'],
)
if request_config and not resource_values_match:
intersight.configure_resource(
moid=moid,
resource_path=module.params['resource_path'],
body=module.params['api_body'],
query_params=module.params['query_params'],
update_method=module.params['update_method'],
)
if module.params['return_list'] and not isinstance(intersight.result['api_response'], list):
intersight.result['api_response'] = []
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,282 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_server_profile
short_description: Server Profile configuration for Cisco Intersight
description:
- Server Profile configuration for Cisco Intersight.
- Used to configure Server Profiles with assigned servers and server policies.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
organization:
description:
- The name of the Organization this resource is assigned to.
- Profiles and Policies that are created within a Custom Organization are applicable only to devices in the same Organization.
default: default
name:
description:
- The name assigned to the Server Profile.
- The name must be between 1 and 62 alphanumeric characters, allowing special characters :-_.
required: true
target_platform:
description:
- The platform for which the server profile is applicable.
- Can either be a server that is operating in Standalone mode or which is attached to a Fabric Interconnect (FIAttached) managed by Intersight.
choices: [Standalone, FIAttached]
default: Standalone
tags:
description:
- List of tags in Key:<user-defined key> Value:<user-defined value> format.
description:
description:
- The user-defined description of the Server Profile.
- Description can contain letters(a-z, A-Z), numbers(0-9), hyphen(-), period(.), colon(:), or an underscore(_).
aliases: [descr]
assigned_server:
description:
- Managed Obect ID (MOID) of assigned server.
- Option can be omitted if user wishes to assign server later.
boot_order_policy:
description:
- Name of Boot Order Policy to associate with this profile.
imc_access_policy:
description:
- Name of IMC Access Policy to associate with this profile.
lan_connectivity_policy:
description:
- Name of LAN Connectivity Policy to associate with this profile.
local_user_policy:
description:
- Name of Local User Policy to associate with this profile.
ntp_policy:
description:
- Name of NTP Policy to associate with this profile.
storage_policy:
description:
- Name of Storage Policy to associate with this profile.
virtual_media_policy:
description:
- Name of Virtual Media Policy to associate with this profile.
author:
- David Soper (@dsoper2)
- Sid Nath (@SidNath21)
- Tse Kai "Kevin" Chan (@BrightScale)
- Soma Tummala (@SOMATUMMALA21)
version_added: '2.10'
'''
EXAMPLES = r'''
- name: Configure Server Profile
cisco.intersight.intersight_server_profile:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
name: SP-Server1
target_platform: FIAttached
tags:
- Key: Site
Value: SJC02
description: Profile for Server1
assigned_server: 5e3b517d6176752d319a9999
boot_order_policy: COS-Boot
imc_access_policy: sjc02-d23-access
lan_connectivity_policy: sjc02-d23-lan
local_user_policy: guest-admin
ntp_policy: lab-ntp
storage_policy: storage
virtual_media_policy: COS-VM
- name: Delete Server Profile
cisco.intersight.intersight_server_profile:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
name: SP-Server1
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"AssignedServer": {
"Moid": "5e3b517d6176752d319a0881",
"ObjectType": "compute.Blade",
},
"Name": "SP-IMM-6454-D23-1-1",
"ObjectType": "server.Profile",
"Tags": [
{
"Key": "Site",
"Value": "SJC02"
}
],
"TargetPlatform": "FIAttached",
"Type": "instance"
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec
def post_profile_to_policy(intersight, moid, resource_path, policy_name):
options = {
'http_method': 'get',
'resource_path': resource_path,
'query_params': {
'$filter': "Name eq '" + policy_name + "'",
},
}
response = intersight.call_api(**options)
if response.get('Results'):
# get expected policy moid from 1st list element
expected_policy_moid = response['Results'][0]['Moid']
actual_policy_moid = ''
# check any current profiles and delete if needed
options = {
'http_method': 'get',
'resource_path': resource_path,
'query_params': {
'$filter': "Profiles/any(t: t/Moid eq '" + moid + "')",
},
}
response = intersight.call_api(**options)
if response.get('Results'):
# get actual moid from 1st list element
actual_policy_moid = response['Results'][0]['Moid']
if actual_policy_moid != expected_policy_moid:
if not intersight.module.check_mode:
# delete the actual policy
options = {
'http_method': 'delete',
'resource_path': resource_path + '/' + actual_policy_moid + '/Profiles',
'moid': moid,
}
intersight.call_api(**options)
actual_policy_moid = ''
if not actual_policy_moid:
if not intersight.module.check_mode:
# post profile to the expected policy
options = {
'http_method': 'post',
'resource_path': resource_path + '/' + expected_policy_moid + '/Profiles',
'body': [
{
'ObjectType': 'server.Profile',
'Moid': moid,
}
]
}
intersight.call_api(**options)
intersight.result['changed'] = True
def main():
argument_spec = intersight_argument_spec
argument_spec.update(
state=dict(type='str', choices=['present', 'absent'], default='present'),
organization=dict(type='str', default='default'),
name=dict(type='str', required=True),
target_platform=dict(type='str', choices=['Standalone', 'FIAttached'], default='Standalone'),
tags=dict(type='list', default=[]),
description=dict(type='str', aliases=['descr'], default=''),
assigned_server=dict(type='str', default=''),
boot_order_policy=dict(type='str'),
imc_access_policy=dict(type='str'),
lan_connectivity_policy=dict(type='str'),
local_user_policy=dict(type='str'),
ntp_policy=dict(type='str'),
storage_policy=dict(type='str'),
virtual_media_policy=dict(type='str'),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
#
# Argument spec above, resource path, and API body should be the only code changed in this module
#
resource_path = '/server/Profiles'
# Define API body used in compares or create
intersight.api_body = {
'Organization': {
'Name': intersight.module.params['organization'],
},
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
}
intersight.result['api_response'] = {}
# Get assigned server information (if defined)
if intersight.module.params['assigned_server']:
intersight.get_resource(
resource_path='/compute/PhysicalSummaries',
query_params={
'$filter': "Moid eq '" + intersight.module.params['assigned_server'] + "'",
}
)
source_object_type = None
if intersight.result['api_response'].get('SourceObjectType'):
source_object_type = intersight.result['api_response']['SourceObjectType']
intersight.api_body['AssignedServer'] = {
'Moid': intersight.module.params['assigned_server'],
'ObjectType': source_object_type,
}
if intersight.module.params['target_platform'] == 'FIAttached':
intersight.api_body['TargetPlatform'] = intersight.module.params['target_platform']
# Configure the profile
moid = intersight.configure_policy_or_profile(resource_path=resource_path)
if moid and intersight.module.params['boot_order_policy']:
post_profile_to_policy(intersight, moid, resource_path='/boot/PrecisionPolicies', policy_name=intersight.module.params['boot_order_policy'])
if moid and intersight.module.params['imc_access_policy']:
post_profile_to_policy(intersight, moid, resource_path='/access/Policies', policy_name=intersight.module.params['imc_access_policy'])
if moid and intersight.module.params['lan_connectivity_policy']:
post_profile_to_policy(intersight, moid, resource_path='/vnic/LanConnectivityPolicies', policy_name=intersight.module.params['lan_connectivity_policy'])
if moid and intersight.module.params['local_user_policy']:
post_profile_to_policy(intersight, moid, resource_path='/iam/EndPointUserPolicies', policy_name=intersight.module.params['local_user_policy'])
if moid and intersight.module.params['ntp_policy']:
post_profile_to_policy(intersight, moid, resource_path='/ntp/Policies', policy_name=intersight.module.params['ntp_policy'])
if moid and intersight.module.params['storage_policy']:
post_profile_to_policy(intersight, moid, resource_path='/storage/StoragePolicies', policy_name=intersight.module.params['storage_policy'])
if moid and intersight.module.params['virtual_media_policy']:
post_profile_to_policy(intersight, moid, resource_path='/vmedia/Policies', policy_name=intersight.module.params['virtual_media_policy'])
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,171 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec
from ansible.module_utils.basic import AnsibleModule
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_target_claim
short_description: Target claim configuraiton for Cisco Intersight
description:
- Target claim configuraiton for Cisco Intersight
- Used to claim or unclaim a Target from Cisco Intersight
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
claim_code:
description:
- Claim code required for registering a new Target
- Required if I(state=present)
type: str
required: no
device_id:
description:
- Device id (serial number) of target
- Targets containing multiple Target ids (e.g. IMM) can be formatted as <target1_id>&<target2_id>
type: dict
required: yes
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
author:
- Brandon Beck (@techBeck03)
- CiscoUcs (@CiscoUcs)
version_added: '2.8'
'''
EXAMPLES = r'''
- name: Claim new Target
cisco.intersight.intersight_target_claim:
device_id: "{{ device_id }}"
claim_code: "{{ claim_code }}"
state: present
- name: Delete a Target (unclaim)
cisco.intersight.intersight_target_claim:
device_id: "{{ device_id }}"
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"Account": {
"ClassId": "mo.MoRef",
"Moid": "8675309",
"ObjectType": "iam.Account",
"link": "https://www.intersight.com/api/v1/iam/Accounts/8675309"
},
"AccountMoid": "8675309",
"Ancestors": null,
"ClassId": "asset.DeviceClaim",
"CreateTime": "2021-05-10T17:32:13.522665238Z",
"Device": {
"ClassId": "mo.MoRef",
"Moid": "9035768",
"ObjectType": "asset.DeviceRegistration",
"link": "https://www.intersight.com/api/v1/asset/DeviceRegistrations/9035768"
},
"DisplayNames": {
"short": [
"FDO241604EM&FDO24161700"
]
},
"DomainGroupMoid": "5b4e48a96a636d6d346cd1c5",
"ModTime": "2021-05-10T17:32:13.522665238Z",
"Moid": "8675309",
"ObjectType": "asset.DeviceClaim",
"Owners": [
"90357688675309"
],
"PermissionResources": null,
"SecurityToken": "A95486674376E",
"SerialNumber": "FDO86753091&FDO86753092",
"SharedScope": "",
"Tags": [],
"trace_id": "NB3e883980a98adace8f7b9c2409cced1a"
}
'''
def main():
argument_spec = intersight_argument_spec
argument_spec.update(
claim_code=dict(type='str'),
device_id=dict(type='str', required=True),
state=dict(type='str', choices=['absent', 'present'], default='present'),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
required_if=[
('state', 'present', (['claim_code']), False),
]
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
# Check if device already exists in target list
target_ids = module.params['device_id'].split('&')
target_filter = ''
for idx, target_id in enumerate(target_ids):
if idx == 0:
target_filter += f"contains(TargetId,'{target_id}')"
else:
target_filter += f" or contains(TargetId,'{target_id}')"
intersight.get_resource(
resource_path='/asset/Targets',
query_params={
"$select": "TargetId,RegisteredDevice",
"$filter": target_filter,
"$expand": "RegisteredDevice($select=DeviceClaim)"
},
return_list=False,
)
if module.params['state'] == 'present':
# Send claim request if device id not already claimed
if not intersight.result['api_response']:
intersight.configure_resource(
moid=None,
resource_path='/asset/DeviceClaims',
body=dict(
SecurityToken=module.params['claim_code'],
SerialNumber=module.params['device_id']
),
query_params=None,
update_method='post'
)
elif module.params['state'] == 'absent':
# Check if target exists
if intersight.result['api_response'].get('Moid'):
intersight.delete_resource(
moid=intersight.result['api_response'].get('RegisteredDevice').get('DeviceClaim').get('Moid'),
resource_path='/asset/DeviceClaims',
)
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()

View File

@@ -0,0 +1,368 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function
__metaclass__ = type
ANSIBLE_METADATA = {'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'}
DOCUMENTATION = r'''
---
module: intersight_virtual_media_policy
short_description: Virtual Media policy configuration for Cisco Intersight
description:
- Virtual Media policy configuration for Cisco Intersight.
- Used to configure Virtual Media image mappings on Cisco Intersight managed devices.
- For more information see L(Cisco Intersight,https://intersight.com/apidocs).
extends_documentation_fragment: intersight
options:
state:
description:
- If C(present), will verify the resource is present and will create if needed.
- If C(absent), will verify the resource is absent and will delete if needed.
choices: [present, absent]
default: present
organization:
description:
- The name of the Organization this resource is assigned to.
- Profiles and Policies that are created within a Custom Organization are applicable only to devices in the same Organization.
default: default
name:
description:
- The name assigned to the NTP policy.
- The name must be between 1 and 62 alphanumeric characters, allowing special characters :-_.
required: true
tags:
description:
- List of tags in Key:<user-defined key> Value:<user-defined value> format.
type: list
descrption:
description:
- The user-defined description of the NTP policy.
- Description can contain letters(a-z, A-Z), numbers(0-9), hyphen(-), period(.), colon(:), or an underscore(_).
aliases: [descr]
enable:
description:
- Enable or disable virtual media.
type: bool
default: true
encryption:
description:
- If enabled, allows encryption of all Virtual Media communications
type: bool
default: false
low_power_usb:
description:
- If enabled, the virtual drives appear on the boot selection menu after mapping the image and rebooting the host.
type: bool
default: true
cdd_virtual_media:
description:
- CDD Virtual Media image mapping options.
suboptions:
enable:
description:
- Enable or disable CDD image mapping.
type: bool
default: true
mount_type:
description:
- Type (protocol) of network share used by the remote_hostname.
- Ensure that the remote_hostname's communication port for the mount type that you choose is accessible from the managed endpoint.
- For CIFS as your mount type, ensure port 445 (which is its communication port) on the remote_hostname is accessible.
- For HTTP, ensure port 80 is accessible.
- For HTTPS, ensure port 443 is accessible.
- For NFS, ensure port 2049 is accessible.
choices: [nfs,cifs,http,https]
required: true
volume:
description:
- A user defined name of the image mounted for mapping.
required: true
remote_hostname:
description:
- Hostname or IP address of the server hosting the virtual media image.
required: true
remote_path:
description:
- Filepath (not including the filename) of the remote image.
- Ex. mnt/SHARE/ISOS
required: true
remote_file:
description:
- Filename of the remote image.
- Ex. custom_image.iso
required: true
username:
description:
- The username for the specified Mount Type, if required.
password:
description:
- The password for the selected username, if required.
hdd_virtual_media:
description:
- HDD Virtual Media image mapping options.
suboptions:
enable:
description:
- Enable or disable HDD image mapping.
type: bool
default: false
mount_type:
description:
- Type (protocol) of network share used by the remote_hostname.
- Ensure that the remote_hostname's communication port for the mount type that you choose is accessible from the managed endpoint.
- For CIFS as your mount type, ensure port 445 (which is its communication port) on the remote_hostname is accessible.
- For HTTP, ensure port 80 is accessible.
- For HTTPS, ensure port 443 is accessible.
- For NFS, ensure port 2049 is accessible.
choices: [nfs,cifs,http,https]
required: true
volume:
description:
- A user defined name of the image mounted for mapping.
required: true
remote_hostname:
description:
- Hostname or IP address of the server hosting the virtual media image.
required: true
remote_path:
description:
- Filepath (not including the filename) of the remote image.
- Ex. mnt/SHARE/ISOS
required: true
remote_file:
description:
- Filename of the remote image.
- Ex. custom_image.iso
required: true
username:
description:
- The username for the specified Mount Type, if required.
password:
description:
- The password for the selected username, if required.
mount_options:
description:
- Mount options for the Virtual Media mapping.
- For NFS, supported options are ro, rw, nolock, noexec, soft, port=VALUE, timeo=VALUE, retry=VALUE
- For CIFS, supported options are soft, nounix, noserverino, guest
required: false
authentication_protocol:
description:
- Authentication Protocol for CIFS Mount Type
required: false
author:
- David Soper (@dsoper2)
- Sid Nath (@SidNath21)
version_added: '2.10'
'''
EXAMPLES = r'''
- name: Configure Virtual Media Policy
cisco.intersight.intersight_virtual_media_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
organization: DevNet
name: lab-vmedia
description: Virutal Media policy for lab use
tags:
- Key: Site
Value: RCDN
cdd_virtual_media:
mount_type: nfs
volume: nfs-cdd
remote_hostname: 172.28.224.77
remote_path: mnt/SHARE/ISOS/CENTOS
remote_file: CentOS7.iso
hdd_virtual_media:
mount_type: nfs
volume: nfs-hdd
remote_hostname: 172.28.224.77
remote_path: mnt/SHARE/ISOS/CENTOS
remote_file: CentOS7.iso
- name: Delete Virtual Media Policy
cisco.intersight.intersight_virtual_media_policy:
api_private_key: "{{ api_private_key }}"
api_key_id: "{{ api_key_id }}"
organization: DevNet
name: lab-vmedia
state: absent
'''
RETURN = r'''
api_repsonse:
description: The API response output returned by the specified resource.
returned: always
type: dict
sample:
"api_response": {
"Name": "lab-ntp",
"ObjectType": "ntp.Policy",
"Tags": [
{
"Key": "Site",
"Value": "RCDN"
}
]
}
'''
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.cisco.intersight.plugins.module_utils.intersight import IntersightModule, intersight_argument_spec, compare_values
def main():
path = '/vmedia/Policies'
virtual_media_mapping = dict(
enable=dict(type='bool', default=True),
mount_type=dict(type='str', choices=['nfs', 'cifs', 'http', 'https'], required=True),
volume=dict(type='str', required=True),
remote_hostname=dict(type='str', required=True),
remote_path=dict(type='str', required=True),
remote_file=dict(type='str', required=True),
mount_options=dict(type='str', default=''),
username=dict(type='str', default=''),
password=dict(type='str', default='', no_log=True),
authentication_protocol=dict(type='str', default='none'),
)
argument_spec = intersight_argument_spec
argument_spec.update(
state=dict(type='str', choices=['present', 'absent'], default='present'),
organization=dict(type='str', default='default'),
name=dict(type='str', required=True),
description=dict(type='str', aliases=['descr'], default=''),
tags=dict(type='list', default=[]),
enable=dict(type='bool', default=True),
encryption=dict(type='bool', default=False),
low_power_usb=dict(type='bool', default=True),
cdd_virtual_media=dict(type='dict', options=virtual_media_mapping),
hdd_virtual_media=dict(type='dict', options=virtual_media_mapping),
)
module = AnsibleModule(
argument_spec,
supports_check_mode=True,
)
intersight = IntersightModule(module)
intersight.result['api_response'] = {}
intersight.result['trace_id'] = ''
# Defined API body used in compares or create
intersight.api_body = {
'Organization': {
'Name': intersight.module.params['organization'],
},
'Name': intersight.module.params['name'],
'Tags': intersight.module.params['tags'],
'Description': intersight.module.params['description'],
'Enabled': intersight.module.params['enable'],
"Encryption": intersight.module.params['encryption'],
"LowPowerUsb": intersight.module.params['low_power_usb'],
'Mappings': [],
}
if intersight.module.params.get('cdd_virtual_media'):
intersight.api_body['Mappings'].append(
{
"ClassId": "vmedia.Mapping",
"ObjectType": "vmedia.Mapping",
"AuthenticationProtocol": intersight.module.params['cdd_virtual_media']['authentication_protocol'],
"DeviceType": "cdd",
"HostName": intersight.module.params['cdd_virtual_media']['remote_hostname'],
"Password": intersight.module.params['cdd_virtual_media']['password'],
"IsPasswordSet": intersight.module.params['cdd_virtual_media']['password'] != '',
"MountOptions": intersight.module.params['cdd_virtual_media']['mount_options'],
"MountProtocol": intersight.module.params['cdd_virtual_media']['mount_type'],
"RemoteFile": intersight.module.params['cdd_virtual_media']['remote_file'],
"RemotePath": intersight.module.params['cdd_virtual_media']['remote_path'],
"Username": intersight.module.params['cdd_virtual_media']['username'],
"VolumeName": intersight.module.params['cdd_virtual_media']['volume'],
}
)
if intersight.module.params.get('hdd_virtual_media'):
intersight.api_body['Mappings'].append(
{
"ClassId": "vmedia.Mapping",
"ObjectType": "vmedia.Mapping",
"AuthenticationProtocol": intersight.module.params['hdd_virtual_media']['authentication_protocol'],
"DeviceType": "hdd",
"HostName": intersight.module.params['hdd_virtual_media']['remote_hostname'],
"Password": intersight.module.params['hdd_virtual_media']['password'],
"IsPasswordSet": intersight.module.params['hdd_virtual_media']['password'] != '',
"MountOptions": intersight.module.params['hdd_virtual_media']['mount_options'],
"MountProtocol": intersight.module.params['hdd_virtual_media']['mount_type'],
"RemoteFile": intersight.module.params['hdd_virtual_media']['remote_file'],
"RemotePath": intersight.module.params['hdd_virtual_media']['remote_path'],
"Username": intersight.module.params['hdd_virtual_media']['username'],
"VolumeName": intersight.module.params['hdd_virtual_media']['volume'],
}
)
organization_moid = None
# GET Organization Moid
intersight.get_resource(
resource_path='/organization/Organizations',
query_params={
'$filter': "Name eq '" + intersight.module.params['organization'] + "'",
'$select': 'Moid',
},
)
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
organization_moid = intersight.result['api_response']['Moid']
intersight.result['api_response'] = {}
# get the current state of the resource
filter_str = "Name eq '" + intersight.module.params['name'] + "'"
filter_str += "and Organization.Moid eq '" + organization_moid + "'"
intersight.get_resource(
resource_path=path,
query_params={
'$filter': filter_str,
'$expand': 'Organization',
},
)
moid = None
resource_values_match = False
if intersight.result['api_response'].get('Moid'):
# resource exists and moid was returned
moid = intersight.result['api_response']['Moid']
if module.params['state'] == 'present':
resource_values_match = compare_values(intersight.api_body, intersight.result['api_response'])
else: # state == 'absent'
intersight.delete_resource(
moid=moid,
resource_path=path,
)
moid = None
if module.params['state'] == 'present' and not resource_values_match:
# remove read-only Organization key
intersight.api_body.pop('Organization')
if not moid:
# Organization must be set, but can't be changed after initial POST
intersight.api_body['Organization'] = {
'Moid': organization_moid,
}
intersight.configure_resource(
moid=moid,
resource_path=path,
body=intersight.api_body,
query_params={
'$filter': filter_str,
},
)
module.exit_json(**intersight.result)
if __name__ == '__main__':
main()