Module harvester_e2e_tests.fixtures.terraform

Functions

def remove_ansicode(ctx)
def tf_executor(tf_script_dir)
def tf_harvester(api_client, tf_script_dir, tf_provider_version, tf_executor)
def tf_provider_rancher_ver(request, harvester_metadata)
def tf_provider_version(request, harvester_metadata)
def tf_rancher(rancher_api_client, tf_script_dir, tf_provider_rancher_ver, tf_executor, harvester, rancher)
def tf_rancher_resource(tf_provider_rancher_ver)
def tf_resource(tf_provider_version)
def tf_script_dir(request)

Classes

class BaseTerraformResource (converter)
Expand source code
class BaseTerraformResource:
    #: Be used to store sub classes of BaseTerraformResource
    #: Type: Dict[Type[BaseTerraformResource], List[Type[BaseTerraformResource]]]
    _sub_classes = dict()

    #: Be used to adjust whether the class is support to specific version
    #: Type: str
    support_to = "0.0.0"

    @classmethod
    def is_support(cls, target_version):
        return parse_version(target_version) >= parse_version(cls.support_to)

    @classmethod
    def for_version(cls, version):
        for c in sorted(cls._sub_classes.get(cls, []),
                        reverse=True, key=lambda x: parse_version(x.support_to).release):
            if c.is_support(version):
                return c
        return cls

    def __init_subclass__(cls):
        for parent in cls.__mro__:
            if issubclass(parent, BaseTerraformResource):
                cls._sub_classes.setdefault(parent, []).append(cls)

    def __init__(self, converter):
        self.executor = Path(converter).resolve()

    def convert_to_hcl(self, json_spec, raw=False):
        rv = run(f"echo {json.dumps(json_spec)!r} | {self.executor!s}",
                 shell=True, stdout=PIPE, stderr=PIPE)
        if raw:
            return rv
        if rv.stderr:
            raise TypeError(rv.stderr, rv.stdout, rv.returncode)
        out = rv.stdout.decode()
        out = re.sub(r'"resource"', "resource", out)    # resource should not quote
        out = re.sub(r"\"(.+?)\" =", r"\1 =", out)      # property should not quote
        out = re.sub(r'"(data\.\S+?)"', r"\1", out)     # data should not quote
        out = re.sub(r"(.[^ ]+) = {", r"\1 {", out)     # block should not have `=`
        return out

    def make_resource(self, resource_type, resource_name, *, convert=True, **properties):
        rv = dict(resource={resource_type: {resource_name: properties}})
        if convert:
            return ResourceContext(resource_type, resource_name, self.convert_to_hcl(rv), rv)
        return rv

Subclasses

Class variables

var support_to

Be used to adjust whether the class is support to specific version Type: str

Static methods

def for_version(version)
def is_support(target_version)

Methods

def convert_to_hcl(self, json_spec, raw=False)
def make_resource(self, resource_type, resource_name, *, convert=True, **properties)
class ResourceContext (type: str, name: str, ctx: str, raw: dict = <factory>)

ResourceContext(type: str, name: str, ctx: str, raw: dict = )

Expand source code
@dataclass
class ResourceContext:
    type: str
    name: str
    ctx: str
    raw: dict = field(default_factory=dict, compare=False)

Class variables

var ctx : str
var name : str
var raw : dict
var type : str
class TerraformHarvester (executor, workdir)
Expand source code
class TerraformHarvester:
    def __init__(self, executor, workdir):
        self.executor = executor.resolve()
        self.workdir = workdir
        self.workdir.mkdir(exist_ok=True)

    def exec_command(self, cmd, raw=False, **kws):
        rv = run(cmd, shell=True, stdout=PIPE, stderr=PIPE, cwd=self.workdir, **kws)

        if raw:
            return rv
        return remove_ansicode(rv.stdout), remove_ansicode(rv.stderr), rv.returncode

    def execute(self, cmd, raw=False, **kws):
        return self.exec_command(f"{self.executor} {cmd}", raw=raw, **kws)

    def initial_provider(self, kubeconfig, provider_version):
        kubefile = self.workdir / "kubeconfig"
        with open(kubefile, "w") as f:
            f.write(kubeconfig)

        with open(self.workdir / "provider.tf", "w") as f:
            f.write(TF_PROVIDER % dict(
                tf_version=">=0.13", config_path=kubefile.resolve(),
                provider_source="harvester/harvester", provider_version=provider_version
            ))
        init_arg = ""

        if provider_version == "0.0.0-dev":
            local_plugin_path = "./registry.terraform.io/harvester/harvester/0.0.0-dev"
            docker_plugin_path = (
                "/root/.terraform.d/plugins/terraform.local/local/"
                "harvester/0.0.0-dev/linux_amd64/terraform-provider-harvester_v0.0.0-dev"
            )
            rv = run(
                f"mkdir -p {local_plugin_path}"
                f"&& mkdir linux_amd64"
                f"&& docker run --pull=always -q --rm --name harv-tf-master-head"
                f" -v ./linux_amd64:/_tf"
                f" rancher/terraform-provider-harvester:master-head-amd64"
                f' bash -c "cp {docker_plugin_path} /_tf/"'
                f"&& mv linux_amd64 {local_plugin_path}",
                shell=True, stdout=PIPE, stderr=PIPE, cwd=self.workdir
            )
            assert not remove_ansicode(rv.stderr) and 0 == rv.returncode
            init_arg = " -plugin-dir ."

        return self.execute(f"init {init_arg}")

    def save_as(self, content, filename, ext=".tf"):
        filepath = self.workdir / f"{filename}{ext}"
        with open(filepath, "w") as f:
            f.write(content)

    def apply_resource(self, resource_type, resource_name):
        return self.execute(f"apply -auto-approve -target {resource_type}.{resource_name}")

    def destroy_resource(self, resource_type, resource_name):
        return self.execute(f"destroy -auto-approve -target {resource_type}.{resource_name}")

