Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions cloudbaseinit/conf/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ def __init__(self, config):
default=[
'cloudbaseinit.metadata.services.httpservice.HttpService',
'cloudbaseinit.metadata.services'
'.vmwareguestinfoservice.VMwareGuestInfoService',
'cloudbaseinit.metadata.services'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this metadata service should not be put as a default service, as it will degrade the performance (cloudbase-init runs mostly on openstack).

'.configdrive.ConfigDriveService',
'cloudbaseinit.metadata.services.ec2service.EC2Service',
'cloudbaseinit.metadata.services'
Expand Down
1 change: 1 addition & 0 deletions cloudbaseinit/conf/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
'cloudbaseinit.conf.openstack.OpenStackOptions',
'cloudbaseinit.conf.azure.AzureOptions',
'cloudbaseinit.conf.ovf.OvfOptions',
'cloudbaseinit.conf.vmwareguestinfo.VMwareGuestInfoConfigOptions',
)


Expand Down
41 changes: 41 additions & 0 deletions cloudbaseinit/conf/vmwareguestinfo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# 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.

"""Config options available for the VMwareGuestInfo metadata service."""

from oslo_config import cfg

from cloudbaseinit.conf import base as conf_base

class VMwareGuestInfoConfigOptions(conf_base.Options):
"""Config options available for the VMwareGuestInfo metadata service."""

def __init__(self, config):
super(VMwareGuestInfoConfigOptions, self).__init__(config, group='vmwareguestinfo')
self._options = [
cfg.StrOpt(
'rpctool_path',
default='C:/Program Files/VMware/VMware Tools/rpctool.exe',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this tool get installed when the vmware tools is installed on windows?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

help='VMware Tools rpctool.exe path'),
]

def register(self):
"""Register the current options to the global ConfigOpts object."""
group = cfg.OptGroup(self.group_name, title="VMwareGuestInfo Config Options")
self._config.register_group(group)
self._config.register_opts(self._options, group=group)

def list(self):
"""Return a list which contains all the available options."""
return self._options
151 changes: 151 additions & 0 deletions cloudbaseinit/metadata/services/vmwareguestinfoservice.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# 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 json
import os

from cloudbaseinit import conf as cloudbaseinit_conf
from cloudbaseinit import exception
from cloudbaseinit.metadata.services import base
from cloudbaseinit.osutils import factory as osutils_factory

CONF = cloudbaseinit_conf.CONF

class VMwareGuestInfoService(base.BaseMetadataService):
"""
This uses the VMware Guest Info interface to obtain the cloud init data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All this information should go into the docs, in the services page.

from the VM extraconfig guestinfo properties using the VMware Tools
rpctool cli application.
You can use the following guestinfo properties:
+--------------------+------------------------------------------------------+
| property | description |
+--------------------+------------------------------------------------------+
| guestinfo.metadata | A JSON document containing the cloud-init metadata. |
| guestinfo.userdata | A YAML document containing the cloud-init userdata, |
| | or a MIME multipart message with the YAML document |
| | containing the cloud-init user data and custom |
| | scripts as described at doc/source/userdata.rst |
+--------------------+------------------------------------------------------+
Each property value should be gzip compressed and must be base64 encoded.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify - the should here is intentional, correct? In that https://github.com/cloudbase/cloudbase-init/pull/20/files#diff-79a52948a1c2159908ab0bec485abdeaR130-R132 suggest that gzipping is not required.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, correct.

When using terraform, you can create a cloud init configuration with, e.g.:
# a cloud-init userdata.
# see https://www.terraform.io/docs/providers/template/d/cloudinit_config.html
# see https://www.terraform.io/docs/configuration/expressions.html#string-literals
data "template_cloudinit_config" "example" {
part {
content_type = "text/cloud-config"
content = <<-EOF
#cloud-config
hostname: example
timezone: Asia/Tbilisi
EOF
}
part {
filename = "example.ps1"
content_type = "text/x-shellscript"
content = <<-EOF
#ps1_sysnative
Start-Transcript -Append "C:\cloudinit-config-example.ps1.log"
function Write-Title($title) {
Write-Output "`n#`n# $title`n#"
}
Write-Title "whoami"
whoami /all
Write-Title "Windows version"
cmd /c ver
Write-Title "Environment Variables"
dir env:
Write-Title "TimeZone"
Get-TimeZone
EOF
}
}
# see https://www.terraform.io/docs/providers/vsphere/r/virtual_machine.html
resource "vsphere_virtual_machine" "example" {
...
# NB this extra_config data ends-up inside the VM .vmx file and will be
# exposed by cloudbase-init as a cloud-init datasource.
extra_config = {
"guestinfo.metadata" = base64gzip(jsonencode({
"admin-username": var.winrm_username,
"admin-password": var.winrm_password,
"public-keys": [trimspace(file("~/.ssh/id_rsa.pub"))],
}))
"guestinfo.userdata" = data.template_cloudinit_config.example.rendered
}
...
}
NB The base image must have the VMware Tools installed.
"""

def __init__(self):
super(VMwareGuestInfoService, self).__init__()
self._meta_data = None
self._user_data = None
self._os_utils = osutils_factory.get_os_utils()

def load(self):
super(VMwareGuestInfoService, self).load()
if not os.path.exists(CONF.vmwareguestinfo.rpctool_path):
return False
self._meta_data = json.loads(self._get_guestinfo_value('metadata') or '{}')
self._user_data = self._get_guestinfo_value('userdata')
return True

def _get_guestinfo_value(self, name):
stdout, stderr, exit_code = self._os_utils.execute_process([
CONF.vmwareguestinfo.rpctool_path,
'info-get guestinfo.%s' % name
])
if exit_code:
raise exception.CloudbaseInitException(
'Failed to execute "%(rpctool_path)s" with '
'exit code: %(exit_code)s\nstdout: %(stdout)s\nstderr: %(stderr)s' % {
'rpctool_path': CONF.vmwareguestinfo.rpctool_path,
'exit_code': exit_code,
'stdout': stdout,
'stderr': stderr})
data = base64.b64decode(stdout)
if data[:2] == self._GZIP_MAGIC_NUMBER:
with gzip.GzipFile(fileobj=io.BytesIO(data), mode='rb') as out:
data = out.read()
return data

def _get_data(self, path):
pass

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):
return self._meta_data.get('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')
2 changes: 1 addition & 1 deletion cloudbaseinit/plugins/common/sshpublickeys.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def execute(self, service, shared_data):
LOG.debug('Public keys not found in metadata')
return base.PLUGIN_EXECUTION_DONE, False

username = CONF.username
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change should be removed from this patch, I will add another patch to have this fix merged asap.

username = service.get_admin_username() or CONF.username

osutils = osutils_factory.get_os_utils()
user_home = osutils.get_user_home(username)
Expand Down