github.com/SUSE/skuba@v1.4.17/ci/infra/testrunner/utils/config.py (about)

     1  import os
     2  import string
     3  import sys
     4  
     5  import yaml
     6  
     7  from utils.format import Format
     8  
     9  class dict_with_default(dict):
    10      def __init__(self, values, default):
    11          self.default = default
    12          super().__init__(values)
    13  
    14      def __missing__(self, key):
    15          return self.default
    16  
    17  class Constant:
    18      TERRAFORM_EXAMPLE = "terraform.tfvars.json.ci.example"
    19      TERRAFORM_JSON_OUT = "tfout.json"
    20      SSH_OPTS = "-oStrictHostKeyChecking=no -oUserKnownHostsFile=/dev/null " + \
    21                 "-oConnectTimeout=60 -oBatchMode=yes "
    22  
    23  
    24  class BaseConfig:
    25  
    26      def __new__(cls, yaml_path, *args, **kwargs):
    27          obj = super().__new__(cls, *args, **kwargs)
    28          obj.yaml_path = yaml_path
    29          obj.platform  = BaseConfig.Platform()
    30          obj.terraform = BaseConfig.Terraform()
    31          obj.openstack = BaseConfig.Openstack()
    32          obj.vmware = BaseConfig.VMware()
    33          obj.libvirt = BaseConfig.Libvirt()
    34          obj.skuba = BaseConfig.Skuba()
    35          obj.test = BaseConfig.Test()
    36          obj.log = BaseConfig.Log()
    37          obj.packages = BaseConfig.Packages()
    38          obj.kubectl = BaseConfig.Kubectl()
    39          obj.utils = BaseConfig.Utils()
    40  
    41          # vars get the values from yaml file
    42          vars = BaseConfig.get_var_dict(yaml_path)
    43          # conf.objects will be overriden by the values from vars and matching ENV variables
    44          BaseConfig.inject_attrs_from_yaml(obj, vars, "")
    45          # Final modification for conf variables
    46          BaseConfig.finalize(obj)
    47          BaseConfig.verify(obj)
    48          return obj
    49  
    50      class NodeConfig:
    51          def __init__(self, count=1, memory=4096, cpu=4):
    52              super().__init__()
    53              self.count = count
    54              self.memory = memory  # MB
    55              self.cpu = cpu
    56              self.ips = []
    57              self.external_ips = []
    58  
    59      class Utils:
    60          def __init__(self):
    61              self.ssh_sock =  "/tmp/testrunner_ssh_sock"
    62              self.ssh_key = "$HOME/.ssh/id_rsa"
    63              self.ssh_user = "sles"
    64  
    65      class Platform:
    66          def __init__(self):
    67              self.log_dir = "$WORKSPACE/platform_logs"
    68  
    69      class Openstack:
    70          def __init__(self):
    71              super().__init__()
    72              self.openrc = None
    73  
    74      class Terraform:
    75          def __init__(self):
    76              super().__init__()
    77              self.retries = 5
    78              self.internal_net = None
    79              self.stack_name = "$USER"
    80              self.workdir = "$WORKSPACE"
    81              self.tfdir = "$WORKSPACE/ci/infra"
    82              self.tfvars = Constant.TERRAFORM_EXAMPLE
    83              self.plugin_dir = None
    84              self.lb = BaseConfig.NodeConfig()
    85              self.master = BaseConfig.NodeConfig()
    86              self.worker = BaseConfig.NodeConfig()
    87  
    88      class Skuba:
    89          def __init__(self):
    90              super().__init__()
    91              self.workdir = "$WORKSPACE"
    92              self.cluster = "test-cluster"
    93              self.binpath = "$WORKSPACE/go/bin/skuba"
    94              self.verbosity = 5
    95  
    96      class Kubectl:
    97          def __init__(self):
    98              super().__init__()
    99              self.workdir = "$WORKSPACE"
   100              self.cluster = "test-cluster"
   101              self.binpath = "/usr/bin/kubectl"
   102              self.kubeconfig = "$WORKSPACE/test-cluster/admin.conf"
   103  
   104      class Test:
   105          def __init__(self):
   106              super().__init__()
   107              self.no_destroy = False
   108  
   109      class Log:
   110          def __init__(self):
   111              super().__init__()
   112              self.level = "INFO"
   113              self.quiet = False
   114              self.file = "$WORKSPACE/testrunner.log"
   115              self.overwrite = False
   116  
   117      class VMware:
   118          def __init__(self):
   119              self.env_file = None
   120              self.template_name = None
   121  
   122      class Libvirt:
   123          def __init__(self):
   124              super().__init__()
   125              self.uri = "qemu:///system"
   126              self.keyfile = None
   127              self.image_uri = None
   128  
   129      class Packages:
   130          def __init__(self):
   131              self.mirror = None
   132              self.registry_code = None
   133              self.additional_repos = None
   134              self.additional_pkgs = None
   135  
   136      @staticmethod
   137      def print(config, level=0, out=sys.stdout):
   138          """ Prints the configuration
   139          """
   140          print(f'{"  "*level}{config.__class__.__name__}:', file=out)
   141          for key, value in config.__dict__.items():
   142              if isinstance(value, BaseConfig.config_classes):
   143                  BaseConfig.print(value, level=level+1, out=out)
   144                  continue
   145  
   146              print(f'{"  "*(level+1)}{key}: {value}', file=out)
   147  
   148      @staticmethod
   149      def get_yaml_path(yaml_path):
   150          utils_dir = os.path.dirname(os.path.realpath(__file__))
   151          testrunner_dir = os.path.join(utils_dir, "..")
   152          config_yaml_file_path = os.path.join(testrunner_dir, yaml_path)
   153          return os.path.abspath(config_yaml_file_path)
   154  
   155      @staticmethod
   156      def get_var_dict(yaml_path):
   157          config_yaml_file_path = BaseConfig.get_yaml_path(yaml_path)
   158          with open(config_yaml_file_path, 'r') as stream:
   159              _conf = yaml.safe_load(stream)
   160          return _conf
   161  
   162      @staticmethod
   163      def inject_attrs_from_yaml(config, vars, ctx):
   164          """ Set values for configuration attributes
   165          The order of precedence is:
   166          - An environment variable exists with the fully qualified name of the
   167            attribute (e.g SKUBA_BINPATH)
   168          - The attribute from vars
   169          - default value for configuration
   170  
   171          After the attribute's value is set, a environement variables in the
   172          value are expanded.
   173          """
   174  
   175          for key, value in config.__dict__.items():
   176              if isinstance(value, BaseConfig.config_classes):
   177                  sub_ctx = "{}{}".format(ctx+"_" if ctx else "", key)
   178                  sub_config = value
   179                  sub_vars = vars.get(key) if vars else None
   180                  BaseConfig.inject_attrs_from_yaml(sub_config, sub_vars, sub_ctx)
   181                  continue
   182  
   183              env_key = "{}{}".format(ctx+"_" if ctx else "", key).upper()
   184              env_value = os.getenv(env_key)
   185  
   186              # If env variable exists, use it. If not, use value fom vars, if
   187              # it exists (otherwise, default value from BaseConfig class will be
   188              # used)
   189              if env_value:
   190                  value = env_value
   191              elif vars and key in vars:
   192                  value = vars[key]
   193  
   194              config.__dict__[key] = BaseConfig.substitute(value)
   195  
   196      @staticmethod
   197      def substitute(value):
   198          """subtitute environment variables in the value of the attribute
   199             recursively substitute values in list or maps
   200          """
   201          if value is not None:
   202              if type(value) == str:
   203                  value = string.Template(value).safe_substitute(dict_with_default(os.environ, ''))
   204              elif type(value) == list:
   205                  value = [BaseConfig.substitute(e) for e in value]
   206              elif type(value) == dict:
   207                  value = { k: BaseConfig.substitute(v) for k,v in value.items()}
   208          return value
   209  
   210      @staticmethod
   211      def finalize(conf):
   212          """ Finalize configuration.
   213          Deprecated. Will be removed
   214          """
   215          return
   216  
   217      @staticmethod
   218      def verify(conf):
   219          """ Validates configuration.
   220          Deprecated. Will be removed
   221          """
   222          return
   223  
   224  
   225      config_classes = (
   226          Platform,
   227          Packages,
   228          NodeConfig,
   229          Test,
   230          Log,
   231          Openstack,
   232          Terraform,
   233          Skuba,
   234          Kubectl,
   235          VMware,
   236          Libvirt,
   237          Utils
   238      )
   239  
   240