2
0
mirror of https://github.com/xcat2/xcat-core.git synced 2025-05-22 19:52:03 +00:00
2018-02-01 13:36:22 +08:00

228 lines
7.5 KiB
Python

#!/usr/bin/env python
###############################################################################
# IBM(c) 2018 EPL license http://www.eclipse.org/legal/epl-v10.html
###############################################################################
# -*- coding: utf-8 -*-
#
import requests
import json
import time
from common import rest
from common.exceptions import SelfClientException, SelfServerException
import logging
logger = logging.getLogger('xcatagent')
HTTP_PROTOCOL = "https://"
PROJECT_URL = "/xyz/openbmc_project"
PROJECT_PAYLOAD = "xyz.openbmc_project."
RPOWER_STATES = {
"on" : "on",
"off" : "off",
"Off" : "off",
"softoff" : "softoff",
"boot" : "reset",
"reset" : "reset",
"bmcreboot" : "BMC reboot",
"Ready" : "BMC Ready",
"NotReady" : "BMC NotReady",
"chassison" : "on (Chassis)",
"Running" : "on",
"Quiesced" : "quiesced",
}
RPOWER_URLS = {
"on" : {
"path" : "/state/host0/attr/RequestedHostTransition",
"field" : "State.Host.Transition.On",
},
"off" : {
"path" : "/state/chassis0/attr/RequestedPowerTransition",
"field" : "State.Chassis.Transition.Off",
},
"softoff" : {
"path" : "/state/host0/attr/RequestedHostTransition",
"field" : "State.Host.Transition.Off",
},
"state" : {
"path" : "/state/enumerate",
},
}
BMC_URLS = {
"reboot" : {
"path" : "/state/bmc0/attr/RequestedBMCTransition",
"field" : "State.BMC.Transition.Reboot",
},
"state" : {
"path" : "/state/bmc0/attr/CurrentBMCState",
},
}
RESULT_OK = 'ok'
RESULT_FAIL = 'fail'
class OpenBMCRest(object):
headers = {'Content-Type': 'application/json'}
def __init__(self, name, **kwargs):
#set default user/passwd
self.name = name
self.username, self.password = ('root', '0penBmc')
if 'nodeinfo' in kwargs:
for key, value in kwargs['nodeinfo'].items():
setattr(self, key, value)
if not hasattr(self, 'bmcip'):
self.bmcip = self.name
self.verbose = kwargs.get('debugmode')
# print back to xcatd or just stdout
self.messager = kwargs.get('messager')
self.session = rest.RestSession()
self.root_url = HTTP_PROTOCOL + self.bmcip + PROJECT_URL
def _print_record_log (self, msg, cmd):
if self.verbose :
localtime = time.asctime( time.localtime(time.time()) )
log = self.name + ': [openbmc_debug] ' + cmd + ' ' + msg
self.messager.info(localtime + ' ' + log)
logger.debug(log)
def _log_request (self, method, url, headers, data=None, files=None, cmd=''):
header_str = ' '.join([ "%s: %s" % (k, v) for k,v in headers.items() ])
msg = 'curl -k -c cjar -b cjar -X %s -H \"%s\" ' % (method, header_str)
if files:
msg += '-T \'%s\' %s -s' % (files, url)
elif data:
if cmd == 'login':
data = data.replace(self.password, "xxxxxx")
msg += '%s -d \'%s\'' % (url, data)
else:
msg += url
self._print_record_log(msg, cmd)
return msg
def handle_response (self, resp, cmd=''):
data = resp.json() # it will raise ValueError
code = resp.status_code
if code != requests.codes.ok:
description = ''.join(data['data']['description'])
error = 'Error: [%d] %s' % (code, description)
self._print_record_log(error, cmd)
raise SelfClientException(error, code)
self._print_record_log(data['message'], cmd)
return data['data']
def request (self, method, resource, headers=None, payload=None, timeout=30, cmd=''):
httpheaders = headers or OpenBMCRest.headers
url = resource
if not url.startswith(HTTP_PROTOCOL):
url = self.root_url + resource
data = None
if payload:
data=json.dumps(payload)
self._log_request(method, url, httpheaders, data=data, cmd=cmd)
try:
response = self.session.request(method, url, httpheaders, data=data)
return self.handle_response(response, cmd=cmd)
except SelfServerException as e:
e.message = 'Error: BMC did not respond. ' \
'Validate BMC configuration and retry the command.'
self._print_record_log(e.message, cmd)
raise
except ValueError:
error = 'Error: Received wrong format response: %s' % response
self._print_record_log(error, cmd)
raise SelfServerException(error)
def upload (self, method, resource, files, headers=None, cmd=''):
httpheaders = headers or OpenBMCRest.headers
url = resource
if not url.startswith(HTTP_PROTOCOL):
url = self.root_url + resource
request_cmd = self._log_request(method, url, httpheaders, files=files, cmd=cmd)
try:
response = self.session.request_upload(method, url, httpheaders, files)
except SelfServerException:
self._print_record_log(error, cmd=cmd)
raise
try:
data = json.loads(response)
except ValueError:
error = 'Error: Received wrong format response when running command \'%s\': %s' % \
(request_cmd, response)
self._print_record_log(error, cmd=cmd)
raise SelfServerException(error)
if data['message'] != '200 OK':
error = 'Error: Failed to upload update file %s : %s-%s' % \
(files, data['message'], \
''.join(data['data']['description']))
self._print_record_log(error, cmd=cmd)
raise SelfClientException(error, code)
self._print_record_log(data['message'], cmd=cmd)
return True
def login(self):
payload = { "data": [ self.username, self.password ] }
url = HTTP_PROTOCOL + self.bmcip + '/login'
self.request('POST', url, payload=payload, timeout=20, cmd='login')
def list_power_states(self):
states = self.request('GET', RPOWER_URLS['state']['path'], cmd='list_power_states')
#filter non used states
try:
host_stat = states[PROJECT_URL + '/state/host0']['CurrentHostState']
chassis_stat = states[PROJECT_URL + '/state/chassis0']['CurrentPowerState']
return {'host': host_stat.split('.')[-1], 'chassis': chassis_stat.split('.')[-1]}
except KeyError:
error = 'Error: Received wrong format response: %s' % states
raise SelfServerException(error)
def set_power_state(self, state):
payload = { "data": PROJECT_PAYLOAD + RPOWER_URLS[state]['field'] }
return self.request('PUT', RPOWER_URLS[state]['path'], payload=payload, cmd='set_power_state')
def get_bmc_state(self):
state = self.request('GET', BMC_URLS['state']['path'], cmd='get_bmc_state')
try:
return {'bmc': state.split('.')[-1]}
except KeyError:
error = 'Error: Received wrong format response: %s' % state
raise SelfServerException(error)
def reboot_bmc(self, optype='warm'):
payload = { "data": PROJECT_PAYLOAD + BMC_URLS['reboot']['field'] }
try:
self.request('PUT', BMC_URLS['reboot']['path'], payload=payload, cmd='bmc_reset')
except SelfServerException,SelfClientException:
# TODO: Need special handling for bmc reset, as it is normal bmc may return error
pass