diff --git a/docs/cluster/auth.html b/docs/cluster/auth.html index 7927b8c8d..15b563f98 100644 --- a/docs/cluster/auth.html +++ b/docs/cluster/auth.html @@ -483,4 +483,4 @@

pdoc 0.10.0.

- + \ No newline at end of file diff --git a/docs/cluster/awload.html b/docs/cluster/awload.html index 2d4c776d1..7abc120a5 100644 --- a/docs/cluster/awload.html +++ b/docs/cluster/awload.html @@ -352,4 +352,4 @@

pdoc 0.10.0.

- + \ No newline at end of file diff --git a/docs/cluster/cluster.html b/docs/cluster/cluster.html index 35dcd9f97..83b2ef5fe 100644 --- a/docs/cluster/cluster.html +++ b/docs/cluster/cluster.html @@ -116,6 +116,8 @@

Module codeflare_sdk.cluster.cluster

instascale = self.config.instascale instance_types = self.config.machine_types env = self.config.envs + local_interactive = self.config.local_interactive + image_pull_secrets = self.config.image_pull_secrets return generate_appwrapper( name=name, namespace=namespace, @@ -130,6 +132,8 @@

Module codeflare_sdk.cluster.cluster

instascale=instascale, instance_types=instance_types, env=env, + local_interactive=local_interactive, + image_pull_secrets=image_pull_secrets, ) # creates a new cluster with the provided or default spec @@ -635,6 +639,8 @@

Classes

instascale = self.config.instascale instance_types = self.config.machine_types env = self.config.envs + local_interactive = self.config.local_interactive + image_pull_secrets = self.config.image_pull_secrets return generate_appwrapper( name=name, namespace=namespace, @@ -649,6 +655,8 @@

Classes

instascale=instascale, instance_types=instance_types, env=env, + local_interactive=local_interactive, + image_pull_secrets=image_pull_secrets, ) # creates a new cluster with the provided or default spec @@ -930,6 +938,8 @@

Methods

instascale = self.config.instascale instance_types = self.config.machine_types env = self.config.envs + local_interactive = self.config.local_interactive + image_pull_secrets = self.config.image_pull_secrets return generate_appwrapper( name=name, namespace=namespace, @@ -944,6 +954,8 @@

Methods

instascale=instascale, instance_types=instance_types, env=env, + local_interactive=local_interactive, + image_pull_secrets=image_pull_secrets, )
@@ -1261,4 +1273,4 @@

pdoc 0.10.0.

- + \ No newline at end of file diff --git a/docs/cluster/config.html b/docs/cluster/config.html index b80192ec8..980155674 100644 --- a/docs/cluster/config.html +++ b/docs/cluster/config.html @@ -79,7 +79,9 @@

Module codeflare_sdk.cluster.config

template: str = f"{dir}/templates/base-template.yaml" instascale: bool = False envs: dict = field(default_factory=dict) - image: str = "ghcr.io/foundation-model-stack/base:ray2.1.0-py38-gpu-pytorch1.12.0cu116-20221213-193103"
+ image: str = "ghcr.io/foundation-model-stack/base:ray2.1.0-py38-gpu-pytorch1.12.0cu116-20221213-193103" + local_interactive: bool = False + image_pull_secrets: list = field(default_factory=list)
@@ -93,7 +95,7 @@

Classes

class ClusterConfiguration -(name: str, namespace: str = None, head_info: list = <factory>, machine_types: list = <factory>, min_cpus: int = 1, max_cpus: int = 1, min_worker: int = 1, max_worker: int = 1, min_memory: int = 2, max_memory: int = 2, gpu: int = 0, template: str = '/home/meyceoz/Documents/codeflare-sdk/src/codeflare_sdk/templates/base-template.yaml', instascale: bool = False, envs: dict = <factory>, image: str = 'ghcr.io/foundation-model-stack/base:ray2.1.0-py38-gpu-pytorch1.12.0cu116-20221213-193103') +(name: str, namespace: str = None, head_info: list = <factory>, machine_types: list = <factory>, min_cpus: int = 1, max_cpus: int = 1, min_worker: int = 1, max_worker: int = 1, min_memory: int = 2, max_memory: int = 2, gpu: int = 0, template: str = '/home/runner/work/codeflare-sdk/codeflare-sdk/src/codeflare_sdk/templates/base-template.yaml', instascale: bool = False, envs: dict = <factory>, image: str = 'ghcr.io/foundation-model-stack/base:ray2.1.0-py38-gpu-pytorch1.12.0cu116-20221213-193103', local_interactive: bool = False, image_pull_secrets: list = <factory>)

This dataclass is used to specify resource requirements and other details, and @@ -122,7 +124,9 @@

Classes

