mirror of
https://github.com/kevingruesser/bootstrap-vz.git
synced 2025-08-24 15:36:27 +00:00
Merge pull request #335 from nbraud/admin_user
admin_user & file_copy: Make paths relative to the manifest
This commit is contained in:
commit
a86337cc69
7 changed files with 71 additions and 25 deletions
|
@ -133,3 +133,8 @@ def copy_tree(from_path, to_path):
|
||||||
for path in files:
|
for path in files:
|
||||||
copy(os.path.join(abs_prefix, path),
|
copy(os.path.join(abs_prefix, path),
|
||||||
os.path.join(to_path, prefix, path))
|
os.path.join(to_path, prefix, path))
|
||||||
|
|
||||||
|
|
||||||
|
def rel_path(base, path):
|
||||||
|
import os.path
|
||||||
|
return os.path.join(os.path.dirname(base), path)
|
||||||
|
|
|
@ -1,13 +1,8 @@
|
||||||
|
|
||||||
|
|
||||||
def validate_manifest(data, validator, error):
|
def validate_manifest(data, validator, error):
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.yml'))
|
schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.yml'))
|
||||||
validator(data, schema_path)
|
validator(data, schema_path)
|
||||||
pubkey = data['plugins']['admin_user'].get('pubkey', None)
|
|
||||||
if pubkey is not None and not os.path.exists(pubkey):
|
|
||||||
msg = 'Could not find public key at %s' % pubkey
|
|
||||||
error(msg, ['plugins', 'admin_user', 'pubkey'])
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_tasks(taskset, manifest):
|
def resolve_tasks(taskset, manifest):
|
||||||
|
@ -24,6 +19,7 @@ def resolve_tasks(taskset, manifest):
|
||||||
taskset.add(tasks.AdminUserPassword)
|
taskset.add(tasks.AdminUserPassword)
|
||||||
|
|
||||||
if 'pubkey' in manifest.plugins['admin_user']:
|
if 'pubkey' in manifest.plugins['admin_user']:
|
||||||
|
taskset.add(tasks.CheckPublicKeyFile)
|
||||||
taskset.add(tasks.AdminUserPublicKey)
|
taskset.add(tasks.AdminUserPublicKey)
|
||||||
elif manifest.provider['name'] == 'ec2':
|
elif manifest.provider['name'] == 'ec2':
|
||||||
logging.getLogger(__name__).info("The SSH key will be obtained from EC2")
|
logging.getLogger(__name__).info("The SSH key will be obtained from EC2")
|
||||||
|
|
|
@ -11,10 +11,10 @@ properties:
|
||||||
properties:
|
properties:
|
||||||
username: {type: string}
|
username: {type: string}
|
||||||
password: {type: string}
|
password: {type: string}
|
||||||
pubkey: {$ref: '#/definitions/absolute_path'}
|
pubkey: {$ref: '#/definitions/path'}
|
||||||
required: [username]
|
required: [username]
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
definitions:
|
definitions:
|
||||||
absolute_path:
|
path:
|
||||||
pattern: ^/[^\0]+$
|
pattern: ^[^\0]+$
|
||||||
type: string
|
type: string
|
||||||
|
|
|
@ -8,6 +8,27 @@ import logging
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class CheckPublicKeyFile(Task):
|
||||||
|
description = 'Check that the public key is a valid file'
|
||||||
|
phase = phases.validation
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls, info):
|
||||||
|
from bootstrapvz.common.tools import log_call, rel_path
|
||||||
|
|
||||||
|
pubkey = info.manifest.plugins['admin_user'].get('pubkey', None)
|
||||||
|
if pubkey is not None:
|
||||||
|
abs_pubkey = rel_path(info.manifest.path, pubkey)
|
||||||
|
if not os.path.isfile(abs_pubkey):
|
||||||
|
msg = 'Could not find public key at %s' % pubkey
|
||||||
|
info.manifest.validation_error(msg, ['plugins', 'admin_user', 'pubkey'])
|
||||||
|
|
||||||
|
ret, _, stderr = log_call('ssh-keygen -l -f ' + abs_pubkey)
|
||||||
|
if ret != 0:
|
||||||
|
msg = 'Invalid public key file at %s' % pubkey
|
||||||
|
info.manifest.validation_error(msg, ['plugins', 'admin_user', 'pubkey'])
|
||||||
|
|
||||||
|
|
||||||
class AddSudoPackage(Task):
|
class AddSudoPackage(Task):
|
||||||
description = 'Adding `sudo\' to the image packages'
|
description = 'Adding `sudo\' to the image packages'
|
||||||
phase = phases.preparation
|
phase = phases.preparation
|
||||||
|
@ -74,14 +95,21 @@ class AdminUserPublicKey(Task):
|
||||||
|
|
||||||
# Get the stuff we need (username & public key)
|
# Get the stuff we need (username & public key)
|
||||||
username = info.manifest.plugins['admin_user']['username']
|
username = info.manifest.plugins['admin_user']['username']
|
||||||
with open(info.manifest.plugins['admin_user']['pubkey']) as pubkey_handle:
|
|
||||||
|
from bootstrapvz.common.tools import rel_path
|
||||||
|
pubkey_path = rel_path(info.manifest.path,
|
||||||
|
info.manifest.plugins['admin_user']['pubkey'])
|
||||||
|
|
||||||
|
with open(pubkey_path) as pubkey_handle:
|
||||||
pubkey = pubkey_handle.read()
|
pubkey = pubkey_handle.read()
|
||||||
|
|
||||||
# paths
|
# paths
|
||||||
ssh_dir_rel = os.path.join('home', username, '.ssh')
|
from os.path import join
|
||||||
auth_keys_rel = os.path.join(ssh_dir_rel, 'authorized_keys')
|
ssh_dir_rel = join('home', username, '.ssh')
|
||||||
ssh_dir_abs = os.path.join(info.root, ssh_dir_rel)
|
auth_keys_rel = join(ssh_dir_rel, 'authorized_keys')
|
||||||
auth_keys_abs = os.path.join(info.root, auth_keys_rel)
|
ssh_dir_abs = join(info.root, ssh_dir_rel)
|
||||||
|
auth_keys_abs = join(info.root, auth_keys_rel)
|
||||||
|
|
||||||
# Create the ssh dir if nobody has created it yet
|
# Create the ssh dir if nobody has created it yet
|
||||||
if not os.path.exists(ssh_dir_abs):
|
if not os.path.exists(ssh_dir_abs):
|
||||||
os.mkdir(ssh_dir_abs, 0700)
|
os.mkdir(ssh_dir_abs, 0700)
|
||||||
|
|
|
@ -17,7 +17,7 @@ The ``file_copy`` plugin takes a (non-empty) ``files`` list, and optionally a ``
|
||||||
Files (items in the ``files`` list) must be objects with the following properties:
|
Files (items in the ``files`` list) must be objects with the following properties:
|
||||||
|
|
||||||
- ``src`` and ``dst`` (required) are the source and destination paths.
|
- ``src`` and ``dst`` (required) are the source and destination paths.
|
||||||
``src`` is relative to the current directory, whereas ``dst`` is a path in the VM.
|
``src`` is relative to the manifest, whereas ``dst`` is a path in the VM.
|
||||||
- ``permissions`` (optional) is a permission string in a format appropriate for ``chmod(1)``.
|
- ``permissions`` (optional) is a permission string in a format appropriate for ``chmod(1)``.
|
||||||
- ``owner`` and ``group`` (optional) are respectively a user and group specification,
|
- ``owner`` and ``group`` (optional) are respectively a user and group specification,
|
||||||
in a format appropriate for ``chown(1)`` and ``chgrp(1)``.
|
in a format appropriate for ``chown(1)`` and ``chgrp(1)``.
|
||||||
|
|
|
@ -7,15 +7,10 @@ def validate_manifest(data, validator, error):
|
||||||
schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.yml'))
|
schema_path = os.path.normpath(os.path.join(os.path.dirname(__file__), 'manifest-schema.yml'))
|
||||||
validator(data, schema_path)
|
validator(data, schema_path)
|
||||||
|
|
||||||
for i, file_entry in enumerate(data['plugins']['file_copy']['files']):
|
|
||||||
srcfile = file_entry['src']
|
|
||||||
if not os.path.exists(srcfile):
|
|
||||||
msg = 'The source file %s does not exist.' % srcfile
|
|
||||||
error(msg, ['plugins', 'file_copy', 'files', i])
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_tasks(taskset, manifest):
|
def resolve_tasks(taskset, manifest):
|
||||||
if ('mkdirs' in manifest.plugins['file_copy']):
|
if ('mkdirs' in manifest.plugins['file_copy']):
|
||||||
taskset.add(tasks.MkdirCommand)
|
taskset.add(tasks.MkdirCommand)
|
||||||
if ('files' in manifest.plugins['file_copy']):
|
if ('files' in manifest.plugins['file_copy']):
|
||||||
|
taskset.add(tasks.ValidateFiles)
|
||||||
taskset.add(tasks.FileCopyCommand)
|
taskset.add(tasks.FileCopyCommand)
|
||||||
|
|
|
@ -36,6 +36,20 @@ class MkdirCommand(Task):
|
||||||
modify_path(info, dir_entry['dir'], dir_entry)
|
modify_path(info, dir_entry['dir'], dir_entry)
|
||||||
|
|
||||||
|
|
||||||
|
class ValidateFiles(Task):
|
||||||
|
description = 'Check that the required files exist'
|
||||||
|
phase = phases.validation
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def run(cls, info):
|
||||||
|
from bootstrapvz.common.tools import rel_path
|
||||||
|
|
||||||
|
for i, file_entry in enumerate(info.manifest.plugins['file_copy']['files']):
|
||||||
|
if not os.path.exists(rel_path(info.manifest.path, file_entry['src'])):
|
||||||
|
msg = 'The source file %s does not exist.' % file_entry['src']
|
||||||
|
info.manifest.validation_error(msg, ['plugins', 'file_copy', 'files', i])
|
||||||
|
|
||||||
|
|
||||||
class FileCopyCommand(Task):
|
class FileCopyCommand(Task):
|
||||||
description = 'Copying user specified files into the image'
|
description = 'Copying user specified files into the image'
|
||||||
phase = phases.user_modification
|
phase = phases.user_modification
|
||||||
|
@ -43,13 +57,21 @@ class FileCopyCommand(Task):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def run(cls, info):
|
def run(cls, info):
|
||||||
|
from bootstrapvz.common.tools import rel_path
|
||||||
|
|
||||||
for file_entry in info.manifest.plugins['file_copy']['files']:
|
for file_entry in info.manifest.plugins['file_copy']['files']:
|
||||||
# note that we don't use os.path.join because it can't
|
# note that we don't use os.path.join because it can't
|
||||||
# handle absolute paths, which 'dst' most likely is.
|
# handle absolute paths, which 'dst' most likely is.
|
||||||
final_destination = os.path.normpath("%s/%s" % (info.root, file_entry['dst']))
|
final_destination = os.path.normpath("%s/%s" % (info.root, file_entry['dst']))
|
||||||
if os.path.isfile(file_entry['src']):
|
src_path = rel_path(info.manifest.path, file_entry['src'])
|
||||||
shutil.copy(file_entry['src'], final_destination)
|
if os.path.isfile(src_path):
|
||||||
|
shutil.copy(src_path, final_destination)
|
||||||
else:
|
else:
|
||||||
shutil.copytree(file_entry['src'], final_destination)
|
shutil.copytree(src_path, final_destination)
|
||||||
|
|
||||||
modify_path(info, file_entry['dst'], file_entry)
|
if os.path.isfile(src_path) and os.path.isdir(final_destination):
|
||||||
|
dst = os.path.join(final_destination, os.path.basename(src_path))
|
||||||
|
else:
|
||||||
|
dst = final_destination
|
||||||
|
|
||||||
|
modify_path(info, dst, file_entry)
|
||||||
|
|
Loading…
Add table
Reference in a new issue