240 lines
7.0 KiB
Python
Executable File
240 lines
7.0 KiB
Python
Executable File
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
# License for the specific language governing permissions and limitations
|
|
# under the License.
|
|
#
|
|
# Copyright (c) 2014 Wind River Systems, Inc.
|
|
#
|
|
# The right to copy, distribute, modify, or otherwise make use
|
|
# of this software may be licensed only pursuant to the terms
|
|
# of an applicable Wind River license agreement.
|
|
#
|
|
|
|
import logging
|
|
import urlparse
|
|
|
|
import requests
|
|
|
|
from openstack_dashboard.api import base
|
|
from requests_toolbelt import MultipartEncoder
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class Client(object):
|
|
def __init__(self, version, url, token_id):
|
|
self.version = version
|
|
self.url = url
|
|
self.token_id = token_id
|
|
|
|
def _make_request(self, token_id, method, api_version, api_cmd,
|
|
encoder=None):
|
|
url = self.url
|
|
url += "/%s/%s" % (api_version, api_cmd)
|
|
# url += "/patch/%s" % (api_cmd)
|
|
|
|
headers = {"X-Auth-Token": token_id,
|
|
"Accept": "application/json"}
|
|
|
|
if method == 'GET':
|
|
req = requests.get(url, headers=headers)
|
|
elif method == 'POST':
|
|
if encoder is not None:
|
|
headers['Content-Type'] = encoder.content_type
|
|
req = requests.post(url, headers=headers, data=encoder)
|
|
|
|
resp = req.json()
|
|
|
|
return resp
|
|
|
|
def get_patches(self):
|
|
return self._make_request(self.token_id, "GET", self.version,
|
|
"query?show=all")
|
|
|
|
def show_patch(self, patch_id):
|
|
return self._make_request(self.token_id, "GET", self.version,
|
|
"show/%s" % patch_id)
|
|
|
|
def get_hosts(self):
|
|
return self._make_request(self.token_id, "GET", self.version,
|
|
"query_hosts")
|
|
|
|
def upload(self, file):
|
|
encoder = MultipartEncoder(fields=file)
|
|
return self._make_request(self.token_id, "POST", self.version,
|
|
"upload", encoder=encoder)
|
|
|
|
def apply(self, patch_ids):
|
|
patches = "/".join(patch_ids)
|
|
return self._make_request(self.token_id, "POST", self.version,
|
|
"apply/%s" % patches)
|
|
|
|
def remove(self, patch_ids):
|
|
patches = "/".join(patch_ids)
|
|
return self._make_request(self.token_id, "POST", self.version,
|
|
"remove/%s" % patches)
|
|
|
|
def delete(self, patch_ids):
|
|
patches = "/".join(patch_ids)
|
|
return self._make_request(self.token_id, "POST", self.version,
|
|
"delete/%s" % patches)
|
|
|
|
def host_install(self, host):
|
|
return self._make_request(self.token_id, "POST", self.version,
|
|
"host_install/%s" % host)
|
|
|
|
def host_install_async(self, host):
|
|
return self._make_request(self.token_id, "POST", self.version,
|
|
"host_install_async/%s" % host)
|
|
|
|
|
|
def _patching_client(request):
|
|
o = urlparse.urlparse(base.url_for(request, 'patching'))
|
|
url = "://".join((o.scheme, o.netloc))
|
|
return Client("v1", url, token_id=request.user.token.id)
|
|
|
|
|
|
class Patch(object):
|
|
_attrs = ['status',
|
|
'sw_version',
|
|
'install_instructions',
|
|
'description',
|
|
'warnings',
|
|
'summary',
|
|
'repostate',
|
|
'patchstate',
|
|
'requires',
|
|
'unremovable',
|
|
'reboot_required']
|
|
|
|
|
|
class Host(object):
|
|
_attrs = ['hostname',
|
|
'installed',
|
|
'ip',
|
|
'missing_pkgs',
|
|
'nodetype',
|
|
'patch_current',
|
|
'patch_failed',
|
|
'requires_reboot',
|
|
'secs_since_ack',
|
|
'stale_details',
|
|
'to_remove',
|
|
'sw_version',
|
|
'state',
|
|
'allow_insvc_patching',
|
|
'interim_state']
|
|
|
|
|
|
def get_patches(request):
|
|
patches = []
|
|
try:
|
|
info = _patching_client(request).get_patches()
|
|
except Exception:
|
|
return patches
|
|
|
|
if info:
|
|
for p in info['pd'].iteritems():
|
|
patch = Patch()
|
|
|
|
for a in patch._attrs:
|
|
if a == 'requires':
|
|
patch.requires = [str(rp) for rp in p[1][a]]
|
|
continue
|
|
|
|
if a == 'reboot_required':
|
|
# Default to "N"
|
|
setattr(patch, a, str(p[1].get(a, "N")))
|
|
continue
|
|
|
|
# Must handle older patches that have metadata that is missing
|
|
# newer attributes. Default missing attributes to "".
|
|
setattr(patch, a, str(p[1].get(a, "")))
|
|
patch.patch_id = str(p[0])
|
|
|
|
patches.append(patch)
|
|
return patches
|
|
|
|
|
|
def get_patch(request, patch_id):
|
|
patches = get_patches(request)
|
|
patch = next((p for p in patches if p.patch_id == patch_id), None)
|
|
|
|
# add on patch contents
|
|
data = _patching_client(request).show_patch(patch_id)
|
|
patch.contents = [str(pkg) for pkg in data['contents'][patch_id]]
|
|
|
|
return patch
|
|
|
|
|
|
def get_hosts(request):
|
|
hosts = []
|
|
try:
|
|
info = _patching_client(request).get_hosts()
|
|
except Exception:
|
|
return hosts
|
|
|
|
if info:
|
|
for h in info['data']:
|
|
host = Host()
|
|
for a in host._attrs:
|
|
setattr(host, a, h[a])
|
|
hosts.append(host)
|
|
return hosts
|
|
|
|
|
|
def get_host(request, hostname):
|
|
phosts = get_hosts(request)
|
|
return next((phost for phost in phosts if phost.hostname == hostname),
|
|
None)
|
|
|
|
|
|
def get_message(data):
|
|
LOG.info("RESPONSE: %s", data)
|
|
if not data or ('error' in data and data["error"] != ""):
|
|
raise ValueError(data["error"] or "Invalid patch file")
|
|
if 'warning' in data and data["warning"] != "":
|
|
return data["warning"]
|
|
if 'info' in data and data["info"] != "":
|
|
return data["info"]
|
|
return ""
|
|
|
|
|
|
def upload_patch(request, patchfile, name):
|
|
file = {'file': (name, patchfile,)}
|
|
resp = _patching_client(request).upload(file)
|
|
return get_message(resp)
|
|
|
|
|
|
def patch_apply_req(request, patch_id):
|
|
resp = _patching_client(request).apply(patch_id)
|
|
return get_message(resp)
|
|
|
|
|
|
def patch_remove_req(request, patch_id):
|
|
resp = _patching_client(request).remove(patch_id)
|
|
return get_message(resp)
|
|
|
|
|
|
def patch_delete_req(request, patch_id):
|
|
resp = _patching_client(request).delete(patch_id)
|
|
return get_message(resp)
|
|
|
|
|
|
def host_install(request, hostname):
|
|
resp = _patching_client(request).host_install(hostname)
|
|
return get_message(resp)
|
|
|
|
|
|
def host_install_async(request, hostname):
|
|
resp = _patching_client(request).host_install_async(hostname)
|
|
return get_message(resp)
|