Skip to content

Commit

Permalink
InstallFromRepository support for firmware update
Browse files Browse the repository at this point in the history
  • Loading branch information
felixs88 committed Oct 18, 2019
1 parent 76619c7 commit 756d7ab
Show file tree
Hide file tree
Showing 6 changed files with 135 additions and 70 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ Dell EMC OpenManage Python SDK is supported for python 2.7 and above.
```
git clone https://github.com/dell/omsdk.git
cd omsdk
sh build.sh 1.2 379
sh build.sh 1.2 387
cd dist
pip install omsdk-1.2.379-py2.py3-none-any.whl
pip install omsdk-1.2.387-py2.py3-none-any.whl
```

* Upgrading to latest version of python setuptools is recommended.
Expand All @@ -39,7 +39,7 @@ Dell EMC OpenManage Python SDK is supported for python 2.7 and above.

* Downgrade pip version to lower than 10.0 and then install omsdk
* Force install omsdk using:
```pip install --ignore-installed omsdk-1.2.379-py2.py3-none-any.whl```
```pip install --ignore-installed omsdk-1.2.387-py2.py3-none-any.whl```
# Uninstallation
* Uninstall this module as follows:
Expand Down
40 changes: 40 additions & 0 deletions omdrivers/enums/iDRAC/iDRACEnums.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,41 @@
'HTTPS': 6
}).enum_type

IFRShareTypeEnum = EnumWrapper('IFRShareTypeEnum', {
'nfs': 'NFS',
'cifs': 'CIFS',
'ftp': 'FTP',
'http': 'HTTP',
'https': 'HTTPS',
'tftp': 'TFTP'
}).enum_type

ApplyUpdateEnum = EnumWrapper('ApplyUpdateEnum', {
'True': 'True',
'False': 'False'
}).enum_type

URLApplyUpdateEnum = EnumWrapper('URLApplyUpdateEnum', {
'True': 1,
'False': 0
}).enum_type

RebootEnum = EnumWrapper('RebootEnum', {
'True': 'TRUE',
'False': 'FALSE'
}).enum_type

URLShareTypeEnum = EnumWrapper('URLShareTypeEnum', {
'ftp': 1,
'http': 3,
'https': 6
}).enum_type

URLCertWarningEnum = EnumWrapper('URLCertWarningEnum', {
'True': 2,
'False': 1
}).enum_type

VideoLogsFileTypeEnum = EnumWrapper("VideoLogsFileTypeEnum", {
'Boot_Capture': 1,
'Crash_Capture': 2
Expand Down Expand Up @@ -323,6 +358,11 @@
'On': 2
}).enum_type

IgnoreCertWarnEnum = EnumWrapper('IgnoreCertWarnEnum', {
'Off': 'Off',
'On': 'On'
}).enum_type

EndHostPowerStateEnum = EnumWrapper('EndHostPowerStateEnum', {
'Off': 'Off',
'On': 'On'
Expand Down
58 changes: 43 additions & 15 deletions omdrivers/lifecycle/iDRAC/iDRACConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ def format_enum_wsman(enval):
return 0


# noinspection PyInterpreter
iDRACWsManCmds = {
###### LC Services
"_lc_status": {
Expand Down Expand Up @@ -1265,14 +1266,8 @@ def format_enum_wsman(enval):
("CatalogFile", "catalog", None, type("Catalog.xml"), None),
("ApplyUpdate", "apply", None, type(0), None), # 0 - report, 1 - apply
("RebootNeeded", "reboot", None, type("TRUE"), None),
# ("ProxyPort", "proxy", 'port', type(100), None),
# ("ProxyType", "proxy", 'type', type("1"), None),
# ("ProxySupport", "proxy", 'support', type("3"), None), # 1-off, 2-user default proxy 3-passed in params
# ("ProxyUName", "proxy_creds", 'username', type("user"), None),
# ("ProxyPasswd", "proxy_creds", 'password', type("password"), None),
]
},

"_update_repo_nfs": {
"ResourceURI": "http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_SoftwareInstallationService",
"Action": "InstallFromRepository",
Expand All @@ -1285,6 +1280,7 @@ def format_enum_wsman(enval):
]},
"Args": {
"share": FileOnShare,
"creds": UserCredentials,
"catalog": str,
"apply": int,
"reboot": str
Expand All @@ -1297,19 +1293,11 @@ def format_enum_wsman(enval):
('ShareName', "share", 'remote_share_name', type("\\test"), None),
('ShareType', "share", 'remote_share_type', Share.ShareType, None),
('FileName', "share", 'remote_file_name', type("filename"), None),
# ("Username", "creds", 'username', type("user"), None),
# ("Password", "creds", 'password', type("password"), None),
("CatalogFile", "catalog", None, type("Catalog.xml"), None),
("ApplyUpdate", "apply", None, type(0), None), # 0 - report, 1 - apply
("RebootNeeded", "reboot", None, type("TRUE"), None),
# ("ProxyPort", "proxy", 'port', type(100), None),
# ("ProxyType", "proxy", 'type', type("1"), None),
# ("ProxySupport", "proxy", 'support', type("3"), None), # 1-off, 2-user default proxy 3-passed in params
# ("ProxyUName", "proxy_creds", 'username', type("user"), None),
# ("ProxyPasswd", "proxy_creds", 'password', type("password"), None),
]
},

