Skip to content

Commit

Permalink
Ansible changes for Image Verification and GPG key installation (#380)
Browse files Browse the repository at this point in the history
* Ansible changes for Image Verification

* add fragments

* resolve build issues

* resolve pep8 issues

* resolve pep8 issues

* code coverage fix

* version changes

* update log

* Update 380-sonic-image-verification.yaml

* fix pylint issue

* Update lldp_global.py

* Address comments

* Address comments

* address comments

* address comments

* modify image name
  • Loading branch information
aravindmani-1 authored Nov 13, 2024
1 parent e500d90 commit 14a07d4
Show file tree
Hide file tree
Showing 7 changed files with 392 additions and 7 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/380-sonic-image-verification.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
minor_changes:
- sonic_image_management - Add support for image GPG Key installation and verification feature in sonic_image_management module (https://github.com/ansible-collections/dellemc.enterprise_sonic/pull/380).
104 changes: 97 additions & 7 deletions plugins/modules/sonic_image_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
short_description: Manage installation of Enterprise SONiC image, software patch and firmware updater
description:
- Manage installation of Enterprise SONiC image, software patch and firmware updater.
author: 'Arun Saravanan Balachandran (@ArunSaravananBalachandran)'
author: 'Arun Saravanan Balachandran (@ArunSaravananBalachandran), Aravind Mani (@aravindmani-1)'
options:
image:
Expand All @@ -35,6 +35,8 @@
- C(set-default) - Set the image specified by I(name) as default boot image.
- C(get-list) - Retrieve list of installed images.
- C(get-status) - Retrieve image installation status.
- C(gpg-key) - Install GPG key.
- C(verify) - Verify the image specified by I(path) using GPG or PKI method.
type: str
choices:
- install
Expand All @@ -43,17 +45,52 @@
- set-default
- get-list
- get-status
- gpg-key
- verify
required: true
path:
description:
- When I(command=install), specifies the path of the image to be installed.
- When I(command=install) or I(command=verify) specifies the path of the image to be installed.
- Path can be a file in the device (file://filepath) or URL (http:// or https://).
type: str
name:
description:
- When I(command=remove) or I(command=set-default), specifies the name of the image.
- When I(command=remove), name can be specified as C(all) to remove all images which are not current or next.
- When I(command=remove) or I(command=set-default) specifies the name of the image.
- When I(command=remove), name can be specified as C(all) to remove all images which are not current or next.
type: str
keyserver:
version_added: '3.0.0'
description:
- GPG Key server URL.
- Required when I(command=gpg-key).
type: str
pubkeyid:
version_added: '3.0.0'
description:
- GPG Key ID to be installed.
- Required when I(command=gpg-key).
type: str
signaturefile:
version_added: '3.0.0'
description:
- GPG/PKI file to be verified.
- Required when I(command=verify).
type: str
pubkeyfilename:
version_added: '3.0.0'
description:
- Specifies the certificate for signature file.
- Required when I(command=verify) and I(verifymethod=pki).
type: str
verifymethod:
version_added: '3.0.0'
description:
- Image verification GPG or PKI method
- Required when I(command=verify).
type: str
choices:
- gpg
- pki
patch:
description:
- Manage installation of software patch.
Expand Down Expand Up @@ -134,6 +171,21 @@
command: install
path: 'file://home/admin/onie-update-full.bin'
- name: Install GPG Key for image verification
dellemc.enterprise_sonic.sonic_image_management:
image:
command: gpg-key
keyserver: 'hkp://keyserver.ubuntu.com:80'
pubkeyid: 'DAFWQGEW12345678'
- name: Verify Enterprise SONiC image
dellemc.enterprise_sonic.sonic_image_management:
image:
command: verify
path: 'home://sonic.bin'
verifymethod: 'gpg'
signaturefile: 'sign.gpg'
"""

RETURN = """
Expand Down Expand Up @@ -197,7 +249,19 @@ def validate_and_retrieve_params(module, warnings):
module.fail_json(msg="{0} -> name is required when {0} -> command = {1}".format(params['category'], params['command']))
if params.get('path'):
warnings.append("{0} -> path is ignored when {0} -> command = {1}".format(params['category'], params['command']))

elif params['command'] == 'gpg-key':
if not params.get('keyserver') or not params.get('pubkeyid'):
module.fail_json(msg="{0} -> keyserver URL and Key ID are required when {0} -> command = {1}".format(params['category'], params['command']))
elif params['command'] == 'verify':
if not params.get('verifymethod'):
module.fail_json(msg="{0} -> verifymethod is required when {0} -> command = verify".format(params['category']))
if params.get('verifymethod') == 'gpg':
if not params.get('path') or not params.get('signaturefile'):
module.fail_json(msg="{0} -> Image path and GPG signature are required when {0} -> command = {1}".format(params['category'], params['command']))
else:
if not params.get('path') or not params.get('signaturefile') or not params.get('pubkeyfilename'):
module.fail_json(
msg="{0} -> Image path, PKI signature and certificate are required when {0} -> command = {1}".format(params['category'], params['command']))
return params


Expand Down Expand Up @@ -225,6 +289,12 @@ def execute_command(module, params, result):
'get-list': {
'path': 'data/openconfig-image-management:image-management',
'response_key': 'openconfig-image-management:image-management'
},
'gpg-key': {
'path': 'operations/openconfig-image-management:image-gpg-install'
},
'verify': {
'path': 'operations/openconfig-image-management:image-verify'
}
},
'patch': {
Expand Down Expand Up @@ -351,6 +421,18 @@ def execute_command(module, params, result):
payload['openconfig-image-management:input'] = {'image-name': params['path']}
elif (params['command'] == 'remove' and params['name'] != 'all') or params['command'] == 'set-default':
payload['openconfig-image-management:input'] = {'image-name': params['name']}
elif params['command'] == 'gpg-key':
payload['openconfig-image-management:input'] = {"key-server": params['keyserver'], "key-id": params['pubkeyid']}
elif params['command'] == 'verify':
if params['verifymethod'] == 'gpg':
payload['openconfig-image-management:input'] = {
"image-name": params['path'], "verify-method": params['verifymethod'], "sigfilename": params['signaturefile']
}
else:
payload['openconfig-image-management:input'] = {
"image-name": params['path'], "verify-method": params['verifymethod'],
"sigfilename": params['signaturefile'], "keyfilename": params['pubkeyfilename']
}
elif params['category'] == 'patch':
if params['command'] == 'install':
payload['openconfig-image-management:input'] = {'patch-name': params['path'], 'skip-image-check': ''}
Expand Down Expand Up @@ -388,10 +470,18 @@ def main():
'command': {
'type': 'str',
'required': True,
'choices': ['install', 'cancel', 'remove', 'set-default', 'get-list', 'get-status']
'choices': ['install', 'cancel', 'remove', 'set-default', 'get-list', 'get-status', 'gpg-key', 'verify']
},
'name': {'type': 'str'},
'path': {'type': 'str'}
'path': {'type': 'str'},
'keyserver': {'type': 'str'},
'pubkeyid': {'type': 'str'},
'pubkeyfilename': {'type': 'str'},
'signaturefile': {'type': 'str'},
'verifymethod': {
'type': 'str',
'choices': ['gpg', 'pki']
}
}
},
'patch': {
Expand Down
58 changes: 58 additions & 0 deletions tests/regression/roles/sonic_image_management/tasks/image_gpg.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
- name: Test case - image gpg-key - Installs GPG key
dellemc.enterprise_sonic.sonic_image_management:
image:
command: 'gpg-key'
keyserver: 'hkp://keyserver.ubuntu.com:80'
pubkeyid: 'DC6E36CC7FDA043B'
register: result
ignore_errors: yes

- ansible.builtin.assert:
that:
- result.failed == false
- result.status is defined
- result.status == 'Installed public GPG key successfully.'
register: assert_result
ignore_errors: yes

- ansible.builtin.include_tasks: image_management.test.facts.report.yml
vars:
test_case_name: 'image_gpg_key_01'
test_case_input:
image:
command: 'gpg-key'
keyserver: 'hkp://keyserver.ubuntu.com:80'
pubkeyid: 'DC6E36CC7FDA043B'

- name: Test case - image gpg-key - Installs GPG key
dellemc.enterprise_sonic.sonic_image_management:
image:
command: 'gpg-key'
keyserver: 'hkp://keyserver.ubuntu.com:80'
pubkeyid: 'DC6E36CC7FDA043A'
register: result
ignore_errors: yes

- ansible.builtin.set_fact:
result_msg: "{{ result.msg | from_yaml }}"
when: result.msg is defined

- ansible.builtin.assert:
that:
- result.failed == true
- result.msg is defined
- result_msg['code'] == 400
- result_msg['ietf-restconf:errors']['error'][0]['error-type'] == 'application'
- result_msg['ietf-restconf:errors']['error'][0]['error-tag'] == 'invalid-value'
register: assert_result
ignore_errors: yes

- ansible.builtin.include_tasks: image_management.test.facts.report.yml
vars:
test_case_name: 'image_gpg_key_02'
test_case_input:
image:
command: 'gpg-key'
keyserver: 'hkp://keyserver.ubuntu.com:80'
pubkeyid: 'DC6E36CC7FDA043A'
130 changes: 130 additions & 0 deletions tests/regression/roles/sonic_image_management/tasks/image_verify.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
---
- name: Test case - image verify - Verifies image using GPG-01
dellemc.enterprise_sonic.sonic_image_management:
image:
command: 'verify'
verifymethod: 'gpg'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.gpg'
register: result
ignore_errors: yes


- ansible.builtin.assert:
that:
- result.failed == false
- result.status is defined
- result.status == 'GPG validation succeeded.'
register: assert_result
ignore_errors: yes

- ansible.builtin.include_tasks: image_management.test.facts.report.yml
vars:
test_case_name: 'image_verify_gpg_01'
test_case_input:
image:
command: 'verify'
verifymethod: 'gpg'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.gpg'

- name: Test case - image verify - Verifies image using GPG-02
dellemc.enterprise_sonic.sonic_image_management:
image:
command: 'verify'
verifymethod: 'gpg'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.sig'
register: result
ignore_errors: yes

- ansible.builtin.set_fact:
result_msg: "{{ result.msg | from_yaml }}"
when: result.msg is defined

- ansible.builtin.assert:
that:
- result.failed == true
- result.msg is defined
- result_msg['code'] == 400
- result_msg['ietf-restconf:errors']['error'][0]['error-type'] == 'application'
- result_msg['ietf-restconf:errors']['error'][0]['error-tag'] == 'invalid-value'
register: assert_result
ignore_errors: yes

- ansible.builtin.include_tasks: image_management.test.facts.report.yml
vars:
test_case_name: 'image_verify_gpg_02'
test_case_input:
image:
command: 'verify'
verifymethod: 'gpg'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.sig'

- name: Test case - image verify - Verifies image using PKI
dellemc.enterprise_sonic.sonic_image_management:
image:
command: 'verify'
verifymethod: 'pki'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.sig'
pubkeyfilename: 'home://DellOS10.cert.pem'
register: result
ignore_errors: yes


- ansible.builtin.assert:
that:
- result.failed == false
- result.status is defined
- result.status == 'PKI validation succeeded.'
register: assert_result
ignore_errors: yes

- ansible.builtin.include_tasks: image_management.test.facts.report.yml
vars:
test_case_name: 'image_verify_pki_01'
test_case_input:
image:
command: 'verify'
verifymethod: 'pki'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.sig'
pubkeyfilename: 'home://DellOS10.cert.pem'

- name: Test case - image verify - Verifies image using PKI
dellemc.enterprise_sonic.sonic_image_management:
image:
command: 'verify'
verifymethod: 'pki'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.gpg'
pubkeyfilename: 'home://DellOS10.cert.pem'
register: result
ignore_errors: yes

- ansible.builtin.set_fact:
result_msg: "{{ result.msg | from_yaml }}"
when: result.msg is defined

- ansible.builtin.assert:
that:
- result.failed == true
- result.msg is defined
- result_msg['code'] == 400
- result_msg['ietf-restconf:errors']['error'][0]['error-type'] == 'application'
- result_msg['ietf-restconf:errors']['error'][0]['error-tag'] == 'invalid-value'
register: assert_result
ignore_errors: yes

- ansible.builtin.include_tasks: image_management.test.facts.report.yml
vars:
test_case_name: 'image_verify_pki_02'
test_case_input:
image:
command: 'verify'
verifymethod: 'pki'
path: 'home://sonic-verify.bin'
signaturefile: 'home://sign.gpg'
pubkeyfilename: 'home://DellOS10.cert.pem'
2 changes: 2 additions & 0 deletions tests/regression/roles/sonic_image_management/tasks/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
- ansible.builtin.include_tasks: image_set_default.yml
- ansible.builtin.include_tasks: image_get_list.yml
- ansible.builtin.include_tasks: image_get_status.yml
- ansible.builtin.include_tasks: image_gpg.yml
- ansible.builtin.include_tasks: image_verify.yml

- ansible.builtin.include_tasks: patch_install.yml
- ansible.builtin.include_tasks: patch_rollback.yml
Expand Down
Loading

0 comments on commit 14a07d4

Please sign in to comment.