template: str = f"{dir}/templates/base-template.yaml" instascale: bool = False envs: dict = field(default_factory=dict) - image: str = "ghcr.io/foundation-model-stack/base:ray2.1.0-py38-gpu-pytorch1.12.0cu116-20221213-193103" + image: str = "ghcr.io/foundation-model-stack/base:ray2.1.0-py38-gpu-pytorch1.12.0cu116-20221213-193103" + local_interactive: bool = False + image_pull_secrets: list = field(default_factory=list)

Class variables

@@ -142,10 +146,18 @@

Class variables

+
var image_pull_secrets : list
+
+
+
var instascale : bool
+
var local_interactive : bool
+
+
+
var machine_types : list
@@ -211,7 +223,9 @@

gpu
  • head_info
  • image
  • +
  • image_pull_secrets
  • instascale
  • +
  • local_interactive
  • machine_types
  • max_cpus
  • max_memory
  • @@ -233,4 +247,4 @@

    pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/cluster/index.html b/docs/cluster/index.html index a6027e6f9..77d4de974 100644 --- a/docs/cluster/index.html +++ b/docs/cluster/index.html @@ -88,4 +88,4 @@

    Index

    Generated by pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/cluster/model.html b/docs/cluster/model.html index 4097aef2b..2a4615559 100644 --- a/docs/cluster/model.html +++ b/docs/cluster/model.html @@ -468,4 +468,4 @@

    pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index bd408f760..eca42a64e 100644 --- a/docs/index.html +++ b/docs/index.html @@ -67,4 +67,4 @@

    Index

    Generated by pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/job/index.html b/docs/job/index.html index 2360deec2..335c2b576 100644 --- a/docs/job/index.html +++ b/docs/job/index.html @@ -62,4 +62,4 @@

    Index

    Generated by pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/job/jobs.html b/docs/job/jobs.html index 366ab862d..08099daac 100644 --- a/docs/job/jobs.html +++ b/docs/job/jobs.html @@ -305,7 +305,7 @@

    Methods

    class DDPJobDefinition -(script: Optional[str] = None, m: Optional[str] = None, script_args: Optional[List[str]] = None, name: Optional[str] = None, cpu: Optional[int] = None, gpu: Optional[int] = None, memMB: Optional[int] = None, h: Optional[str] = None, j: Optional[str] = None, env: Optional[Dict[str, str]] = None, max_retries: int = 0, mounts: Optional[List[str]] = None, rdzv_port: int = 29500, rdzv_backend: str = None, scheduler_args: Optional[Dict[str, str]] = None, image: Optional[str] = None, workspace: Optional[str] = 'file:///home/meyceoz/Documents/codeflare-sdk') +(script: Optional[str] = None, m: Optional[str] = None, script_args: Optional[List[str]] = None, name: Optional[str] = None, cpu: Optional[int] = None, gpu: Optional[int] = None, memMB: Optional[int] = None, h: Optional[str] = None, j: Optional[str] = None, env: Optional[Dict[str, str]] = None, max_retries: int = 0, mounts: Optional[List[str]] = None, rdzv_port: int = 29500, rdzv_backend: str = None, scheduler_args: Optional[Dict[str, str]] = None, image: Optional[str] = None, workspace: Optional[str] = 'file:///home/runner/work/codeflare-sdk/codeflare-sdk')
    @@ -593,4 +593,4 @@

    pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/utils/generate_cert.html b/docs/utils/generate_cert.html new file mode 100644 index 000000000..5f1fa18af --- /dev/null +++ b/docs/utils/generate_cert.html @@ -0,0 +1,395 @@ + + + + + + +codeflare_sdk.utils.generate_cert API documentation + + + + + + + + + + + +
    +
    +
    +

    Module codeflare_sdk.utils.generate_cert

    +
    +
    +
    + +Expand source code + +
    # Copyright 2022 IBM, Red Hat
    +#
    +# Licensed under the Apache License, Version 2.0 (the "License");
    +# you may not use this file except in compliance with the License.
    +# You may obtain a copy of the License at
    +#
    +#      http://www.apache.org/licenses/LICENSE-2.0
    +#
    +# Unless required by applicable law or agreed to in writing, software
    +# distributed under the License is distributed on an "AS IS" BASIS,
    +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    +# See the License for the specific language governing permissions and
    +# limitations under the License.
    +
    +import base64
    +import os
    +from cryptography.hazmat.primitives import serialization, hashes
    +from cryptography.hazmat.primitives.asymmetric import rsa
    +from cryptography import x509
    +from cryptography.x509.oid import NameOID
    +import datetime
    +from kubernetes import client, config
    +
    +
    +def generate_ca_cert(days: int = 30):
    +    # Generate base64 encoded ca.key and ca.cert
    +    # Similar to:
    +    # openssl req -x509 -nodes -newkey rsa:2048 -keyout ca.key -days 1826 -out ca.crt -subj '/CN=root-ca'
    +    # base64 -i ca.crt -i ca.key
    +
    +    private_key = rsa.generate_private_key(
    +        public_exponent=65537,
    +        key_size=2048,
    +    )
    +
    +    key = base64.b64encode(
    +        private_key.private_bytes(
    +            serialization.Encoding.PEM,
    +            serialization.PrivateFormat.PKCS8,
    +            serialization.NoEncryption(),
    +        )
    +    ).decode("utf-8")
    +
    +    # Generate Certificate
    +    one_day = datetime.timedelta(1, 0, 0)
    +    public_key = private_key.public_key()
    +    builder = (
    +        x509.CertificateBuilder()
    +        .subject_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "root-ca"),
    +                ]
    +            )
    +        )
    +        .issuer_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "root-ca"),
    +                ]
    +            )
    +        )
    +        .not_valid_before(datetime.datetime.today() - one_day)
    +        .not_valid_after(datetime.datetime.today() + (one_day * days))
    +        .serial_number(x509.random_serial_number())
    +        .public_key(public_key)
    +    )
    +    certificate = base64.b64encode(
    +        builder.sign(private_key=private_key, algorithm=hashes.SHA256()).public_bytes(
    +            serialization.Encoding.PEM
    +        )
    +    ).decode("utf-8")
    +    return key, certificate
    +
    +
    +def generate_tls_cert(cluster_name, namespace, days=30):
    +    # Create a folder tls-<cluster>-<namespace> and store three files: ca.crt, tls.crt, and tls.key
    +    tls_dir = os.path.join(os.getcwd(), f"tls-{cluster_name}-{namespace}")
    +    if not os.path.exists(tls_dir):
    +        os.makedirs(tls_dir)
    +
    +    # Similar to:
    +    # oc get secret ca-secret-<cluster-name> -o template='{{index .data "ca.key"}}'
    +    # oc get secret ca-secret-<cluster-name> -o template='{{index .data "ca.crt"}}'|base64 -d > ${TLSDIR}/ca.crt
    +    config.load_kube_config()
    +    v1 = client.CoreV1Api()
    +    secret = v1.read_namespaced_secret(f"ca-secret-{cluster_name}", namespace).data
    +    ca_cert = secret.get("ca.crt")
    +    ca_key = secret.get("ca.key")
    +
    +    with open(os.path.join(tls_dir, "ca.crt"), "w") as f:
    +        f.write(base64.b64decode(ca_cert).decode("utf-8"))
    +
    +    # Generate tls.key and signed tls.cert locally for ray client
    +    # Similar to running these commands:
    +    # openssl req -nodes -newkey rsa:2048 -keyout ${TLSDIR}/tls.key -out ${TLSDIR}/tls.csr -subj '/CN=local'
    +    # cat <<EOF >${TLSDIR}/domain.ext
    +    # authorityKeyIdentifier=keyid,issuer
    +    # basicConstraints=CA:FALSE
    +    # subjectAltName = @alt_names
    +    # [alt_names]
    +    # DNS.1 = 127.0.0.1
    +    # DNS.2 = localhost
    +    # EOF
    +    # openssl x509 -req -CA ${TLSDIR}/ca.crt -CAkey ${TLSDIR}/ca.key -in ${TLSDIR}/tls.csr -out ${TLSDIR}/tls.crt -days 365 -CAcreateserial -extfile ${TLSDIR}/domain.ext
    +    key = rsa.generate_private_key(
    +        public_exponent=65537,
    +        key_size=2048,
    +    )
    +
    +    tls_key = key.private_bytes(
    +        serialization.Encoding.PEM,
    +        serialization.PrivateFormat.PKCS8,
    +        serialization.NoEncryption(),
    +    )
    +    with open(os.path.join(tls_dir, "tls.key"), "w") as f:
    +        f.write(tls_key.decode("utf-8"))
    +
    +    one_day = datetime.timedelta(1, 0, 0)
    +    tls_cert = (
    +        x509.CertificateBuilder()
    +        .issuer_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "root-ca"),
    +                ]
    +            )
    +        )
    +        .subject_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "local"),
    +                ]
    +            )
    +        )
    +        .public_key(key.public_key())
    +        .not_valid_before(datetime.datetime.today() - one_day)
    +        .not_valid_after(datetime.datetime.today() + (one_day * days))
    +        .serial_number(x509.random_serial_number())
    +        .add_extension(
    +            x509.SubjectAlternativeName(
    +                [x509.DNSName("localhost"), x509.DNSName("127.0.0.1")]
    +            ),
    +            False,
    +        )
    +        .sign(
    +            serialization.load_pem_private_key(base64.b64decode(ca_key), None),
    +            hashes.SHA256(),
    +        )
    +    )
    +
    +    with open(os.path.join(tls_dir, "tls.crt"), "w") as f:
    +        f.write(tls_cert.public_bytes(serialization.Encoding.PEM).decode("utf-8"))
    +
    +
    +def export_env(cluster_name, namespace):
    +    tls_dir = os.path.join(os.getcwd(), f"tls-{cluster_name}-{namespace}")
    +    os.environ["RAY_USE_TLS"] = "1"
    +    os.environ["RAY_TLS_SERVER_CERT"] = os.path.join(tls_dir, "tls.crt")
    +    os.environ["RAY_TLS_SERVER_KEY"] = os.path.join(tls_dir, "tls.key")
    +    os.environ["RAY_TLS_CA_CERT"] = os.path.join(tls_dir, "ca.crt")
    +
    +
    +
    +
    +
    +
    +
    +

    Functions

    +
    +
    +def export_env(cluster_name, namespace) +
    +
    +
    +
    + +Expand source code + +
    def export_env(cluster_name, namespace):
    +    tls_dir = os.path.join(os.getcwd(), f"tls-{cluster_name}-{namespace}")
    +    os.environ["RAY_USE_TLS"] = "1"
    +    os.environ["RAY_TLS_SERVER_CERT"] = os.path.join(tls_dir, "tls.crt")
    +    os.environ["RAY_TLS_SERVER_KEY"] = os.path.join(tls_dir, "tls.key")
    +    os.environ["RAY_TLS_CA_CERT"] = os.path.join(tls_dir, "ca.crt")
    +
    +
    +
    +def generate_ca_cert(days: int = 30) +
    +
    +
    +
    + +Expand source code + +
    def generate_ca_cert(days: int = 30):
    +    # Generate base64 encoded ca.key and ca.cert
    +    # Similar to:
    +    # openssl req -x509 -nodes -newkey rsa:2048 -keyout ca.key -days 1826 -out ca.crt -subj '/CN=root-ca'
    +    # base64 -i ca.crt -i ca.key
    +
    +    private_key = rsa.generate_private_key(
    +        public_exponent=65537,
    +        key_size=2048,
    +    )
    +
    +    key = base64.b64encode(
    +        private_key.private_bytes(
    +            serialization.Encoding.PEM,
    +            serialization.PrivateFormat.PKCS8,
    +            serialization.NoEncryption(),
    +        )
    +    ).decode("utf-8")
    +
    +    # Generate Certificate
    +    one_day = datetime.timedelta(1, 0, 0)
    +    public_key = private_key.public_key()
    +    builder = (
    +        x509.CertificateBuilder()
    +        .subject_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "root-ca"),
    +                ]
    +            )
    +        )
    +        .issuer_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "root-ca"),
    +                ]
    +            )
    +        )
    +        .not_valid_before(datetime.datetime.today() - one_day)
    +        .not_valid_after(datetime.datetime.today() + (one_day * days))
    +        .serial_number(x509.random_serial_number())
    +        .public_key(public_key)
    +    )
    +    certificate = base64.b64encode(
    +        builder.sign(private_key=private_key, algorithm=hashes.SHA256()).public_bytes(
    +            serialization.Encoding.PEM
    +        )
    +    ).decode("utf-8")
    +    return key, certificate
    +
    +
    +
    +def generate_tls_cert(cluster_name, namespace, days=30) +
    +
    +
    +
    + +Expand source code + +
    def generate_tls_cert(cluster_name, namespace, days=30):
    +    # Create a folder tls-<cluster>-<namespace> and store three files: ca.crt, tls.crt, and tls.key
    +    tls_dir = os.path.join(os.getcwd(), f"tls-{cluster_name}-{namespace}")
    +    if not os.path.exists(tls_dir):
    +        os.makedirs(tls_dir)
    +
    +    # Similar to:
    +    # oc get secret ca-secret-<cluster-name> -o template='{{index .data "ca.key"}}'
    +    # oc get secret ca-secret-<cluster-name> -o template='{{index .data "ca.crt"}}'|base64 -d > ${TLSDIR}/ca.crt
    +    config.load_kube_config()
    +    v1 = client.CoreV1Api()
    +    secret = v1.read_namespaced_secret(f"ca-secret-{cluster_name}", namespace).data
    +    ca_cert = secret.get("ca.crt")
    +    ca_key = secret.get("ca.key")
    +
    +    with open(os.path.join(tls_dir, "ca.crt"), "w") as f:
    +        f.write(base64.b64decode(ca_cert).decode("utf-8"))
    +
    +    # Generate tls.key and signed tls.cert locally for ray client
    +    # Similar to running these commands:
    +    # openssl req -nodes -newkey rsa:2048 -keyout ${TLSDIR}/tls.key -out ${TLSDIR}/tls.csr -subj '/CN=local'
    +    # cat <<EOF >${TLSDIR}/domain.ext
    +    # authorityKeyIdentifier=keyid,issuer
    +    # basicConstraints=CA:FALSE
    +    # subjectAltName = @alt_names
    +    # [alt_names]
    +    # DNS.1 = 127.0.0.1
    +    # DNS.2 = localhost
    +    # EOF
    +    # openssl x509 -req -CA ${TLSDIR}/ca.crt -CAkey ${TLSDIR}/ca.key -in ${TLSDIR}/tls.csr -out ${TLSDIR}/tls.crt -days 365 -CAcreateserial -extfile ${TLSDIR}/domain.ext
    +    key = rsa.generate_private_key(
    +        public_exponent=65537,
    +        key_size=2048,
    +    )
    +
    +    tls_key = key.private_bytes(
    +        serialization.Encoding.PEM,
    +        serialization.PrivateFormat.PKCS8,
    +        serialization.NoEncryption(),
    +    )
    +    with open(os.path.join(tls_dir, "tls.key"), "w") as f:
    +        f.write(tls_key.decode("utf-8"))
    +
    +    one_day = datetime.timedelta(1, 0, 0)
    +    tls_cert = (
    +        x509.CertificateBuilder()
    +        .issuer_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "root-ca"),
    +                ]
    +            )
    +        )
    +        .subject_name(
    +            x509.Name(
    +                [
    +                    x509.NameAttribute(NameOID.COMMON_NAME, "local"),
    +                ]
    +            )
    +        )
    +        .public_key(key.public_key())
    +        .not_valid_before(datetime.datetime.today() - one_day)
    +        .not_valid_after(datetime.datetime.today() + (one_day * days))
    +        .serial_number(x509.random_serial_number())
    +        .add_extension(
    +            x509.SubjectAlternativeName(
    +                [x509.DNSName("localhost"), x509.DNSName("127.0.0.1")]
    +            ),
    +            False,
    +        )
    +        .sign(
    +            serialization.load_pem_private_key(base64.b64decode(ca_key), None),
    +            hashes.SHA256(),
    +        )
    +    )
    +
    +    with open(os.path.join(tls_dir, "tls.crt"), "w") as f:
    +        f.write(tls_cert.public_bytes(serialization.Encoding.PEM).decode("utf-8"))
    +
    +
    +
    +
    +
    +
    +
    + +
    + + + \ No newline at end of file diff --git a/docs/utils/generate_yaml.html b/docs/utils/generate_yaml.html index a1dfeddd5..9dc44b427 100644 --- a/docs/utils/generate_yaml.html +++ b/docs/utils/generate_yaml.html @@ -52,6 +52,7 @@

    Module codeflare_sdk.utils.generate_yaml

    import sys import argparse import uuid +import openshift as oc def read_template(template): @@ -81,6 +82,16 @@

    Module codeflare_sdk.utils.generate_yaml

    spec["to"]["name"] = f"{cluster_name}-head-svc" +# ToDo: refactor the update_x_route() functions +def update_rayclient_route(route_item, cluster_name, namespace): + metadata = route_item.get("generictemplate", {}).get("metadata") + metadata["name"] = f"rayclient-{cluster_name}" + metadata["namespace"] = namespace + metadata["labels"]["odh-ray-cluster-service"] = f"{cluster_name}-head-svc" + spec = route_item.get("generictemplate", {}).get("spec") + spec["to"]["name"] = f"{cluster_name}-head-svc" + + def update_names(yaml, item, appwrapper_name, cluster_name, namespace): metadata = yaml.get("metadata") metadata["name"] = appwrapper_name @@ -161,6 +172,13 @@

    Module codeflare_sdk.utils.generate_yaml

    container["image"] = image +def update_image_pull_secrets(spec, image_pull_secrets): + template_secrets = spec.get("imagePullSecrets", []) + spec["imagePullSecrets"] = template_secrets + [ + {"name": x} for x in image_pull_secrets + ] + + def update_env(spec, env): containers = spec.get("containers") for container in containers: @@ -198,6 +216,7 @@

    Module codeflare_sdk.utils.generate_yaml

    image, instascale, env, + image_pull_secrets, ): if "generictemplate" in item.keys(): head = item.get("generictemplate").get("spec").get("headGroupSpec") @@ -213,6 +232,7 @@

    Module codeflare_sdk.utils.generate_yaml

    for comp in [head, worker]: spec = comp.get("template").get("spec") update_affinity(spec, appwrapper_name, instascale) + update_image_pull_secrets(spec, image_pull_secrets) update_image(spec, image) update_env(spec, env) if comp == head: @@ -222,6 +242,78 @@

    Module codeflare_sdk.utils.generate_yaml

    update_resources(spec, min_cpu, max_cpu, min_memory, max_memory, gpu) +def update_ca_secret(ca_secret_item, cluster_name, namespace): + from . import generate_cert + + metadata = ca_secret_item.get("generictemplate", {}).get("metadata") + metadata["name"] = f"ca-secret-{cluster_name}" + metadata["namespace"] = namespace + metadata["labels"]["odh-ray-cluster-service"] = f"{cluster_name}-head-svc" + data = ca_secret_item.get("generictemplate", {}).get("data") + data["ca.key"], data["ca.crt"] = generate_cert.generate_ca_cert(365) + + +def enable_local_interactive(resources, cluster_name, namespace): + rayclient_route_item = resources["resources"].get("GenericItems")[2] + ca_secret_item = resources["resources"].get("GenericItems")[3] + item = resources["resources"].get("GenericItems")[0] + update_rayclient_route(rayclient_route_item, cluster_name, namespace) + update_ca_secret(ca_secret_item, cluster_name, namespace) + # update_ca_secret_volumes + item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"]["volumes"][0][ + "secret" + ]["secretName"] = f"ca-secret-{cluster_name}" + item["generictemplate"]["spec"]["workerGroupSpecs"][0]["template"]["spec"][ + "volumes" + ][0]["secret"]["secretName"] = f"ca-secret-{cluster_name}" + # update_tls_env + item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"]["containers"][ + 0 + ]["env"][1]["value"] = "1" + item["generictemplate"]["spec"]["workerGroupSpecs"][0]["template"]["spec"][ + "containers" + ][0]["env"][1]["value"] = "1" + # update_init_container + command = item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"][ + "initContainers" + ][0].get("command")[2] + + command = command.replace("deployment-name", cluster_name) + + server_name = ( + oc.whoami("--show-server").split(":")[1].split("//")[1].replace("api", "apps") + ) + + command = command.replace("server-name", server_name) + + item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"][ + "initContainers" + ][0].get("command")[2] = command + + +def disable_raycluster_tls(resources): + del resources["GenericItems"][0]["generictemplate"]["spec"]["headGroupSpec"][ + "template" + ]["spec"]["volumes"] + del resources["GenericItems"][0]["generictemplate"]["spec"]["headGroupSpec"][ + "template" + ]["spec"]["containers"][0]["volumeMounts"] + del resources["GenericItems"][0]["generictemplate"]["spec"]["headGroupSpec"][ + "template" + ]["spec"]["initContainers"] + del resources["GenericItems"][0]["generictemplate"]["spec"]["workerGroupSpecs"][0][ + "template" + ]["spec"]["volumes"] + del resources["GenericItems"][0]["generictemplate"]["spec"]["workerGroupSpecs"][0][ + "template" + ]["spec"]["containers"][0]["volumeMounts"] + del resources["GenericItems"][0]["generictemplate"]["spec"]["workerGroupSpecs"][0][ + "template" + ]["spec"]["initContainers"][1] + del resources["GenericItems"][3] # rayclient route + del resources["GenericItems"][2] # ca-secret + + def write_user_appwrapper(user_yaml, output_file_name): with open(output_file_name, "w") as outfile: yaml.dump(user_yaml, outfile, default_flow_style=False) @@ -242,6 +334,8 @@

    Module codeflare_sdk.utils.generate_yaml

    instascale: bool, instance_types: list, env, + local_interactive: bool, + image_pull_secrets: list, ): user_yaml = read_template(template) appwrapper_name, cluster_name = gen_names(name) @@ -265,8 +359,13 @@

    Module codeflare_sdk.utils.generate_yaml

    image, instascale, env, + image_pull_secrets, ) update_dashboard_route(route_item, cluster_name, namespace) + if local_interactive: + enable_local_interactive(resources, cluster_name, namespace) + else: + disable_raycluster_tls(resources["resources"]) outfile = appwrapper_name + ".yaml" write_user_appwrapper(user_yaml, outfile) return outfile @@ -346,6 +445,18 @@

    Module codeflare_sdk.utils.generate_yaml

    default="default", help="Set the kubernetes namespace you want to deploy your cluster to. Default. If left blank, uses the 'default' namespace", ) + parser.add_argument( + "--local-interactive", + required=False, + default=False, + help="Enable local interactive mode", + ) + parser.add_argument( + "--image-pull-secrets", + required=False, + default=[], + help="Set image pull secrets for private registries", + ) args = parser.parse_args() name = args.name @@ -360,7 +471,9 @@

    Module codeflare_sdk.utils.generate_yaml

    instascale = args.instascale instance_types = args.instance_types namespace = args.namespace + local_interactive = args.local_interactive env = {} + image_pull_secrets = args.image_pull_secrets outfile = generate_appwrapper( name, @@ -375,7 +488,9 @@

    Module codeflare_sdk.utils.generate_yaml

    image, instascale, instance_types, + local_interactive, env, + image_pull_secrets, ) return outfile @@ -391,6 +506,85 @@

    Module codeflare_sdk.utils.generate_yaml

    Functions

    +
    +def disable_raycluster_tls(resources) +
    +
    +
    +
    + +Expand source code + +
    def disable_raycluster_tls(resources):
    +    del resources["GenericItems"][0]["generictemplate"]["spec"]["headGroupSpec"][
    +        "template"
    +    ]["spec"]["volumes"]
    +    del resources["GenericItems"][0]["generictemplate"]["spec"]["headGroupSpec"][
    +        "template"
    +    ]["spec"]["containers"][0]["volumeMounts"]
    +    del resources["GenericItems"][0]["generictemplate"]["spec"]["headGroupSpec"][
    +        "template"
    +    ]["spec"]["initContainers"]
    +    del resources["GenericItems"][0]["generictemplate"]["spec"]["workerGroupSpecs"][0][
    +        "template"
    +    ]["spec"]["volumes"]
    +    del resources["GenericItems"][0]["generictemplate"]["spec"]["workerGroupSpecs"][0][
    +        "template"
    +    ]["spec"]["containers"][0]["volumeMounts"]
    +    del resources["GenericItems"][0]["generictemplate"]["spec"]["workerGroupSpecs"][0][
    +        "template"
    +    ]["spec"]["initContainers"][1]
    +    del resources["GenericItems"][3]  # rayclient route
    +    del resources["GenericItems"][2]  # ca-secret
    +
    +
    +
    +def enable_local_interactive(resources, cluster_name, namespace) +
    +
    +
    +
    + +Expand source code + +
    def enable_local_interactive(resources, cluster_name, namespace):
    +    rayclient_route_item = resources["resources"].get("GenericItems")[2]
    +    ca_secret_item = resources["resources"].get("GenericItems")[3]
    +    item = resources["resources"].get("GenericItems")[0]
    +    update_rayclient_route(rayclient_route_item, cluster_name, namespace)
    +    update_ca_secret(ca_secret_item, cluster_name, namespace)
    +    # update_ca_secret_volumes
    +    item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"]["volumes"][0][
    +        "secret"
    +    ]["secretName"] = f"ca-secret-{cluster_name}"
    +    item["generictemplate"]["spec"]["workerGroupSpecs"][0]["template"]["spec"][
    +        "volumes"
    +    ][0]["secret"]["secretName"] = f"ca-secret-{cluster_name}"
    +    # update_tls_env
    +    item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"]["containers"][
    +        0
    +    ]["env"][1]["value"] = "1"
    +    item["generictemplate"]["spec"]["workerGroupSpecs"][0]["template"]["spec"][
    +        "containers"
    +    ][0]["env"][1]["value"] = "1"
    +    # update_init_container
    +    command = item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"][
    +        "initContainers"
    +    ][0].get("command")[2]
    +
    +    command = command.replace("deployment-name", cluster_name)
    +
    +    server_name = (
    +        oc.whoami("--show-server").split(":")[1].split("//")[1].replace("api", "apps")
    +    )
    +
    +    command = command.replace("server-name", server_name)
    +
    +    item["generictemplate"]["spec"]["headGroupSpec"]["template"]["spec"][
    +        "initContainers"
    +    ][0].get("command")[2] = command
    +
    +
    def gen_names(name)
    @@ -411,7 +605,7 @@

    Functions

    -def generate_appwrapper(name: str, namespace: str, min_cpu: int, max_cpu: int, min_memory: int, max_memory: int, gpu: int, workers: int, template: str, image: str, instascale: bool, instance_types: list, env) +def generate_appwrapper(name: str, namespace: str, min_cpu: int, max_cpu: int, min_memory: int, max_memory: int, gpu: int, workers: int, template: str, image: str, instascale: bool, instance_types: list, env, local_interactive: bool, image_pull_secrets: list)
    @@ -433,6 +627,8 @@

    Functions

    instascale: bool, instance_types: list, env, + local_interactive: bool, + image_pull_secrets: list, ): user_yaml = read_template(template) appwrapper_name, cluster_name = gen_names(name) @@ -456,8 +652,13 @@

    Functions

    image, instascale, env, + image_pull_secrets, ) update_dashboard_route(route_item, cluster_name, namespace) + if local_interactive: + enable_local_interactive(resources, cluster_name, namespace) + else: + disable_raycluster_tls(resources["resources"]) outfile = appwrapper_name + ".yaml" write_user_appwrapper(user_yaml, outfile) return outfile
    @@ -546,6 +747,18 @@

    Functions

    default="default", help="Set the kubernetes namespace you want to deploy your cluster to. Default. If left blank, uses the 'default' namespace", ) + parser.add_argument( + "--local-interactive", + required=False, + default=False, + help="Enable local interactive mode", + ) + parser.add_argument( + "--image-pull-secrets", + required=False, + default=[], + help="Set image pull secrets for private registries", + ) args = parser.parse_args() name = args.name @@ -560,7 +773,9 @@

    Functions

    instascale = args.instascale instance_types = args.instance_types namespace = args.namespace + local_interactive = args.local_interactive env = {} + image_pull_secrets = args.image_pull_secrets outfile = generate_appwrapper( name, @@ -575,7 +790,9 @@

    Functions

    image, instascale, instance_types, + local_interactive, env, + image_pull_secrets, ) return outfile
    @@ -620,6 +837,26 @@

    Functions

    spec.pop("affinity")
    +
    +def update_ca_secret(ca_secret_item, cluster_name, namespace) +
    +
    +
    +
    + +Expand source code + +
    def update_ca_secret(ca_secret_item, cluster_name, namespace):
    +    from . import generate_cert
    +
    +    metadata = ca_secret_item.get("generictemplate", {}).get("metadata")
    +    metadata["name"] = f"ca-secret-{cluster_name}"
    +    metadata["namespace"] = namespace
    +    metadata["labels"]["odh-ray-cluster-service"] = f"{cluster_name}-head-svc"
    +    data = ca_secret_item.get("generictemplate", {}).get("data")
    +    data["ca.key"], data["ca.crt"] = generate_cert.generate_ca_cert(365)
    +
    +
    def update_custompodresources(item, min_cpu, max_cpu, min_memory, max_memory, gpu, workers)
    @@ -715,6 +952,22 @@

    Functions

    container["image"] = image
    +
    +def update_image_pull_secrets(spec, image_pull_secrets) +
    +
    +
    +
    + +Expand source code + +
    def update_image_pull_secrets(spec, image_pull_secrets):
    +    template_secrets = spec.get("imagePullSecrets", [])
    +    spec["imagePullSecrets"] = template_secrets + [
    +        {"name": x} for x in image_pull_secrets
    +    ]
    +
    +
    def update_labels(yaml, instascale, instance_types)
    @@ -760,7 +1013,7 @@

    Functions

    -def update_nodes(item, appwrapper_name, min_cpu, max_cpu, min_memory, max_memory, gpu, workers, image, instascale, env) +def update_nodes(item, appwrapper_name, min_cpu, max_cpu, min_memory, max_memory, gpu, workers, image, instascale, env, image_pull_secrets)
    @@ -780,6 +1033,7 @@

    Functions

    image, instascale, env, + image_pull_secrets, ): if "generictemplate" in item.keys(): head = item.get("generictemplate").get("spec").get("headGroupSpec") @@ -795,6 +1049,7 @@

    Functions

    for comp in [head, worker]: spec = comp.get("template").get("spec") update_affinity(spec, appwrapper_name, instascale) + update_image_pull_secrets(spec, image_pull_secrets) update_image(spec, image) update_env(spec, env) if comp == head: @@ -804,6 +1059,24 @@

    Functions

    update_resources(spec, min_cpu, max_cpu, min_memory, max_memory, gpu)
    +
    +def update_rayclient_route(route_item, cluster_name, namespace) +
    +
    +
    +
    + +Expand source code + +
    def update_rayclient_route(route_item, cluster_name, namespace):
    +    metadata = route_item.get("generictemplate", {}).get("metadata")
    +    metadata["name"] = f"rayclient-{cluster_name}"
    +    metadata["namespace"] = namespace
    +    metadata["labels"]["odh-ray-cluster-service"] = f"{cluster_name}-head-svc"
    +    spec = route_item.get("generictemplate", {}).get("spec")
    +    spec["to"]["name"] = f"{cluster_name}-head-svc"
    +
    +
    def update_resources(spec, min_cpu, max_cpu, min_memory, max_memory, gpu)
    @@ -861,18 +1134,23 @@

    Index

  • Functions

    @@ -884,4 +1162,4 @@

    Index

    Generated by pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/utils/index.html b/docs/utils/index.html index 3c887e468..bfbc5d7b3 100644 --- a/docs/utils/index.html +++ b/docs/utils/index.html @@ -26,6 +26,10 @@

    Module codeflare_sdk.utils

    Sub-modules

    +
    codeflare_sdk.utils.generate_cert
    +
    +
    +
    codeflare_sdk.utils.generate_yaml

    This sub-module exists primarily to be used internally by the Cluster object @@ -58,6 +62,7 @@

    Index

  • Sub-modules

    @@ -69,4 +74,4 @@

    Index

    Generated by pdoc 0.10.0.

    - + \ No newline at end of file diff --git a/docs/utils/pretty_print.html b/docs/utils/pretty_print.html index bc45a951b..d6f64b3a7 100644 --- a/docs/utils/pretty_print.html +++ b/docs/utils/pretty_print.html @@ -450,4 +450,4 @@

    Index

    Generated by pdoc 0.10.0.

    - + \ No newline at end of file