The on-disk configuration format and its behavior
are fully backwards compatible with the previous
implementation.
Signed-off-by: Andrea Bolognani <abologna(a)redhat.com>
---
guests/lcitool | 112 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 112 insertions(+)
diff --git a/guests/lcitool b/guests/lcitool
index 1cba8ad..e03b388 100755
--- a/guests/lcitool
+++ b/guests/lcitool
@@ -18,6 +18,10 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
import argparse
+import crypt
+import os
+import random
+import string
import sys
import textwrap
@@ -32,9 +36,117 @@ class Error(Exception):
def __init__(self, message):
self.message = message
+class Util:
+
+ @staticmethod
+ def mksalt():
+ alphabeth = string.ascii_letters + string.digits
+ salt = "".join(random.choice(alphabeth) for x in range(0, 16))
+ return "$6${}$".format(salt)
+
+class Config:
+
+ def _get_config_file(self, name):
+ try:
+ config_dir = os.environ["XDG_CONFIG_HOME"]
+ except KeyError:
+ config_dir = os.path.join(os.environ["HOME"],
".config/")
+ config_dir = os.path.join(config_dir, "lcitool/")
+
+ # Create the directory if it doesn't already exist
+ if not os.path.exists(config_dir):
+ try:
+ os.mkdir(config_dir)
+ except:
+ raise Error(
+ "Can't create configuration directory ({})".format(
+ config_dir,
+ )
+ )
+
+ return os.path.join(config_dir, name)
+
+ def get_flavor(self):
+ flavor_file = self._get_config_file("flavor")
+
+ try:
+ with open(flavor_file, "r") as f:
+ flavor = f.readline().strip()
+ except:
+ # If the flavor has not been configured, we choose the default
+ # and store it on disk to ensure consistent behavior from now on
+ flavor = "test"
+ try:
+ with open(flavor_file, "w") as f:
+ f.write("{}\n".format(flavor))
+ except:
+ raise Error(
+ "Can't write flavor file ({})".format(
+ flavor_file,
+ )
+ )
+
+ if flavor != "test" and flavor != "jenkins":
+ raise Error("Invalid flavor '{}'".format(flavor))
+
+ return flavor
+
+ def get_vault_password_file(self):
+ vault_pass_file = None
+
+ # The vault password is only needed for the jenkins flavor, but in
+ # that case we want to make sure there's *something* in there
+ if self.get_flavor() != "test":
+ vault_pass_file = self._get_config_file("vault-password")
+
+ try:
+ with open(vault_pass_file, 'r') as f:
+ if len(f.readline().strip()) == 0:
+ raise ValueError
+ except:
+ raise Error(
+ "Missing or invalid vault password file ({})".format(
+ vault_pass_file,
+ )
+ )
+
+ return vault_pass_file
+
+ def get_root_password_file(self):
+ root_pass_file = self._get_config_file("root-password")
+ root_hash_file = self._get_config_file(".root-password.hash")
+
+ try:
+ with open(root_pass_file, "r") as f:
+ root_pass = f.readline().strip()
+ except:
+ raise Error(
+ "Missing or invalid root password file ({})".format(
+ root_pass_file,
+ )
+ )
+
+ # The hash will be different every time we run, but that doesn't
+ # matter - it will still validate the correct root password
+ root_hash = crypt.crypt(root_pass, Util.mksalt())
+
+ try:
+ with open(root_hash_file, "w") as f:
+ f.write("{}\n".format(root_hash))
+ except:
+ raise Error(
+ "Can't write hashed root password file ({})".format(
+ root_hash_file,
+ )
+ )
+
+ return root_hash_file
+
class Application:
def __init__(self):
+ self._config = Config()
+
self._parser = argparse.ArgumentParser(
conflict_handler = "resolve",
formatter_class = argparse.RawDescriptionHelpFormatter,
--
2.17.1