Subclasses

Methods

def apply_resource(self, resource_type, resource_name)
def destroy_resource(self, resource_type, resource_name)
def exec_command(self, cmd, raw=False, **kws)
def execute(self, cmd, raw=False, **kws)
def initial_provider(self, kubeconfig, provider_version)
def save_as(self, content, filename, ext='.tf')
class TerraformRancher (executor, workdir)
Expand source code
class TerraformRancher(TerraformHarvester):
    def initial_provider(self, kubeconfig, provider_version, harvester, rancher):
        kubefile = self.workdir / "kubeconfig"
        with open(kubefile, "w") as f:
            f.write(kubeconfig)

        with open(self.workdir / "provider.tf", "w") as f:
            f.write(TF_PROVIDER_RANCHER % {
                "provider_source": "rancher/rancher2",
                "provider_version": provider_version,
                "rancher_endpoint": rancher["endpoint"],
                "rancher_token": rancher["token"],
                "harvester_name": harvester["name"]
            })

        return self.execute("init")

Ancestors

Methods

def initial_provider(self, kubeconfig, provider_version, harvester, rancher)
class TerraformRancherResource (converter)
Expand source code
class TerraformRancherResource(BaseTerraformResource):
    ''' https://github.com/rancher/terraform-provider-rancher2/tree/v1.20.0/docs/resources
    '''
    support_to = "1.20.0"

    def machine_config(self, rke_cluster_name, network_id, image_id, ssh_user):
        hcl_str = TF_MACHINE_CONFIG % {
            "name": rke_cluster_name,
            "harvester_config": TF_HARVESTER_CONFIG % {
                "ssh_user": ssh_user,
                "disk_info": TF_DISK_INFO % {"image_name": image_id},
                "network_info": TF_NETWORK_INFO % {"network_name": network_id},
                "user_data": TF_USER_DATA
            }
        }
        return ResourceContext("rancher2_machine_config_v2", rke_cluster_name, hcl_str, "")

    def cluster_config(self, rke_cluster_name, k8s_version, harvester_name, cloud_credential_name):
        machine_pools = TF_MACHINE_POOLS % {
            "cloud_credential_name": cloud_credential_name,
            "machine_config_name": rke_cluster_name
        }
        rke_config = TF_RKE_CONFIG % {
            "machine_pools": machine_pools,
            "harvester_name": harvester_name
        }
        hcl_str = TF_CLUSTER_CONFIG % {
            "name": rke_cluster_name,
            "rke2_version": k8s_version,
            "rke_config": rke_config
        }
        return ResourceContext("rancher2_cluster_v2", rke_cluster_name, hcl_str, "")

Ancestors

Subclasses

Methods

def cluster_config(self, rke_cluster_name, k8s_version, harvester_name, cloud_credential_name)
def machine_config(self, rke_cluster_name, network_id, image_id, ssh_user)

Inherited members

class TerraformRancherResource_123 (converter)
Expand source code
class TerraformRancherResource_123(TerraformRancherResource):
    ''' https://github.com/rancher/terraform-provider-rancher2/tree/v1.23.0/docs/resources
    '''
    support_to = "1.23.0"

    def cloud_credential(self, name, harvester_name, *, convert=True, **properties):
        harvester_credential_config = {
            "cluster_id": f"data.rancher2_cluster_v2.{harvester_name}.cluster_v1_id",
            "cluster_type": "imported",
            "kubeconfig_content": f"data.rancher2_cluster_v2.{harvester_name}.kube_config"
        }
        return self.make_resource("rancher2_cloud_credential", name,
                                  name=name,
                                  harvester_credential_config=harvester_credential_config,
                                  convert=convert, **properties)

Ancestors

Methods

def cloud_credential(self, name, harvester_name, *, convert=True, **properties)

Inherited members

