Skip to content

Commit

Permalink
Merge 'sync-back' and simple prepare [#31]
Browse files Browse the repository at this point in the history
  • Loading branch information
psss committed Nov 5, 2019
2 parents 89ef801 + 46a5188 commit 54e1a75
Showing 1 changed file with 116 additions and 99 deletions.
215 changes: 116 additions & 99 deletions tmt/steps/provision/vagrant.py
Expand Up @@ -8,7 +8,7 @@
import re

from tmt.steps.provision.base import ProvisionBase
from tmt.utils import ConvertError, StructuredFieldError, SpecificationError
from tmt.utils import ConvertError, StructuredFieldError, SpecificationError, GeneralError

from click import echo
from urllib.parse import urlparse
Expand All @@ -32,7 +32,6 @@ class ProvisionVagrant(ProvisionBase):
default_image = 'centos/7'
default_container = 'centos:7'
default_indent = 16
image_uri = None
timeout = 333
eol = '\n'

Expand All @@ -44,40 +43,25 @@ def __init__(self, data, step):
self.vagrantfile = os.path.join(self.provision_dir, 'Vagrantfile')
self.vf_data = ''

# Are we resuming?
if os.path.exists(self.vagrantfile) and os.path.isfile(self.vagrantfile):
self.validate()
return

# Check for working Vagrant
self.run_vagrant('version')

# Let's check what's needed
self.check_how()

# TODO: where should this run?
self.init()

def load(self):
""" Load ProvisionVagrant step """
#TODO: ensure this loads self.data[*]
# instancename and regenerates provision_dir and vagrantfile
self.super.load()

def save(self):
""" Save ProvisionVagrant step """
#TODO: ensure this saves self.data[*]
# instancename
self.super.save()
#TypeError: save() takes 1 positional argument but 2 were given

# def wake(self):
# """ Prepare the Vagrantfile """
# self.super.wake(self)
# # capabilities? providers?

def go(self):
""" Execute actual provisioning """
self.init()
self.info('Provisioning vagrant, Vagrantfile', self.vf_read())
self.run_vagrant('up')

Expand All @@ -86,7 +70,8 @@ def execute(self, cmd):
self.run_vagrant('ssh', '-c', cmd)

def show(self):
""" Show execute details """
""" Create and show the Vagrantfile """
self.init()
self.super.show(keys=['how', 'box', 'image'])
self.info('Vagrantfile', self.vf_read())

Expand All @@ -97,7 +82,8 @@ def sync_workdir_to_guest(self):

def sync_workdir_from_guest(self):
""" sync from guest to host """
raise ConvertError('NYI: cannot currently sync from guest.')
self.plugin_install('vagrant-rsync-back')
self.run_vagrant('rsync-back')

def copy_from_guest(self, target):
""" copy file/folder from guest to host's copy dir """
Expand All @@ -119,15 +105,32 @@ def destroy(self):
""" remove instance """
self.run_vagrant('destroy', '-f')

def prepare(self, name, path):
def prepare(self, how, what, name='prepare'):
""" add single 'preparator' and run it """
raise ConvertError('NYI: cannot currently add preparators.')
self.add_config('provision', name, 'path')
if is_uri(what):
method = 'path'
else:
method = 'inline'

cmd = 'provision'

self.add_config(cmd,
quote(name),
self.kv('type', how),
self.kv('run', 'never'),
self.kv(method, what))

self.run_vagrant(cmd, f'--{cmd}-with', name)


## Additional API ##
def init(self):
""" Initialize Vagrantfile """
# Are we resuming?
if os.path.exists(self.vagrantfile) and os.path.isfile(self.vagrantfile):
self.validate()
return

# Create a Vagrantfile
self.create()

Expand All @@ -143,13 +146,6 @@ def create(self):
self.info('Initialized new Vagrantfile', self.vf_read())
self.validate()

def status(self):
""" Get vagrant's status """
raise ConvertError('NYI: cannot currently return status.')
# TODO: how to get stdout from self.run?
#csp = self.run_vagrant('status')
#return self.hr(csp.stdout)

def clean(self):
""" remove box and base box """
self.run_vagrant('box', 'remove', '-f', self.data['box'])
Expand All @@ -163,6 +159,9 @@ def reload(self):
""" restart guest """
self.run_vagrant('reload')

def plugin_install(self, plugin):
self.run_vagrant('plugin', 'install', plugin)


## Knowhow ##
def check_how(self):
Expand All @@ -176,17 +175,7 @@ def check_how(self):

image = self.data['image']

try:
i = urlparse(image)
if not i.schema:
raise (i)
self.image_uri = i
except:
pass

self.info('image_uri', self.image_uri)

if self.image_uri:
if self.is_uri(image):
self.set_default('box', 'box_' + self.instance_name)

if re.search(r"\.box$", image) is None:
Expand All @@ -203,38 +192,44 @@ def check_how(self):

else:
self.set_default('box', image)
self.data['image'] = None

for x in ('how','box','image'):
for x in ('how', 'box', 'image'):
self.info(x, self.data[x])

def add_how(self):
target = f"how_{self.data['how']}"
self.debug(f"Relaying to: {target}")
""" Add provider (in Vagrant-speak) specifics """
getattr(self,
target,
f"how_{self.data['how']}",
lambda: 'generic',
)()

def how_virtual(self):
self.debug(f"generating: virtual")
# let's just do libvirt for now
self.debug("generating", "virtual")

image = self.data['image']

if image:
self.add_config_value("box_url", image)

# let's try libvirt as default for now
self.how_libvirt()

def how_generic():
self.debug(f"generating: generic")
self.add_provider_config(self.data['how'])
self.debug("generating", "generic")
self.add_provider(self.data['how'])

def how_libvirt(self):
self.debug(f"generating: libvirt")
self.vf_backup()
self.debug("generating", "libvirt")
self.vf_backup("QEMU session")
try:
self.debug(f"Trying QEMU session.")
self.add_provider_config('libvirt', 'qemu_use_session = true')
except:
self.add_provider('libvirt', 'qemu_use_session = true')
except GeneralError as error:
self.debug(error)
self.vf_restore()

def how_openstack(self):
self.debug(f"generating: openstack")
self.debug("generating", "openstack")
raise SpecificationError('NYI: cannot currently run on openstack.')

def how_docker(self):
Expand All @@ -244,11 +239,18 @@ def how_podman(self):
self.how_container()

def how_container(self):
self.debug(f"generating: container")
self.debug("generating", "container")
raise SpecificationError('NYI: cannot currently run containers.')


## END of API ##
def vagrant_status(self):
""" Get vagrant's status """
raise ConvertError('NYI: cannot currently return status.')
# TODO: how to get stdout from self.run?
#csp = self.run_vagrant('status')
#return self.hr(csp.stdout)

def add_defaults(self):
""" Adds default config entries
1) Disable default sync
Expand Down Expand Up @@ -283,26 +285,37 @@ def add_synced_folder(self, sync_from, sync_to, *args):
self.add_config('synced_folder',
self.quote(sync_from),
self.quote(sync_to),
f'type: {self.quote(self.sync_type)}', *args)
self.kv('type', self.sync_type),
*args)

def add_provider(self, provider, *config):
self.add_config_block('provider', provider, *config)

def add_provider_config(self, provider, *config):
def add_config_block(self, name, block, *config):
""" Add config block into Vagrantfile
"""
config_str = ''
for c in config:
config_str += f'{provider}.{c}; '
config_str += f'{block}.{c}; '

self.add_raw_config(f"provider '{provider}' do |{provider}| {config_str}; end")
self.add_config(f"{name} '{block}' do |{block}| {config_str}end")

def add_config(self, *config):
""" Add config entry into Vagrantfile
def add_config_value(self, key, value):
""" Add config = value into Vagrantfile
"""
self.add_config(f"{key} = '{value}'")

config = "string"
def add_config(self, *config):
""" Add config entry into Vagrantfile right before last 'end',
and prepends it with `config_prefix`.
or:
Adding arbitrary config entry:
config = "string"
config = ['one', 'two', 'three']
or, with conversion:
config = ['one', 'two', 'three']
=> one "two", three
see add_raw_config
"""
if len(config) == 1:
config = config[0]
Expand All @@ -311,14 +324,7 @@ def add_config(self, *config):
else:
config = f'{config[0]} ' + ', '.join(config[1:])

self.add_raw_config(config)

def add_raw_config(self, config):
""" Add arbitrary config entry into Vagrantfile
right before last 'end'.
Prepends with `config_prefix`.
"""
self.info('Adding into Vagrantfile', [config])
self.info('Adding into Vagrantfile', config)

vf_tmp = self.vf_read()

Expand Down Expand Up @@ -354,13 +360,18 @@ def vf_write(self, vf_tmp):

self.validate()

def vf_backup(self):
def vf_backup(self, msg=''):
""" backup Vagrantfile contents to vf_data """
if msg:
self.info("Trying", msg)
self.msg = msg
self.vf_data = self.vf_read()

def vf_restore(self):
""" restore Vagrantfile contents frmo vf_data"""
self.debug('Restoring Vagrantfile from memory.')
if self.msg:
self.info('Reverting', self.msg, 'red')
self.msg = ''
self.vf_write(self.vf_data)


Expand All @@ -377,34 +388,32 @@ def debug(self, key = '', val = '', color='yellow'):
"""
self.msgout('debug', key, val, color)

def msgout(self, mtype, key = '', val = '', color = 'Red'):
def msgout(self, mtype, key = '', val = '', color = 'red'):
""" args: key, value, indent, color
all optional
"""
# Avoid unneccessary processing
if self.opt(mtype) or self.opt('debug'):
if type(val) is list and len(val):
ind_val = self.eol
for v in val:
if v:
ind_val += ' '*self.default_indent + self.hr(v) + self.eol

val = ind_val
else:
val = self.hr(val)
if type(val) is list and len(val):
ind_val = self.eol
for v in val:
if v:
ind_val += ' '*self.default_indent + self.hr(v) + self.eol

emsg = lambda: RuntimeError(f"Message type unknown: {mtype}")
val = ind_val
else:
val = self.hr(val)

if val:
getattr(self.super,
mtype,
emsg,
)(key, val, color)
else:
getattr(self.super,
mtype,
emsg,
)(key)
emsg = lambda: RuntimeError(f"Message type unknown: {mtype}")

if val:
getattr(self.super,
mtype,
emsg,
)(key, val, color)
else:
getattr(self.super,
mtype,
emsg,
)(key)

def hr(self, val):
""" return human readable data """
Expand Down Expand Up @@ -452,3 +461,11 @@ def cmd_mkcp(self, target_dir, target):

def quote(self, string):
return f'"{string}"'

def is_uri(self, uri):
return getattr(urlparse(uri),
'schema',
None)

def kv(self, key, val):
return f'{key}: "{val}"'

0 comments on commit 54e1a75

Please sign in to comment.