diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/README.md b/Infrastructure_as_Code/Ansible/Volume_Management/README.md index 3e2754c..8a5adca 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/README.md +++ b/Infrastructure_as_Code/Ansible/Volume_Management/README.md @@ -7,16 +7,24 @@ node to have network connectivity to the FSx for ONTAP file system. For more inf Workload Factory Link, please refer to the [NetApp Workload Factory documentation](https://docs.netapp.com/us-en/workload-fsx-ontap/links-overview.html). The list of playbooks included in this folder is as follows: -- create\_snapshot.yaml -- delete\_snapshot.yaml -- create\_volume.yaml -- delete\_volume.yaml -- create\_volume\_and\_share.yaml -- delete\_volume\_and\_share.yaml +| Playbook Name | Description | +|:-----|:------| +| clone_volume.yaml | Clones an existing volume.| +| create_cifs_share.yaml | Creates a new CIFS share on an existing volume.| +| create_cifs_unix_symlink_mapping.yaml | Creates a CIFS symlink mapping. | +| create_snapshot.yaml | Creates a snapshot of an existing volume.| +| create_volume.yaml | Creates a new volume.| +| create_volume_and_share.yaml | Creates a new volume with a CIFS share that points to it. It also enables ONTAP efficiencies and potentially sets the autosize mode.| +| delete_cifs_share.yaml | Deletes an existing CIFS share.| +| delete_snapshot.yaml | Deletes an existing snapshot.| +| delete_volume.yaml | Deletes an existing volume.| +| delete_volume_and_share.yaml | Deletes an existing volume and its associated CIFS share.| +| set_volume_autosize.yaml | Sets the autosize policy on an existing volume.| +| set_volume_efficiency.yaml | Enables or disables ONTAP efficiencies on an existing volume.| ## Requirements - Ansible 2.9 or later. Installation instructions can be found [here](https://docs.ansible.com/ansible/latest/installation_guide/index.html) -- NetApp ONTAP Ansible collection. +- NetApp ONTAP Ansible collection. Version 2.17.14 or later. - AWS Ansible collection. - An AWS secret with the credentials necessary to run the required volume APIs against the FSx for ONTAP file system. The required format of the secret is described below. @@ -83,7 +91,7 @@ ok: [localhost] TASK [Set use_lambda to true if lambda_function_name is provided.] ********************************************************* ok: [localhost] -TASK [Set aws_provide to "default" if not provided.] *********************************************************************** +TASK [Set aws_profile to "default" if not provided.] *********************************************************************** ok: [localhost] TASK [Set junction path to "/" if not provided.] ************************************************************** diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/clone_volume.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/clone_volume.yaml new file mode 100644 index 0000000..9b5d348 --- /dev/null +++ b/Infrastructure_as_Code/Ansible/Volume_Management/clone_volume.yaml @@ -0,0 +1,66 @@ +# Title: clone_volume.yaml + +--- +- name: Playbook to clone a volume in an FSx for ONTAP file system. + hosts: localhost + collections: + - netapp.ontap + - amazon.aws + gather_facts: false + vars_files: + - variables.yaml + vars: + use_lambda: false + + tasks: + - name: Ensure required variables are set. + fail: + msg: "Required variable {{item}} has not been provided." + when: vars[item] is undefined + loop: + - clone_volume_name + - volume_name + - vserver + - secret_name + - fsxn_hostname + + - name: Set use_lambda to true if lambda_function_name is provided. + set_fact: + use_lambda: true + when: lambda_function_name is defined + + - name: Ensure that aws_region has been provided if use_lambda is true. + fail: + msg: "aws_region must be defined when use_lambda is true." + when: use_lambda and aws_region is not defined + + - name: Get username and password from AWS secret. + set_fact: + username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" + password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" + no_log: true + + - name: Set junction path to "/" if not provided. + set_fact: + junction_path: "/{{ clone_volume_name }}" + when: junction_path is not defined + + - name: Create the clone + netapp.ontap.na_ontap_volume_clone: + state: present + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + username: "{{ username }}" + password: "{{ password }}" + validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + name: "{{ clone_volume_name }}" + parent_volume: "{{ volume_name }}" + parent_vserver: "{{ parent_vserver | default(omit) }}" + parent_snapshot: "{{ parent_snapshot | default(omit) }}" + junction_path: "{{ junction_path }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/create_cifs_share.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/create_cifs_share.yaml new file mode 100644 index 0000000..44058bc --- /dev/null +++ b/Infrastructure_as_Code/Ansible/Volume_Management/create_cifs_share.yaml @@ -0,0 +1,58 @@ +# Title: create_cifs_share.yaml + +--- +- name: Playbook to create a CIFS share + hosts: localhost + collections: + - netapp.ontap + - amazon.aws + gather_facts: false + vars_files: + - variables.yaml + vars: + use_lambda: false + + tasks: + - name: Ensure required variables are set. + fail: + msg: "Required variable {{item}} has not been provided." + when: vars[item] is undefined + loop: + - share_path + - share_name + - vserver + - secret_name + - fsxn_hostname + + - name: Set use_lambda to true if lambda_function_name is provided. + set_fact: + use_lambda: true + when: lambda_function_name is defined + + - name: Ensure that aws_region has been provided if use_lambda is true. + fail: + msg: "aws_region must be defined when use_lambda is true." + when: use_lambda and aws_region is not defined + + - name: Get username and password from AWS secret. + set_fact: + username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" + password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" + no_log: true + + - name: Create CIFS Share + netapp.ontap.na_ontap_cifs: + state: present + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + username: "{{ username }}" + password: "{{ password }}" + validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + name: "{{ share_name }}" + path: "{{ share_path }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/create_cifs_unix_symlink_mapping.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/create_cifs_unix_symlink_mapping.yaml new file mode 100644 index 0000000..5566203 --- /dev/null +++ b/Infrastructure_as_Code/Ansible/Volume_Management/create_cifs_unix_symlink_mapping.yaml @@ -0,0 +1,63 @@ +# Title: create_cifs_unix_symlink_mapping.yaml + +--- +- name: Playbook to create a CIFS unix symlink mapping. + hosts: localhost + collections: + - netapp.ontap + - amazon.aws + gather_facts: false + vars_files: + - variables.yaml + vars: + use_lambda: false + + tasks: + - name: Ensure required variables are set. + fail: + msg: "Required variable {{item}} has not been provided." + when: vars[item] is undefined + loop: + - unix_path + - share_name + - cifs_path + - cifs_server + - vserver + - secret_name + - fsxn_hostname + + - name: Set use_lambda to true if lambda_function_name is provided. + set_fact: + use_lambda: true + when: lambda_function_name is defined + + - name: Ensure that aws_region has been provided if use_lambda is true. + fail: + msg: "aws_region must be defined when use_lambda is true." + when: use_lambda and aws_region is not defined + + - name: Get username and password from AWS secret. + set_fact: + username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" + password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" + no_log: true + + - name: Create the CIFS unix symlink mapping. + netapp.ontap.na_ontap_cifs_unix_symlink_mapping: + state: present + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + username: "{{ username }}" + password: "{{ password }}" + validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + unix_path: "{{ unix_path }}" + share_name: "{{ share_name }}" + cifs_path: "{{ cifs_path }}" + cifs_server: "{{ cifs_server }}" + locality: "{{ locality | default('local') }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/create_snapshot.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/create_snapshot.yaml index 707388f..9761908 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/create_snapshot.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/create_snapshot.yaml @@ -7,10 +7,10 @@ - netapp.ontap - amazon.aws gather_facts: false - vars: - use_lambda: false vars_files: - variables.yaml + vars: + use_lambda: false tasks: - name: Ensure required variables are set. @@ -29,26 +29,11 @@ use_lambda: true when: lambda_function_name is defined - - name: Set aws_profile to its default value of 'default' if not provided. - set_fact: - aws_profile: "default" - when: aws_profile is not defined - - name: Ensure that aws_region has been provided if use_lambda is true. fail: msg: "aws_region must be defined when use_lambda is true." when: use_lambda and aws_region is not defined - - name: Set aws_region to "" if not set at this point. - set_fact: - aws_region: "" - when: aws_region is not defined - - - name: Set lambda_function_name to "" if not set at this point. - set_fact: - lambda_function_name: "" - when: lambda_function_name is not defined - - name: Get username and password from AWS secret set_fact: username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" @@ -58,15 +43,16 @@ - name: Create snapshot on volume netapp.ontap.na_ontap_snapshot: state: present - volume: "{{ volume_name }}" - vserver: "{{ vserver }}" - snapshot: "{{ snapshot_name }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" username: "{{ username }}" password: "{{ password }}" validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + volume: "{{ volume_name }}" + snapshot: "{{ snapshot_name }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/create_volume.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/create_volume.yaml index dc787a0..c17429b 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/create_volume.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/create_volume.yaml @@ -23,76 +23,46 @@ - vserver - secret_name - fsxn_hostname - # - # Give default values to optional variables if they are not defined - - name: Set security_style to unix if not provided. - set_fact: - security_style: "unix" - when: security_style is not defined - - - name: Set aggr to 'aggr1' if not provided. - set_fact: - aggr: "aggr1" - when: aggr is not defined - - - name: Set volume_type to "rw" if not provided. - set_fact: - volume_type: "rw" - when: volume_type is not defined - + - name: Set use_lambda to true if lambda_function_name is provided. set_fact: use_lambda: true when: lambda_function_name is defined - - name: Set aws_profile to "default" if not provided. - set_fact: - aws_profile: "default" - when: aws_profile is not defined - - - name: Set junction path to "/" if not provided. - set_fact: - junction_path: "/{{ volume_name }}" - when: junction_path is not defined - - name: Ensure that aws_region has been provided if use_lambda is true. fail: msg: "aws_region must be defined when use_lambda is true." when: use_lambda and aws_region is not defined - - name: Set aws_region to "" if not set at this point. - set_fact: - aws_region: "" - when: aws_region is not defined - - - name: Set lambda_function_name to "" if not set at this point. - set_fact: - lambda_function_name: "" - when: lambda_function_name is not defined - - name: Get username and password from AWS secret. set_fact: username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" no_log: true + - name: Set junction path to "/" if not provided. + set_fact: + junction_path: "/{{ volume_name }}" + when: junction_path is not defined + - name: Create the volume netapp.ontap.na_ontap_volume: state: present - name: "{{ volume_name }}" - size: "{{ volume_size }}" - vserver: "{{ vserver }}" - aggregate_name: "{{ aggr }}" - junction_path: "{{ junction_path }}" - volume_security_style: "{{ security_style }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" - type: "{{ volume_type }}" - size_unit: "mb" hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" username: "{{ username }}" password: "{{ password }}" validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + name: "{{ volume_name }}" + size: "{{ volume_size }}" + aggregate_name: "{{ aggr | default('aggr1')}}" + junction_path: "{{ junction_path }}" + volume_security_style: "{{ security_style | default('unix') }}" + type: "{{ volume_type | default('rw') }}" + size_unit: "mb" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/create_volume_and_share.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/create_volume_and_share.yaml index 6d4ff13..1d003d3 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/create_volume_and_share.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/create_volume_and_share.yaml @@ -1,7 +1,7 @@ # Title: create_volume_and_share.yaml --- -- name: Playbook to create a volume and a CIFS share that points to it on an FSx for ONTAP file system. +- name: Playbook to create a volume and a CIFS share that points to it. This playbook will also set the autosize mode and enable efficiencies. hosts: localhost collections: - netapp.ontap @@ -12,6 +12,17 @@ vars: use_lambda: false + module_defaults: + group/netapp.ontap.netapp_ontap: + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + validate_certs: false + use_lambda: "{{ use_lambda | default('true') }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + tasks: - name: Ensure required variables are set. fail: @@ -23,97 +34,84 @@ - vserver - secret_name - fsxn_hostname - # - # Give default values to optional variables if they are not defined - - name: Set security_style to ntfs if not provided. - set_fact: - security_style: "ntfs" - when: security_style is not defined - - - name: Set aggr to 'aggr1' if not provided. - set_fact: - aggr: "aggr1" - when: aggr is not defined - - - name: Set volume_type to "rw" if not provided. - set_fact: - volume_type: "rw" - when: volume_type is not defined - + - name: Set use_lambda to true if lambda_function_name is provided. set_fact: use_lambda: true when: lambda_function_name is defined - - - name: Set aws_profile to "default" if not provided. - set_fact: - aws_profile: "default" - when: aws_profile is not defined - - - name: Set junction_path to "/" if not provided. - set_fact: - junction_path: "/{{ volume_name }}" - when: junction_path is not defined - - - name: Set share_name to "" if not provided. - set_fact: - share_name: "{{ volume_name }}" - when: share_name is not defined - + - name: Ensure that aws_region has been provided if use_lambda is true. fail: msg: "aws_region must be defined when use_lambda is true." when: use_lambda and aws_region is not defined - - - name: Set aws_region to "" if not set at this point. - set_fact: - aws_region: "" - when: aws_region is not defined - - - name: Set lambda_function_name to "" if not set at this point. - set_fact: - lambda_function_name: "" - when: lambda_function_name is not defined - + - name: Get username and password from AWS secret. set_fact: username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" no_log: true + - name: Set junction_path to "/" if not provided. + set_fact: + junction_path: "/{{ volume_name }}" + when: junction_path is not defined + + - name: Give efficiency_mode a default if it hasn't already been set. + set_fact: + efficiency_mode: "enabled" + when: efficiency_mode is not defined + + - name: Ensure efficiency_mode is either 'enabled' or 'disabled' + fail: + msg: "efficiency_mode must be either 'enabled' or 'disabled'." + when: efficiency_mode not in ['enabled', 'disabled'] + + - name: Ensure autosize_mode is valid if it is defined. + fail: + msg: "autosize_mode must be either 'grow', 'grow_shrink', or 'off'." + when: autosize_mode is defined and autosize_mode not in ['grow', 'off', 'grow_shrink'] + - name: Create the volume netapp.ontap.na_ontap_volume: state: present + username: "{{ username }}" + password: "{{ password }}" + name: "{{ volume_name }}" size: "{{ volume_size }}" - vserver: "{{ vserver }}" - aggregate_name: "{{ aggr }}" + aggregate_name: "{{ aggr | default('aggr1')}}" junction_path: "{{ junction_path }}" - volume_security_style: "{{ security_style }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" - type: "{{ volume_type }}" + volume_security_style: "{{ security_style | default('ntfs') }}" + type: "{{ volume_type | default('rw')}}" size_unit: "mb" - hostname: "{{ fsxn_hostname }}" + + - name: Set Autosize + netapp.ontap.na_ontap_volume_autosize: + username: "{{ username }}" + password: "{{ password }}" + + volume: "{{ volume_name }}" + mode: "{{ autosize_mode }}" + maximum_size: "{{ autosize_max_size | default(omit) }}" + minimum_size: "{{ autosize_min_size | default(omit) }}" + when: autosize_mode is defined + + - name: Set efficiency of the volume based on the value of efficiency_mode variable. + netapp.ontap.na_ontap_volume_efficiency: + state: "{{ 'present' if efficiency_mode == 'enabled' else 'absent' }}" username: "{{ username }}" password: "{{ password }}" - validate_certs: false + + volume_name: "{{ volume_name }}" + enable_data_compaction: "{{ 'true' if efficiency_mode == 'enabled' else 'false' }}" + enable_inline_compression: "{{ 'true' if efficiency_mode == 'enabled' else 'false' }}" + enable_inline_dedupe: "{{ 'true' if efficiency_mode == 'enabled' else 'false' }}" - name: Create CIFS Share netapp.ontap.na_ontap_cifs: state: present - name: "{{ share_name }}" - path: "{{ junction_path }}" - vserver: "{{ vserver }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" - hostname: "{{ fsxn_hostname }}" username: "{{ username }}" password: "{{ password }}" - validate_certs: false + + name: "{{ share_name | default(volume_name)}}" + path: "{{ junction_path }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/delete_cifs_share.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/delete_cifs_share.yaml new file mode 100644 index 0000000..c096934 --- /dev/null +++ b/Infrastructure_as_Code/Ansible/Volume_Management/delete_cifs_share.yaml @@ -0,0 +1,56 @@ +# Title: delete_cifs_share.yaml + +--- +- name: Playbook to delete a CIFS share + hosts: localhost + collections: + - netapp.ontap + - amazon.aws + gather_facts: false + vars_files: + - variables.yaml + vars: + use_lambda: false + + tasks: + - name: Ensure required variables are set. + fail: + msg: "Required variable {{item}} has not been provided." + when: vars[item] is undefined + loop: + - delete_share_name + - vserver + - secret_name + - fsxn_hostname + + - name: Set use_lambda to true if lambda_function_name is provided. + set_fact: + use_lambda: true + when: lambda_function_name is defined + + - name: Ensure that aws_region has been provided if use_lambda is true. + fail: + msg: "aws_region must be defined when use_lambda is true." + when: use_lambda and aws_region is not defined + + - name: Get username and password from AWS secret. + set_fact: + username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" + password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" + no_log: true + + - name: Delete CIFS Share + netapp.ontap.na_ontap_cifs: + state: absent + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + username: "{{ username }}" + password: "{{ password }}" + validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + name: "{{ delete_share_name }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/delete_snapshot.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/delete_snapshot.yaml index 90a2e6e..03af0eb 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/delete_snapshot.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/delete_snapshot.yaml @@ -7,10 +7,10 @@ - netapp.ontap - amazon.aws gather_facts: false - vars: - use_lambda: false vars_files: - variables.yaml + vars: + use_lambda: false tasks: - name: Ensure required variables are set. @@ -19,7 +19,7 @@ when: vars[item] is undefined loop: - volume_name - - snapshot_name + - delete_snapshot_name - vserver - fsxn_hostname - secret_name @@ -29,44 +29,30 @@ use_lambda: true when: lambda_function_name is defined - - name: Set aws_profile to its default value of 'default' if not provided. - set_fact: - aws_profile: "default" - when: aws_profile is not defined - - name: Ensure that aws_region has been provided if use_lambda is true. fail: msg: "aws_region must be defined when use_lambda is true." when: use_lambda and aws_region is not defined - - name: Set aws_region to "" if not set at this point. - set_fact: - aws_region: "" - when: aws_region is not defined - - - name: Set lambda_function_name to "" if not set at this point. - set_fact: - lambda_function_name: "" - when: lambda_function_name is not defined - - name: Get username and password from AWS secret set_fact: username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" no_log: true - - name: Create snapshot on volume + - name: Default snapshot on volume netapp.ontap.na_ontap_snapshot: state: absent - volume: "{{ volume_name }}" - vserver: "{{ vserver }}" - snapshot: "{{ snapshot_name }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" username: "{{ username }}" password: "{{ password }}" validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + volume: "{{ volume_name }}" + snapshot: "{{ delete_snapshot_name }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume.yaml index 83f2933..cf2088d 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume.yaml @@ -7,10 +7,10 @@ - netapp.ontap - amazon.aws gather_facts: false - vars: - use_lambda: false vars_files: - variables.yaml + vars: + use_lambda: false tasks: - name: Ensure required variables are set. @@ -18,7 +18,7 @@ msg: "Required variable {{item}} has not been provided." when: vars[item] is undefined loop: - - volume_name + - delete_volume_name - vserver - fsxn_hostname - secret_name @@ -28,26 +28,11 @@ use_lambda: true when: lambda_function_name is defined - - name: Set aws_profile to its default value of 'default' if not provided. - set_fact: - aws_profile: "default" - when: aws_profile is not defined - - name: Ensure that aws_region has been provided if use_lambda is true. fail: msg: "aws_region must be defined when use_lambda is true." when: use_lambda and aws_region is not defined - - name: Set aws_region to "" if not set at this point. - set_fact: - aws_region: "" - when: aws_region is not defined - - - name: Set lambda_function_name to "" if not set at this point. - set_fact: - lambda_function_name: "" - when: lambda_function_name is not defined - - name: Get username and password from AWS secret set_fact: username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" @@ -57,14 +42,15 @@ - name: Delete the volume netapp.ontap.na_ontap_volume: state: absent - name: "{{ volume_name }}" - vserver: "{{ vserver }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" username: "{{ username }}" password: "{{ password }}" validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + name: "{{ delete_volume_name }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume_and_share.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume_and_share.yaml index afee118..6e7876e 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume_and_share.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/delete_volume_and_share.yaml @@ -1,7 +1,7 @@ # Title: delete_volume_and_share.yaml --- -- name: Playbook to delete a volume and a CIFS share that points to it on an FSx for ONTAP file system. +- name: Playbook to delete a volume and the CIFS share that points to it. hosts: localhost collections: - netapp.ontap @@ -12,6 +12,17 @@ vars: use_lambda: false + module_defaults: + group/netapp.ontap.netapp_ontap: + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + validate_certs: false + use_lambda: "{{ use_lambda | default('true') }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + tasks: - name: Ensure required variables are set. fail: @@ -22,92 +33,48 @@ - vserver - secret_name - fsxn_hostname - # - # Give default values to optional variables if they are not defined - - name: Set security_style to ntfs if not provide. - set_fact: - security_style: "ntfs" - when: security_style is not defined - - - name: Set aggr to 'aggr1' if not provided. - set_fact: - aggr: "aggr1" - when: aggr is not defined - - - name: Set volume_type to "rw" if not provided. - set_fact: - volume_type: "rw" - when: volume_type is not defined - + - name: Set use_lambda to true if lambda_function_name is provided. set_fact: use_lambda: true when: lambda_function_name is defined - - name: Set aws_provide to "default" if not provided. - set_fact: - aws_profile: "default" - when: aws_profile is not defined - - - name: Set junction_path to "/" if not provided. - set_fact: - junction_path: "/{{ volume_name }}" - when: junction_path is not defined - - - name: Set share_name to "" if not provided. - set_fact: - share_name: "{{ volume_name }}" - when: share_name is not defined - - name: Ensure that aws_region has been provided if use_lambda is true. fail: msg: "aws_region must be defined when use_lambda is true." when: use_lambda and aws_region is not defined - - name: Set aws_region to "" if not set at this point. - set_fact: - aws_region: "" - when: aws_region is not defined - - - name: Set lambda_function_name to "" if not set at this point. - set_fact: - lambda_function_name: "" - when: lambda_function_name is not defined - - name: Get username and password from AWS secret. set_fact: username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" no_log: true + - name: Set junction_path to "/" if not provided. + set_fact: + junction_path: "/{{ volume_name }}" + when: junction_path is not defined + + - name: Set share_name to "" if not provided. + set_fact: + share_name: "{{ volume_name }}" + when: share_name is not defined + - name: Delete CIFS Share netapp.ontap.na_ontap_cifs: state: absent + username: "{{ username }}" + password: "{{ password }}" + name: "{{ share_name }}" path: "{{ junction_path }}" vserver: "{{ vserver }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" - hostname: "{{ fsxn_hostname }}" - username: "{{ username }}" - password: "{{ password }}" - validate_certs: false - name: Delete the volume netapp.ontap.na_ontap_volume: state: absent - name: "{{ volume_name }}" - vserver: "{{ vserver }}" - aggregate_name: "{{ aggr }}" - use_lambda: "{{ use_lambda }}" - lambda_config: - aws_profile: "{{ aws_profile }}" - aws_region: "{{ aws_region }}" - function_name: "{{ lambda_function_name }}" - hostname: "{{ fsxn_hostname }}" username: "{{ username }}" password: "{{ password }}" - validate_certs: false + + name: "{{ volume_name }}" + vserver: "{{ vserver }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/set_volume_autosize.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/set_volume_autosize.yaml new file mode 100644 index 0000000..35e7d43 --- /dev/null +++ b/Infrastructure_as_Code/Ansible/Volume_Management/set_volume_autosize.yaml @@ -0,0 +1,64 @@ +# Title: set_volume_autosize.yaml + +--- +- name: Playbook to create set the autosize of a volume on an FSx for ONTAP file system. + hosts: localhost + collections: + - netapp.ontap + - amazon.aws + gather_facts: false + vars_files: + - variables.yaml + vars: + use_lambda: false + + tasks: + - name: Ensure required variables are set. + fail: + msg: "Required variable '{{ item }}' has not been provided." + when: vars[item] is undefined + loop: + - volume_name + - vserver + - fsxn_hostname + - secret_name + - autosize_mode + + - name: Set use_lambda to true if lambda_function_name is provided. + set_fact: + use_lambda: true + when: lambda_function_name is defined + + - name: Ensure that aws_region has been provided if use_lambda is true. + fail: + msg: "aws_region must be defined when use_lambda is true." + when: use_lambda and aws_region is not defined + + - name: Ensure autosize_mode is valid. + fail: + msg: "autosize_mode must be either 'grow', 'grow_shrink', or 'off'." + when: autosize_mode not in ['grow', 'off', 'grow_shrink'] + + - name: Get username and password from AWS secret + set_fact: + username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" + password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" + no_log: true + + - name: Set autosize + netapp.ontap.na_ontap_volume_autosize: + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + username: "{{ username }}" + password: "{{ password }}" + validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + volume: "{{ volume_name }}" + mode: "{{ autosize_mode }}" + minimum_size: "{{ autosize_min_size | default(omit) }}" + maximum_size: "{{ autosize_max_size | default(omit) }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/set_volume_efficiency.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/set_volume_efficiency.yaml new file mode 100644 index 0000000..731911d --- /dev/null +++ b/Infrastructure_as_Code/Ansible/Volume_Management/set_volume_efficiency.yaml @@ -0,0 +1,65 @@ +# Title: set_volume_efficiency.yaml + +--- +- name: Playbook to set a volumes efficiencies. + hosts: localhost + collections: + - netapp.ontap + - amazon.aws + gather_facts: false + vars_files: + - variables.yaml + vars: + use_lambda: false + + tasks: + - name: Ensure required variables are set. + fail: + msg: "Required variable '{{ item }}' has not been provided." + when: vars[item] is undefined + loop: + - volume_name + - vserver + - fsxn_hostname + - secret_name + - efficiency_mode + + - name: Set use_lambda to true if lambda_function_name is provided. + set_fact: + use_lambda: true + when: lambda_function_name is defined + + - name: Ensure that aws_region has been provided if use_lambda is true. + fail: + msg: "aws_region must be defined when use_lambda is true." + when: use_lambda and aws_region is not defined + + - name: Get username and password from AWS secret + set_fact: + username: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.username', nested=true) }}" + password: "{{ lookup('amazon.aws.aws_secret', '{{ secret_name }}.password', nested=true) }}" + no_log: true + + - name: Ensure efficiency_mode is either 'enabled' or 'disabled' + fail: + msg: "efficiency_mode must be either 'enabled' or 'disabled'." + when: efficiency_mode not in ['enabled', 'disabled'] + + - name: Set efficiency of the volume based on the value of efficiency_mode variable. + netapp.ontap.na_ontap_volume_efficiency: + state: "{{ 'present' if efficiency_mode == 'enabled' else 'absent' }}" + hostname: "{{ fsxn_hostname }}" + vserver: "{{ vserver }}" + username: "{{ username }}" + password: "{{ password }}" + validate_certs: false + use_lambda: "{{ use_lambda }}" + lambda_config: + aws_profile: "{{ aws_profile | default('default') }}" + aws_region: "{{ aws_region | default('') }}" + function_name: "{{ lambda_function_name | default('') }}" + + volume_name: "{{ volume_name }}" + enable_data_compaction: "{{ 'true' if efficiency_mode == 'enabled' else 'false' }}" + enable_inline_compression: "{{ 'true' if efficiency_mode == 'enabled' else 'false' }}" + enable_inline_dedupe: "{{ 'true' if efficiency_mode == 'enabled' else 'false' }}" diff --git a/Infrastructure_as_Code/Ansible/Volume_Management/variables.yaml b/Infrastructure_as_Code/Ansible/Volume_Management/variables.yaml index 62016e8..bc4fa19 100644 --- a/Infrastructure_as_Code/Ansible/Volume_Management/variables.yaml +++ b/Infrastructure_as_Code/Ansible/Volume_Management/variables.yaml @@ -1,8 +1,9 @@ -volume_name: "vol1" -volume_size: 100 +volume_name: "test_volume" +volume_size: 1024 vserver: "fsx" -fsxn_hostname: "10.0.0.13" -lambda_function_name: "lambda-8nlmlCR" +fsxn_hostname: "10.1.1.1" +lambda_function_name: "lambda-aaaaaaaa" aws_region: "us-west-2" secret_name: "fsxn/default" -snapshot_name: "snapshot1" +snapshot_name: "test_snapshot" +autosize_mode: "grow" diff --git a/Management-Utilities/Workload-Factory-API-Samples/README.md b/Management-Utilities/Workload-Factory-API-Samples/README.md index 064391d..eb0e56d 100644 --- a/Management-Utilities/Workload-Factory-API-Samples/README.md +++ b/Management-Utilities/Workload-Factory-API-Samples/README.md @@ -44,6 +44,7 @@ If you do create a new script, please consider contributing it back to this repo | [bluexp_organization_delete](bluexp_organization_delete) | This deletes a BlueXP organization (a.k.a. account). | | [bluexp_organization_rename](bluexp_organization_rename) | This renames a BlueXP organization (a.k.a. account). | | [credentials_delete](credentials_delete) | This deletes a Workload Factory credential. | +| [credentials_create](credentials_create) | This create a Workload Factory credential. | | [fsxn_credentials_set](fsxn_credentials_set) | This sets the credentials for a specified FSx for ONTAP file system. | | [get_latency_details](get_latency_details) | Get the specific details of a latency event. | | [link_associate](link_associate) | This associates a Workload Factory Link with a specified FSx for ONTAP file system. | @@ -70,9 +71,10 @@ If you do create a new script, please consider contributing it back to this repo | [snapmirror_reverse](snapmirror_reverse) | This reverses the SnapMirror relationship for the specified relationship. | | [snapmirror_update](snapmirror_update) | This updates the SnapMirror relationship for the specified relationship. | | [snapshot_create](snapshot_create) | This creates a snapshot of the specified volume. | -| [volume_clone](volume_clone) | This clones the specified volume. | | [volume_cifs_share_create](volume_cifs_share_create) | This will create a CIFS share in a volume. | | [volume_cifs_share_delete](volume_cifs_share_delete) | This will delete a CIFS share from a volume. | +| [volume_clone](volume_clone) | This clones the specified volume. | +| [volume_create](volume_create) | This a volume with the specified name, size, and SVM. | | [volume_delete](volume_delete) | This deletes the specified volume. | | [wf_utils](wf_utils) | This file contains common functions used by all the scripts. It includes the `get_token()` function that retrieves an access token from the Workload Factory API. | diff --git a/Management-Utilities/Workload-Factory-API-Samples/credentials_create b/Management-Utilities/Workload-Factory-API-Samples/credentials_create new file mode 100755 index 0000000..e4f5f77 --- /dev/null +++ b/Management-Utilities/Workload-Factory-API-Samples/credentials_create @@ -0,0 +1,105 @@ +#!/bin/bash +# +################################################################################ +# This script is used to create AWS credentials for Workload Factory. +# +# It is dependent on the 'wf_utils' file that is included in this repo. That +# file contains the 'get_token' function that is used to obtain a valid +# access token that is needed to run the Workload Factory APIs. The file needs +# to either be in the command search path or in the current directory. +################################################################################ +# +################################################################################ +# This function displays the usage of this script and exits. +################################################################################ +usage() { + cat >&2 < + export BLUEXP_ACCOUNT_ID= +EOF + exit 1 +} + +################################################################################ +# Main logic starts here. +################################################################################ + +tmpout=$(mktemp /tmp/credentials_delete-out.XXXXXX) +tmperr=$(mktemp /tmp/credentials_delete-err.XXXXXX) +trap 'rm -f $tmpout $tmperr' exit +# +# Source the wf_utils file. +wf_utils=$(command -v wf_utils) +if [ -z "$wf_utils" ]; then + if [ ! -x "./wf_utils" ]; then + cat >&2 < /dev/null; then + echo "Error: The required command '$cmd' was not found. Please install it." >&2 + exit 1 + fi +done +# +# Get the token to use for the API call. +token=$(get_token) +if [ -z "$token" ]; then + echo "Error: Failed to obtain an access token. Exiting." >&2 + exit 1 +fi +data='{ +"arn":"'$ROLE_ARN'", +"name":"'$CREDENTIALS_NAME'", +"externalId":"'$BLUEXP_ACCOUNT_ID'", +"accountType":"STANDARD" +}' +run_curl POST "$token" "https://api.workloads.netapp.com/accounts/${BLUEXP_ACCOUNT_ID}/credentials/v1/aws/assume-role" $tmpout $tmperr "$data" diff --git a/Management-Utilities/Workload-Factory-API-Samples/get_latency_metrics b/Management-Utilities/Workload-Factory-API-Samples/get_latency_metrics index 2342609..4ae64cc 100755 --- a/Management-Utilities/Workload-Factory-API-Samples/get_latency_metrics +++ b/Management-Utilities/Workload-Factory-API-Samples/get_latency_metrics @@ -35,14 +35,18 @@ following environment variables: Legend: Timestamp - The time the metrics were collected. Volume ID - The ID of the volume these metrics are for. - Network - The network latency in milliseconds. - Cluster - The cluster interconnect latency in milliseconds. - Data - The CPU latency in milliseconds. - Disk - The disk latency in milliseconds. - QoS - The QoS latency in milliseconds. - NVRAM - The NVRAM synchronization latency in milliseconds. - Cloud - The tiering latency in milliseconds. - Details - Any details about the latency analysis. + Network - The network latency. + Cluster - The cluster interconnect latency. + Data - The CPU latency. + Disk - The disk latency. + QoS Max - The latency caused by a QoS Maximum settings. + QoS Min - The latency caused by a QoS Minimum settings. + NVRAM - The NVRAM synchronization latency. + Cloud - The tiering latency. + FlexCache - The latency caused by retrieving data from a FlexCache source. + SM Sync - The latency caused by a SnapMirror synchronous operations. + VA - The latency caused by volume activation (VA) operations. + Details - Any details about the latency event. EOF exit 1 } @@ -111,7 +115,7 @@ fi if [ "$JSON_OUTPUT" == true ]; then jq_query='.' else - jq_query='.items[] | "\(.createdAt / 1000 | todate),\(.volumeId),\(if(.latencyAnalysis.Network) then .latencyAnalysis.Network else 0 end),\(if(.latencyAnalysis.Cluster) then .latencyAnalysis.Cluster else 0 end),\(if(.latencyAnalysis.Data) then .latencyAnalysis.Data else 0 end),\(if(.latencyAnalysis.Disk) then .latencyAnalysis.Disk else 0 end),\(if(.latencyAnalysiss.QoS) then .latencyAnalysis.QoS else 0 end),\(if(.latencyAnalysis.NVRAM) then .latencyAnalysis.NVRAM else 0 end),\(if(.latencyAnalysis.Cloud) then .latencyAnalysis.Cloud else 0 end),\(.details)"' + jq_query='.items[] | "\(.createdAt),\(.volumeId),\(if(.latencyAnalysis.Network) then .latencyAnalysis.Network else 0 end),\(if(.latencyAnalysis.Cluster) then .latencyAnalysis.Cluster else 0 end),\(if(.latencyAnalysis.Data) then .latencyAnalysis.Data else 0 end),\(if(.latencyAnalysis.Disk) then .latencyAnalysis.Disk else 0 end),\(if(.latencyAnalysis."QoS Max") then .latencyAnalysis."QoS Max" else 0 end),\(if(.latencyAnalysis.NVRAM) then .latencyAnalysis.NVRAM else 0 end),\(if(.latencyAnalysis.Cloud) then .latencyAnalysis.Cloud else 0 end),\(if(.latencyAnalysis.FlexCache) then .latencyFlexCache else 0 end),\(.details)"' fi URL="https://api.workloads.netapp.com/accounts/${BLUEXP_ACCOUNT_ID}/builders/v1/latency/analysis/${VOLUME_ID}/history" @@ -141,5 +145,5 @@ done if [ "$JSON_OUTPUT" == true ]; then cat $tmpout2 else - sort -f $tmpout2 | column -s, -t -R 3,4,5,6,7,8,9 -N "Timestamp,Volume ID,Network,Cluster Inter,Data (CPU),Disk,QoS,NVRAM Sync,Cloud Tiering,Details" + sort -f $tmpout2 | column -s, -t -R 3,4,5,6,7,8,9,10 -N "Timestamp,Volume ID,Network,Cluster Inter,Data (CPU),Disk,QoS,NVRAM Sync,Cloud Tiering,Flex Cache,Details" fi diff --git a/Management-Utilities/Workload-Factory-API-Samples/volume_create b/Management-Utilities/Workload-Factory-API-Samples/volume_create new file mode 100755 index 0000000..7f4fd4e --- /dev/null +++ b/Management-Utilities/Workload-Factory-API-Samples/volume_create @@ -0,0 +1,132 @@ +#!/bin/bash +# +################################################################################ +# This script is used to create a volume on an ONTAP file system. +# +# It is dependent on the 'wf_utils' file that is included in this repo. That +# file contains the 'get_token' function that is used to obtain a valid +# access token that is needed to run the Workload Factory APIs. The file needs +# to either be in the command search path or in the current directory. +################################################################################ + +################################################################################ +# This function just prints the usage of this script and exits the program. +################################################################################ +usage() { + cat >&2 < + export BLUEXP_ACCOUNT_ID= + export CREDENTIALS_ID= + export AWS_REGION= +EOF + exit 1 +} + +################################################################################ +# Main logic starts here. +################################################################################ +tmpout=$(mktemp /tmp/create_share-out.XXXXXX) +tmperr=$(mktemp /tmp/create_share-err.XXXXXX) +trap 'rm -f $tmpout $tmperr' exit +# +# Source the wf_utils file. +wf_utils=$(command -v wf_utils) +if [ -z "$wf_utils" ]; then + if [ ! -x "./wf_utils" ]; then + cat >&2 < /dev/null; then + echo "Error: The required command '$cmd' was not found. Please install it." >&2 + exit 1 + fi +done + +token=$(get_token) +if [ -z "$token" ]; then + echo "Error: Failed to obtain an access token. Exiting." >&2 + exit 1 +fi + +data='{ + "name": "'$VOLUME_NAME'", + "region": "'$AWS_REGION'", + "credentialsId": "'$CREDENTIALS_ID'", + "fileSystemId": "'$FILESYSTEM_ID'", + '$JUNCTION_PATH' + "size": {"value": '$SIZE', "unit": "MiB"}, + "svmId": "'$SVM_ID'", + "securityStyle": "'$SECURITY_STYLE'" +}' +# +# Create the volume +run_curl POST "$token" "https://api.workloads.netapp.com/accounts/${BLUEXP_ACCOUNT_ID}/fsx/v2/volumes" $tmpout $tmperr "$data"