class TerraformResource (converter)
Expand source code
class TerraformResource(BaseTerraformResource):
    ''' https://github.com/harvester/terraform-provider-harvester/blob/v0.1.0/docs/resources/ '''
    support_to = "0.1.0"

    def ssh_key(self, resource_name, name, public_key, *, convert=True, **properties):
        return self.make_resource(
            "harvester_ssh_key", resource_name, name=name, public_key=public_key,
            convert=convert, **properties
        )

    def volume(self, resource_name, name, size=1, *, convert=True, **properties):
        size = size if isinstance(size, str) else f"{size}Gi"
        return self.make_resource(
            "harvester_volume", resource_name, name=name, size=size,
            convert=convert, **properties
        )

    def image_download(
        self, resource_name, name, display_name, url, *, convert=True, **properties
    ):
        return self.make_resource(
            "harvester_image", resource_name, name=name, display_name=display_name, url=url,
            source_type="download", convert=convert, **properties
        )

    def image_export_from_volume(
        self, resource_name, name, display_name, pvc_name, pvc_namespace,
        *, convert=True, **properties
    ):
        return self.make_resource(
            "harvester_image", resource_name, name=name, display_name=display_name,
            pvc_name=pvc_name, pvc_namespace=pvc_namespace, source_type="export-from-volume",
            convert=convert, **properties
        )

    def virtual_machine(self, resource_name, name, disks, nics, *, convert=True, **properties):
        disks.extend(properties.pop("disk", []))
        nics.extend(properties.pop("network_interface", []))
        return self.make_resource(
            "harvester_virtualmachine", resource_name, name=name, disk=disks,
            network_interface=nics, convert=convert, **properties
        )

    vm = virtual_machine  # alias

    def network(self, resource_name, name, vlan_id, *, convert=True, **properties):
        return self.make_resource(
            "harvester_network", resource_name, name=name, vlan_id=vlan_id,
            convert=convert, **properties
        )

Ancestors

Subclasses

Methods

def image_download(self, resource_name, name, display_name, url, *, convert=True, **properties)
def image_export_from_volume(self, resource_name, name, display_name, pvc_name, pvc_namespace, *, convert=True, **properties)
def network(self, resource_name, name, vlan_id, *, convert=True, **properties)
def ssh_key(self, resource_name, name, public_key, *, convert=True, **properties)
def virtual_machine(self, resource_name, name, disks, nics, *, convert=True, **properties)
def vm(self, resource_name, name, disks, nics, *, convert=True, **properties)
def volume(self, resource_name, name, size=1, *, convert=True, **properties)

Inherited members

class TerraformResource_060 (converter)
Expand source code
class TerraformResource_060(TerraformResource):
    ''' https://github.com/harvester/terraform-provider-harvester/blob/v0.6.0/docs/resources/ '''
    support_to = "0.6.0"

    def storage_class(
        self, resource_name, name, replicas=1, stale_timeout=30, migratable="true",
        *, convert=True, **properties
    ):
        params = {
                "migratable": migratable,
                "numberOfReplicas": str(replicas),
                "staleReplicaTimeout": str(stale_timeout)
        }
        params.update(properties.pop('parameters', {}))
        return self.make_resource(
            "harvester_storageclass", resource_name, name=name, parameters=params,
            convert=convert, **properties
        )

    def cluster_network(self, resource_name, name, *, convert=True, **properties):
        return self.make_resource(
            "harvester_clusternetwork", resource_name, name=name, convert=convert, **properties
        )

    def vlanconfig(
        self, resource_name, name, cluster_network_name, nics, *, convert=True, **properties
    ):
        uplink = properties.pop('uplink', dict())
        uplink['nics'] = nics

        return self.make_resource(
            "harvester_vlanconfig", resource_name, name=name, uplink=uplink,
            cluster_network_name=cluster_network_name, convert=convert, **properties
        )

    def network(
        self, resource_name, name, vlan_id, cluster_network_name, *, convert=True, **properties
    ):
        return super().network(
            resource_name, name, vlan_id, cluster_network_name=cluster_network_name,
            convert=convert, **properties
        )

Ancestors

Subclasses

Methods

def cluster_network(self, resource_name, name, *, convert=True, **properties)
def network(self, resource_name, name, vlan_id, cluster_network_name, *, convert=True, **properties)
def storage_class(self, resource_name, name, replicas=1, stale_timeout=30, migratable='true', *, convert=True, **properties)
def vlanconfig(self, resource_name, name, cluster_network_name, nics, *, convert=True, **properties)

Inherited members

class TerraformResource_063 (converter)
Expand source code
class TerraformResource_063(TerraformResource_060):
    ''' https://github.com/harvester/terraform-provider-harvester/blob/v0.6.3/docs/resources/ '''

    support_to = "0.6.3"

    def cloudinit_secret(
        self, resource_name, name, user_data="", network_data="", *, convert=True, **properties
    ):
        return self.make_resource(
            "harvester_cloudinit_secret", resource_name,
            user_data=user_data, network_data=network_data, convert=convert, **properties
        )

Ancestors

Methods

def cloudinit_secret(self, resource_name, name, user_data='', network_data='', *, convert=True, **properties)

Inherited members