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