"_update_repo_url": {
"ResourceURI": "http://schemas.dell.com/wbem/wscim/1/cim-schema/2/DCIM_SoftwareInstallationService",
"Action": "InstallFromRepository",
Expand Down Expand Up @@ -1354,6 +1342,46 @@ def format_enum_wsman(enval):
]
},

"_update_from_repo_using_redfish": {
"ResourceURI": "/redfish/v1/Dell/Systems/System.Embedded.1/DellSoftwareInstallationService/Actions/DellSoftwareInstallationService",
"Action": "InstallFromRepository",
"HttpMethod": "post",
"SuccessCode": [202],
"ReturnsJobid": True,
"Args": {
"ipaddress": str,
"share_name": str,
"share_type": IFRShareTypeEnum,
"username": str,
"password": str,
"catalog_file": str,
"apply_update": ApplyUpdateEnum,
"reboot_needed": bool,
"ignore_cert_warning": IgnoreCertWarnEnum
},
"Return": { "File": "file" },
"Parameters": [
('IPAddress', 'ipaddress', None, str, None),
('ShareName', 'share_name', None, str, None),
('ShareType', 'share_type', None, IFRShareTypeEnum, None),
('UserName', 'username', None, str, None),
('Password', 'password', None, str, None),
('RebootNeeded', 'reboot_needed', None, bool, None),
('CatalogFile', 'catalog_file', None, type('Catalog.xml'), None),
('ApplyUpdate', 'apply_update', None, ApplyUpdateEnum, None),
('IgnoreCertWarning', 'ignore_cert_warning', None, IgnoreCertWarnEnum, None)
]
},

"_get_update_from_repo_list_using_redfish": {
"ResourceURI": "/redfish/v1/Dell/Systems/System.Embedded.1/DellSoftwareInstallationService/Actions/DellSoftwareInstallationService",
"Action": "GetRepoBasedUpdateList",
"HttpMethod": "post",
"SuccessCode": [200],
"ReturnsJobid": False,
"Args": {},
"Parameters": []
},

##############
##### End Update Management
Expand Down Expand Up @@ -2169,7 +2197,7 @@ def format_enum_wsman(enval):
('ShareParameters/ShareType', "share", "remote_share_type_redfish", Share.ShareTypeRedfish, None),
('ShareParameters/FileName', "share", "remote_file_name", type("filename"), None),
('ShareParameters/UserName', "creds", "username", type("user"), None),
('ShareParameters/Username', "creds", "username", type("user"), None), # workaround solution(JIT-132580):
('ShareParameters/Username', "creds", "username", type("user"), None), # workaround solution(JIT-132580):
# Need to adhere with REDFish schema, 14G server changes has reflected.
# For 12G, 13G changes will be reflected september 2019 onwards.
('ShareParameters/Password', "creds", "password", type("password"), None),
Expand Down
2 changes: 1 addition & 1 deletion omdrivers/lifecycle/iDRAC/iDRACJobs.py
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ def get_job_status_redfish(self, jobid):
return jobdetail

jobdetail_data = jobdetail['Data']['Jobs']
if jobdetail_data['PercentComplete'] < 100:
if (jobdetail_data['PercentComplete'] < 100) or (100 < jobdetail_data['PercentComplete']):
jobstaten = JobStatusEnum.InProgress
elif jobdetail_data['JobState'] == 'Completed':
jobstaten = self.get_job_status_by_msgid(jobdetail_data['MessageId'])
Expand Down
93 changes: 44 additions & 49 deletions omdrivers/lifecycle/iDRAC/iDRACUpdate.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,6 @@ def serialize_inventory(self, myshare):
sort_keys=True, indent=4, separators=(',', ': ')))

