add
This commit is contained in:
parent
06cffbdbd7
commit
d6e3e05796
0
__init__.py
Normal file
0
__init__.py
Normal file
@ -1,4 +1,6 @@
|
||||
import sys
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
import gentooimgr.chroot
|
||||
|
||||
def command(config, *args):
|
||||
|
@ -15,9 +15,8 @@ def older_than_a_day(fullpath):
|
||||
return time.time() - filetime > (gentooimgr.config.DAY_IN_SECONDS *
|
||||
gentooimgr.config.DAYS)
|
||||
|
||||
|
||||
|
||||
def find_iso(download_dir):
|
||||
LOG.info(f"Looking for iso in {download_dir}")
|
||||
name = None
|
||||
ext = None
|
||||
found = []
|
||||
@ -34,9 +33,10 @@ def make_iso_from_dir(mydir):
|
||||
path to iso that was created or NoneType if mydir is not found
|
||||
"""
|
||||
if not os.path.exists(mydir):
|
||||
LOG.warn(f"\t:: dir not found {mydir}")
|
||||
return
|
||||
|
||||
print(f"\t:: Making ISO with dir of {mydir}")
|
||||
LOG.info(f"\t:: Making ISO with dir of {mydir}")
|
||||
path = os.path.join(mydir, "..", "cloudgen.iso")
|
||||
proc = Popen(["mkisofs",
|
||||
"--input-charset", "utf-8",
|
||||
@ -52,15 +52,17 @@ def make_iso_from_dir(mydir):
|
||||
|
||||
return path
|
||||
|
||||
def portage_from_dir(d, filename=None):
|
||||
def portage_from_dir(download_dir, filename=None):
|
||||
"""Find portage file from directory. Will do a check in os.listdir() for portage*.tar.bz2.
|
||||
|
||||
If a filename is provided, this function either returns that filename assuming it exists in d,
|
||||
or return None. If filename is None, this looks through all entries for portage files and if
|
||||
only one exists, returns it, otherwise None.
|
||||
"""
|
||||
assert download_dir, f"empty {download_dir} for for portage"
|
||||
LOG.info(f"Looking for portage in {download_dir}")
|
||||
found = []
|
||||
for f in os.listdir(d):
|
||||
for f in os.listdir(download_dir):
|
||||
if filename is not None:
|
||||
if filename == f:
|
||||
found.append(f)
|
||||
@ -70,7 +72,7 @@ def portage_from_dir(d, filename=None):
|
||||
if len(found) > 1:
|
||||
LOG.error("\tEE: More than one portage file exists, please specify the exact portage file with --portage [file] or remove all others\n")
|
||||
LOG.error(''.join([f"\t{f}\n" for f in found]))
|
||||
LOG.error(f"in {d}\n")
|
||||
LOG.error(f"in {download_dir}\n")
|
||||
sys.exit(1)
|
||||
|
||||
return found[0] if found else None
|
||||
|
@ -72,7 +72,7 @@
|
||||
"syslog-ng": "default",
|
||||
"cronie": "default",
|
||||
"acpid": "default",
|
||||
"ntp": "default"
|
||||
"ntp": "default",
|
||||
"qemu-guest-agent": "default"
|
||||
},
|
||||
"iso": null,
|
||||
|
@ -151,7 +151,7 @@ def step10_emerge_pkgs(args, cfg):
|
||||
proc = Popen(["emerge", "-j1", single])
|
||||
proc.communicate()
|
||||
|
||||
LOG.info("KERNEL PACKAGES", packages.get("kernel"))
|
||||
LOG.info(f"KERNEL PACKAGES {packages.get('kernel')}")
|
||||
if packages.get("kernel", []):
|
||||
cmd = ["emerge", "-j", str(args.threads)] + packages.get("kernel", [])
|
||||
proc = Popen(cmd)
|
||||
|
@ -3,6 +3,8 @@ import os
|
||||
import sys
|
||||
import argparse
|
||||
from subprocess import Popen, PIPE
|
||||
|
||||
from gentooimgr import LOG
|
||||
import gentooimgr.config
|
||||
import gentooimgr.common
|
||||
def create_image(args, config: dict, overwrite: bool = False) -> str:
|
||||
@ -36,6 +38,8 @@ def run_image(
|
||||
- mount_isos: list of iso paths to mount in qemu as disks.
|
||||
"""
|
||||
iso = config.get("iso")
|
||||
prefix = args.temporary_dir
|
||||
LOG.info(f"iso from config {iso}")
|
||||
if iso is None:
|
||||
iso = gentooimgr.common.find_iso(
|
||||
os.path.join(
|
||||
@ -43,6 +47,13 @@ def run_image(
|
||||
".."
|
||||
)
|
||||
)
|
||||
LOG.info(f"iso from cwd {iso}")
|
||||
if not iso:
|
||||
prefix = config.get('temporary_dir')
|
||||
iso = gentooimgr.common.find_iso(prefix)
|
||||
LOG.info(f"iso from {prefix} {iso}")
|
||||
|
||||
assert iso, f"iso not found {iso}"
|
||||
|
||||
if isinstance(iso, list):
|
||||
assert len(iso), f"iso list is empty {iso}"
|
||||
@ -55,6 +66,11 @@ def run_image(
|
||||
qmounts.append("-drive")
|
||||
qmounts.append(f"file={i},media=cdrom")
|
||||
|
||||
assert image, f"image is empty {image}"
|
||||
if not os.path.exists(image):
|
||||
if os.path.exists(os.path.join(prefix, image)):
|
||||
image = os.path.join(prefix, image)
|
||||
assert os.path.exists(image), f"image not found {image}"
|
||||
threads = args.threads
|
||||
cmd = [
|
||||
"qemu-system-x86_64",
|
||||
@ -65,7 +81,6 @@ def run_image(
|
||||
"-drive", f"file={image},if=virtio,index=0",
|
||||
"-cdrom", iso,
|
||||
"-net", "nic,model=virtio",
|
||||
"-net", "user",
|
||||
"-vga", "virtio",
|
||||
"-cpu", "kvm64",
|
||||
"-chardev", "file,id=charserial0,path=gentoo.log",
|
||||
@ -73,12 +88,14 @@ def run_image(
|
||||
"-chardev", "pty,id=charserial1",
|
||||
"-device", "isa-serial,chardev=charserial1,id=serial1"
|
||||
]
|
||||
# "-net", "user",
|
||||
# -net user: network backend 'user' is not compiled into this binary"
|
||||
|
||||
cmd += qmounts
|
||||
print(cmd)
|
||||
LOG.info(cmd)
|
||||
proc = Popen(cmd, stderr=PIPE, stdout=PIPE)
|
||||
stdout, stderr = proc.communicate()
|
||||
if stderr:
|
||||
sys.stderr.write(str(stderr))
|
||||
sys.stderr.write("\n")
|
||||
LOG.error(str(stderr))
|
||||
|
||||
|
||||
|
@ -23,6 +23,11 @@ def run(args, config: dict) -> None:
|
||||
assert os.path.isfile(main_iso), f"iso not found {main_iso}"
|
||||
LOG.info(args)
|
||||
LOG.info(f'iso={args.iso}')
|
||||
if args.iso != config['iso']:
|
||||
LOG.warn(f'iso={args.iso}')
|
||||
config['iso'] = args.iso
|
||||
else:
|
||||
LOG.info(f'iso={args.iso}')
|
||||
gentooimgr.qemu.run_image(
|
||||
args,
|
||||
config,
|
||||
|
@ -17,14 +17,17 @@ Step 16: Sysconfig
|
||||
Step 17: fstab
|
||||
"""
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
|
||||
# from gentooimgr import LOG
|
||||
import gentooimgr.config
|
||||
import gentooimgr.configs
|
||||
from gentooimgr import install
|
||||
|
||||
def print_template(args, configjson):
|
||||
def print_template(args, configjson, prefix='/tmp'):
|
||||
print(__doc__)
|
||||
sys.stderr.write(f"the last step to succeed is {install.getlaststep(prefix)}\n")
|
||||
print(f"the last step to succeed is {install.getlaststep(prefix)}\n")
|
||||
print(f"""------------------------ STATUS ------------------------
|
||||
|
||||
|
189
library/ansible-keepassxc.py
Executable file
189
library/ansible-keepassxc.py
Executable file
@ -0,0 +1,189 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import traceback
|
||||
from ansible.module_utils.basic import AnsibleModule, missing_required_lib
|
||||
|
||||
IMPORT_ERR = None
|
||||
try:
|
||||
# import _argon2_xffi_bindings
|
||||
import pykeepass as keepass
|
||||
except ImportError:
|
||||
IMPORT_ERR = traceback.format_exc()
|
||||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: ansible-keepassxc
|
||||
|
||||
short_description: Module to read credentials from KeePassXC
|
||||
|
||||
version_added: "0.0.1"
|
||||
|
||||
description: Module to read credentials from KeePassXC
|
||||
|
||||
options:
|
||||
database:
|
||||
description: Path to database file
|
||||
required: true
|
||||
type: str
|
||||
password:
|
||||
description: Database Password
|
||||
required: true
|
||||
type: str
|
||||
keyfile:
|
||||
description: Path to key file
|
||||
required: false
|
||||
type: str
|
||||
entry:
|
||||
description: Entry name for the attribute to fetch
|
||||
required: true
|
||||
type: str
|
||||
group:
|
||||
decription: Group name that the Entry belongs to
|
||||
required: false
|
||||
type: str
|
||||
|
||||
author:
|
||||
- Jeremy Lumley (@jlumley)
|
||||
'''
|
||||
|
||||
EXAMPLES = r'''
|
||||
# Fetch the credentials for the server_1 entry in any group
|
||||
- name: Fetch server_1 credentials
|
||||
jlumley.jlumley.ansible-keepassxc:
|
||||
database: "/secrets/db.kdbx"
|
||||
password: "s3cure_p4550rd"
|
||||
entry: "server_1"
|
||||
|
||||
# Fetch the reddit entry in the social group
|
||||
- name: Fetching reddit credentials
|
||||
jlumley.jlumley.ansible-keepassxc:
|
||||
database: "/secrets/db.kdbx"
|
||||
password: "sup3r_s3cure_p4550rd"
|
||||
entry: "reddit"
|
||||
group: "social"
|
||||
|
||||
# Fetch a custom strig attribute from the github entry
|
||||
- name: Fetch Github API Token
|
||||
jlumley.jlumley.ansible-keepassxc:
|
||||
database: "/secrets/db.kdbx"
|
||||
password: "d0pe_s3cure_p4550rd"
|
||||
keyfile: "/secrets/top_secret_key"
|
||||
entry: "github"
|
||||
group: "development"
|
||||
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
# Return values
|
||||
username:
|
||||
description: Username of entry if present
|
||||
type: str
|
||||
returned: always
|
||||
sample: 's3cr3t_us3r'
|
||||
password:
|
||||
description: Password of entry if present
|
||||
type: str
|
||||
returned: always
|
||||
sample: 's3cr3t_p455word'
|
||||
url:
|
||||
description: Url of entry if present
|
||||
type: str
|
||||
returned: always
|
||||
sample: 'http://reddit.com'
|
||||
custom_fields:
|
||||
description: dictionary containing all custom fields
|
||||
type: dict
|
||||
returned: always
|
||||
sample: False
|
||||
no_log:
|
||||
description: suppress logging of password
|
||||
type: bool
|
||||
returned: never
|
||||
sample: False
|
||||
'''
|
||||
|
||||
def run_module():
|
||||
# define available arguments/parameters a user can pass to the module
|
||||
module_args = dict(
|
||||
database = dict(type='str', required=True),
|
||||
password = dict(type='str', required=False,
|
||||
default=os.environ.get('ANSIBLE_KEEPASSXC_PASSWORD')),
|
||||
keyfile = dict(type='str', required=False, default=None),
|
||||
entry = dict(type='str', required=True),
|
||||
group = dict(type='str', required=False),
|
||||
no_log = dict(type='bool', required=False, default=False),
|
||||
)
|
||||
|
||||
# seed the result dict in the object
|
||||
result = dict(
|
||||
changed=False,
|
||||
username='',
|
||||
password='',
|
||||
url='',
|
||||
custom_fields={}
|
||||
)
|
||||
|
||||
# Currently no support for a check_mode this maybe added later if
|
||||
# functionality to modify the database is added later
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=False,
|
||||
)
|
||||
|
||||
if IMPORT_ERR:
|
||||
module.fail_json(
|
||||
msg=missing_required_lib("pykeepass"),
|
||||
exception=IMPORT_ERR
|
||||
)
|
||||
|
||||
# unlock local keepass database
|
||||
try:
|
||||
kp = keepass.PyKeePass(
|
||||
module.params['database'],
|
||||
password=module.params['password'],
|
||||
keyfile=module.params['keyfile'])
|
||||
except keepass.exceptions.CredentialsError:
|
||||
module.fail_json(msg='Invalid Credentials')
|
||||
|
||||
# find entry
|
||||
entry = kp.find_entries(
|
||||
title=module.params['entry'],
|
||||
group=module.params['group']
|
||||
)
|
||||
|
||||
# fail is entry is not present
|
||||
if not entry:
|
||||
module.fail_json(msg=f"Unable to find entry: {module.params['entry']}")
|
||||
|
||||
else:
|
||||
entry = entry[0]
|
||||
custom_field_keys = entry._get_string_field_keys(exclude_reserved=True)
|
||||
custom_fields = dict()
|
||||
for key in custom_field_keys:
|
||||
custom_fields[key] = entry.get_custom_property(key)
|
||||
result = dict (
|
||||
changed=False,
|
||||
username=entry.username,
|
||||
password=entry.password,
|
||||
url=entry.url,
|
||||
custom_fields=custom_fields
|
||||
)
|
||||
|
||||
# in the event of a successful module execution, you will want to
|
||||
# simple AnsibleModule.exit_json(), passing the key/value results
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
def main():
|
||||
run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
|
224
library/ansible_gentooimgr.py
Executable file
224
library/ansible_gentooimgr.py
Executable file
@ -0,0 +1,224 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
from argparse import Namespace
|
||||
import pathlib
|
||||
import traceback
|
||||
|
||||
sys.path.append('/mnt/o/var/local/src/play_tox/src/ansible_gentooimgr')
|
||||
# in the library
|
||||
mod_path = os.path.dirname(os.path.realpath('__file__'))
|
||||
mod_path = os.path.join(mod_path, 'src', 'ansible_gentooimgr')
|
||||
assert os.path.isdir(mod_path), f"parent {mod_path}"
|
||||
assert os.path.isfile(os.path.join(mod_path, '__init__.py')),f"index {mod_path}"
|
||||
assert os.path.isdir(os.path.join(mod_path, 'gentooimgr')), f"sub {mod_path}"
|
||||
sys.path.append(mod_path)
|
||||
try:
|
||||
import gentooimgr
|
||||
except Exception as e:
|
||||
sys.stderr.write(f"{mod_path} {sys.path} {traceback.print_exc()}")
|
||||
raise
|
||||
import ansible
|
||||
|
||||
DOCUMENTATION = rf'''
|
||||
---
|
||||
module: gentooimgr
|
||||
|
||||
short_description: Gentoo Image Builder for Cloud and Turnkey ISO installers
|
||||
|
||||
|
||||
version_added: "1.0.0"
|
||||
|
||||
description:
|
||||
* This project enables easy access to building ``systemd`` or ``openrc`` -based images.
|
||||
* Performs automatic download AND verification of the linux iso, stage3 tarball and portage.
|
||||
* Caches the iso and stage3 .txt files for at most a day before redownloading and rechecking for new files
|
||||
* Sane and readable cli commands to build, run and test.
|
||||
* Step system to enable user to continue off at the same place if a step fails
|
||||
* No heavy packages like rust included ** TODO
|
||||
|
||||
options:
|
||||
action:
|
||||
description: The action to be run by the image builder
|
||||
choices:
|
||||
- build
|
||||
- run
|
||||
- status
|
||||
- install
|
||||
- chroot
|
||||
- unchroot
|
||||
- command
|
||||
- shrink
|
||||
- kernel
|
||||
required: true
|
||||
# clean test
|
||||
config:
|
||||
default: cloud.json
|
||||
description: init configuration file or or base.json or cloud.json
|
||||
required: false
|
||||
loglevel:
|
||||
default: {logging.INFO}
|
||||
description: python logging level <= 50, INFO=20
|
||||
required: false
|
||||
threads:
|
||||
default: 1
|
||||
description: Number of threads to use
|
||||
required: false
|
||||
profile:
|
||||
default: openrc
|
||||
description: The init system
|
||||
choices:
|
||||
- openrc
|
||||
- systemd
|
||||
required: false
|
||||
kernel_dir:
|
||||
default: /usr/src/linux
|
||||
description: Where kernel is specified. By default uses the active linux kernel
|
||||
required: false
|
||||
portage:
|
||||
description: Extract the specified portage tarball onto the filesystem
|
||||
required: false
|
||||
stage3:
|
||||
description: Extract the specified stage3 package onto the filesystema
|
||||
required: false
|
||||
action_args:
|
||||
default: []
|
||||
description: Arguments for some of the actions - UNUSED!
|
||||
required: false
|
||||
temporary_dir:
|
||||
description: Path to temporary directory for downloading files (20G)
|
||||
required: false
|
||||
qcow:
|
||||
description: Path to file to serve as the base image
|
||||
required: false
|
||||
|
||||
# Specify this value according to your collection
|
||||
# in format of namespace.collection.doc_fragment_name
|
||||
# extends_documentation_fragment:
|
||||
# - my_namespace.my_collection.my_doc_fragment_name
|
||||
|
||||
author:
|
||||
- Your Name (@yourGitHubHandle)
|
||||
'''
|
||||
|
||||
#[-y DAYS]
|
||||
# [-d DOWNLOAD_DIR]
|
||||
# [-f]
|
||||
# [--format FORMAT]
|
||||
|
||||
EXAMPLES = r'''
|
||||
# Pass in a message
|
||||
- name: Test with a message
|
||||
my_namespace.my_collection.my_test:
|
||||
name: hello world
|
||||
|
||||
# pass in a message and have changed true
|
||||
- name: Test with a message and changed output
|
||||
my_namespace.my_collection.my_test:
|
||||
name: hello world
|
||||
new: true
|
||||
|
||||
# fail the module
|
||||
- name: Test failure of the module
|
||||
my_namespace.my_collection.my_test:
|
||||
name: fail me
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
# These are examples of possible return values, and in general should use other names for return values.
|
||||
message:
|
||||
description: The output message that the test module generates.
|
||||
type: str
|
||||
returned: always
|
||||
sample: 'goodbye'
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
|
||||
def run_module():
|
||||
# define available arguments/parameters a user can pass to the module
|
||||
module_args = dict(
|
||||
action=dict(type='str', required=True),
|
||||
loglevel=dict(type='int', required=False, default=logging.INFO),
|
||||
threads=dict(type='int', required=False, default=1),
|
||||
config=dict(type='str', default='cloud.json', required=False),
|
||||
profile=dict(type='str', required=False),
|
||||
kernel_dir=dict(type='path', required=False),
|
||||
portage=dict(type='path', required=False),
|
||||
stage3=dict(type='path', required=False),
|
||||
temporary_dir=dict(type='path', required=False, default=pathlib.Path(os.getcwd())),
|
||||
download_dir=dict(type='path', required=False, default=pathlib.Path(os.getcwd())),
|
||||
qcow=dict(type='path', required=False),
|
||||
)
|
||||
|
||||
# seed the result dict in the object
|
||||
# we primarily care about changed and state
|
||||
# changed is if this module effectively modified the target
|
||||
# state will include any data that you want your module to pass back
|
||||
# for consumption, for example, in a subsequent task
|
||||
result = dict(
|
||||
changed=False,
|
||||
original_message='',
|
||||
message=''
|
||||
)
|
||||
|
||||
# the AnsibleModule object will be our abstraction working with Ansible
|
||||
# this includes instantiation, a couple of common attr would be the
|
||||
# args/params passed to the execution, as well as if the module
|
||||
# supports check mode
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
# if the user is working with this module in only check mode we do not
|
||||
# want to make any changes to the environment, just return the current
|
||||
# state with no modifications
|
||||
if module.check_mode:
|
||||
module.exit_json(**result)
|
||||
|
||||
# manipulate or modify the state as needed (this is going to be the
|
||||
# part where your module will do what it needs to do)
|
||||
# if module.params.get('thirsty'):
|
||||
|
||||
oargs = Namespace(**module.params)
|
||||
# during the execution of the module, if there is an exception or a
|
||||
# conditional state that effectively causes a failure, run
|
||||
# AnsibleModule.fail_json() to pass in the message and the result
|
||||
result['original_message'] = ""
|
||||
try:
|
||||
from gentooimgr.__main__ import main
|
||||
retval = main(oargs)
|
||||
except Exception as e:
|
||||
result['message'] = str(e)
|
||||
e = traceback.print_exc()
|
||||
if e: result['original_message'] += f"{e}"
|
||||
module.fail_json(msg='Exception', **result)
|
||||
else:
|
||||
result['message'] = str(retval)
|
||||
|
||||
# use whatever logic you need to determine whether or not this module
|
||||
# made any modifications to your target
|
||||
if dArgs['action'] in ['status']:
|
||||
result['changed'] = False
|
||||
else:
|
||||
result['changed'] = True
|
||||
|
||||
# in the event of a successful module execution, you will want to
|
||||
# simple AnsibleModule.exit_json(), passing the key/value results
|
||||
module.exit_json(**result)
|
||||
|
||||
|
||||
def main():
|
||||
run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Loading…
Reference in New Issue
Block a user