cloudbase-init/cloudbaseinit/metadata/services/vmwareguestinfoservice.py

174 lines
5.9 KiB
Python

# Copyright 2020 Cloudbase Solutions Srl
# Copyright 2019 ruilopes.com
#
# 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.
import base64
import gzip
import io
import os
from oslo_log import log as oslo_logging
from cloudbaseinit import conf as cloudbaseinit_conf
from cloudbaseinit import exception
from cloudbaseinit.metadata.services import base
from cloudbaseinit.metadata.services import nocloudservice
from cloudbaseinit.osutils import factory as osutils_factory
from cloudbaseinit.utils import serialization
CONF = cloudbaseinit_conf.CONF
LOG = oslo_logging.getLogger(__name__)
class VMwareGuestInfoService(base.BaseMetadataService):
def __init__(self):
super(VMwareGuestInfoService, self).__init__()
self._rpc_tool_path = None
self._osutils = osutils_factory.get_os_utils()
self._meta_data = {}
self._user_data = None
@staticmethod
def _decode_data(raw_data, is_base64, is_gzip):
"""Decode raw_data from base64 / ungzip"""
if not raw_data:
return
if is_base64:
raw_data = base64.b64decode(raw_data)
if is_gzip:
with gzip.GzipFile(fileobj=io.BytesIO(raw_data), mode='rb') as dt:
raw_data = dt.read()
return raw_data
def _get_guestinfo_value(self, key):
rpc_command = 'info-get guestinfo.%s' % key
data, stderr, exit_code = self._osutils.execute_process([
self._rpc_tool_path,
rpc_command
])
if exit_code:
LOG.debug(
'Failed to execute "%(rpctool_path)s \'%(rpc_command)s\'" '
'with exit code: %(exit_code)s\nstdout: '
'%(stdout)s\nstderr: %(stderr)s' % {
'rpctool_path': self._rpc_tool_path,
'rpc_command': rpc_command, 'exit_code': exit_code,
'stdout': data, 'stderr': stderr})
return
return data
def _get_guest_data(self, key):
is_base64 = False
is_gzip = False
encoding_plain_text = 'plaintext'
raw_data = self._get_guestinfo_value(key)
raw_encoding = self._get_guestinfo_value("%s.encoding" % key)
if not raw_encoding or not raw_encoding.strip():
raw_encoding = encoding_plain_text
encoding = raw_encoding.strip()
if isinstance(encoding, bytes):
encoding = encoding.decode("utf-8")
if encoding in ('gzip+base64', 'gz+b64'):
is_gzip = True
is_base64 = True
elif encoding in ('base64', 'b64'):
is_base64 = True
elif encoding != encoding_plain_text:
raise exception.CloudbaseInitException(
"Encoding %s not supported" % encoding)
LOG.debug("Decoding key %s: encoding %s", key, encoding)
return self._decode_data(raw_data, is_base64, is_gzip)
def load(self):
super(VMwareGuestInfoService, self).load()
if not CONF.vmwareguestinfo.vmware_rpctool_path:
LOG.info("rpctool_path is empty. "
"Please provide a value for VMware rpctool path.")
return False
self._rpc_tool_path = os.path.abspath(
os.path.expandvars(CONF.vmwareguestinfo.vmware_rpctool_path))
if not os.path.exists(self._rpc_tool_path):
LOG.info("%s does not exist. "
"Please provide a valid value for VMware rpctool path."
% self._rpc_tool_path)
return False
self._meta_data = serialization.parse_json_yaml(
self._get_guest_data('metadata'))
if not isinstance(self._meta_data, dict):
LOG.warning("Instance metadata is not a dictionary.")
self._meta_data = {}
self._user_data = self._get_guest_data('userdata')
if self._meta_data or self._user_data:
return True
def _get_data(self, path):
pass
def get_instance_id(self):
return self._meta_data.get('instance-id')
def get_user_data(self):
return self._user_data
def get_host_name(self):
return self._meta_data.get('local-hostname')
def get_public_keys(self):
public_keys = []
public_keys_data = self._meta_data.get('public-keys-data')
if public_keys_data:
public_keys = public_keys_data.splitlines()
return list(set((key.strip() for key in public_keys)))
def get_admin_username(self):
return self._meta_data.get('admin-username')
def get_admin_password(self):
return self._meta_data.get('admin-password')
def get_network_details_v2(self):
network_data = self._meta_data.get('network')
if not network_data:
LOG.info("No network configuration found in metadata")
return
if 'version' not in network_data:
LOG.error("No network version information found in metadata")
return
network_data_version = network_data.get('version')
if network_data_version != 1:
LOG.error("Network data version '%s' is not supported",
network_data_version)
return
if 'config' not in network_data:
LOG.error("Network configuration does not exist")
return
network_config_parser = nocloudservice.NoCloudNetworkConfigV1Parser()
return network_config_parser.parse(network_data.get("config"))