def update_from_repo(self, catalog_path, apply_update=True, reboot_needed=False, job_wait=True):
appUpdateLookup = {True: 1, False: 0}
rebootLookup = {True: "TRUE", False: "FALSE"}
appUpdate = appUpdateLookup[apply_update]
rebootNeeded = rebootLookup[reboot_needed]

if isinstance(catalog_path, str):
# Catalog name
updmgr = UpdateManager.get_instance()
Expand All @@ -252,64 +247,60 @@ def update_from_repo(self, catalog_path, apply_update=True, reboot_needed=False,
else:
# DRM Repo
cache_share = catalog_path
catalog_dir = FileOnShare(remote=cache_share.remote_folder_path,
isFolder=True, creds=cache_share.creds)
catalog_dir = FileOnShare(remote=cache_share.remote_folder_path, isFolder=True, creds=cache_share.creds)
catalog_file = cache_share.remote_file_name

if self.entity.use_redfish:
if isinstance(catalog_path, FileOnShare) and catalog_path.mount_point is None:
logger.error("Share path or mount point does not exist")
raise ValueError("Share path or mount point does not exist")
return self.update_from_repo_usingscp_redfish(catalog_dir, catalog_file,
mount_point=catalog_path.mount_point.mountable_path,
reboot_needed=reboot_needed, job_wait=job_wait)

rjson = self.entity._update_from_repo_using_redfish(ipaddress=catalog_dir.remote_ipaddr,
share_name=catalog_dir.remote.share_name,
share_type=IFRShareTypeEnum[catalog_dir.remote_share_type.name.lower()],
username=catalog_dir.creds.username,
password=catalog_dir.creds.password,
reboot_needed=reboot_needed,
catalog_file=catalog_file,
apply_update=ApplyUpdateEnum[str(apply_update)],
ignore_cert_warning=IgnoreCertWarnEnum['On'])
if TypeHelper.resolve(catalog_dir.remote_share_type) == TypeHelper.resolve(ShareTypeEnum.NFS):
rjson = self.entity._update_repo_nfs(share=catalog_dir,
catalog=catalog_file,
apply=appUpdate, reboot=rebootNeeded)
rjson = self.entity._update_repo_nfs(share=catalog_dir, creds=catalog_dir.creds, catalog=catalog_file,
apply=URLApplyUpdateEnum[str(apply_update)].value,
reboot=RebootEnum[str(reboot_needed)].value)
else:
rjson = self.entity._update_repo(share=catalog_dir,
creds=catalog_dir.creds, catalog=catalog_file,
apply=appUpdate, reboot=rebootNeeded)

rjson = self.entity._update_repo(share=catalog_dir, creds=catalog_dir.creds, catalog=catalog_file,
apply=URLApplyUpdateEnum[str(apply_update)].value,
reboot=RebootEnum[str(reboot_needed)].value)
rjson['file'] = str(cache_share)
if job_wait:
rjson = self._job_mgr._job_wait(rjson['file'], rjson)
if apply_update and rjson['Status'] == 'Success' and not self.entity.use_redfish:
rjson['job_details'] = self.entity._update_get_repolist()
return rjson

def update_from_repo_url(self, ipaddress, share_type, share_name,
share_user, share_pwd, catalog_file,
apply_update=True, reboot_needed=False,
def update_from_repo_url(self, ipaddress=None, share_type=None, share_name=None, share_user=None,
share_pwd=None, catalog_file="Catalog.xml", apply_update=True, reboot_needed=False,
ignore_cert_warning=True, job_wait=True):

appUpdateLookup = {True: 1, False: 0}
rebootLookup = {True: "TRUE", False: "FALSE"}
ignoreCertWarnLookup = {True: 2, False: 1}
shareTypeLookup = {"ftp": 1, "http": 3, "https": 6}

appUpdate = appUpdateLookup[apply_update]
rebootNeeded = rebootLookup[reboot_needed]
ignoreCertWarn = ignoreCertWarnLookup[ignore_cert_warning]

rjson = self.entity._update_repo_url(
ipaddress=ipaddress,
share_type=shareTypeLookup[share_type],
share_name=share_name,
# username=share_user, password=share_pwd,
catalog_file=catalog_file, apply_update=appUpdate,
reboot_needed=rebootNeeded,
ignore_cert_warning=ignoreCertWarn)

# re-create url from share_type, share_name and catalog file
rjson['file'] = share_type + "://" + ipaddress + share_name + "/" + catalog_file

if self.entity.use_redfish:
warning = IgnoreCertWarnEnum["On"] if ignore_cert_warning else IgnoreCertWarnEnum["Off"]
rjson = self.entity._update_from_repo_using_redfish(ipaddress=ipaddress, share_name=share_name,
share_type=IFRShareTypeEnum[share_type],
username=share_user, password=share_pwd,
reboot_needed=reboot_needed, catalog_file=catalog_file,
apply_update=ApplyUpdateEnum[str(apply_update)],
ignore_cert_warning=warning.value)
else:
rjson = self.entity._update_repo_url(ipaddress=ipaddress, share_type=URLShareTypeEnum[share_type].value,
share_name=share_name, catalog_file=catalog_file,
apply_update=URLApplyUpdateEnum[str(apply_update)].value,
reboot_needed=RebootEnum[str(reboot_needed)].value,
ignore_cert_warning=URLCertWarningEnum[str(ignore_cert_warning)].value)
file_format = "{0}://{1}/{2}/{3}" if share_name else "{0}://{1}{2}/{3}"
rjson['file'] = file_format.format(share_type, ipaddress, share_name, catalog_file)
if job_wait:
rjson = self._job_mgr._job_wait(rjson['file'], rjson)

if apply_update and rjson['Status'] == 'Success' and not self.entity.use_redfish:
rjson['job_details'] = self.entity._update_get_repolist()
return rjson


##below methods to update firmware using redfish will be reimplemented using Type Manager system
def _get_scp_path(self, catalog_dir):
"""
Expand All @@ -334,7 +325,7 @@ def update_from_repo_usingscp_redfish(self, catalog_dir, catalog_file, mount_poi
:param catalog_file: str.
:param mount_point: local share on which remote(catalog_dir) folder has been mounted
:param mount_point: str.
:returns: returns status of firmare update through scp
:returns: returns status of firmware update through scp
"""
(scp_path, scp_file) = self._get_scp_path(catalog_dir)
Expand All @@ -344,13 +335,17 @@ def update_from_repo_usingscp_redfish(self, catalog_dir, catalog_file, mount_poi
if 'Status' not in rjson or rjson['Status'] != 'Success':
return {'Status': 'Failed', 'Message': 'Export of scp failed for firmware update'}
scpattrval = {'RepositoryUpdate': catalog_file}
localfile = mount_point + os.path.sep + scp_file
localfile = mount_point.share_path + os.path.sep + scp_file
self.edit_xml_file(localfile, scpattrval)
if reboot_needed:
shutdown = ShutdownTypeEnum.Graceful
else:
shutdown = ShutdownTypeEnum.NoReboot
rjson = self.entity.config_mgr.scp_import(share_path=myshare, shutdown_type=shutdown, job_wait=job_wait)
if job_wait:
rjson['file'] = localfile
rjson = self._job_mgr._job_wait(rjson['file'], rjson)
rjson['job_details'] = self.entity._update_get_repolist()
return rjson

def edit_xml_file(self, file_location, attr_val_dict):
Expand Down
6 changes: 4 additions & 2 deletions omsdk/http/sdkwsmanbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def _pack_http_method_args(self, resource_path, http_headers, http_body=None, ht
method_args['body'] = http_body
return method_args

def _pack_rest_method_args(self, auth, verify=False, data=None, headers=None):
def _pack_rest_method_args(self, auth, verify=False, data={}, headers=None):
"""Pack the arguments required for the rest methods (post/get/put/patch ...) as a key value pair in a dictionary
:param auth: authentication object.
Expand All @@ -231,8 +231,10 @@ def _pack_rest_method_args(self, auth, verify=False, data=None, headers=None):
method_args['verify'] = verify
if headers:
method_args['headers'] = headers
if data:
if data is not None:
method_args['data'] = json.dumps(data)
else:
method_args['data'] = '{}'
return method_args

def _get_base_url(self, ipaddr, resouce_path, port=443):
Expand Down

0 comments on commit 756d7ab

Please sign in to comment.