From a735926f8ce029670fb0294af71e0e7dcf9a341a Mon Sep 17 00:00:00 2001 From: Naresh Sharma Date: Wed, 27 Sep 2023 23:27:14 -0400 Subject: [PATCH 001/309] updated kubeflow to v1.6 Signed-off-by: Naresh Sharma --- platforms/kubeflow.yml | 23 +- platforms/roles/kubeflow/defaults/main.yml | 5 + platforms/roles/kubeflow/handlers/main.yml | 12 + .../roles/kubeflow/tasks/deploy_kubeflow.yml | 253 - .../roles/kubeflow/tasks/firewalld_config.yml | 45 - .../roles/kubeflow/tasks/kubeflow_deploy.yml | 124 + .../kubeflow/tasks/kustomize_install.yml | 24 + platforms/roles/kubeflow/tasks/main.yml | 23 +- .../roles/kubeflow/tasks/prerequisite.yml | 28 + .../template/crd_mpijobs_kubeflow.yaml.j2 | 7863 +++++++++++++++++ platforms/roles/kubeflow/vars/main.yml | 48 - 11 files changed, 8068 insertions(+), 380 deletions(-) create mode 100644 platforms/roles/kubeflow/defaults/main.yml create mode 100644 platforms/roles/kubeflow/handlers/main.yml delete mode 100644 platforms/roles/kubeflow/tasks/deploy_kubeflow.yml delete mode 100644 platforms/roles/kubeflow/tasks/firewalld_config.yml create mode 100644 platforms/roles/kubeflow/tasks/kubeflow_deploy.yml create mode 100644 platforms/roles/kubeflow/tasks/kustomize_install.yml create mode 100644 platforms/roles/kubeflow/tasks/prerequisite.yml create mode 100644 platforms/roles/kubeflow/template/crd_mpijobs_kubeflow.yaml.j2 delete mode 100644 platforms/roles/kubeflow/vars/main.yml diff --git a/platforms/kubeflow.yml b/platforms/kubeflow.yml index d48587d9e..b2bb6842e 100644 --- a/platforms/kubeflow.yml +++ b/platforms/kubeflow.yml @@ -1,20 +1,9 @@ -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved. -# -# 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. --- +- name: Deploy kubeflow 1.6 on k8s cluster + hosts: manager, compute + become: true + gather_facts: true -- name: Installing Kubeflow - hosts: manager - gather_facts: false + # role to deploy kubeflow roles: - - kubeflow \ No newline at end of file + - kubeflow diff --git a/platforms/roles/kubeflow/defaults/main.yml b/platforms/roles/kubeflow/defaults/main.yml new file mode 100644 index 000000000..119f8cdde --- /dev/null +++ b/platforms/roles/kubeflow/defaults/main.yml @@ -0,0 +1,5 @@ +--- +kustomize_url: https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.1.0/kustomize_v5.1.0_linux_amd64.tar.gz +kubeflow_url: https://github.com/kubeflow/manifests.git +istio_ingressgateway_service_yaml_file_path: /kubeflow/common/istio-1-14/istio-install/base/patches/service.yaml +training_operator_deployment_yaml_file_path: /kubeflow/apps/training-operator/upstream/base/deployment.yaml diff --git a/platforms/roles/kubeflow/handlers/main.yml b/platforms/roles/kubeflow/handlers/main.yml new file mode 100644 index 000000000..13b903ae5 --- /dev/null +++ b/platforms/roles/kubeflow/handlers/main.yml @@ -0,0 +1,12 @@ +--- +- name: Load kernel modules + command: /sbin/modprobe {{ item }} + with_items: + - br_netfilter + - nf_nat + - xt_REDIRECT + - xt_owner + - iptable_nat + - iptable_mangle + - iptable_filter + when: inventory_hostname in groups["compute"] \ No newline at end of file diff --git a/platforms/roles/kubeflow/tasks/deploy_kubeflow.yml b/platforms/roles/kubeflow/tasks/deploy_kubeflow.yml deleted file mode 100644 index f3d4e7bf2..000000000 --- a/platforms/roles/kubeflow/tasks/deploy_kubeflow.yml +++ /dev/null @@ -1,253 +0,0 @@ -# Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved. -# -# 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. ---- - -- name: Download kfctl release from the Kubeflow releases page - unarchive: - src: "{{ kfctl_download_url }}" - dest: "{{ kfctl_download_dest_path }}" - mode: "{{ kfctl_download_file_mode }}" - remote_src: yes - -- name: Delete omnia kubeflow directory if exists - file: - path: "{{ omnia_kubeflow_dir_path }}" - state: absent - -- name: Create omnia kubeflow directory - file: - path: "{{ omnia_kubeflow_dir_path }}" - state: directory - mode: "{{ omnia_kubeflow_dir_mode }}" - recurse: yes - -- name: Build kubeflow configuration - command: - cmd: /usr/bin/kfctl build -V -f "{{ kubeflow_config_yaml_url }}" - chdir: "{{ omnia_kubeflow_dir_path }}" - changed_when: true - -- name: Modify CPU limits for istio-pilot - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_pilot.yaml.tmpl' - before: '---' - regexp: 'cpu: 2000m' - replace: 'cpu: 2' - -- name: Modify Memory limits for istio-pilot - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_pilot.yaml.tmpl' - before: '---' - regexp: 'memory: 128Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU request for istio-pilot - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_pilot.yaml.tmpl' - before: '---' - regexp: 'cpu: 10m' - replace: 'cpu: 1' - -- name: Modify Memory request for istio-pilot - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_pilot.yaml.tmpl' - before: '---' - regexp: 'memory: 40Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU limits for istio-policy - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_policy.yaml.tmpl' - before: '---' - regexp: 'cpu: 2000m' - replace: 'cpu: 2' - -- name: Modify Memory limits for istio-policy - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_policy.yaml.tmpl' - before: '---' - regexp: 'memory: 128Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU request for istio-policy - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_policy.yaml.tmpl' - before: '---' - regexp: 'cpu: 10m' - replace: 'cpu: 1' - -- name: Modify Memory request for istio-policy - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_policy.yaml.tmpl' - before: '---' - regexp: 'memory: 40Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU limits for istio-telemetry - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_telemetry.yaml.tmpl' - before: '---' - regexp: 'cpu: 2000m' - replace: 'cpu: 2' - -- name: Modify Memory limits for istio-telemetry - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_telemetry.yaml.tmpl' - before: '---' - regexp: 'memory: 128Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU request for istio-telemetry - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_telemetry.yaml.tmpl' - before: '---' - regexp: 'cpu: 10m' - replace: 'cpu: 1' - -- name: Modify Memory request for istio-telemetry - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'envoy_telemetry.yaml.tmpl' - before: '---' - regexp: 'memory: 40Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU limit for istio-ingressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: '---' - regexp: 'cpu: 100m' - replace: 'cpu: 2' - -- name: Modify memory limit for istio-ingressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: '---' - regexp: 'memory: 128Mi' - replace: 'memory: 512Mi' - -- name: Modify CPU request for istio-ingressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: '---' - regexp: 'cpu: 10m' - replace: 'cpu: 1' - -- name: Modify memory request for istio-ingressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: '---' - regexp: 'memory: 40Mi' - replace: 'memory: 256Mi' - -- name: Modify CPU limits for istio-engressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-egressgateway-service-account' - before: '---' - regexp: 'cpu: 100m' - replace: 'cpu: 2' - -- name: Modify CPU request for istio-engressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-egressgateway-service-account' - before: '---' - regexp: 'cpu: 10m' - replace: 'cpu: 1' - -- name: Modify memory request for istio-engressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-egressgateway-service-account' - before: '---' - regexp: 'memory: 128Mi' - replace: 'memory: 512Mi' - -- name: Modify memory request for istio-engressgateway-service-account - replace: - path: "{{ istio_noauth_yaml_file_path }}" - after: 'serviceAccountName: istio-egressgateway-service-account' - before: '---' - regexp: 'memory: 40Mi' - replace: 'memory: 512Mi' - -- name: Modify CPU limit for kfserving-gateway - replace: - path: "{{ kfserving_gateway_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: 'env:' - regexp: 'cpu: 100m' - replace: 'cpu: 2' - -- name: Modify memory limit for kfserving-gateway - replace: - path: "{{ kfserving_gateway_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: 'env:' - regexp: 'memory: 128Mi' - replace: 'memory: 512Mi' - -- name: Modify CPU request for kfserving-gateway - replace: - path: "{{ kfserving_gateway_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: 'env:' - regexp: 'cpu: 10m' - replace: 'cpu: 1' - -- name: Modify memory request for kfserving-gateway - replace: - path: "{{ kfserving_gateway_yaml_file_path }}" - after: 'serviceAccountName: istio-ingressgateway-service-account' - before: 'env:' - regexp: 'memory: 40Mi' - replace: 'memory: 256Mi' - -- name: Change argo base service from NodePort to LoadBalancer - replace: - path: "{{ argo_yaml_file_path }}" - regexp: 'NodePort' - replace: 'LoadBalancer' - -- name: Change istio-install base istio-noauth service from NodePort to LoadBalancer - replace: - path: "{{ istio_noauth_yaml_file_path }}" - regexp: 'NodePort' - replace: 'LoadBalancer' - -- name: Apply kubeflow configuration - command: - cmd: "/usr/bin/kfctl apply -V -f '{{ kubeflow_config_file }}'" - chdir: "{{ omnia_kubeflow_dir_path }}" - changed_when: true - register: apply_kubeflow_config - until: apply_kubeflow_config is not failed - retries: 20 - delay: 10 \ No newline at end of file diff --git a/platforms/roles/kubeflow/tasks/firewalld_config.yml b/platforms/roles/kubeflow/tasks/firewalld_config.yml deleted file mode 100644 index bcce82360..000000000 --- a/platforms/roles/kubeflow/tasks/firewalld_config.yml +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved. -# -# 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. ---- - -- name: Install firewalld - package: - name: firewalld - state: present - tags: firewalld - -- name: Start and enable firewalld - service: - name: firewalld - state: started - enabled: yes - tags: firewalld - -- name: Configure firewalld on master nodes - firewalld: - port: "{{ item }}/tcp" - permanent: yes - state: enabled - with_items: '{{ kubeflow_firewalld_ports }}' - tags: firewalld - -- name: Masquerade the firewall - command: firewall-cmd --add-masquerade --permanent - changed_when: true - tags: firewalld - -- name: Reload firewalld - command: firewall-cmd --reload - changed_when: true - tags: firewalld \ No newline at end of file diff --git a/platforms/roles/kubeflow/tasks/kubeflow_deploy.yml b/platforms/roles/kubeflow/tasks/kubeflow_deploy.yml new file mode 100644 index 000000000..b834e165d --- /dev/null +++ b/platforms/roles/kubeflow/tasks/kubeflow_deploy.yml @@ -0,0 +1,124 @@ +--- +- name: Load kernel modules + command: | + modprobe -q {{ item }} || modprobe {{ item }} + with_items: + - br_netfilter + - nf_nat + - xt_REDIRECT + - xt_owner + - iptable_nat + - iptable_mangle + - iptable_filter + when: inventory_hostname in groups["compute"] + +- name: Create Istio modules directory + file: + path: /etc/modules-load.d + state: directory + mode: '0755' + when: inventory_hostname in groups["compute"] + +- name: Create Istio modules conf file + file: + path: /etc/modules-load.d/99-istio-modules.conf + state: touch + mode: '0755' + when: inventory_hostname in groups["compute"] + +- name: Create Istio modules file + blockinfile: + path: /etc/modules-load.d/99-istio-modules.conf + block: | + # These modules need to be loaded on boot so that Istio (as required by + # Kubeflow) runs properly. + # + # See also: https://github.com/istio/istio/issues/23009 + br_netfilter + nf_nat + xt_REDIRECT + xt_owner + iptable_nat + iptable_mangle + iptable_filter + when: inventory_hostname in groups["compute"] + notify: + - Load kernel modules + +- name: clone kubeflow repositiry + ansible.builtin.git: + repo: "{{ kubeflow_url }}" + dest: /kubeflow + single_branch: yes + version: v1.6-branch + when: inventory_hostname in groups["manager"] + +- name: Change istio ingressgateway service from NodePort to LoadBalancer + replace: + path: "{{ istio_ingressgateway_service_yaml_file_path }}" + regexp: 'NodePort' + replace: 'LoadBalancer' + when: inventory_hostname in groups["manager"] + +- name: Modify CPU limit for training-operator + replace: + path: "{{ training_operator_deployment_yaml_file_path }}" + after: 'limits:' + before: 'requests:' + regexp: 'cpu: 100m' + replace: 'cpu: 1' + when: inventory_hostname in groups["manager"] + +- name: Modify Memory limit for training-operator + replace: + path: "{{ training_operator_deployment_yaml_file_path }}" + after: 'limits:' + before: 'requests:' + regexp: 'memory: 30Mi' + replace: 'memory: 256Mi' + when: inventory_hostname in groups["manager"] + +- name: Modify CPU Request for training-operator + replace: + path: "{{ training_operator_deployment_yaml_file_path }}" + after: 'requests:' + before: 'serviceAccountName: training-operator' + regexp: 'cpu: 100m' + replace: 'cpu: 1' + when: inventory_hostname in groups["manager"] + +- name: Modify Memory Request for training-operator + replace: + path: "{{ training_operator_deployment_yaml_file_path }}" + after: 'requests:' + before: 'serviceAccountName: training-operator' + regexp: 'memory: 20Mi' + replace: 'memory: 256Mi' + when: inventory_hostname in groups["manager"] + +- name: Delete mpijobs.kubeflow.org CRD + kubernetes.core.k8s: + definition: + apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: mpijobs.kubeflow.org + state: absent + when: inventory_hostname in groups["manager"] + +- name: Deploy CRD mpijobs + kubernetes.core.k8s: + api_version: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + name: mpijobs.kubeflow.org + definition: "{{ lookup('template', 'template/crd_mpijobs_kubeflow.yaml.j2') | from_yaml }}" + when: inventory_hostname in groups["manager"] + +- name: deploy kubeflow + ansible.builtin.shell: cd /kubeflow && + while ! /usr/local/bin/kustomize build example | kubectl apply -f -; do echo "Retrying to apply resources"; sleep 10; done + async: 10 + poll: 0 + register: output + when: inventory_hostname in groups["manager"] + diff --git a/platforms/roles/kubeflow/tasks/kustomize_install.yml b/platforms/roles/kubeflow/tasks/kustomize_install.yml new file mode 100644 index 000000000..ba0194d54 --- /dev/null +++ b/platforms/roles/kubeflow/tasks/kustomize_install.yml @@ -0,0 +1,24 @@ +--- +# Install kfctl cli on target server +- name: Install Kustomize + ansible.builtin.get_url: + url: "{{ kustomize_url }}" + dest: "/tmp/kustomize_v5.0.0_linux_arm64.tar.gz" + mode: "0644" + when: inventory_hostname in groups["manager"] + +- name: Extract kustomize + ansible.builtin.unarchive: + src: "/tmp/kustomize_v5.0.0_linux_arm64.tar.gz" + dest: "/usr/local/bin" + remote_src: true + creates: "/usr/local/bin/kustomize" + mode: '0755' + when: inventory_hostname in groups["manager"] + +- name: Make kustomize executable + file: + path: "/usr/local/bin/kustomize" + state: file + mode: "0775" + when: inventory_hostname in groups["manager"] \ No newline at end of file diff --git a/platforms/roles/kubeflow/tasks/main.yml b/platforms/roles/kubeflow/tasks/main.yml index ce7b4b8c1..fda3655dd 100644 --- a/platforms/roles/kubeflow/tasks/main.yml +++ b/platforms/roles/kubeflow/tasks/main.yml @@ -1,20 +1,9 @@ -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved. -# -# 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. --- +- name: "prerequisite Installation" + ansible.builtin.include_tasks: prerequisite.yml -- name: Configure firewalld ports - import_tasks: firewalld_config.yml +- name: "Kustomize Installation" + ansible.builtin.include_tasks: kustomize_install.yml -- name: Deploy kubeflow - import_tasks: deploy_kubeflow.yml +- name: "Kubeflow deployment" + ansible.builtin.include_tasks: kubeflow_deploy.yml diff --git a/platforms/roles/kubeflow/tasks/prerequisite.yml b/platforms/roles/kubeflow/tasks/prerequisite.yml new file mode 100644 index 000000000..962002838 --- /dev/null +++ b/platforms/roles/kubeflow/tasks/prerequisite.yml @@ -0,0 +1,28 @@ +--- +- name: install git if not present + package: + name: git + state: present + when: inventory_hostname in groups["manager"] + +- name: python and pip packages + block: + - name: Install pip3 on centos/RHEL + ansible.builtin.yum: + name: python3-pip + state: present + when: ansible_distribution in ["CentOS", "RedHat", "Rocky"] + + - name: Install pip3 on Debian/Ubuntu + ansible.builtin.apt: + name: python3-pip + state: present + when: ansible_distribution in ["Debian", "Ubuntu"] + + - name: Install pre-requisites python modules + ansible.builtin.pip: + name: + - kubernetes + - openshift + extra_args: "--ignore-installed" + when: inventory_hostname in groups["manager"] \ No newline at end of file diff --git a/platforms/roles/kubeflow/template/crd_mpijobs_kubeflow.yaml.j2 b/platforms/roles/kubeflow/template/crd_mpijobs_kubeflow.yaml.j2 new file mode 100644 index 000000000..090b83f17 --- /dev/null +++ b/platforms/roles/kubeflow/template/crd_mpijobs_kubeflow.yaml.j2 @@ -0,0 +1,7863 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.12.0 + name: mpijobs.kubeflow.org +spec: + group: kubeflow.org + names: + kind: MPIJob + listKind: MPIJobList + plural: mpijobs + singular: mpijob + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + - jsonPath: .status.conditions[-1:].type + name: State + type: string + name: v1 + schema: + openAPIV3Schema: + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + cleanPodPolicy: + description: CleanPodPolicy defines the policy that whether to kill + pods after the job completes. Defaults to None. + type: string + mainContainer: + description: MainContainer specifies name of the main container which + executes the MPI code. + type: string + mpiReplicaSpecs: + additionalProperties: + description: ReplicaSpec is a description of the replica + properties: + replicas: + description: Replicas is the desired number of replicas of the + given template. If unspecified, defaults to 1. + format: int32 + type: integer + restartPolicy: + description: Restart policy for all replicas within the job. + One of Always, OnFailure, Never and ExitCode. Default to Never. + type: string + template: + description: Template is the object that describes the pod that + will be created for this replica. RestartPolicy in PodTemplateSpec + will be overide by RestartPolicy in ReplicaSpec + properties: + metadata: + description: 'Standard object''s metadata. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata' + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: 'Specification of the desired behavior of the + pod. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status' + properties: + activeDeadlineSeconds: + description: Optional duration in seconds the pod may + be active on the node relative to StartTime before + the system will actively try to mark it failed and + kill associated containers. Value must be a positive + integer. + format: int64 + type: integer + affinity: + description: If specified, the pod's scheduling constraints + properties: + nodeAffinity: + description: Describes node affinity scheduling + rules for the pod. + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose + a node that violates one or more of the expressions. + The node that is most preferred is the one + with the greatest sum of weights, i.e. for + each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc. + items: + description: An empty preferred scheduling + term matches all objects with implicit weight + 0 (i.e. it's a no-op). A null preferred + scheduling term matches no objects (i.e. + is also a no-op). + properties: + preference: + description: A node selector term, associated + with the corresponding weight. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, + and Lt. + type: string + values: + description: An array of string + values. If the operator is + In or NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, + the values array must have + a single element, which will + be interpreted as an integer. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, + and Lt. + type: string + values: + description: An array of string + values. If the operator is + In or NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, + the values array must have + a single element, which will + be interpreted as an integer. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + weight: + description: Weight associated with matching + the corresponding nodeSelectorTerm, + in the range 1-100. + format: int32 + type: integer + required: + - preference + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, + the pod will not be scheduled onto the node. + If the affinity requirements specified by + this field cease to be met at some point during + pod execution (e.g. due to an update), the + system may or may not try to eventually evict + the pod from its node. + properties: + nodeSelectorTerms: + description: Required. A list of node selector + terms. The terms are ORed. + items: + description: A null or empty node selector + term matches no objects. The requirements + of them are ANDed. The TopologySelectorTerm + type implements a subset of the NodeSelectorTerm. + properties: + matchExpressions: + description: A list of node selector + requirements by node's labels. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, + and Lt. + type: string + values: + description: An array of string + values. If the operator is + In or NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, + the values array must have + a single element, which will + be interpreted as an integer. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchFields: + description: A list of node selector + requirements by node's fields. + items: + description: A node selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: The label key that + the selector applies to. + type: string + operator: + description: Represents a key's + relationship to a set of values. + Valid operators are In, NotIn, + Exists, DoesNotExist. Gt, + and Lt. + type: string + values: + description: An array of string + values. If the operator is + In or NotIn, the values array + must be non-empty. If the + operator is Exists or DoesNotExist, + the values array must be empty. + If the operator is Gt or Lt, + the values array must have + a single element, which will + be interpreted as an integer. + This array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + type: object + x-kubernetes-map-type: atomic + type: array + required: + - nodeSelectorTerms + type: object + x-kubernetes-map-type: atomic + type: object + podAffinity: + description: Describes pod affinity scheduling rules + (e.g. co-locate this pod in the same node, zone, + etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the affinity expressions + specified by this field, but it may choose + a node that violates one or more of the expressions. + The node that is most preferred is the one + with the greatest sum of weights, i.e. for + each node that meets all of the scheduling + requirements (resource request, requiredDuringScheduling + affinity expressions, etc. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added + per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity + term, associated with the corresponding + weight. + properties: + labelSelector: + description: A label query over a + set of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term + applies to. The term is applied + to the union of the namespaces selected + by this field and the ones listed + in the namespaces field. null selector + and null or empty namespaces list + means "this pod's namespace". An + empty selector ({}) matches all + namespaces. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies + a static list of namespace names + that the term applies to. The term + is applied to the union of the namespaces + listed in this field and the ones + selected by namespaceSelector. null + or empty namespaces list and null + namespaceSelector means "this pod's + namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running + on a node whose value of the label + with key topologyKey matches that + of any node on which any of the + selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in + the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the affinity requirements specified + by this field are not met at scheduling time, + the pod will not be scheduled onto the node. + If the affinity requirements specified by + this field cease to be met at some point during + pod execution (e.g. due to a pod label update), + the system may or may not try to eventually + evict the pod from its node. + items: + description: Defines a set of pods (namely + those matching the labelSelector relative + to the given namespace(s)) that this pod + should be co-located (affinity) or not co-located + (anti-affinity) with, where co-located is + defined as running on a node whose value + of the label with key matches + that of any node on which a pod of the set + of pods is running + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this field + and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. The term is applied to the + union of the namespaces listed in this + field and the ones selected by namespaceSelector. + null or empty namespaces list and null + namespaceSelector means "this pod's + namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + podAntiAffinity: + description: Describes pod anti-affinity scheduling + rules (e.g. avoid putting this pod in the same + node, zone, etc. as some other pod(s)). + properties: + preferredDuringSchedulingIgnoredDuringExecution: + description: The scheduler will prefer to schedule + pods to nodes that satisfy the anti-affinity + expressions specified by this field, but it + may choose a node that violates one or more + of the expressions. The node that is most + preferred is the one with the greatest sum + of weights, i.e. + items: + description: The weights of all of the matched + WeightedPodAffinityTerm fields are added + per-node to find the most preferred node(s) + properties: + podAffinityTerm: + description: Required. A pod affinity + term, associated with the corresponding + weight. + properties: + labelSelector: + description: A label query over a + set of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the + set of namespaces that the term + applies to. The term is applied + to the union of the namespaces selected + by this field and the ones listed + in the namespaces field. null selector + and null or empty namespaces list + means "this pod's namespace". An + empty selector ({}) matches all + namespaces. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies + a static list of namespace names + that the term applies to. The term + is applied to the union of the namespaces + listed in this field and the ones + selected by namespaceSelector. null + or empty namespaces list and null + namespaceSelector means "this pod's + namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where + co-located is defined as running + on a node whose value of the label + with key topologyKey matches that + of any node on which any of the + selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + weight: + description: weight associated with matching + the corresponding podAffinityTerm, in + the range 1-100. + format: int32 + type: integer + required: + - podAffinityTerm + - weight + type: object + type: array + requiredDuringSchedulingIgnoredDuringExecution: + description: If the anti-affinity requirements + specified by this field are not met at scheduling + time, the pod will not be scheduled onto the + node. If the anti-affinity requirements specified + by this field cease to be met at some point + during pod execution (e.g. due to a pod label + update), the system may or may not try to + eventually evict the pod from its node. + items: + description: Defines a set of pods (namely + those matching the labelSelector relative + to the given namespace(s)) that this pod + should be co-located (affinity) or not co-located + (anti-affinity) with, where co-located is + defined as running on a node whose value + of the label with key matches + that of any node on which a pod of the set + of pods is running + properties: + labelSelector: + description: A label query over a set + of resources, in this case pods. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaceSelector: + description: A label query over the set + of namespaces that the term applies + to. The term is applied to the union + of the namespaces selected by this field + and the ones listed in the namespaces + field. null selector and null or empty + namespaces list means "this pod's namespace". + An empty selector ({}) matches all namespaces. + properties: + matchExpressions: + description: matchExpressions is a + list of label selector requirements. + The requirements are ANDed. + items: + description: A label selector requirement + is a selector that contains values, + a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label + key that the selector applies + to. + type: string + operator: + description: operator represents + a key's relationship to a + set of values. Valid operators + are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array + of string values. If the operator + is In or NotIn, the values + array must be non-empty. If + the operator is Exists or + DoesNotExist, the values array + must be empty. This array + is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map + of {key,value} pairs. A single {key,value} + in the matchLabels map is equivalent + to an element of matchExpressions, + whose key field is "key", the operator + is "In", and the values array contains + only "value". The requirements are + ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + namespaces: + description: namespaces specifies a static + list of namespace names that the term + applies to. The term is applied to the + union of the namespaces listed in this + field and the ones selected by namespaceSelector. + null or empty namespaces list and null + namespaceSelector means "this pod's + namespace". + items: + type: string + type: array + topologyKey: + description: This pod should be co-located + (affinity) or not co-located (anti-affinity) + with the pods matching the labelSelector + in the specified namespaces, where co-located + is defined as running on a node whose + value of the label with key topologyKey + matches that of any node on which any + of the selected pods is running. Empty + topologyKey is not allowed. + type: string + required: + - topologyKey + type: object + type: array + type: object + type: object + automountServiceAccountToken: + description: AutomountServiceAccountToken indicates + whether a service account token should be automatically + mounted. + type: boolean + containers: + description: List of containers belonging to the pod. + Containers cannot currently be added or removed. There + must be at least one container in a Pod. Cannot be + updated. + items: + description: A single application container that you + want to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The + container image''s CMD is used if this is not + provided. Variable references $(VAR_NAME) are + expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for + escaping the $(VAR_NAME) syntax: i.e.' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e.' + items: + type: string + type: array + env: + description: List of environment variables to + set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container + and any service environment variables. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. Double $$ are reduced to a + single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used if value + is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the + pod: supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined + within a source must be a C_IDENTIFIER. All + invalid keys will be reported as an event when + the container is starting. When a key exists + in multiple sources, the value associated with + the last source will take precedence. Values + defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be + a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: + https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level + config management to default or override container + images in workload controllers like Deployments + and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it + is not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the pod + IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: PreStop is called immediately + before a container is terminated due to + an API request or management event such + as liveness/startup probe failure, preemption, + resource contention, etc. The handler is + not called if the container crashes or exits. + The Pod's termination grace period countdown + begins before the PreStop hook is executed. + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it + is not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the pod + IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the + container. Not specifying a port here DOES NOT + prevent that port from being exposed. Any port + which is listening on the default "0.0.0.0" + address inside a container will be accessible + from the network. Modifying this array with + strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on + the pod's IP address. This must be a valid + port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on + the host. If specified, this must be a + valid port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be + an IANA_SVC_NAME and unique within the + pod. Each named port in a pod must have + a unique name. Name for the port that + can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be + UDP, TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which + this resource resize policy applies. Supported + values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not + specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are + used by this container. \n This is an alpha + field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If + Requests is omitted for a container, it + defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If + set, the fields of SecurityContext override + the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) + run as Privileged 2) has CAP_SYS_ADMIN Note + that this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults to the + default set of capabilities granted by the + container runtime. Note that this field + cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults + to false. Note that this field cannot be + set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of + proc mount to use for the containers. The + default is DefaultProcMount which uses the + container runtime defaults for readonly + paths and masked paths. This requires the + ProcMountType feature flag to be enabled. + Note that this field cannot be set when + spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a + read-only root filesystem. Default is false. + Note that this field cannot be set when + spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, the + Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 + (root) and fail to start the container if + it does. If unset or false, no such validation + will be performed. May also be set in PodSecurityContext. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults to user + specified in image metadata if unspecified. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in + PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by + this container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be + preconfigured on the node to work. Must + be a descending path, relative to the + kubelet's configured seccomp profile + location. Must only be set if type is + "Localhost". + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. + Valid options are: \n Localhost - a + profile defined in a file on the node + should be used. RuntimeDefault - the + container runtime default profile should + be used. Unconfined - no profile should + be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is + the name of the GMSA credential spec + to use. + type: string + hostProcess: + description: HostProcess determines if + a container should be run as a 'Host + Process' container. This field is alpha-level + and will only be honored by components + that enable the WindowsHostProcessContainers + feature flag. Setting this field without + the feature flag will result in errors + when validating the Pod. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container + process. Defaults to the user specified + in image metadata if unspecified. May + also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: StartupProbe indicates that the Pod + has successfully initialized. If specified, + no other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. + If this is not set, reads from stdin in the + container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file + to which the container''s termination message + will be written is mounted into the container''s + filesystem. Message written is intended to be + brief final status, such as an assertion failure + message. Will be truncated by the node if greater + than 4096 bytes. The total message length across + all containers will be limited to 12kb. Defaults + to /dev/termination-log.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. + FallbackToLogsOnError will use the last chunk + of container log output if the termination message + file is empty and the container exited with + an error. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will + be mapped to. + type: string + name: + description: name must match the name of + a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is + used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of + a Volume. + type: string + readOnly: + description: Mounted read-only if true, + read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: Path within the volume from + which the container's volume should be + mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If + not specified, the container runtime's default + will be used, which might be configured in the + container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + dnsConfig: + description: Specifies the DNS parameters of a pod. + Parameters specified here will be merged to the generated + DNS configuration based on DNSPolicy. + properties: + nameservers: + description: A list of DNS name server IP addresses. + This will be appended to the base nameservers + generated from DNSPolicy. Duplicated nameservers + will be removed. + items: + type: string + type: array + options: + description: A list of DNS resolver options. This + will be merged with the base options generated + from DNSPolicy. Duplicated entries will be removed. + Resolution options given in Options will override + those that appear in the base DNSPolicy. + items: + description: PodDNSConfigOption defines DNS resolver + options of a pod. + properties: + name: + description: Required. + type: string + value: + type: string + type: object + type: array + searches: + description: A list of DNS search domains for host-name + lookup. This will be appended to the base search + paths generated from DNSPolicy. Duplicated search + paths will be removed. + items: + type: string + type: array + type: object + dnsPolicy: + description: Set DNS policy for the pod. Defaults to + "ClusterFirst". Valid values are 'ClusterFirstWithHostNet', + 'ClusterFirst', 'Default' or 'None'. DNS parameters + given in DNSConfig will be merged with the policy + selected with DNSPolicy. To have DNS options set along + with hostNetwork, you have to specify DNS policy explicitly + to 'ClusterFirstWithHostNet'. + type: string + enableServiceLinks: + description: 'EnableServiceLinks indicates whether information + about services should be injected into pod''s environment + variables, matching the syntax of Docker links. Optional: + Defaults to true.' + type: boolean + ephemeralContainers: + description: List of ephemeral containers run in this + pod. Ephemeral containers may be run in an existing + pod to perform user-initiated actions such as debugging. + This list cannot be specified when creating a pod, + and it cannot be modified by updating the pod spec. + In order to add an ephemeral container to an existing + pod, use the pod's ephemeralcontainers subresource. + items: + description: An EphemeralContainer is a temporary + container that you may add to an existing Pod for + user-initiated activities such as debugging. Ephemeral + containers have no resource or scheduling guarantees, + and they will not be restarted when they exit or + when a Pod is removed or restarted. The kubelet + may evict a Pod if an ephemeral container causes + the Pod to exceed its resource allocation. + properties: + args: + description: 'Arguments to the entrypoint. The + image''s CMD is used if this is not provided. + Variable references $(VAR_NAME) are expanded + using the container''s environment. If a variable + cannot be resolved, the reference in the input + string will be unchanged. Double $$ are reduced + to a single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" will + produce the string literal "$(VAR_NAME)".' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The image''s ENTRYPOINT is used if + this is not provided. Variable references $(VAR_NAME) + are expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for + escaping the $(VAR_NAME) syntax: i.e.' + items: + type: string + type: array + env: + description: List of environment variables to + set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container + and any service environment variables. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. Double $$ are reduced to a + single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used if value + is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the + pod: supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined + within a source must be a C_IDENTIFIER. All + invalid keys will be reported as an event when + the container is starting. When a key exists + in multiple sources, the value associated with + the last source will take precedence. Values + defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be + a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: + https://kubernetes.io/docs/concepts/containers/images' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Lifecycle is not allowed for ephemeral + containers. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it + is not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the pod + IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: PreStop is called immediately + before a container is terminated due to + an API request or management event such + as liveness/startup probe failure, preemption, + resource contention, etc. The handler is + not called if the container crashes or exits. + The Pod's termination grace period countdown + begins before the PreStop hook is executed. + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it + is not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the pod + IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: Probes are not allowed for ephemeral + containers. + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the ephemeral container specified + as a DNS_LABEL. This name must be unique among + all containers, init containers and ephemeral + containers. + type: string + ports: + description: Ports are not allowed for ephemeral + containers. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on + the pod's IP address. This must be a valid + port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on + the host. If specified, this must be a + valid port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be + an IANA_SVC_NAME and unique within the + pod. Each named port in a pod must have + a unique name. Name for the port that + can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be + UDP, TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: Probes are not allowed for ephemeral + containers. + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which + this resource resize policy applies. Supported + values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not + specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: Resources are not allowed for ephemeral + containers. Ephemeral containers use spare resources + already allocated to the pod. + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are + used by this container. \n This is an alpha + field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If + Requests is omitted for a container, it + defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'Optional: SecurityContext defines + the security options the ephemeral container + should be run with. If set, the fields of SecurityContext + override the equivalent fields of PodSecurityContext.' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) + run as Privileged 2) has CAP_SYS_ADMIN Note + that this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults to the + default set of capabilities granted by the + container runtime. Note that this field + cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults + to false. Note that this field cannot be + set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of + proc mount to use for the containers. The + default is DefaultProcMount which uses the + container runtime defaults for readonly + paths and masked paths. This requires the + ProcMountType feature flag to be enabled. + Note that this field cannot be set when + spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a + read-only root filesystem. Default is false. + Note that this field cannot be set when + spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, the + Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 + (root) and fail to start the container if + it does. If unset or false, no such validation + will be performed. May also be set in PodSecurityContext. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults to user + specified in image metadata if unspecified. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in + PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by + this container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be + preconfigured on the node to work. Must + be a descending path, relative to the + kubelet's configured seccomp profile + location. Must only be set if type is + "Localhost". + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. + Valid options are: \n Localhost - a + profile defined in a file on the node + should be used. RuntimeDefault - the + container runtime default profile should + be used. Unconfined - no profile should + be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is + the name of the GMSA credential spec + to use. + type: string + hostProcess: + description: HostProcess determines if + a container should be run as a 'Host + Process' container. This field is alpha-level + and will only be honored by components + that enable the WindowsHostProcessContainers + feature flag. Setting this field without + the feature flag will result in errors + when validating the Pod. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container + process. Defaults to the user specified + in image metadata if unspecified. May + also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: Probes are not allowed for ephemeral + containers. + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. + If this is not set, reads from stdin in the + container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. + type: boolean + targetContainerName: + description: "If set, the name of the container + from PodSpec that this ephemeral container targets. + The ephemeral container will be run in the namespaces + (IPC, PID, etc) of this container. If not set + then the ephemeral container uses the namespaces + configured in the Pod spec. \n The container + runtime must implement support for this feature." + type: string + terminationMessagePath: + description: 'Optional: Path at which the file + to which the container''s termination message + will be written is mounted into the container''s + filesystem. Message written is intended to be + brief final status, such as an assertion failure + message. Will be truncated by the node if greater + than 4096 bytes. The total message length across + all containers will be limited to 12kb. Defaults + to /dev/termination-log.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. + FallbackToLogsOnError will use the last chunk + of container log output if the termination message + file is empty and the container exited with + an error. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will + be mapped to. + type: string + name: + description: name must match the name of + a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Subpath mounts are not allowed for + ephemeral containers. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is + used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of + a Volume. + type: string + readOnly: + description: Mounted read-only if true, + read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: Path within the volume from + which the container's volume should be + mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If + not specified, the container runtime's default + will be used, which might be configured in the + container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + hostAliases: + description: HostAliases is an optional list of hosts + and IPs that will be injected into the pod's hosts + file if specified. This is only valid for non-hostNetwork + pods. + items: + description: HostAlias holds the mapping between IP + and hostnames that will be injected as an entry + in the pod's hosts file. + properties: + hostnames: + description: Hostnames for the above IP address. + items: + type: string + type: array + ip: + description: IP address of the host file entry. + type: string + type: object + type: array + hostIPC: + description: 'Use the host''s ipc namespace. Optional: + Default to false.' + type: boolean + hostNetwork: + description: Host networking requested for this pod. + Use the host's network namespace. If this option is + set, the ports that will be used must be specified. + Default to false. + type: boolean + hostPID: + description: 'Use the host''s pid namespace. Optional: + Default to false.' + type: boolean + hostUsers: + description: 'Use the host''s user namespace. Optional: + Default to true. If set to true or not present, the + pod will be run in the host user namespace, useful + for when the pod needs a feature only available to + the host user namespace, such as loading a kernel + module with CAP_SYS_MODULE. When set to false, a new + userns is created for the pod.' + type: boolean + hostname: + description: Specifies the hostname of the Pod If not + specified, the pod's hostname will be set to a system-defined + value. + type: string + imagePullSecrets: + description: 'ImagePullSecrets is an optional list of + references to secrets in the same namespace to use + for pulling any of the images used by this PodSpec. + If specified, these secrets will be passed to individual + puller implementations for them to use. More info: + https://kubernetes.io/docs/concepts/containers/images#specifying-imagepullsecrets-on-a-pod' + items: + description: LocalObjectReference contains enough + information to let you locate the referenced object + inside the same namespace. + properties: + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, kind, + uid?' + type: string + type: object + x-kubernetes-map-type: atomic + type: array + initContainers: + description: List of initialization containers belonging + to the pod. Init containers are executed in order + prior to containers being started. If any init container + fails, the pod is considered to have failed and is + handled according to its restartPolicy. The name for + an init container or normal container must be unique + among all containers. + items: + description: A single application container that you + want to run within a pod. + properties: + args: + description: 'Arguments to the entrypoint. The + container image''s CMD is used if this is not + provided. Variable references $(VAR_NAME) are + expanded using the container''s environment. + If a variable cannot be resolved, the reference + in the input string will be unchanged. Double + $$ are reduced to a single $, which allows for + escaping the $(VAR_NAME) syntax: i.e.' + items: + type: string + type: array + command: + description: 'Entrypoint array. Not executed within + a shell. The container image''s ENTRYPOINT is + used if this is not provided. Variable references + $(VAR_NAME) are expanded using the container''s + environment. If a variable cannot be resolved, + the reference in the input string will be unchanged. + Double $$ are reduced to a single $, which allows + for escaping the $(VAR_NAME) syntax: i.e.' + items: + type: string + type: array + env: + description: List of environment variables to + set in the container. Cannot be updated. + items: + description: EnvVar represents an environment + variable present in a Container. + properties: + name: + description: Name of the environment variable. + Must be a C_IDENTIFIER. + type: string + value: + description: 'Variable references $(VAR_NAME) + are expanded using the previously defined + environment variables in the container + and any service environment variables. + If a variable cannot be resolved, the + reference in the input string will be + unchanged. Double $$ are reduced to a + single $, which allows for escaping the + $(VAR_NAME) syntax: i.e. "$$(VAR_NAME)" + will produce the string literal "$(VAR_NAME)".' + type: string + valueFrom: + description: Source for the environment + variable's value. Cannot be used if value + is not empty. + properties: + configMapKeyRef: + description: Selects a key of a ConfigMap. + properties: + key: + description: The key to select. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + ConfigMap or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + fieldRef: + description: 'Selects a field of the + pod: supports metadata.name, metadata.namespace, + `metadata.labels['''']`, `metadata.annotations['''']`, + spec.nodeName, spec.serviceAccountName, + status.hostIP, status.podIP, status.podIPs.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + limits.ephemeral-storage, requests.cpu, + requests.memory and requests.ephemeral-storage) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + secretKeyRef: + description: Selects a key of a secret + in the pod's namespace + properties: + key: + description: The key of the secret + to select from. Must be a valid + secret key. + type: string + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: Specify whether the + Secret or its key must be defined + type: boolean + required: + - key + type: object + x-kubernetes-map-type: atomic + type: object + required: + - name + type: object + type: array + envFrom: + description: List of sources to populate environment + variables in the container. The keys defined + within a source must be a C_IDENTIFIER. All + invalid keys will be reported as an event when + the container is starting. When a key exists + in multiple sources, the value associated with + the last source will take precedence. Values + defined by an Env with a duplicate key will + take precedence. Cannot be updated. + items: + description: EnvFromSource represents the source + of a set of ConfigMaps + properties: + configMapRef: + description: The ConfigMap to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the ConfigMap + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + prefix: + description: An optional identifier to prepend + to each key in the ConfigMap. Must be + a C_IDENTIFIER. + type: string + secretRef: + description: The Secret to select from + properties: + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: Specify whether the Secret + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + type: object + type: array + image: + description: 'Container image name. More info: + https://kubernetes.io/docs/concepts/containers/images + This field is optional to allow higher level + config management to default or override container + images in workload controllers like Deployments + and StatefulSets.' + type: string + imagePullPolicy: + description: 'Image pull policy. One of Always, + Never, IfNotPresent. Defaults to Always if :latest + tag is specified, or IfNotPresent otherwise. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images' + type: string + lifecycle: + description: Actions that the management system + should take in response to container lifecycle + events. Cannot be updated. + properties: + postStart: + description: 'PostStart is called immediately + after a container is created. If the handler + fails, the container is terminated and restarted + according to its restart policy. Other management + of the container blocks until the hook completes. + More info: https://kubernetes.io/docs/concepts/containers/container-lifecycle-hooks/#container-hooks' + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it + is not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the pod + IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + preStop: + description: PreStop is called immediately + before a container is terminated due to + an API request or management event such + as liveness/startup probe failure, preemption, + resource contention, etc. The handler is + not called if the container crashes or exits. + The Pod's termination grace period countdown + begins before the PreStop hook is executed. + properties: + exec: + description: Exec specifies the action + to take. + properties: + command: + description: Command is the command + line to execute inside the container, + the working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it + is not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to + explicitly call out to that shell. + Exit status of 0 is treated as live/healthy + and non-zero is unhealthy. + items: + type: string + type: array + type: object + httpGet: + description: HTTPGet specifies the http + request to perform. + properties: + host: + description: Host name to connect + to, defaults to the pod IP. You + probably want to set "Host" in httpHeaders + instead. + type: string + httpHeaders: + description: Custom headers to set + in the request. HTTP allows repeated + headers. + items: + description: HTTPHeader describes + a custom header to be used in + HTTP probes + properties: + name: + description: The header field + name. This will be canonicalized + upon output, so case-variant + names will be understood as + the same header. + type: string + value: + description: The header field + value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the + HTTP server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + tcpSocket: + description: Deprecated. TCPSocket is + NOT supported as a LifecycleHandler + and kept for the backward compatibility. + There are no validation of this field + and lifecycle hooks will fail in runtime + when tcp handler is specified. + properties: + host: + description: 'Optional: Host name + to connect to, defaults to the pod + IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the + port to access on the container. + Number must be in the range 1 to + 65535. Name must be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + type: object + type: object + livenessProbe: + description: 'Periodic probe of container liveness. + Container will be restarted if the probe fails. + Cannot be updated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + name: + description: Name of the container specified as + a DNS_LABEL. Each container in a pod must have + a unique name (DNS_LABEL). Cannot be updated. + type: string + ports: + description: List of ports to expose from the + container. Not specifying a port here DOES NOT + prevent that port from being exposed. Any port + which is listening on the default "0.0.0.0" + address inside a container will be accessible + from the network. Modifying this array with + strategic merge patch may corrupt the data. + For more information See https://github.com/kubernetes/kubernetes/issues/108255. + items: + description: ContainerPort represents a network + port in a single container. + properties: + containerPort: + description: Number of port to expose on + the pod's IP address. This must be a valid + port number, 0 < x < 65536. + format: int32 + type: integer + hostIP: + description: What host IP to bind the external + port to. + type: string + hostPort: + description: Number of port to expose on + the host. If specified, this must be a + valid port number, 0 < x < 65536. If HostNetwork + is specified, this must match ContainerPort. + Most containers do not need this. + format: int32 + type: integer + name: + description: If specified, this must be + an IANA_SVC_NAME and unique within the + pod. Each named port in a pod must have + a unique name. Name for the port that + can be referred to by services. + type: string + protocol: + default: TCP + description: Protocol for port. Must be + UDP, TCP, or SCTP. Defaults to "TCP". + type: string + required: + - containerPort + type: object + type: array + x-kubernetes-list-map-keys: + - containerPort + - protocol + x-kubernetes-list-type: map + readinessProbe: + description: 'Periodic probe of container service + readiness. Container will be removed from service + endpoints if the probe fails. Cannot be updated. + More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + resizePolicy: + description: Resources resize policy for the container. + items: + description: ContainerResizePolicy represents + resource resize policy for the container. + properties: + resourceName: + description: 'Name of the resource to which + this resource resize policy applies. Supported + values: cpu, memory.' + type: string + restartPolicy: + description: Restart policy to apply when + specified resource is resized. If not + specified, it defaults to NotRequired. + type: string + required: + - resourceName + - restartPolicy + type: object + type: array + x-kubernetes-list-type: atomic + resources: + description: 'Compute Resources required by this + container. Cannot be updated. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + properties: + claims: + description: "Claims lists the names of resources, + defined in spec.resourceClaims, that are + used by this container. \n This is an alpha + field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable. + It can only be set for containers." + items: + description: ResourceClaim references one + entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match the name + of one entry in pod.spec.resourceClaims + of the Pod where this field is used. + It makes that resource available inside + a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes the maximum + amount of compute resources allowed. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes the minimum + amount of compute resources required. If + Requests is omitted for a container, it + defaults to Limits if that is explicitly + specified, otherwise to an implementation-defined + value. Requests cannot exceed Limits. More + info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + securityContext: + description: 'SecurityContext defines the security + options the container should be run with. If + set, the fields of SecurityContext override + the equivalent fields of PodSecurityContext. + More info: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/' + properties: + allowPrivilegeEscalation: + description: 'AllowPrivilegeEscalation controls + whether a process can gain more privileges + than its parent process. This bool directly + controls if the no_new_privs flag will be + set on the container process. AllowPrivilegeEscalation + is true always when the container is: 1) + run as Privileged 2) has CAP_SYS_ADMIN Note + that this field cannot be set when spec.os.name + is windows.' + type: boolean + capabilities: + description: The capabilities to add/drop + when running containers. Defaults to the + default set of capabilities granted by the + container runtime. Note that this field + cannot be set when spec.os.name is windows. + properties: + add: + description: Added capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + drop: + description: Removed capabilities + items: + description: Capability represent POSIX + capabilities type + type: string + type: array + type: object + privileged: + description: Run container in privileged mode. + Processes in privileged containers are essentially + equivalent to root on the host. Defaults + to false. Note that this field cannot be + set when spec.os.name is windows. + type: boolean + procMount: + description: procMount denotes the type of + proc mount to use for the containers. The + default is DefaultProcMount which uses the + container runtime defaults for readonly + paths and masked paths. This requires the + ProcMountType feature flag to be enabled. + Note that this field cannot be set when + spec.os.name is windows. + type: string + readOnlyRootFilesystem: + description: Whether this container has a + read-only root filesystem. Default is false. + Note that this field cannot be set when + spec.os.name is windows. + type: boolean + runAsGroup: + description: The GID to run the entrypoint + of the container process. Uses runtime default + if unset. May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container + must run as a non-root user. If true, the + Kubelet will validate the image at runtime + to ensure that it does not run as UID 0 + (root) and fail to start the container if + it does. If unset or false, no such validation + will be performed. May also be set in PodSecurityContext. + type: boolean + runAsUser: + description: The UID to run the entrypoint + of the container process. Defaults to user + specified in image metadata if unspecified. + May also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied + to the container. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in + PodSecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is windows. + properties: + level: + description: Level is SELinux level label + that applies to the container. + type: string + role: + description: Role is a SELinux role label + that applies to the container. + type: string + type: + description: Type is a SELinux type label + that applies to the container. + type: string + user: + description: User is a SELinux user label + that applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by + this container. If seccomp options are provided + at both the pod & container level, the container + options override the pod options. Note that + this field cannot be set when spec.os.name + is windows. + properties: + localhostProfile: + description: localhostProfile indicates + a profile defined in a file on the node + should be used. The profile must be + preconfigured on the node to work. Must + be a descending path, relative to the + kubelet's configured seccomp profile + location. Must only be set if type is + "Localhost". + type: string + type: + description: "type indicates which kind + of seccomp profile will be applied. + Valid options are: \n Localhost - a + profile defined in a file on the node + should be used. RuntimeDefault - the + container runtime default profile should + be used. Unconfined - no profile should + be applied." + type: string + required: + - type + type: object + windowsOptions: + description: The Windows specific settings + applied to all containers. If unspecified, + the options from the PodSecurityContext + will be used. If set in both SecurityContext + and PodSecurityContext, the value specified + in SecurityContext takes precedence. Note + that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where + the GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName + field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is + the name of the GMSA credential spec + to use. + type: string + hostProcess: + description: HostProcess determines if + a container should be run as a 'Host + Process' container. This field is alpha-level + and will only be honored by components + that enable the WindowsHostProcessContainers + feature flag. Setting this field without + the feature flag will result in errors + when validating the Pod. + type: boolean + runAsUserName: + description: The UserName in Windows to + run the entrypoint of the container + process. Defaults to the user specified + in image metadata if unspecified. May + also be set in PodSecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext + takes precedence. + type: string + type: object + type: object + startupProbe: + description: StartupProbe indicates that the Pod + has successfully initialized. If specified, + no other probes are executed until this completes + successfully. If this probe fails, the Pod will + be restarted, just as if the livenessProbe failed. + properties: + exec: + description: Exec specifies the action to + take. + properties: + command: + description: Command is the command line + to execute inside the container, the + working directory for the command is + root ('/') in the container's filesystem. + The command is simply exec'd, it is + not run inside a shell, so traditional + shell instructions ('|', etc) won't + work. To use a shell, you need to explicitly + call out to that shell. Exit status + of 0 is treated as live/healthy and + non-zero is unhealthy. + items: + type: string + type: array + type: object + failureThreshold: + description: Minimum consecutive failures + for the probe to be considered failed after + having succeeded. Defaults to 3. Minimum + value is 1. + format: int32 + type: integer + grpc: + description: GRPC specifies an action involving + a GRPC port. + properties: + port: + description: Port number of the gRPC service. + Number must be in the range 1 to 65535. + format: int32 + type: integer + service: + description: "Service is the name of the + service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + \n If this is not specified, the default + behavior is defined by gRPC." + type: string + required: + - port + type: object + httpGet: + description: HTTPGet specifies the http request + to perform. + properties: + host: + description: Host name to connect to, + defaults to the pod IP. You probably + want to set "Host" in httpHeaders instead. + type: string + httpHeaders: + description: Custom headers to set in + the request. HTTP allows repeated headers. + items: + description: HTTPHeader describes a + custom header to be used in HTTP probes + properties: + name: + description: The header field name. + This will be canonicalized upon + output, so case-variant names + will be understood as the same + header. + type: string + value: + description: The header field value + type: string + required: + - name + - value + type: object + type: array + path: + description: Path to access on the HTTP + server. + type: string + port: + anyOf: + - type: integer + - type: string + description: Name or number of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + scheme: + description: Scheme to use for connecting + to the host. Defaults to HTTP. + type: string + required: + - port + type: object + initialDelaySeconds: + description: 'Number of seconds after the + container has started before liveness probes + are initiated. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + periodSeconds: + description: How often (in seconds) to perform + the probe. Default to 10 seconds. Minimum + value is 1. + format: int32 + type: integer + successThreshold: + description: Minimum consecutive successes + for the probe to be considered successful + after having failed. Defaults to 1. Must + be 1 for liveness and startup. Minimum value + is 1. + format: int32 + type: integer + tcpSocket: + description: TCPSocket specifies an action + involving a TCP port. + properties: + host: + description: 'Optional: Host name to connect + to, defaults to the pod IP.' + type: string + port: + anyOf: + - type: integer + - type: string + description: Number or name of the port + to access on the container. Number must + be in the range 1 to 65535. Name must + be an IANA_SVC_NAME. + x-kubernetes-int-or-string: true + required: + - port + type: object + terminationGracePeriodSeconds: + description: Optional duration in seconds + the pod needs to terminate gracefully upon + probe failure. The grace period is the duration + in seconds after the processes running in + the pod are sent a termination signal and + the time when the processes are forcibly + halted with a kill signal. Set this value + longer than the expected cleanup time for + your process. + format: int64 + type: integer + timeoutSeconds: + description: 'Number of seconds after which + the probe times out. Defaults to 1 second. + Minimum value is 1. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes' + format: int32 + type: integer + type: object + stdin: + description: Whether this container should allocate + a buffer for stdin in the container runtime. + If this is not set, reads from stdin in the + container will always result in EOF. Default + is false. + type: boolean + stdinOnce: + description: Whether the container runtime should + close the stdin channel after it has been opened + by a single attach. When stdin is true the stdin + stream will remain open across multiple attach + sessions. + type: boolean + terminationMessagePath: + description: 'Optional: Path at which the file + to which the container''s termination message + will be written is mounted into the container''s + filesystem. Message written is intended to be + brief final status, such as an assertion failure + message. Will be truncated by the node if greater + than 4096 bytes. The total message length across + all containers will be limited to 12kb. Defaults + to /dev/termination-log.' + type: string + terminationMessagePolicy: + description: Indicate how the termination message + should be populated. File will use the contents + of terminationMessagePath to populate the container + status message on both success and failure. + FallbackToLogsOnError will use the last chunk + of container log output if the termination message + file is empty and the container exited with + an error. + type: string + tty: + description: Whether this container should allocate + a TTY for itself, also requires 'stdin' to be + true. Default is false. + type: boolean + volumeDevices: + description: volumeDevices is the list of block + devices to be used by the container. + items: + description: volumeDevice describes a mapping + of a raw block device within a container. + properties: + devicePath: + description: devicePath is the path inside + of the container that the device will + be mapped to. + type: string + name: + description: name must match the name of + a persistentVolumeClaim in the pod + type: string + required: + - devicePath + - name + type: object + type: array + volumeMounts: + description: Pod volumes to mount into the container's + filesystem. Cannot be updated. + items: + description: VolumeMount describes a mounting + of a Volume within a container. + properties: + mountPath: + description: Path within the container at + which the volume should be mounted. Must + not contain ':'. + type: string + mountPropagation: + description: mountPropagation determines + how mounts are propagated from the host + to container and the other way around. + When not set, MountPropagationNone is + used. This field is beta in 1.10. + type: string + name: + description: This must match the Name of + a Volume. + type: string + readOnly: + description: Mounted read-only if true, + read-write otherwise (false or unspecified). + Defaults to false. + type: boolean + subPath: + description: Path within the volume from + which the container's volume should be + mounted. Defaults to "" (volume's root). + type: string + subPathExpr: + description: Expanded path within the volume + from which the container's volume should + be mounted. Behaves similarly to SubPath + but environment variable references $(VAR_NAME) + are expanded using the container's environment. + Defaults to "" (volume's root). SubPathExpr + and SubPath are mutually exclusive. + type: string + required: + - mountPath + - name + type: object + type: array + workingDir: + description: Container's working directory. If + not specified, the container runtime's default + will be used, which might be configured in the + container image. Cannot be updated. + type: string + required: + - name + type: object + type: array + nodeName: + description: NodeName is a request to schedule this + pod onto a specific node. If it is non-empty, the + scheduler simply schedules this pod onto that node, + assuming that it fits resource requirements. + type: string + nodeSelector: + additionalProperties: + type: string + description: 'NodeSelector is a selector which must + be true for the pod to fit on a node. Selector which + must match a node''s labels for the pod to be scheduled + on that node. More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/' + type: object + x-kubernetes-map-type: atomic + os: + description: "Specifies the OS of the containers in + the pod. Some pod and container fields are restricted + if this is set. \n If the OS field is set to linux, + the following fields must be unset: -securityContext.windowsOptions + \n If the OS field is set to windows, following fields + must be unset: - spec.hostPID - spec.hostIPC - spec.hostUsers + - spec.securityContext.seLinuxOptions - spec.securityContext." + properties: + name: + description: 'Name is the name of the operating + system. The currently supported values are linux + and windows. Additional value may be defined in + future and can be one of: https://github.com/opencontainers/runtime-spec/blob/master/config.md#platform-specific-configuration + Clients should expect to handle additional values + and treat unrecognized values in this field as + os: null' + type: string + required: + - name + type: object + overhead: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: Overhead represents the resource overhead + associated with running a pod for a given RuntimeClass. + This field will be autopopulated at admission time + by the RuntimeClass admission controller. If the RuntimeClass + admission controller is enabled, overhead must not + be set in Pod create requests. The RuntimeClass admission + controller will reject Pod create requests which have + the overhead already set. + type: object + preemptionPolicy: + description: PreemptionPolicy is the Policy for preempting + pods with lower priority. One of Never, PreemptLowerPriority. + Defaults to PreemptLowerPriority if unset. + type: string + priority: + description: The priority value. Various system components + use this field to find the priority of the pod. When + Priority Admission Controller is enabled, it prevents + users from setting this field. The admission controller + populates this field from PriorityClassName. The higher + the value, the higher the priority. + format: int32 + type: integer + priorityClassName: + description: If specified, indicates the pod's priority. + "system-node-critical" and "system-cluster-critical" + are two special keywords which indicate the highest + priorities with the former being the highest priority. + Any other name must be defined by creating a PriorityClass + object with that name. If not specified, the pod priority + will be default or zero if there is no default. + type: string + readinessGates: + description: 'If specified, all readiness gates will + be evaluated for pod readiness. A pod is ready when + all its containers are ready AND all conditions specified + in the readiness gates have status equal to "True" + More info: https://git.k8s.io/enhancements/keps/sig-network/580-pod-readiness-gates' + items: + description: PodReadinessGate contains the reference + to a pod condition + properties: + conditionType: + description: ConditionType refers to a condition + in the pod's condition list with matching type. + type: string + required: + - conditionType + type: object + type: array + resourceClaims: + description: "ResourceClaims defines which ResourceClaims + must be allocated and reserved before the Pod is allowed + to start. The resources will be made available to + those containers which consume them by name. \n This + is an alpha field and requires enabling the DynamicResourceAllocation + feature gate. \n This field is immutable." + items: + description: PodResourceClaim references exactly one + ResourceClaim through a ClaimSource. It adds a name + to it that uniquely identifies the ResourceClaim + inside the Pod. Containers that need access to the + ResourceClaim reference it with this name. + properties: + name: + description: Name uniquely identifies this resource + claim inside the pod. This must be a DNS_LABEL. + type: string + source: + description: Source describes where to find the + ResourceClaim. + properties: + resourceClaimName: + description: ResourceClaimName is the name + of a ResourceClaim object in the same namespace + as this pod. + type: string + resourceClaimTemplateName: + description: "ResourceClaimTemplateName is + the name of a ResourceClaimTemplate object + in the same namespace as this pod. \n The + template will be used to create a new ResourceClaim, + which will be bound to this pod. When this + pod is deleted, the ResourceClaim will also + be deleted. The name of the ResourceClaim + will be -, where + is the PodResourceClaim.Name." + type: string + type: object + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + restartPolicy: + description: 'Restart policy for all containers within + the pod. One of Always, OnFailure, Never. In some + contexts, only a subset of those values may be permitted. + Default to Always. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/#restart-policy' + type: string + runtimeClassName: + description: 'RuntimeClassName refers to a RuntimeClass + object in the node.k8s.io group, which should be used + to run this pod. If no RuntimeClass resource matches + the named class, the pod will not be run. If unset + or empty, the "legacy" RuntimeClass will be used, + which is an implicit class with an empty definition + that uses the default runtime handler. More info: + https://git.k8s.' + type: string + schedulerName: + description: If specified, the pod will be dispatched + by specified scheduler. If not specified, the pod + will be dispatched by default scheduler. + type: string + schedulingGates: + description: "SchedulingGates is an opaque list of values + that if specified will block scheduling the pod. If + schedulingGates is not empty, the pod will stay in + the SchedulingGated state and the scheduler will not + attempt to schedule the pod. \n SchedulingGates can + only be set at pod creation time, and be removed only + afterwards. \n This is a beta feature enabled by the + PodSchedulingReadiness feature gate." + items: + description: PodSchedulingGate is associated to a + Pod to guard its scheduling. + properties: + name: + description: Name of the scheduling gate. Each + scheduling gate must have a unique name field. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + securityContext: + description: 'SecurityContext holds pod-level security + attributes and common container settings. Optional: + Defaults to empty. See type description for default + values of each field.' + properties: + fsGroup: + description: "A special supplemental group that + applies to all containers in a pod. Some volume + types allow the Kubelet to change the ownership + of that volume to be owned by the pod: \n 1. The + owning GID will be the FSGroup 2. The setgid bit + is set (new files created in the volume will be + owned by FSGroup) 3." + format: int64 + type: integer + fsGroupChangePolicy: + description: 'fsGroupChangePolicy defines behavior + of changing ownership and permission of the volume + before being exposed inside Pod. This field will + only apply to volume types which support fsGroup + based ownership(and permissions). It will have + no effect on ephemeral volume types such as: secret, + configmaps and emptydir. Valid values are "OnRootMismatch" + and "Always". If not specified, "Always" is used.' + type: string + runAsGroup: + description: The GID to run the entrypoint of the + container process. Uses runtime default if unset. + May also be set in SecurityContext. If set in + both SecurityContext and PodSecurityContext, the + value specified in SecurityContext takes precedence + for that container. Note that this field cannot + be set when spec.os.name is windows. + format: int64 + type: integer + runAsNonRoot: + description: Indicates that the container must run + as a non-root user. If true, the Kubelet will + validate the image at runtime to ensure that it + does not run as UID 0 (root) and fail to start + the container if it does. If unset or false, no + such validation will be performed. May also be + set in SecurityContext. + type: boolean + runAsUser: + description: The UID to run the entrypoint of the + container process. Defaults to user specified + in image metadata if unspecified. May also be + set in SecurityContext. If set in both SecurityContext + and PodSecurityContext, the value specified in + SecurityContext takes precedence for that container. + Note that this field cannot be set when spec.os.name + is windows. + format: int64 + type: integer + seLinuxOptions: + description: The SELinux context to be applied to + all containers. If unspecified, the container + runtime will allocate a random SELinux context + for each container. May also be set in SecurityContext. If + set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence + for that container. Note that this field cannot + be set when spec.os.name is windows. + properties: + level: + description: Level is SELinux level label that + applies to the container. + type: string + role: + description: Role is a SELinux role label that + applies to the container. + type: string + type: + description: Type is a SELinux type label that + applies to the container. + type: string + user: + description: User is a SELinux user label that + applies to the container. + type: string + type: object + seccompProfile: + description: The seccomp options to use by the containers + in this pod. Note that this field cannot be set + when spec.os.name is windows. + properties: + localhostProfile: + description: localhostProfile indicates a profile + defined in a file on the node should be used. + The profile must be preconfigured on the node + to work. Must be a descending path, relative + to the kubelet's configured seccomp profile + location. Must only be set if type is "Localhost". + type: string + type: + description: "type indicates which kind of seccomp + profile will be applied. Valid options are: + \n Localhost - a profile defined in a file + on the node should be used. RuntimeDefault + - the container runtime default profile should + be used. Unconfined - no profile should be + applied." + type: string + required: + - type + type: object + supplementalGroups: + description: A list of groups applied to the first + process run in each container, in addition to + the container's primary GID, the fsGroup (if specified), + and group memberships defined in the container + image for the uid of the container process. If + unspecified, no additional groups are added to + any container. + items: + format: int64 + type: integer + type: array + sysctls: + description: Sysctls hold a list of namespaced sysctls + used for the pod. Pods with unsupported sysctls + (by the container runtime) might fail to launch. + Note that this field cannot be set when spec.os.name + is windows. + items: + description: Sysctl defines a kernel parameter + to be set + properties: + name: + description: Name of a property to set + type: string + value: + description: Value of a property to set + type: string + required: + - name + - value + type: object + type: array + windowsOptions: + description: The Windows specific settings applied + to all containers. If unspecified, the options + within a container's SecurityContext will be used. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes precedence. + Note that this field cannot be set when spec.os.name + is linux. + properties: + gmsaCredentialSpec: + description: GMSACredentialSpec is where the + GMSA admission webhook (https://github.com/kubernetes-sigs/windows-gmsa) + inlines the contents of the GMSA credential + spec named by the GMSACredentialSpecName field. + type: string + gmsaCredentialSpecName: + description: GMSACredentialSpecName is the name + of the GMSA credential spec to use. + type: string + hostProcess: + description: HostProcess determines if a container + should be run as a 'Host Process' container. + This field is alpha-level and will only be + honored by components that enable the WindowsHostProcessContainers + feature flag. Setting this field without the + feature flag will result in errors when validating + the Pod. + type: boolean + runAsUserName: + description: The UserName in Windows to run + the entrypoint of the container process. Defaults + to the user specified in image metadata if + unspecified. May also be set in PodSecurityContext. + If set in both SecurityContext and PodSecurityContext, + the value specified in SecurityContext takes + precedence. + type: string + type: object + type: object + serviceAccount: + description: 'DeprecatedServiceAccount is a depreciated + alias for ServiceAccountName. Deprecated: Use serviceAccountName + instead.' + type: string + serviceAccountName: + description: 'ServiceAccountName is the name of the + ServiceAccount to use to run this pod. More info: + https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/' + type: string + setHostnameAsFQDN: + description: If true the pod's hostname will be configured + as the pod's FQDN, rather than the leaf name (the + default). In Linux containers, this means setting + the FQDN in the hostname field of the kernel (the + nodename field of struct utsname). + type: boolean + shareProcessNamespace: + description: 'Share a single process namespace between + all of the containers in a pod. When this is set containers + will be able to view and signal processes from other + containers in the same pod, and the first process + in each container will not be assigned PID 1. HostPID + and ShareProcessNamespace cannot both be set. Optional: + Default to false.' + type: boolean + subdomain: + description: If specified, the fully qualified Pod hostname + will be "...svc.". If not specified, the pod will not have + a domainname at all. + type: string + terminationGracePeriodSeconds: + description: Optional duration in seconds the pod needs + to terminate gracefully. May be decreased in delete + request. Value must be non-negative integer. The value + zero indicates stop immediately via the kill signal + (no opportunity to shut down). If this value is nil, + the default grace period will be used instead. + format: int64 + type: integer + tolerations: + description: If specified, the pod's tolerations. + items: + description: The pod this Toleration is attached to + tolerates any taint that matches the triple + using the matching operator . + properties: + effect: + description: Effect indicates the taint effect + to match. Empty means match all taint effects. + When specified, allowed values are NoSchedule, + PreferNoSchedule and NoExecute. + type: string + key: + description: Key is the taint key that the toleration + applies to. Empty means match all taint keys. + If the key is empty, operator must be Exists; + this combination means to match all values and + all keys. + type: string + operator: + description: Operator represents a key's relationship + to the value. Valid operators are Exists and + Equal. Defaults to Equal. Exists is equivalent + to wildcard for value, so that a pod can tolerate + all taints of a particular category. + type: string + tolerationSeconds: + description: TolerationSeconds represents the + period of time the toleration (which must be + of effect NoExecute, otherwise this field is + ignored) tolerates the taint. By default, it + is not set, which means tolerate the taint forever + (do not evict). Zero and negative values will + be treated as 0 (evict immediately) by the system. + format: int64 + type: integer + value: + description: Value is the taint value the toleration + matches to. If the operator is Exists, the value + should be empty, otherwise just a regular string. + type: string + type: object + type: array + topologySpreadConstraints: + description: TopologySpreadConstraints describes how + a group of pods ought to spread across topology domains. + Scheduler will schedule pods in a way which abides + by the constraints. All topologySpreadConstraints + are ANDed. + items: + description: TopologySpreadConstraint specifies how + to spread matching pods among the given topology. + properties: + labelSelector: + description: LabelSelector is used to find matching + pods. Pods that match this label selector are + counted to determine the number of pods in their + corresponding topology domain. + properties: + matchExpressions: + description: matchExpressions is a list of + label selector requirements. The requirements + are ANDed. + items: + description: A label selector requirement + is a selector that contains values, a + key, and an operator that relates the + key and values. + properties: + key: + description: key is the label key that + the selector applies to. + type: string + operator: + description: operator represents a key's + relationship to a set of values. Valid + operators are In, NotIn, Exists and + DoesNotExist. + type: string + values: + description: values is an array of string + values. If the operator is In or NotIn, + the values array must be non-empty. + If the operator is Exists or DoesNotExist, + the values array must be empty. This + array is replaced during a strategic + merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} + pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, + whose key field is "key", the operator is + "In", and the values array contains only + "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + matchLabelKeys: + description: MatchLabelKeys is a set of pod label + keys to select the pods over which spreading + will be calculated. The keys are used to lookup + values from the incoming pod labels, those key-value + labels are ANDed with labelSelector to select + the group of existing pods over which spreading + will be calculated for the incoming pod. The + same key is forbidden to exist in both MatchLabelKeys + and LabelSelector. + items: + type: string + type: array + x-kubernetes-list-type: atomic + maxSkew: + description: MaxSkew describes the degree to which + pods may be unevenly distributed. When `whenUnsatisfiable=DoNotSchedule`, + it is the maximum permitted difference between + the number of matching pods in the target topology + and the global minimum. The global minimum is + the minimum number of matching pods in an eligible + domain or zero if the number of eligible domains + is less than MinDomains. + format: int32 + type: integer + minDomains: + description: MinDomains indicates a minimum number + of eligible domains. When the number of eligible + domains with matching topology keys is less + than minDomains, Pod Topology Spread treats + "global minimum" as 0, and then the calculation + of Skew is performed. And when the number of + eligible domains with matching topology keys + equals or greater than minDomains, this value + has no effect on scheduling. + format: int32 + type: integer + nodeAffinityPolicy: + description: "NodeAffinityPolicy indicates how + we will treat Pod's nodeAffinity/nodeSelector + when calculating pod topology spread skew. Options + are: - Honor: only nodes matching nodeAffinity/nodeSelector + are included in the calculations. - Ignore: + nodeAffinity/nodeSelector are ignored. All nodes + are included in the calculations. \n If this + value is nil, the behavior is equivalent to + the Honor policy." + type: string + nodeTaintsPolicy: + description: "NodeTaintsPolicy indicates how we + will treat node taints when calculating pod + topology spread skew. Options are: - Honor: + nodes without taints, along with tainted nodes + for which the incoming pod has a toleration, + are included. - Ignore: node taints are ignored. + All nodes are included. \n If this value is + nil, the behavior is equivalent to the Ignore + policy." + type: string + topologyKey: + description: TopologyKey is the key of node labels. + Nodes that have a label with this key and identical + values are considered to be in the same topology. + We consider each as a "bucket", + and try to put balanced number of pods into + each bucket. We define a domain as a particular + instance of a topology. + type: string + whenUnsatisfiable: + description: WhenUnsatisfiable indicates how to + deal with a pod if it doesn't satisfy the spread + constraint. - DoNotSchedule (default) tells + the scheduler not to schedule it. - ScheduleAnyway + tells the scheduler to schedule the pod in any + location, but giving higher precedence to topologies + that would help reduce the skew. + type: string + required: + - maxSkew + - topologyKey + - whenUnsatisfiable + type: object + type: array + x-kubernetes-list-map-keys: + - topologyKey + - whenUnsatisfiable + x-kubernetes-list-type: map + volumes: + description: 'List of volumes that can be mounted by + containers belonging to the pod. More info: https://kubernetes.io/docs/concepts/storage/volumes' + items: + description: Volume represents a named volume in a + pod that may be accessed by any container in the + pod. + properties: + awsElasticBlockStore: + description: 'awsElasticBlockStore represents + an AWS Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty).' + format: int32 + type: integer + readOnly: + description: 'readOnly value true will force + the readOnly setting in VolumeMounts. More + info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: boolean + volumeID: + description: 'volumeID is unique ID of the + persistent disk resource in AWS (Amazon + EBS volume). More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore' + type: string + required: + - volumeID + type: object + azureDisk: + description: azureDisk represents an Azure Data + Disk mount on the host and bind mount to the + pod. + properties: + cachingMode: + description: 'cachingMode is the Host Caching + mode: None, Read Only, Read Write.' + type: string + diskName: + description: diskName is the Name of the data + disk in the blob storage + type: string + diskURI: + description: diskURI is the URI of data disk + in the blob storage + type: string + fsType: + description: fsType is Filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + kind: + description: 'kind expected values are Shared: + multiple blob disks per storage account Dedicated: + single blob disk per storage account Managed: + azure managed data disk (only in managed + availability set). defaults to shared' + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + required: + - diskName + - diskURI + type: object + azureFile: + description: azureFile represents an Azure File + Service mount on the host and bind mount to + the pod. + properties: + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretName: + description: secretName is the name of secret + that contains Azure Storage Account Name + and Key + type: string + shareName: + description: shareName is the azure share + Name + type: string + required: + - secretName + - shareName + type: object + cephfs: + description: cephFS represents a Ceph FS mount + on the host that shares a pod's lifetime + properties: + monitors: + description: 'monitors is Required: Monitors + is a collection of Ceph monitors More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + items: + type: string + type: array + path: + description: 'path is Optional: Used as the + mounted root, rather than the full Ceph + tree, default is /' + type: string + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts. + More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: boolean + secretFile: + description: 'secretFile is Optional: SecretFile + is the path to key ring for User, default + is /etc/ceph/user.secret More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + secretRef: + description: 'secretRef is Optional: SecretRef + is reference to the authentication secret + for User, default is empty. More info: https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is optional: User is the + rados user name, default is admin More info: + https://examples.k8s.io/volumes/cephfs/README.md#how-to-use-it' + type: string + required: + - monitors + type: object + cinder: + description: 'cinder represents a cinder volume + attached and mounted on kubelets host machine. + More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + readOnly: + description: 'readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: boolean + secretRef: + description: 'secretRef is optional: points + to a secret object containing parameters + used to connect to OpenStack.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeID: + description: 'volumeID used to identify the + volume in cinder. More info: https://examples.k8s.io/mysql-cinder-pd/README.md' + type: string + required: + - volumeID + type: object + configMap: + description: configMap represents a configMap + that should populate this volume + properties: + defaultMode: + description: 'defaultMode is optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting.' + format: int32 + type: integer + items: + description: items if unspecified, each key-value + pair in the Data field of the referenced + ConfigMap will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. More info: + https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + optional: + description: optional specify whether the + ConfigMap or its keys must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + csi: + description: csi (Container Storage Interface) + represents ephemeral storage that is handled + by certain external CSI drivers (Beta feature). + properties: + driver: + description: driver is the name of the CSI + driver that handles this volume. Consult + with your admin for the correct name as + registered in the cluster. + type: string + fsType: + description: fsType to mount. Ex. "ext4", + "xfs", "ntfs". If not provided, the empty + value is passed to the associated CSI driver + which will determine the default filesystem + to apply. + type: string + nodePublishSecretRef: + description: nodePublishSecretRef is a reference + to the secret object containing sensitive + information to pass to the CSI driver to + complete the CSI NodePublishVolume and NodeUnpublishVolume + calls. This field is optional, and may + be empty if no secret is required. If the + secret object contains more than one secret, + all secret references are passed. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + readOnly: + description: readOnly specifies a read-only + configuration for the volume. Defaults to + false (read/write). + type: boolean + volumeAttributes: + additionalProperties: + type: string + description: volumeAttributes stores driver-specific + properties that are passed to the CSI driver. + Consult your driver's documentation for + supported values. + type: object + required: + - driver + type: object + downwardAPI: + description: downwardAPI represents downward API + about the pod that should populate this volume + properties: + defaultMode: + description: 'Optional: mode bits to use on + created files by default. Must be a Optional: + mode bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting.' + format: int32 + type: integer + items: + description: Items is a list of downward API + volume file + items: + description: DownwardAPIVolumeFile represents + information to create the file containing + the pod field + properties: + fieldRef: + description: 'Required: Selects a field + of the pod: only annotations, labels, + name and namespace are supported.' + properties: + apiVersion: + description: Version of the schema + the FieldPath is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the field to + select in the specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode bits used + to set permissions on this file, must + be an octal value between 0000 and + 0777 or a decimal value between 0 + and 511. YAML accepts both octal and + decimal values, JSON requires decimal + values for mode bits. If not specified, + the volume defaultMode will be used.' + format: int32 + type: integer + path: + description: 'Required: Path is the + relative path name of the file to + be created. Must not be absolute or + contain the ''..'' path. Must be utf-8 + encoded. The first item of the relative + path must not start with ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource of + the container: only resources limits + and requests (limits.cpu, limits.memory, + requests.cpu and requests.memory) + are currently supported.' + properties: + containerName: + description: 'Container name: required + for volumes, optional for env + vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies the output + format of the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: resource + to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + emptyDir: + description: 'emptyDir represents a temporary + directory that shares a pod''s lifetime. More + info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + properties: + medium: + description: 'medium represents what type + of storage medium should back this directory. + The default is "" which means to use the + node''s default medium. Must be an empty + string (default) or Memory. More info: https://kubernetes.io/docs/concepts/storage/volumes#emptydir' + type: string + sizeLimit: + anyOf: + - type: integer + - type: string + description: 'sizeLimit is the total amount + of local storage required for this EmptyDir + volume. The size limit is also applicable + for memory medium. The maximum usage on + memory medium EmptyDir would be the minimum + value between the SizeLimit specified here + and the sum of memory limits of all containers + in a pod. The default is nil which means + that the limit is undefined. More info: + https://kubernetes.' + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + ephemeral: + description: ephemeral represents a volume that + is handled by a cluster storage driver. The + volume's lifecycle is tied to the pod that defines + it - it will be created before the pod starts, + and deleted when the pod is removed. + properties: + volumeClaimTemplate: + description: Will be used to create a stand-alone + PVC to provision the volume. The pod in + which this EphemeralVolumeSource is embedded + will be the owner of the PVC, i.e. the PVC + will be deleted together with the pod. The + name of the PVC will be `-` where `` is the name + from the `PodSpec.Volumes` array entry. + properties: + metadata: + description: May contain labels and annotations + that will be copied into the PVC when + creating it. No other fields are allowed + and will be rejected during validation. + properties: + annotations: + additionalProperties: + type: string + type: object + finalizers: + items: + type: string + type: array + labels: + additionalProperties: + type: string + type: object + name: + type: string + namespace: + type: string + type: object + spec: + description: The specification for the + PersistentVolumeClaim. The entire content + is copied unchanged into the PVC that + gets created from this template. The + same fields as in a PersistentVolumeClaim + are also valid here. + properties: + accessModes: + description: 'accessModes contains + the desired access modes the volume + should have. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes-1' + items: + type: string + type: array + dataSource: + description: 'dataSource field can + be used to specify either: * An + existing VolumeSnapshot object (snapshot.storage.k8s.io/VolumeSnapshot) + * An existing PVC (PersistentVolumeClaim) + If the provisioner or an external + controller can support the specified + data source, it will create a new + volume based on the contents of + the specified data source.' + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + required: + - kind + - name + type: object + x-kubernetes-map-type: atomic + dataSourceRef: + description: dataSourceRef specifies + the object from which to populate + the volume with data, if a non-empty + volume is desired. This may be any + object from a non-empty API group + (non core object) or a PersistentVolumeClaim + object. When this field is specified, + volume binding will only succeed + if the type of the specified object + matches some installed volume populator + or dynamic provisioner. + properties: + apiGroup: + description: APIGroup is the group + for the resource being referenced. + If APIGroup is not specified, + the specified Kind must be in + the core API group. For any + other third-party types, APIGroup + is required. + type: string + kind: + description: Kind is the type + of resource being referenced + type: string + name: + description: Name is the name + of resource being referenced + type: string + namespace: + description: Namespace is the + namespace of resource being + referenced Note that when a + namespace is specified, a gateway.networking.k8s.io/ReferenceGrant + object is required in the referent + namespace to allow that namespace's + owner to accept the reference. + See the ReferenceGrant documentation + for details. (Alpha) This field + requires the CrossNamespaceVolumeDataSource + feature gate to be enabled. + type: string + required: + - kind + - name + type: object + resources: + description: 'resources represents + the minimum resources the volume + should have. If RecoverVolumeExpansionFailure + feature is enabled users are allowed + to specify resource requirements + that are lower than previous value + but must still be higher than capacity + recorded in the status field of + the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#resources' + properties: + claims: + description: "Claims lists the + names of resources, defined + in spec.resourceClaims, that + are used by this container. + \n This is an alpha field and + requires enabling the DynamicResourceAllocation + feature gate. \n This field + is immutable. It can only be + set for containers." + items: + description: ResourceClaim references + one entry in PodSpec.ResourceClaims. + properties: + name: + description: Name must match + the name of one entry + in pod.spec.resourceClaims + of the Pod where this + field is used. It makes + that resource available + inside a container. + type: string + required: + - name + type: object + type: array + x-kubernetes-list-map-keys: + - name + x-kubernetes-list-type: map + limits: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Limits describes + the maximum amount of compute + resources allowed. More info: + https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + requests: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + description: 'Requests describes + the minimum amount of compute + resources required. If Requests + is omitted for a container, + it defaults to Limits if that + is explicitly specified, otherwise + to an implementation-defined + value. Requests cannot exceed + Limits. More info: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/' + type: object + type: object + selector: + description: selector is a label query + over volumes to consider for binding. + properties: + matchExpressions: + description: matchExpressions + is a list of label selector + requirements. The requirements + are ANDed. + items: + description: A label selector + requirement is a selector + that contains values, a key, + and an operator that relates + the key and values. + properties: + key: + description: key is the + label key that the selector + applies to. + type: string + operator: + description: operator represents + a key's relationship to + a set of values. Valid + operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an + array of string values. + If the operator is In + or NotIn, the values array + must be non-empty. If + the operator is Exists + or DoesNotExist, the values + array must be empty. This + array is replaced during + a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a + map of {key,value} pairs. A + single {key,value} in the matchLabels + map is equivalent to an element + of matchExpressions, whose key + field is "key", the operator + is "In", and the values array + contains only "value". The requirements + are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + storageClassName: + description: 'storageClassName is + the name of the StorageClass required + by the claim. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#class-1' + type: string + volumeMode: + description: volumeMode defines what + type of volume is required by the + claim. Value of Filesystem is implied + when not included in claim spec. + type: string + volumeName: + description: volumeName is the binding + reference to the PersistentVolume + backing this claim. + type: string + type: object + required: + - spec + type: object + type: object + fc: + description: fc represents a Fibre Channel resource + that is attached to a kubelet's host machine + and then exposed to the pod. + properties: + fsType: + description: 'fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. TODO: how do we prevent + errors in the filesystem from compromising + the machine' + type: string + lun: + description: 'lun is Optional: FC target lun + number' + format: int32 + type: integer + readOnly: + description: 'readOnly is Optional: Defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + targetWWNs: + description: 'targetWWNs is Optional: FC target + worldwide names (WWNs)' + items: + type: string + type: array + wwids: + description: 'wwids Optional: FC volume world + wide identifiers (wwids) Either wwids or + combination of targetWWNs and lun must be + set, but not both simultaneously.' + items: + type: string + type: array + type: object + flexVolume: + description: flexVolume represents a generic volume + resource that is provisioned/attached using + an exec based plugin. + properties: + driver: + description: driver is the name of the driver + to use for this volume. + type: string + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". The default filesystem depends + on FlexVolume script. + type: string + options: + additionalProperties: + type: string + description: 'options is Optional: this field + holds extra command options if any.' + type: object + readOnly: + description: 'readOnly is Optional: defaults + to false (read/write). ReadOnly here will + force the ReadOnly setting in VolumeMounts.' + type: boolean + secretRef: + description: 'secretRef is Optional: secretRef + is reference to the secret object containing + sensitive information to pass to the plugin + scripts. This may be empty if no secret + object is specified. If the secret object + contains more than one secret, all secrets + are passed to the plugin scripts.' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + required: + - driver + type: object + flocker: + description: flocker represents a Flocker volume + attached to a kubelet's host machine. This depends + on the Flocker control service being running + properties: + datasetName: + description: datasetName is Name of the dataset + stored as metadata -> name on the dataset + for Flocker should be considered as deprecated + type: string + datasetUUID: + description: datasetUUID is the UUID of the + dataset. This is unique identifier of a + Flocker dataset + type: string + type: object + gcePersistentDisk: + description: 'gcePersistentDisk represents a GCE + Disk resource that is attached to a kubelet''s + host machine and then exposed to the pod. More + info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + properties: + fsType: + description: 'fsType is filesystem type of + the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + partition: + description: 'partition is the partition in + the volume that you want to mount. If omitted, + the default is to mount by volume name. + Examples: For volume /dev/sda1, you specify + the partition as "1". Similarly, the volume + partition for /dev/sda is "0" (or you can + leave the property empty). More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + format: int32 + type: integer + pdName: + description: 'pdName is unique name of the + PD resource in GCE. Used to identify the + disk in GCE. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://kubernetes.io/docs/concepts/storage/volumes#gcepersistentdisk' + type: boolean + required: + - pdName + type: object + gitRepo: + description: 'gitRepo represents a git repository + at a particular revision. DEPRECATED: GitRepo + is deprecated. To provision a container with + a git repo, mount an EmptyDir into an InitContainer + that clones the repo using git, then mount the + EmptyDir into the Pod''s container.' + properties: + directory: + description: directory is the target directory + name. Must not contain or start with '..'. If + '.' is supplied, the volume directory will + be the git repository. Otherwise, if specified, + the volume will contain the git repository + in the subdirectory with the given name. + type: string + repository: + description: repository is the URL + type: string + revision: + description: revision is the commit hash for + the specified revision. + type: string + required: + - repository + type: object + glusterfs: + description: 'glusterfs represents a Glusterfs + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/glusterfs/README.md' + properties: + endpoints: + description: 'endpoints is the endpoint name + that details Glusterfs topology. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + path: + description: 'path is the Glusterfs volume + path. More info: https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: string + readOnly: + description: 'readOnly here will force the + Glusterfs volume to be mounted with read-only + permissions. Defaults to false. More info: + https://examples.k8s.io/volumes/glusterfs/README.md#create-a-pod' + type: boolean + required: + - endpoints + - path + type: object + hostPath: + description: 'hostPath represents a pre-existing + file or directory on the host machine that is + directly exposed to the container. This is generally + used for system agents or other privileged things + that are allowed to see the host machine. Most + containers will NOT need this. More info: https://kubernetes.' + properties: + path: + description: 'path of the directory on the + host. If the path is a symlink, it will + follow the link to the real path. More info: + https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + type: + description: 'type for HostPath Volume Defaults + to "" More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath' + type: string + required: + - path + type: object + iscsi: + description: 'iscsi represents an ISCSI Disk resource + that is attached to a kubelet''s host machine + and then exposed to the pod. More info: https://examples.k8s.io/volumes/iscsi/README.md' + properties: + chapAuthDiscovery: + description: chapAuthDiscovery defines whether + support iSCSI Discovery CHAP authentication + type: boolean + chapAuthSession: + description: chapAuthSession defines whether + support iSCSI Session CHAP authentication + type: boolean + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#iscsi + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + initiatorName: + description: initiatorName is the custom iSCSI + Initiator Name. If initiatorName is specified + with iscsiInterface simultaneously, new + iSCSI interface : will be created for the connection. + type: string + iqn: + description: iqn is the target iSCSI Qualified + Name. + type: string + iscsiInterface: + description: iscsiInterface is the interface + Name that uses an iSCSI transport. Defaults + to 'default' (tcp). + type: string + lun: + description: lun represents iSCSI Target Lun + number. + format: int32 + type: integer + portals: + description: portals is the iSCSI Target Portal + List. The portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + items: + type: string + type: array + readOnly: + description: readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. + type: boolean + secretRef: + description: secretRef is the CHAP Secret + for iSCSI target and initiator authentication + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + targetPortal: + description: targetPortal is iSCSI Target + Portal. The Portal is either an IP or ip_addr:port + if the port is other than default (typically + TCP ports 860 and 3260). + type: string + required: + - iqn + - lun + - targetPortal + type: object + name: + description: 'name of the volume. Must be a DNS_LABEL + and unique within the pod. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names' + type: string + nfs: + description: 'nfs represents an NFS mount on the + host that shares a pod''s lifetime More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + properties: + path: + description: 'path that is exported by the + NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + readOnly: + description: 'readOnly here will force the + NFS export to be mounted with read-only + permissions. Defaults to false. More info: + https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: boolean + server: + description: 'server is the hostname or IP + address of the NFS server. More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs' + type: string + required: + - path + - server + type: object + persistentVolumeClaim: + description: 'persistentVolumeClaimVolumeSource + represents a reference to a PersistentVolumeClaim + in the same namespace. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + properties: + claimName: + description: 'claimName is the name of a PersistentVolumeClaim + in the same namespace as the pod using this + volume. More info: https://kubernetes.io/docs/concepts/storage/persistent-volumes#persistentvolumeclaims' + type: string + readOnly: + description: readOnly Will force the ReadOnly + setting in VolumeMounts. Default false. + type: boolean + required: + - claimName + type: object + photonPersistentDisk: + description: photonPersistentDisk represents a + PhotonController persistent disk attached and + mounted on kubelets host machine + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + pdID: + description: pdID is the ID that identifies + Photon Controller persistent disk + type: string + required: + - pdID + type: object + portworxVolume: + description: portworxVolume represents a portworx + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fSType represents the filesystem + type to mount Must be a filesystem type + supported by the host operating system. + Ex. "ext4", "xfs". Implicitly inferred to + be "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + volumeID: + description: volumeID uniquely identifies + a Portworx volume + type: string + required: + - volumeID + type: object + projected: + description: projected items for all in one resources + secrets, configmaps, and downward API + properties: + defaultMode: + description: defaultMode are the mode bits + used to set permissions on created files + by default. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal and decimal + values, JSON requires decimal values for + mode bits. Directories within the path are + not affected by this setting. + format: int32 + type: integer + sources: + description: sources is the list of volume + projections + items: + description: Projection that may be projected + along with other supported volume types + properties: + configMap: + description: configMap information about + the configMap data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced ConfigMap + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional specify whether + the ConfigMap or its keys must + be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + downwardAPI: + description: downwardAPI information + about the downwardAPI data to project + properties: + items: + description: Items is a list of + DownwardAPIVolume file + items: + description: DownwardAPIVolumeFile + represents information to create + the file containing the pod + field + properties: + fieldRef: + description: 'Required: Selects + a field of the pod: only + annotations, labels, name + and namespace are supported.' + properties: + apiVersion: + description: Version of + the schema the FieldPath + is written in terms + of, defaults to "v1". + type: string + fieldPath: + description: Path of the + field to select in the + specified API version. + type: string + required: + - fieldPath + type: object + x-kubernetes-map-type: atomic + mode: + description: 'Optional: mode + bits used to set permissions + on this file, must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used.' + format: int32 + type: integer + path: + description: 'Required: Path + is the relative path name + of the file to be created. + Must not be absolute or + contain the ''..'' path. + Must be utf-8 encoded. The + first item of the relative + path must not start with + ''..''' + type: string + resourceFieldRef: + description: 'Selects a resource + of the container: only resources + limits and requests (limits.cpu, + limits.memory, requests.cpu + and requests.memory) are + currently supported.' + properties: + containerName: + description: 'Container + name: required for volumes, + optional for env vars' + type: string + divisor: + anyOf: + - type: integer + - type: string + description: Specifies + the output format of + the exposed resources, + defaults to "1" + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + resource: + description: 'Required: + resource to select' + type: string + required: + - resource + type: object + x-kubernetes-map-type: atomic + required: + - path + type: object + type: array + type: object + secret: + description: secret information about + the secret data to project + properties: + items: + description: items if unspecified, + each key-value pair in the Data + field of the referenced Secret + will be projected into the volume + as a file whose name is the key + and content is the value. If specified, + the listed keys will be projected + into the specified paths, and + unlisted keys will not be present. + items: + description: Maps a string key + to a path within a volume. + properties: + key: + description: key is the key + to project. + type: string + mode: + description: 'mode is Optional: + mode bits used to set permissions + on this file. Must be an + octal value between 0000 + and 0777 or a decimal value + between 0 and 511. YAML + accepts both octal and decimal + values, JSON requires decimal + values for mode bits. If + not specified, the volume + defaultMode will be used.' + format: int32 + type: integer + path: + description: path is the relative + path of the file to map + the key to. May not be an + absolute path. May not contain + the path element '..'. May + not start with the string + '..'. + type: string + required: + - key + - path + type: object + type: array + name: + description: 'Name of the referent. + More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. + apiVersion, kind, uid?' + type: string + optional: + description: optional field specify + whether the Secret or its key + must be defined + type: boolean + type: object + x-kubernetes-map-type: atomic + serviceAccountToken: + description: serviceAccountToken is + information about the serviceAccountToken + data to project + properties: + audience: + description: audience is the intended + audience of the token. A recipient + of a token must identify itself + with an identifier specified in + the audience of the token, and + otherwise should reject the token. + The audience defaults to the identifier + of the apiserver. + type: string + expirationSeconds: + description: expirationSeconds is + the requested duration of validity + of the service account token. + As the token approaches expiration, + the kubelet volume plugin will + proactively rotate the service + account token. The kubelet will + start trying to rotate the token + if the token is older than 80 + percent of its time to live or + if the token is older than 24 + hours.Defaults to 1 hour and must + be at least 10 minutes. + format: int64 + type: integer + path: + description: path is the path relative + to the mount point of the file + to project the token into. + type: string + required: + - path + type: object + type: object + type: array + type: object + quobyte: + description: quobyte represents a Quobyte mount + on the host that shares a pod's lifetime + properties: + group: + description: group to map volume access to + Default is no group + type: string + readOnly: + description: readOnly here will force the + Quobyte volume to be mounted with read-only + permissions. Defaults to false. + type: boolean + registry: + description: registry represents a single + or multiple Quobyte Registry services specified + as a string as host:port pair (multiple + entries are separated with commas) which + acts as the central registry for volumes + type: string + tenant: + description: tenant owning the given Quobyte + volume in the Backend Used with dynamically + provisioned Quobyte volumes, value is set + by the plugin + type: string + user: + description: user to map volume access to + Defaults to serivceaccount user + type: string + volume: + description: volume is a string that references + an already created Quobyte volume by name. + type: string + required: + - registry + - volume + type: object + rbd: + description: 'rbd represents a Rados Block Device + mount on the host that shares a pod''s lifetime. + More info: https://examples.k8s.io/volumes/rbd/README.md' + properties: + fsType: + description: 'fsType is the filesystem type + of the volume that you want to mount. Tip: + Ensure that the filesystem type is supported + by the host operating system. Examples: + "ext4", "xfs", "ntfs". Implicitly inferred + to be "ext4" if unspecified. More info: + https://kubernetes.io/docs/concepts/storage/volumes#rbd + TODO: how do we prevent errors in the filesystem + from compromising the machine' + type: string + image: + description: 'image is the rados image name. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + keyring: + description: 'keyring is the path to key ring + for RBDUser. Default is /etc/ceph/keyring. + More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + monitors: + description: 'monitors is a collection of + Ceph monitors. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + items: + type: string + type: array + pool: + description: 'pool is the rados pool name. + Default is rbd. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + readOnly: + description: 'readOnly here will force the + ReadOnly setting in VolumeMounts. Defaults + to false. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: boolean + secretRef: + description: 'secretRef is name of the authentication + secret for RBDUser. If provided overrides + keyring. Default is nil. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + user: + description: 'user is the rados user name. + Default is admin. More info: https://examples.k8s.io/volumes/rbd/README.md#how-to-use-it' + type: string + required: + - image + - monitors + type: object + scaleIO: + description: scaleIO represents a ScaleIO persistent + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Default is "xfs". + type: string + gateway: + description: gateway is the host address of + the ScaleIO API Gateway. + type: string + protectionDomain: + description: protectionDomain is the name + of the ScaleIO Protection Domain for the + configured storage. + type: string + readOnly: + description: readOnly Defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef references to the secret + for ScaleIO user and other sensitive information. + If this is not provided, Login operation + will fail. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + sslEnabled: + description: sslEnabled Flag enable/disable + SSL communication with Gateway, default + false + type: boolean + storageMode: + description: storageMode indicates whether + the storage for a volume should be ThickProvisioned + or ThinProvisioned. Default is ThinProvisioned. + type: string + storagePool: + description: storagePool is the ScaleIO Storage + Pool associated with the protection domain. + type: string + system: + description: system is the name of the storage + system as configured in ScaleIO. + type: string + volumeName: + description: volumeName is the name of a volume + already created in the ScaleIO system that + is associated with this volume source. + type: string + required: + - gateway + - secretRef + - system + type: object + secret: + description: 'secret represents a secret that + should populate this volume. More info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + properties: + defaultMode: + description: 'defaultMode is Optional: mode + bits used to set permissions on created + files by default. Must be an octal value + between 0000 and 0777 or a decimal value + between 0 and 511. YAML accepts both octal + and decimal values, JSON requires decimal + values for mode bits. Defaults to 0644. + Directories within the path are not affected + by this setting.' + format: int32 + type: integer + items: + description: items If unspecified, each key-value + pair in the Data field of the referenced + Secret will be projected into the volume + as a file whose name is the key and content + is the value. If specified, the listed keys + will be projected into the specified paths, + and unlisted keys will not be present. + items: + description: Maps a string key to a path + within a volume. + properties: + key: + description: key is the key to project. + type: string + mode: + description: 'mode is Optional: mode + bits used to set permissions on this + file. Must be an octal value between + 0000 and 0777 or a decimal value between + 0 and 511. YAML accepts both octal + and decimal values, JSON requires + decimal values for mode bits. If not + specified, the volume defaultMode + will be used.' + format: int32 + type: integer + path: + description: path is the relative path + of the file to map the key to. May + not be an absolute path. May not contain + the path element '..'. May not start + with the string '..'. + type: string + required: + - key + - path + type: object + type: array + optional: + description: optional field specify whether + the Secret or its keys must be defined + type: boolean + secretName: + description: 'secretName is the name of the + secret in the pod''s namespace to use. More + info: https://kubernetes.io/docs/concepts/storage/volumes#secret' + type: string + type: object + storageos: + description: storageOS represents a StorageOS + volume attached and mounted on Kubernetes nodes. + properties: + fsType: + description: fsType is the filesystem type + to mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + readOnly: + description: readOnly defaults to false (read/write). + ReadOnly here will force the ReadOnly setting + in VolumeMounts. + type: boolean + secretRef: + description: secretRef specifies the secret + to use for obtaining the StorageOS API credentials. If + not specified, default values will be attempted. + properties: + name: + description: 'Name of the referent. More + info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names + TODO: Add other useful fields. apiVersion, + kind, uid?' + type: string + type: object + x-kubernetes-map-type: atomic + volumeName: + description: volumeName is the human-readable + name of the StorageOS volume. Volume names + are only unique within a namespace. + type: string + volumeNamespace: + description: volumeNamespace specifies the + scope of the volume within StorageOS. If + no namespace is specified then the Pod's + namespace will be used. This allows the + Kubernetes name scoping to be mirrored within + StorageOS for tighter integration. Set VolumeName + to any name to override the default behaviour. + Set to "default" if you are not using namespaces + within StorageOS. + type: string + type: object + vsphereVolume: + description: vsphereVolume represents a vSphere + volume attached and mounted on kubelets host + machine + properties: + fsType: + description: fsType is filesystem type to + mount. Must be a filesystem type supported + by the host operating system. Ex. "ext4", + "xfs", "ntfs". Implicitly inferred to be + "ext4" if unspecified. + type: string + storagePolicyID: + description: storagePolicyID is the storage + Policy Based Management (SPBM) profile ID + associated with the StoragePolicyName. + type: string + storagePolicyName: + description: storagePolicyName is the storage + Policy Based Management (SPBM) profile name. + type: string + volumePath: + description: volumePath is the path that identifies + vSphere volume vmdk + type: string + required: + - volumePath + type: object + required: + - name + type: object + type: array + required: + - containers + type: object + type: object + type: object + description: '`MPIReplicaSpecs` contains maps from `MPIReplicaType` + to `ReplicaSpec` that specify the MPI replicas to run.' + type: object + runPolicy: + description: '`RunPolicy` encapsulates various runtime policies of + the distributed training job, for example how to clean up resources + and how long the job can stay active.' + properties: + activeDeadlineSeconds: + description: Specifies the duration in seconds relative to the + startTime that the job may be active before the system tries + to terminate it; value must be positive integer. + format: int64 + type: integer + backoffLimit: + description: Optional number of retries before marking this job + failed. + format: int32 + type: integer + cleanPodPolicy: + description: CleanPodPolicy defines the policy to kill pods after + the job completes. Default to None. + type: string + schedulingPolicy: + description: SchedulingPolicy defines the policy related to scheduling, + e.g. gang-scheduling + properties: + minAvailable: + format: int32 + type: integer + minResources: + additionalProperties: + anyOf: + - type: integer + - type: string + pattern: ^(\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\+|-)?(([0-9]+(\.[0-9]*)?)|(\.[0-9]+))))?$ + x-kubernetes-int-or-string: true + type: object + priorityClass: + type: string + queue: + type: string + scheduleTimeoutSeconds: + format: int32 + type: integer + type: object + suspend: + default: false + description: suspend specifies whether the Job controller should + create Pods or not. If a Job is created with suspend set to + true, no Pods are created by the Job controller. If a Job is + suspended after creation (i.e. the flag goes from false to true), + the Job controller will delete all active Pods and PodGroups + associated with this Job. Users must design their workload to + gracefully handle this. + type: boolean + ttlSecondsAfterFinished: + description: TTLSecondsAfterFinished is the TTL to clean up jobs. + It may take extra ReconcilePeriod seconds for the cleanup, since + reconcile gets called periodically. Default to infinite. + format: int32 + type: integer + type: object + slotsPerWorker: + description: Specifies the number of slots per worker used in hostfile. + Defaults to 1. + format: int32 + type: integer + required: + - mpiReplicaSpecs + type: object + status: + description: JobStatus represents the current observed state of the training + Job. + properties: + completionTime: + description: Represents time when the job was completed. It is not + guaranteed to be set in happens-before order across separate operations. + It is represented in RFC3339 form and is in UTC. + format: date-time + type: string + conditions: + description: Conditions is an array of current observed job conditions. + items: + description: JobCondition describes the state of the job at a certain + point. + properties: + lastTransitionTime: + description: Last time the condition transitioned from one status + to another. + format: date-time + type: string + lastUpdateTime: + description: The last time this condition was updated. + format: date-time + type: string + message: + description: A human readable message indicating details about + the transition. + type: string + reason: + description: The reason for the condition's last transition. + type: string + status: + description: Status of the condition, one of True, False, Unknown. + type: string + type: + description: Type of job condition. + type: string + required: + - status + - type + type: object + type: array + lastReconcileTime: + description: Represents last time when the job was reconciled. It + is not guaranteed to be set in happens-before order across separate + operations. It is represented in RFC3339 form and is in UTC. + format: date-time + type: string + replicaStatuses: + additionalProperties: + description: ReplicaStatus represents the current observed state + of the replica. + properties: + active: + description: The number of actively running pods. + format: int32 + type: integer + failed: + description: The number of pods which reached phase Failed. + format: int32 + type: integer + labelSelector: + description: 'Deprecated: Use Selector instead' + properties: + matchExpressions: + description: matchExpressions is a list of label selector + requirements. The requirements are ANDed. + items: + description: A label selector requirement is a selector + that contains values, a key, and an operator that relates + the key and values. + properties: + key: + description: key is the label key that the selector + applies to. + type: string + operator: + description: operator represents a key's relationship + to a set of values. Valid operators are In, NotIn, + Exists and DoesNotExist. + type: string + values: + description: values is an array of string values. + If the operator is In or NotIn, the values array + must be non-empty. If the operator is Exists or + DoesNotExist, the values array must be empty. This + array is replaced during a strategic merge patch. + items: + type: string + type: array + required: + - key + - operator + type: object + type: array + matchLabels: + additionalProperties: + type: string + description: matchLabels is a map of {key,value} pairs. + A single {key,value} in the matchLabels map is equivalent + to an element of matchExpressions, whose key field is + "key", the operator is "In", and the values array contains + only "value". The requirements are ANDed. + type: object + type: object + x-kubernetes-map-type: atomic + selector: + description: A Selector is a label query over a set of resources. + The result of matchLabels and matchExpressions are ANDed. + An empty Selector matches all objects. A null Selector matches + no objects. + type: string + succeeded: + description: The number of pods which reached phase Succeeded. + format: int32 + type: integer + type: object + description: ReplicaStatuses is map of ReplicaType and ReplicaStatus, + specifies the status of each replica. + type: object + startTime: + description: Represents time when the job was acknowledged by the + job controller. It is not guaranteed to be set in happens-before + order across separate operations. It is represented in RFC3339 form + and is in UTC. + format: date-time + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/platforms/roles/kubeflow/vars/main.yml b/platforms/roles/kubeflow/vars/main.yml deleted file mode 100644 index 1e4bdbe24..000000000 --- a/platforms/roles/kubeflow/vars/main.yml +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2020 Dell Inc. or its subsidiaries. All Rights Reserved. -# -# 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. ---- - -kubeflow_firewalld_ports: - - 15020 - - 80 - - 443 - - 31400 - - 15011 - - 8060 - - 853 - - 15029 - - 15030 - - 15031 - - 15032 - - 15443 - -kfctl_download_url: https://github.com/kubeflow/kfctl/releases/download/v1.0.2/kfctl_v1.0.2-0-ga476281_linux.tar.gz - -kfctl_download_dest_path: /usr/bin/ - -kfctl_download_file_mode: 0755 - -omnia_kubeflow_dir_path: /root/k8s/omnia-kubeflow - -omnia_kubeflow_dir_mode: 0755 - -kubeflow_config_yaml_url: https://raw.githubusercontent.com/kubeflow/manifests/v1.0-branch/kfdef/kfctl_k8s_istio.v1.0.2.yaml - -istio_noauth_yaml_file_path: "{{ omnia_kubeflow_dir_path }}/kustomize/istio-install/base/istio-noauth.yaml" - -kfserving_gateway_yaml_file_path: "{{ omnia_kubeflow_dir_path }}/kustomize/kfserving-gateway/base/deployment.yaml" - -argo_yaml_file_path: "{{ omnia_kubeflow_dir_path }}/kustomize/argo/base/service.yaml" - -kubeflow_config_file: "{{ omnia_kubeflow_dir_path }}/kfctl_k8s_istio.v1.0.2.yaml" From 27cdc2302b2dcc78a3a251cf51de842c25751da6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 18 Oct 2023 10:37:06 +0530 Subject: [PATCH 002/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Overview/newfeatures.rst | 36 +++++++++++++-- docs/source/Overview/releasenotes.rst | 65 +++++++++++++++++++++++++-- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/docs/source/Overview/newfeatures.rst b/docs/source/Overview/newfeatures.rst index 40625608b..64920deda 100644 --- a/docs/source/Overview/newfeatures.rst +++ b/docs/source/Overview/newfeatures.rst @@ -1,10 +1,38 @@ New Features =========== -* Expanded `telemetry collection <../Roles/Telemetry/index.html>`_ support to Regular, health check and GPU metrics. -* `Rsyslog <../Logging/ControlPlaneLogs.html>`_ : Added ability to aggregate logs via xCAT's syslog. -* Integration of apptainer for `containerized HPC benchmark execution <../InstallationGuides/Benchmarks/index.html>`_. -* Integration of `grafana and loki installation <../Roles/Telemetry/index.html>`_ within ``telemetry.yml``. +* `Extensive Telemetry and Monitoring <../Roles/Telemetry/index.html>`_ has been added to the Omnia stack, intended for consumption by customers that are using Dell systems and Omnia to provide SaaS/IaaS solutions. These include, but are not limited to: + – CPU Utilization and status + + – GPU utilization + + – Node Count + + – Network Packet I/O + + – HDD capacity and free space + + – Memory capacity and utilization + + – Queued and Running Job Count + + – User Count + + – Cluster HW Health Checks (PCIE, NVLINK, BMC, Temps) + + – Cluster SW Health Checks (dmesg, BeeGFS, k8s nodes/pods, mySQL on control plane) + +* Metrics are extracted using a combination of the following: PSUtil, Smartctl, beegfs-ctl, nvidia-smi, rocm-smi. Since groundwork is already laid, additional requests from these tools will be quicker to implement in the future. + +* Telemetry and health checks can be optionally disabled. + +* `Log Aggregation <../Logging/ControlPlaneLogs.html>`_ via xCAT syslog: + + – Aggregated on control plane, grouping default is “severity” with others available. + + – Uses Grafani-Loki for viewing. + +* Automatic (empty) Docker Registry Creation. diff --git a/docs/source/Overview/releasenotes.rst b/docs/source/Overview/releasenotes.rst index 02cd98661..aff109414 100644 --- a/docs/source/Overview/releasenotes.rst +++ b/docs/source/Overview/releasenotes.rst @@ -4,13 +4,70 @@ Releases 1.5 ---- -* Expanded `telemetry collection <../Roles/Telemetry/index.html>`_ support to Regular, health check and GPU metrics. -* `Rsyslog <../Logging/ControlPlaneLogs.html>`_ : Added ability to aggregate logs via xCAT's syslog. +* `Extensive Telemetry and Monitoring <../Roles/Telemetry/index.html>`_ has been added to the Omnia stack, intended for consumption by customers that are using Dell systems and Omnia to provide SaaS/IaaS solutions. These include, but are not limited to: -* Integration of apptainer for `containerized HPC benchmark execution <../InstallationGuides/Benchmarks/index.html>`_. + – CPU Utilization and status + + – GPU utilization + + – Node Count + + – Network Packet I/O + + – HDD capacity and free space + + – Memory capacity and utilization + + – Queued and Running Job Count + + – User Count + + – Cluster HW Health Checks (PCIE, NVLINK, BMC, Temps) + + – Cluster SW Health Checks (dmesg, BeeGFS, k8s nodes/pods, mySQL on control plane) + +* Metrics are extracted using a combination of the following: PSUtil, Smartctl, beegfs-ctl, nvidia-smi, rocm-smi. Since groundwork is already laid, additional requests from these tools will be quicker to implement in the future. + +* Telemetry and health checks can be optionally disabled. + +* `Log Aggregation <../Logging/ControlPlaneLogs.html>`_ via xCAT syslog: + + – Aggregated on control plane, grouping default is “severity” with others available. + + – Uses Grafani-Loki for viewing. + +* Automatic (empty) Docker Registry Creation. + + +1.4.3.1 +-------- + + +– Hardware Support: Intel E810 NIC, ConnectX-5/6 NICs. + + * Omnia github now hosts a “genesis” image with this functionality baked in for initial bootup. + +– Host aliasing for Scheduler and IPA authentication. + +– Login and Manager Node access from both public and private NIC. + +– Validation check enhancements: + + * Rearranged to occur as early as possible. + + * Isolate checks when running smaller playbooks. + +– Documentation Updates: + + * `How to check node installation status and dump the inventory of hostname/mac/IP/port <../InstallationGuides/InstallingProvisionTool/ViewingDB.html>`_. + + * `How to Add Nodes to Existing Cluster <../InstallationGuides/addinganewnode.html>`_. + + * `Detailed support matrix `_ of GPU, NIC, and storage controllers. + + * `Benchmark Install Guide <../InstallationGuides/Benchmarks/index.html>`_: OneAPI for Intel, MPI AOCC HPL for AMD. -* Integration of `grafana and loki installation <../Roles/Telemetry/index.html>`_ within ``telemetry.yml``. 1.4.3 ------ From 75aaa4cb92df29ba78f70d9f319e1d08968bd1cd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 18 Oct 2023 11:19:18 +0530 Subject: [PATCH 003/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Overview/newfeatures.rst | 23 +++++++++++++++++------ docs/source/Overview/releasenotes.rst | 23 +++++++---------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/docs/source/Overview/newfeatures.rst b/docs/source/Overview/newfeatures.rst index 64920deda..b7cb2fb01 100644 --- a/docs/source/Overview/newfeatures.rst +++ b/docs/source/Overview/newfeatures.rst @@ -1,8 +1,3 @@ -New Features -=========== - - - * `Extensive Telemetry and Monitoring <../Roles/Telemetry/index.html>`_ has been added to the Omnia stack, intended for consumption by customers that are using Dell systems and Omnia to provide SaaS/IaaS solutions. These include, but are not limited to: – CPU Utilization and status @@ -35,4 +30,20 @@ New Features – Uses Grafani-Loki for viewing. -* Automatic (empty) Docker Registry Creation. +* Hardware Support: Intel E810 NIC, ConnectX-5/6 NICs. + + * Omnia github now hosts a “genesis” image with this functionality baked in for initial bootup. + +* Host aliasing for Scheduler and IPA authentication. + +* Login and Manager Node access from both public and private NIC. + +* Validation check enhancements: + + * Rearranged to occur as early as possible. + + * Isolate checks when running smaller playbooks. + +* Docker Registry Creation. + +* Integration of apptainer for `containerized HPC benchmark execution <../InstallationGuides/Benchmarks/index.html>`_. diff --git a/docs/source/Overview/releasenotes.rst b/docs/source/Overview/releasenotes.rst index aff109414..49fae5aa8 100644 --- a/docs/source/Overview/releasenotes.rst +++ b/docs/source/Overview/releasenotes.rst @@ -37,36 +37,27 @@ Releases – Uses Grafani-Loki for viewing. -* Automatic (empty) Docker Registry Creation. +* Docker Registry Creation. +* Integration of apptainer for `containerized HPC benchmark execution <../InstallationGuides/Benchmarks/hpcsoftwarestack.html>`_. -1.4.3.1 --------- - - -– Hardware Support: Intel E810 NIC, ConnectX-5/6 NICs. +* Hardware Support: Intel E810 NIC, ConnectX-5/6 NICs. * Omnia github now hosts a “genesis” image with this functionality baked in for initial bootup. -– Host aliasing for Scheduler and IPA authentication. +* Host aliasing for Scheduler and IPA authentication. -– Login and Manager Node access from both public and private NIC. +* Login and Manager Node access from both public and private NIC. -– Validation check enhancements: +* Validation check enhancements: * Rearranged to occur as early as possible. * Isolate checks when running smaller playbooks. -– Documentation Updates: - - * `How to check node installation status and dump the inventory of hostname/mac/IP/port <../InstallationGuides/InstallingProvisionTool/ViewingDB.html>`_. - - * `How to Add Nodes to Existing Cluster <../InstallationGuides/addinganewnode.html>`_. +* Added a `Benchmark Install Guide <../InstallationGuides/Benchmarks/index.html>`_: OneAPI for Intel, MPI AOCC HPL for AMD. - * `Detailed support matrix `_ of GPU, NIC, and storage controllers. - * `Benchmark Install Guide <../InstallationGuides/Benchmarks/index.html>`_: OneAPI for Intel, MPI AOCC HPL for AMD. 1.4.3 From 777a4ccb852d4dff16d127ef5f80aea7f3fb89c0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 18 Oct 2023 11:27:24 +0530 Subject: [PATCH 004/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Overview/newfeatures.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/Overview/newfeatures.rst b/docs/source/Overview/newfeatures.rst index b7cb2fb01..7dc2cfb87 100644 --- a/docs/source/Overview/newfeatures.rst +++ b/docs/source/Overview/newfeatures.rst @@ -1,3 +1,6 @@ +New Features +=========== + * `Extensive Telemetry and Monitoring <../Roles/Telemetry/index.html>`_ has been added to the Omnia stack, intended for consumption by customers that are using Dell systems and Omnia to provide SaaS/IaaS solutions. These include, but are not limited to: – CPU Utilization and status From babfb4681de9637e005bc2e56b494d6b258c8f7a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 18 Oct 2023 11:45:14 +0530 Subject: [PATCH 005/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Overview/newfeatures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Overview/newfeatures.rst b/docs/source/Overview/newfeatures.rst index 7dc2cfb87..be8a486db 100644 --- a/docs/source/Overview/newfeatures.rst +++ b/docs/source/Overview/newfeatures.rst @@ -23,7 +23,7 @@ New Features – Cluster SW Health Checks (dmesg, BeeGFS, k8s nodes/pods, mySQL on control plane) -* Metrics are extracted using a combination of the following: PSUtil, Smartctl, beegfs-ctl, nvidia-smi, rocm-smi. Since groundwork is already laid, additional requests from these tools will be quicker to implement in the future. +* Metrics are extracted using a combination of the following: PSUtil, Smartctl, beegfs-ctl, nvidia-smi, rocm-smi. * Telemetry and health checks can be optionally disabled. From d35d0c1854ccdd54af28c183f7951ffedc52b3ee Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 19 Oct 2023 16:43:30 +0530 Subject: [PATCH 006/309] Updating documentation Signed-off-by: cgoveas --- docs/source/images/Omnia_Architecture.png | Bin 127722 -> 722777 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/source/images/Omnia_Architecture.png b/docs/source/images/Omnia_Architecture.png index 98c10dd110e63bf8cd26aa9a28b8a17d43e2dabd..7fb0f5a4c73465e284f411e7debd53f83d4a602c 100644 GIT binary patch literal 722777 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 z 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%0A4QTg06=!I$+Z7iSN?`o#p;om$3eBYn=4 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 z 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 z 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%0Dr%}UiW@nkSKgiw1|d<{)Nk^y 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 VX?Un)NIlZQ?~Z(1;&}4P{{tQkToM2P literal 127722 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

    9epy%F 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%0DVP7q*{3EYP3;Phl>N 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%0Dj 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 From f80e9678ba08e9bf4c7c84a987c36c137bb7b34a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 20 Oct 2023 16:27:30 +0530 Subject: [PATCH 007/309] Updating documentation Signed-off-by: cgoveas --- .../InstallingProvisionTool/provisionprereqs.rst | 3 +++ docs/source/InstallationGuides/RunningInit/index.rst | 2 ++ 2 files changed, 5 insertions(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 1c0dc5227..c8f181ec0 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -2,6 +2,9 @@ Before you run the provision tool --------------------------------- * (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.12.10 `_ and `Python 3.8 `_ are installed on the system. SELinux should also be disabled. + +* If the control plane is running on the minimal edition of the OS, ensure that ``chrony`` and ``podman`` are installed before running ``provision.yml``. + * Set the IP address of the control plane with a /16 subnet mask. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. figure:: ../../images/ControlPlaneNic.png diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index ff968e012..dd6f01650 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -9,6 +9,8 @@ Running prereq.sh .. note:: * If SELinux is not disabled, it will be disabled by the script and the user will be prompted to reboot the control plane. + * If the control plane is running on the minimal edition of the OS, ensure that ``chrony`` and ``podman`` are installed before running ``provision.yml``. + From 1bca3238a2451af302c082b622093cc27e6b9fbc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 6 Nov 2023 09:53:25 +0530 Subject: [PATCH 008/309] Updating documentation Signed-off-by: cgoveas --- scheduler/readme.rst | 182 ++----------------------------------------- 1 file changed, 7 insertions(+), 175 deletions(-) diff --git a/scheduler/readme.rst b/scheduler/readme.rst index 545aac3f9..2c2ac0887 100644 --- a/scheduler/readme.rst +++ b/scheduler/readme.rst @@ -1,186 +1,18 @@ Scheduler ========== -Before you build clusters --------------------------- - -* Verify that all inventory files are updated. - -* If the target cluster requires more than 10 kubernetes nodes, use a docker enterprise account to avoid docker pull limits. - -* Verify that all nodes are assigned a group. Use the inventory as a reference. - - * The manager group should have exactly 1 manager node. - - * The compute group should have at least 1 node. - - * The login_node group is optional. If present, it should have exactly 1 node. - - * Users should also ensure that all repos are available on the target nodes running RHEL. - -.. note:: The inventory file accepts both IPs and FQDNs as long as they can be resolved by DNS. - - -* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``scheduler.yml`` on RHEL target nodes. - -* For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - **Features enabled by omnia.yml** -* Slurm: Once all the required parameters in ``omnia_config.yml`` are filled in, ``omnia.yml`` can be used to set up slurm. - -* Login Node (Additionally secure login node) - -* Kubernetes: Once all the required parameters in ``omnia_config.yml`` are filled in, ``omnia.yml`` can be used to set up kubernetes. - -* BeeGFS bolt on installation - -* NFS bolt on support - - -Input parameters for the cluster -------------------------------------- - -These parameters are located in ``input/omnia_config.yml`` - -.. note:: - - The ``input/omnia_config.yml`` file is encrypted on the first run of the provision tool: - To view the encrypted parameters: :: - - ansible-vault view omnia_config.yml --vault-password-file .omnia_vault_key - - To edit the encrypted parameters: :: - - ansible-vault edit omnia_config.yml --vault-password-file .omnia_vault_key - - -Building clusters ------------------- - -1. In the ``input/omnia_config.yml`` file, provide the `required details `_. - -.. note:: Without the login node, Slurm jobs can be scheduled only through the manager node. - -2. Create an inventory file in the *omnia* folder. Add login node IP address under the manager node IP address under the *[manager]* group, compute node IP addresses under the *[compute]* group, and Login node IP under the *[login_node]* group,. Check out the `sample inventory for more information <../samplefiles.html>`_. - -.. note:: - * RedHat nodes that are not configured by Omnia need to have a valid subscription. To set up a subscription, `click here `_. - * Omnia creates a log file which is available at: ``/var/log/omnia.log``. - * If only Slurm is being installed on the cluster, docker credentials are not required. - -3. To run ``omnia.yml``: :: - - ansible-playbook omnia.yml -i inventory - - -.. note:: - * To visualize the cluster (Slurm/Kubernetes) metrics on Grafana (On the control plane) during the run of ``omnia.yml``, add the parameters ``grafana_username`` and ``grafana_password`` (That is ``ansible-playbook omnia.yml -i inventory -e grafana_username="" -e grafana_password=""``). Alternatively, Grafana is not installed by ``omnia.yml`` if it's not available on the Control Plane. - * Having the same node in the manager and login_node groups in the inventory is not recommended by Omnia. - -**Using Skip Tags** - -Using skip tags, the scheduler running on the cluster can be set to Slurm or Kubernetes while running the ``omnia.yml`` playbook. This choice can be made depending on the expected HPC/AI workloads. - - * Kubernetes: ``ansible-playbook omnia.yml -i inventory --skip-tags "kubernetes"`` (To set Slurm as the scheduler) - - * Slurm: ``ansible-playbook omnia.yml -i inventory --skip-tags "slurm"`` (To set Kubernetes as the scheduler) - -.. note:: - * If you want to view or edit the ``omnia_config.yml`` file, run the following command: - - - ``ansible-vault view omnia_config.yml --vault-password-file .omnia_vault_key`` -- To view the file. - - - ``ansible-vault edit omnia_config.yml --vault-password-file .omnia_vault_key`` -- To edit the file. - - * It is suggested that you use the ansible-vault view or edit commands and that you do not use the ansible-vault decrypt or encrypt commands. If you have used the ansible-vault decrypt or encrypt commands, provide 644 permission to ``omnia_config.yml``. - -**Kubernetes Roles** - -As part of setting up Kubernetes roles, ``omnia.yml`` handles the following tasks on the manager and compute nodes: - - * Docker is installed. - * Kubernetes is installed. - * Helm package manager is installed. - * All required services are started (Such as kubelet). - * Different operators are configured via Helm. - * Prometheus is installed. - -**Slurm Roles** - -As part of setting up Slurm roles, ``omnia.yml`` handles the following tasks on the manager and compute nodes: - - * Slurm is installed. - * All required services are started (Such as slurmd, slurmctld, slurmdbd). - * Prometheus is installed to visualize slurm metrics. - * Lua and Lmod are installed as slurm modules. - * Slurm restd is set up. - -**Login node** - -If a login node is available and mentioned in the inventory file, the following tasks are executed: - - * Slurmd is installed. - * All required configurations are made to ``slurm.conf`` file to enable a slurm login node. - -.. include:: ../../Appendices/hostnamereqs.rst - -.. note:: - - * To enable the login node, ensure that ``login_node_required`` in ``input/omnia_config.yml`` is set to true. - -**Slurm job based user access** - -To ensure security while running jobs on the cluster, users can be assigned permissions to access compute nodes only while their jobs are running. To enable the feature: :: - - cd scheduler - ansible-playbook job_based_user_access.yml -i inventory - - -.. note:: - - * The inventory queried in the above command is to be created by the user prior to running ``omnia.yml`` as ``scheduler.yml`` is invoked by ``omnia.yml`` - - * Only users added to the 'slurm' group can execute slurm jobs. To add users to the group, use the command: ``usermod -a -G slurm ``. - - - -**Running Slurm MPI jobs on clusters** - -To enhance the productivity of the cluster, Slurm allows users to run jobs in a parallel-computing architecture. This is used to efficiently utilize all available computing resources. - -.. note:: - - * Omnia does not install MPI packages by default. Users hoping to leverage the Slurm-based MPI execution feature are required to install the relevant packages from a source of their choosing. - - * Running jobs as individual users (and not as root) requires that passwordSSH be enabled between compute nodes for the user. - -**For Intel** - - -To run an MPI job on an intel processor, set the following environmental variables on the head nodes or within the job script: - - - ``I_MPI_PMI_LIBRARY`` = ``/usr/lib64/pmix/`` - - ``FI_PROVIDER`` = ``sockets`` (When InfiniBand network is not available, this variable needs to be set) - - ``LD_LIBRARY_PATH`` (Use this variable to point to the location of the Intel/Python library folder. For example: ``$LD_LIBRARY_PATH:/mnt/jobs/intelpython/python3.9/envs/2022.2.1/lib/``) - -**For AMD** - -To run an MPI job on an AMD processor, set the following environmental variables on the head nodes or within the job script: - - - ``PATH`` (Use this variable to point to the location of the OpenMPI binary folder. For example: ``PATH=$PATH:/appshare/openmpi/bin``) - - ``LD_LIBRARY_PATH`` (Use this variable to point to the location of the OpenMPI library folder. For example: ``$LD_LIBRARY_PATH:/appshare/openmpi/lib``) - - ``OMPI_ALLOW_RUN_AS_ROOT`` = ``1`` (To run jobs as a root user, set this variable to ``1``) - - ``OMPI_ALLOW_RUN_AS_ROOT_CONFIRM`` = ``1`` (To run jobs as a root user, set this variable to ``1``) - - - - - - + * Centralized authentication: Once all the required parameters in `security_config.yml `_ are filled in, ``omnia.yml`` can be used to set up FreeIPA/LDAP. + * Slurm: Once all the required parameters in `omnia_config.yml `_ are filled in, ``omnia.yml`` can be used to set up slurm. + * Login Node (Additionally secure login node) + * Kubernetes: Once all the required parameters in `omnia_config.yml `_ are filled in, ``omnia.yml`` can be used to set up kubernetes. + * BeeGFS bolt on installation: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up NFS. + * NFS bolt on support: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up BeeGFS. + * Telemetry: Once all the required parameters in `telemetry_config.yml `_ are filled in, ``omnia.yml`` sets up `Omnia telemetry and/or iDRAC telemetry `_. It also installs `Grafana `_ and `Loki `_ as Kubernetes pods. From 1915b025352689e3f7af6122475c21545a8da31a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 6 Nov 2023 10:09:26 +0530 Subject: [PATCH 009/309] Updating documentation Signed-off-by: cgoveas --- logging/README.rst | 6 ++ network/README.rst | 41 +--------- provision/README.rst | 17 ++++ security/readme.rst | 165 +------------------------------------ storage/README.rst | 188 +------------------------------------------ telemetry/readme.rst | 107 +----------------------- 6 files changed, 30 insertions(+), 494 deletions(-) create mode 100644 logging/README.rst diff --git a/logging/README.rst b/logging/README.rst new file mode 100644 index 000000000..843452516 --- /dev/null +++ b/logging/README.rst @@ -0,0 +1,6 @@ +Log management +--------------- + +Omnia installs a suite of log management solutions on the cluster. + +For more information, `click here. `_ \ No newline at end of file diff --git a/network/README.rst b/network/README.rst index bbd0b170a..84c7f0976 100644 --- a/network/README.rst +++ b/network/README.rst @@ -3,43 +3,4 @@ Network In your HPC cluster, connect the Mellanox InfiniBand switches using the Fat-Tree topology. In the fat-tree topology, switches in layer 1 are connected through the switches in the upper layer, i.e., layer 2. And, all the compute nodes in the cluster, such as PowerEdge servers and PowerVault storage devices, are connected to switches in layer 1. With this topology in place, we ensure that a 1x1 communication path is established between the compute nodes. For more information on the fat-tree topology, see `Designing an HPC cluster with Mellanox infiniband-solutions `_. -.. note:: - - * From Omnia 1.4, the Subnet Manager runs on the target Infiniband switches and not the control plane. - - * When ``ib_nic_subnet`` is provided in ``input/provision_config.yml``, the infiniband NIC on target nodes are assigned IPv4 addresses within the subnet without user intervention during the execution of ``provision.yml``. - - -Some of the network features Omnia offers are: - -1. Mellanox OFED - -2. Infiniband switch configuration - -To install OFED drivers, enter all required parameters in ``input/network_config.yml``: - - -+------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Name | Description | -+==============================+=========================================================================================================================================================================================+ -| mlnx_ofed_offline_path | Absolute path to local copy of .tgz file containing mlnx_ofed package. The package can be downloaded from https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/. | -| [optional] | | -| ``string`` | | -+------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mlnx_ofed_version | Indicates the version of mlnx_ofed to be downloaded. If ``mlnx_ofed_offline_path`` is not given, declaring this variable is mandatory. | -| [optional] | | -| ``string`` | **Default value**: 5.7-1.0.2.0 | -+------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mlnx_ofed_add_kernel_support | Indicates whether the kernel needs to be upgraded to be compatible with mlnx_ofed. | -| [required] | | -| ``boolean`` | **Choices**: | -| | | -| | * ``false`` <- Default | -| | * ``true`` | -+------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -To run the script: :: - - cd network - ansible-playbook network.yml - +For more information, `click here. `_ \ No newline at end of file diff --git a/provision/README.rst b/provision/README.rst index a52442f69..dd44d6f27 100644 --- a/provision/README.rst +++ b/provision/README.rst @@ -1,4 +1,21 @@ Provision ---------- +Installing the provision tool +============================= + +This playbook achieves the following tasks: + + * Discovers potential cluster nodes + + * Installs Rocky or RHEL on the nodes + + * Assigns admin/infiniband IPs with optional DHCP routing + + * Creates access to offline repositories + + * Configures a docker registry to pull images from the internet and store them locally + + * Optionally installs OFED and CUDA + `Click here `_ for more information on ``provision.yml``. \ No newline at end of file diff --git a/security/readme.rst b/security/readme.rst index 0cf9851d0..4cec88910 100644 --- a/security/readme.rst +++ b/security/readme.rst @@ -1,163 +1,6 @@ -Security -========= +Centralized authentication on the cluster +========================================== -The security role allows users to set up FreeIPA and LDAP to help authenticate into HPC clusters. +The security feature allows users to set up FreeIPA and LDAP to help authenticate into HPC clusters. -.. note:: - * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``security.yml`` on RHEL target nodes. - * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - - -Configuring FreeIPA/LDAP security -________________________________ - -Enter the following parameters in ``input/security_config.yml``. - -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+============================+=================================================================================================================================================================================================================================================================+ -| freeipa_required | Boolean indicating whether FreeIPA is required or not. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``true`` <- Default | -| | * ``false`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| realm_name | Sets the intended realm name. | -| ``string`` | | -| Optional | **Default values**: ``OMNIA.TEST`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| directory_manager_password | Password authenticating admin level access to the Directory for system management tasks. It will be added to the instance of directory server created for IPA.Required Length: 8 characters. The password must not contain -,, ‘,” | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| kerberos_admin_password | “admin” user password for the IPA server on RockyOS. | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_required | Boolean indicating whether ldap client is required or not. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | * ``true`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| domain_name | Sets the intended domain name. | -| ``string`` | | -| Optional | **Default values**: ``omnia.test`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_server_ip | LDAP server IP. Required if ``ldap_required`` is true. There should be an explicit LDAP server running on this IP. | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_connection_type | For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. | -| ``string`` | | -| Optional | **Default values**: ``TLS`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_ca_cert_path | This variable accepts Server Certificate Path. Make sure certificate is present in the path provided. The certificate should have .pem or .crt extension. This variable is mandatory if connection type is TLS. | -| ``string`` | | -| Optional | **Default values**: ``/etc/openldap/certs/omnialdap.pem`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| user_home_dir | This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. | -| ``string`` | | -| Optional | **Default values**: ``/home`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_bind_username | If LDAP server is configured with bind dn then bind dn user to be provided. If this value is not provided (when bind is configured in server) then ldap authentication fails. Omnia does not validate this input. Ensure that it is valid and proper. | -| ``string`` | | -| Optional | **Default values**: ``admin`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_bind_password | If LDAP server is configured with bind dn then bind dn password to be provided. If this value is not provided (when bind is configured in server) then ldap authentication fails. Omnia does not validate this input. Ensure that it is valid and proper. | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| enable_secure_login_node | Boolean value deciding whether security features are enabled on the Login Node. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | * ``true`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -.. note:: When ``ldap_required`` is true, ``freeipa_required`` has to be false. Conversely, when `freeipa_required`` is true, ``ldap_required`` has to be false. - - - -Configuring login node security -________________________________ - -Enter the following parameters in ``input/login_node_security_config.yml``. - -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Variable | Details | -+==========================+================================================================================================================================================================================+ -| max_failures | The number of login failures that can take place before the account is locked out. | -| ``integer`` | | -| Optional | **Default values**: ``3`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| failure_reset_interval | Period (in seconds) after which the number of failed login attempts is reset. Min value: 30; Max value: 60. | -| ``integer`` | | -| Optional | **Default values**: ``60`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| lockout_duration | Period (in seconds) for which users are locked out. Min value: 5; Max value: 10. | -| ``integer`` | | -| Optional | **Default values**: ``10`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| session_timeout | User sessions that have been idle for a specific period can be ended automatically. Min value: 90; Max value: 180. | -| ``integer`` | | -| Optional | **Default values**: ``180`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| alert_email_address | Email address used for sending alerts in case of authentication failure. When blank, authentication failure alerts are disabled. Currently, only one email ID is accepted. | -| ``string`` | | -| Optional | | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| user | Access control list of users. Accepted formats are username@ip (root@1.2.3.4) or username (root). Multiple users can be separated using whitespaces. | -| ``string`` | | -| Optional | | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| allow_deny | This variable decides whether users are to be allowed or denied access. Ensure that AllowUsers or DenyUsers entries on sshd configuration file are not commented. | -| ``string`` | | -| Optional | Choices: | -| | | -| | * ``allow`` <- Default | -| | * ``deny`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| restrict_program_support | This variable is used to disable services. Root access is mandatory. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | * ``true`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| restrict_softwares | List of services to be disabled (Comma-separated). Example: 'telnet,lpd,bluetooth' | -| ``string`` | | -| Optional | Choices: | -| | | -| | * ``telnet`` | -| | * ``lpd`` | -| | * ``bluetooth`` | -| | * ``rlogin`` | -| | * ``rexec`` | -+--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -Installing LDAP Client -________________________ - -Manager and compute nodes will have LDAP client installed and configured if ``ldap_required`` is set to true. The login node does not have LDAP client installed. - -.. caution:: No users/groups will be created by Omnia. - - -**Running the security role** - -Run: :: - - cd security - ansible-playbook security.yml -i inventory - -The inventory should contain compute, manager, login_node as per the inventory file in `samplefiles `_. - - * To enable security features on the login node, ensure that ``enable_secure_login_node`` in ``input/security_config.yml`` is set to true. - * To customize the security features on the login node, fill out the parameters in ``input/login_node_security_config.yml``. - -.. caution:: No users/groups will be created by Omnia. +For more information, `click here. `_ \ No newline at end of file diff --git a/storage/README.rst b/storage/README.rst index 314797dbe..3f041d096 100644 --- a/storage/README.rst +++ b/storage/README.rst @@ -3,190 +3,4 @@ Storage The storage role allows users to configure PowerVault Storage devices, BeeGFS and NFS services on the cluster. -First, enter all required parameters in ``input/storage_config.yml`` - -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Name | Details | -+=================================+======================================================================================================================================================================================================================================================+ -| beegfs_support | This variable is used to install beegfs-client on compute and manager nodes | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_rdma_support | This variable is used if user has RDMA-capable network hardware (e.g., InfiniBand) | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_ofed_kernel_modules_path | The path where separate OFED kernel modules are installed. | -| ``string`` | | -| Optional | **Default value**: ``"/usr/src/ofa_kernel/default/include"`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mgmt_server | BeeGFS management server IP. Note: The provided IP should have an explicit BeeGFS management server running . | -| ``string`` | | -| Required | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mounts | Beegfs-client file system mount location. If ``storage_yml`` is being used to change the BeeGFS mounts location, set beegfs_unmount_client to true | -| ``string`` | **Default value**: "/mnt/beegfs" | -| Optional | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_unmount_client | Changing this value to true will unmount running instance of BeeGFS client and should only be used when decommisioning BeeGFS, changing the mount location or changing the BeeGFS version. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_client_version | Beegfs client version needed on compute and manager nodes. | -| ``string`` | | -| Optional | **Default value**: 7.2.6 | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_version_change | Use this variable to change the BeeGFS version on the target nodes. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| nfs_client_params | If NFS client services are to be deployed, enter the configuration required here in JSON format. The server_ip provided should have an explicit NFS server running. If left blank, no NFS configuration takes place. Possible values include: | -| ``JSON list`` | 1. Single NFS file system: A single filesystem from a single NFS server is mounted. | -| Optional | | -| | Sample value: ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/share”, client_share_path: “/mnt/client”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | 2. Multiple Mount NFS file system: Multiple filesystems from a single NFS server are mounted. | -| | Sample values: | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/server1”, client_share_path: “/mnt/client1”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/server2”, client_share_path: “/mnt/client2”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | 3. Multiple NFS file systems: Multiple filesystems are mounted from multiple servers. | -| | Sample Values: ``- { server_ip: zz.zz.zz.zz, server_share_path: “/mnt/share1”, client_share_path: “/mnt/client1”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/share2”, client_share_path: “/mnt/client2”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | ``- { server_ip: yy.yy.yy.yy, server_share_path: “/mnt/share3”, client_share_path: “/mnt/client3”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | | -| | | -| | **Default value**: ``{ server_ip: , server_share_path: , client_share_path: , client_mount_options: }`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_secret_storage_filepath | * The filepath (including the filename) where the ``connauthfile`` is placed. | -| ``string`` | * Required for Beegfs version >= 7.2.7 | -| Required | | -| | | -| | **Default values**: ``/home/connauthfile`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -.. note:: If ``storage.yml`` is run with the ``input/storage_config.yml`` filled out, BeeGFS and NFS client will be set up. - -**Installing BeeGFS Client** - -* If the user intends to use BeeGFS, ensure that a BeeGFS cluster has been set up with beegfs-mgmtd, beegfs-meta, beegfs-storage services running. - - Ensure that the following ports are open for TCP and UDP connectivity: - - +------+-----------------------------------+ - | Port | Service | - +======+===================================+ - | 8008 | Management service (beegfs-mgmtd) | - +------+-----------------------------------+ - | 8003 | Storage service (beegfs-storage) | - +------+-----------------------------------+ - | 8004 | Client service (beegfs-client) | - +------+-----------------------------------+ - | 8005 | Metadata service (beegfs-meta) | - +------+-----------------------------------+ - | 8006 | Helper service (beegfs-helperd) | - +------+-----------------------------------+ - - - -To open the ports required, use the following steps: - - 1. ``firewall-cmd --permanent --zone=public --add-port=/tcp`` - - 2. ``firewall-cmd --permanent --zone=public --add-port=/udp`` - - 3. ``firewall-cmd --reload`` - - 4. ``systemctl status firewalld`` - - - -* Ensure that the nodes in the inventory have been assigned **only** these roles: manager and compute. - - .. note:: - - * When working with RHEL, ensure that the BeeGFS configuration is supported using the `link here <../../Overview/SupportMatrix/OperatingSystems/RedHat.html>`_. - - * If the BeeGFS server (MGMTD, Meta, or storage) is running BeeGFS version 7.3.1 or higher, the security feature on the server should be disabled. Change the value of ``connDisableAuthentication`` to ``true`` in /etc/beegfs/beegfs-mgmtd.conf, /etc/beegfs/beegfs-meta.conf and /etc/beegfs/beegfs-storage.conf. Restart the services to complete the task: :: - - systemctl restart beegfs-mgmtd - systemctl restart beegfs-meta - systemctl restart beegfs-storage - systemctl status beegfs-mgmtd - systemctl status beegfs-meta - systemctl status beegfs-storage - - -**NFS bolt-on** - -* Ensure that an external NFS server is running. NFS clients are mounted using the external NFS server's IP. - -* Fill out the ``nfs_client_params`` variable in the ``storage_config.yml`` file in JSON format using the samples provided above. - -* This role runs on manager, compute and login nodes. - -* Make sure that ``/etc/exports`` on the NFS server is populated with the same paths listed as ``server_share_path`` in the ``nfs_client_params`` in ``omnia_config.yml``. - -* Post configuration, enable the following services (using this command: ``firewall-cmd --permanent --add-service=``) and then reload the firewall (using this command: ``firewall-cmd --reload``). - - - nfs - - - rpc-bind - - - mountd - -* Omnia supports all NFS mount options. Without user input, the default mount options are nosuid,rw,sync,hard,intr. For a list of mount options, `click here `_. - -* The fields listed in ``nfs_client_params`` are: - - - server_ip: IP of NFS server - - - server_share_path: Folder on which NFS server mounted - - - client_share_path: Target directory for the NFS mount on the client. If left empty, respective ``server_share_path value`` will be taken for ``client_share_path``. - - - client_mount_options: The mount options when mounting the NFS export on the client. Default value: nosuid,rw,sync,hard,intr. - - - -* There are 3 ways to configure the feature: - - 1. **Single NFS node** : A single NFS filesystem is mounted from a single NFS server. The value of ``nfs_client_params`` would be:: - - - { server_ip: xx.xx.xx.xx, server_share_path: "/mnt/share", client_share_path: "/mnt/client", client_mount_options: "nosuid,rw,sync,hard,intr" } - - 2. **Multiple Mount NFS Filesystem**: Multiple filesystems are mounted from a single NFS server. The value of ``nfs_client_params`` would be:: - - - { server_ip: xx.xx.xx.xx, server_share_path: "/mnt/server1", client_share_path: "/mnt/client1", client_mount_options: "nosuid,rw,sync,hard,intr" } - - { server_ip: xx.xx.xx.xx, server_share_path: "/mnt/server2", client_share_path: "/mnt/client2", client_mount_options: "nosuid,rw,sync,hard,intr" } - - 3. **Multiple NFS Filesystems**: Multiple filesystems are mounted from multiple NFS servers. The value of ``nfs_client_params`` would be:: - - - { server_ip: xx.xx.xx.xx, server_share_path: "/mnt/server1", client_share_path: "/mnt/client1", client_mount_options: "nosuid,rw,sync,hard,intr" } - - { server_ip: yy.yy.yy.yy, server_share_path: "/mnt/server2", client_share_path: "/mnt/client2", client_mount_options: "nosuid,rw,sync,hard,intr" } - - { server_ip: zz.zz.zz.zz, server_share_path: "/mnt/server3", client_share_path: "/mnt/client3", client_mount_options: "nosuid,rw,sync,hard,intr" } - - - -**To run the playbook:** :: - - cd omnia/storage - ansible-playbook storage.yml -i inventory - -(Where inventory refers to the `inventory file <../../samplefiles.html>`_ listing manager, login_node and compute nodes.) - - +For more information on this playbook, `click here. `_ \ No newline at end of file diff --git a/telemetry/readme.rst b/telemetry/readme.rst index b6ad063c5..4aabeb992 100644 --- a/telemetry/readme.rst +++ b/telemetry/readme.rst @@ -3,109 +3,4 @@ Telemetry The telemetry role allows users to set up iDRAC telemetry support and visualizations. -To initiate telemetry support, fill out the following parameters in ``omnia/input/telemetry_config.yml``: - -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Name | Description | -+=========================+=============================================================================================================================================================+ -| idrac_telemetry_support | Enables iDRAC telemetry support and visualizations. | -| ``boolean`` | | -| Required | **Values** | -| | * ``true`` <- Default | -| | * ``false`` | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| slurm_telemetry_support | Enables slurm telemetry support and visualizations. | -| ``boolean`` | | -| Required | **Values** | -| | * ``true`` <- Default | -| | * ``false`` | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| timescaledb_name | Postgres DB name with timescale extension is used for storing iDRAC and slurm telemetry metrics. | -| ``string`` | | -| Optional | **Default values**: telemetry_metrics | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mysqldb_name | MySQL DB name used to store IPs and credentials of iDRACs having datacenter license | -| ``string`` | | -| Optional | **Default values**: idrac_telemetrysource_services_db | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| timezone | This is the timezone that will be set during provisioning of OS. Accepted values are listed in ``telemetry/common/files/timezone.txt``. | -| ``string`` | | -| Optional | **Default values**: GMT | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| timescaledb_user | Username used for to authenticate to timescale db. The username must not contain -,\, ',". The Length of the username should be at least 2 characters. | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| timescaledb_password | Password used for to authenticate to timescale db. The username must not contain -,\, ',". The Length of the username should be at least 2 characters. | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mysqldb_user | Username used for to authenticate to mysql db. The username must not contain -,\, ',". The Length of the username should be at least 2 characters. | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mysqldb_password | Password used for to authenticate to mysql db. The username must not contain -,\, ',". The Length of the username should be at least 2 characters. | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mysqldb_root_password | Root password used for to authenticate to mysql db. The username must not contain -,\, ',". The Length of the username should be at least 2 characters. | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| idrac_username | The username for iDRAC. The username must not contain -,\, ',". Required only if idrac_telemetry_support is true. | -| ``string`` | | -| Optional | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| idrac_password | The password for iDRAC. The username must not contain -,\, ',". Required only if idrac_telemetry_support is true. | -| ``string`` | | -| Optional | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| grafana_username | The username for grafana UI. The length of username should be at least 5. The username must not contain -,\, ',". | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| grafana_password | The password for grafana UI. The length of username should be at least 5. The username must not contain -,\, ',". 'admin' is not an accepted value. | -| ``string`` | | -| Required | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| node_password | Password of manager node. Required only if ``slurm_telemetry_support`` is true. | -| ``string`` | | -| Optional | | -+-------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -Once ``control_plane.yml`` and ``omnia.yml`` are executed, run the following commands from ``omnia/telemetry``: :: - - ansible-playbook telemetry.yml -i inventory - -.. note:: The passed inventory should have 3 groups: idrac, manager, compute. - -After initiation, new nodes can be added to telemetry by running the following commands from ``omnia/telemetry``: :: - - ansible-playbook add_idrac_node.yml -i inventory - -.. note:: - * The passed inventory should have an idrac group. - * ``telemetry_config.yml`` is encrypted upon executing ``telemetry.yml``. To edit the file, use ``ansible-vault edit telemetry_config.yml --vault-password-file .telemetry_vault_key``. - * If ``idrac_telemetry`` is ``true`` while executing ``telemetry.yml``, **or** while running ``add_idrac_node.yml``, if the inventory passed does not contain an idrac group, idrac telemetry will run on IP’s present under ``/opt/omnia/provisioned_idrac_inventory`` of control plane. - -Viewing Performance Stats on Grafana -++++++++++++++++++++++++++++++++++++ - -Using `Texas Technical University data visualization lab `_, data polled from iDRAC and Slurm can be processed to generate live graphs. These Graphs can be accessed on the Grafana UI. - -Once ``provision.yml`` is executed and Grafana is set up, use ``telemetry.yml`` to initiate the Graphs. Data polled via Slurm and iDRAC is streamed into internal databases. This data is processed to create the 4 graphs listed below. - - -.. note:: This feature only works on Nodes using iDRACs with a datacenter license running a minimum firmware of 4.0. - -All your data in a glance - -Using the following graphs, data can be visualized to gather correlational information. - -* `ParallelCoordinates `_ -* `SankeyLayout `_ -* `SpiralLayout `_ -* `PowerMap `_ - -.. note:: The timestamps used for the time metric are based on the timezone set in ``input/provision_config.yml``. In the event of a mismatch between the timezone on the browser being used to access Grafana UI and the timezone in ``input/provision_config.yml``, the time range being used to filter information on the Grafana UI will have to be adjusted per the timezone in ``input/provision_config.yml``. - +For more information on this playbook, `click here. `_ \ No newline at end of file From d0af0837115d693b6e5b9ea10d83414ef602295d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 21 Nov 2023 07:39:33 +0530 Subject: [PATCH 010/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Overview/SupportMatrix/ConfigSupport.rst | 6 ++++-- .../Overview/SupportMatrix/Hardware/switches.rst | 12 ++++++------ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/docs/source/Overview/SupportMatrix/ConfigSupport.rst b/docs/source/Overview/SupportMatrix/ConfigSupport.rst index 1b3ed29c3..0f133dc6a 100644 --- a/docs/source/Overview/SupportMatrix/ConfigSupport.rst +++ b/docs/source/Overview/SupportMatrix/ConfigSupport.rst @@ -63,9 +63,9 @@ NICs +--------------------------------------------------+ | NIC | +==================================================+ -| Intel(R) Ethernet 10G 4P X710/I350 rNDC | +| Intel® Ethernet 10G 4P X710/I350 rNDC | +--------------------------------------------------+ -| Intel(R) Ethernet Converged Network Adapter X710 | +| Intel® Ethernet Converged Network Adapter X710 | +--------------------------------------------------+ | Mellanox ConnectX-5 Single Port 100 GbE QSFP+ | +--------------------------------------------------+ @@ -89,6 +89,8 @@ NICs +--------------------------------------------------+ | Mellanox ConnectX-5 Ex 100 GbE QSFP | +--------------------------------------------------+ +| Intel® Ethernet 100GbE Network Adapter E810 | ++--------------------------------------------------+ GPUs +++++ diff --git a/docs/source/Overview/SupportMatrix/Hardware/switches.rst b/docs/source/Overview/SupportMatrix/Hardware/switches.rst index 60caef2a7..0ac7873e7 100644 --- a/docs/source/Overview/SupportMatrix/Hardware/switches.rst +++ b/docs/source/Overview/SupportMatrix/Hardware/switches.rst @@ -8,16 +8,16 @@ Switches +------------------------------+-------------------------------------------------------------------------------------+ -+--------------------------+------------------------------------------------------------------------------------------+ -| Switch Type | Switch Model | -+==========================+==========================================================================================+ -| Dell Networking Switches | PowerSwitch S3048-ON PowerSwitch S5232F-ON PowerSwitch Z9264F-ON PowerSwitch N3248TE-ON | -+--------------------------+------------------------------------------------------------------------------------------+ ++--------------------------+------------------------------------------------------------------------------------------------------------+ +| Switch Type | Switch Model | ++==========================+============================================================================================================+ +| Dell Networking Switches | PowerSwitch S3048-ON PowerSwitch S5232F-ON PowerSwitch Z9264F-ON PowerSwitch N3248TE-ON PowerSwitch S4148 | ++--------------------------+------------------------------------------------------------------------------------------------------------+ .. note:: - * The switches that have reached EOL might not function properly. It is recommended by Omnia to use the switch models mentioned in support matrix. + * The switches that have reached EOL might not function properly. It is recommended by Omnia to use switch models mentioned in support matrix. * Omnia requires that OS10 be installed on ethernet switches. From 8deb010ebc0b3388622a2cd807ecdfd27db5a07e Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Wed, 20 Dec 2023 22:07:56 +0200 Subject: [PATCH 011/309] feat(provisioning): add new bluefield role Signed-off-by: Boris Glimcher --- .../SupportMatrix/omniainstalledsoftware.rst | 2 ++ provision/bluefield.yml | 21 +++++++++++++++++++ .../bluefield/tasks/check_prerequisites.yml | 21 +++++++++++++++++++ provision/roles/bluefield/tasks/main.yml | 20 ++++++++++++++++++ provision/roles/bluefield/vars/main.yml | 20 ++++++++++++++++++ 5 files changed, 84 insertions(+) create mode 100644 provision/bluefield.yml create mode 100644 provision/roles/bluefield/tasks/check_prerequisites.yml create mode 100644 provision/roles/bluefield/tasks/main.yml create mode 100644 provision/roles/bluefield/vars/main.yml diff --git a/docs/source/Overview/SupportMatrix/omniainstalledsoftware.rst b/docs/source/Overview/SupportMatrix/omniainstalledsoftware.rst index 037714cad..1ba159efd 100644 --- a/docs/source/Overview/SupportMatrix/omniainstalledsoftware.rst +++ b/docs/source/Overview/SupportMatrix/omniainstalledsoftware.rst @@ -140,4 +140,6 @@ Software Installed by Omnia +------------------------------------+------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | python.requests | Apache-2.0 | Makes HTTP requests simpler and more human-friendly. | +------------------------------------+------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| nvidia.dpu_ops | MIT License | NVIDIA DPU OPs collection. | ++------------------------------------+------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/provision/bluefield.yml b/provision/bluefield.yml new file mode 100644 index 000000000..3d6656c85 --- /dev/null +++ b/provision/bluefield.yml @@ -0,0 +1,21 @@ +# Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +- name: Deploy BlueField DPU + hosts: all + connection: local + gather_facts: false + roles: + - bluefield diff --git a/provision/roles/bluefield/tasks/check_prerequisites.yml b/provision/roles/bluefield/tasks/check_prerequisites.yml new file mode 100644 index 000000000..b7ecf18e2 --- /dev/null +++ b/provision/roles/bluefield/tasks/check_prerequisites.yml @@ -0,0 +1,21 @@ +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +- name: Install ansible-galaxy modules + ansible.builtin.command: ansible-galaxy collection install {{ item }} + changed_when: true + with_items: "{{ bluefield_collections }}" + run_once: true + diff --git a/provision/roles/bluefield/tasks/main.yml b/provision/roles/bluefield/tasks/main.yml new file mode 100644 index 000000000..1692c5e25 --- /dev/null +++ b/provision/roles/bluefield/tasks/main.yml @@ -0,0 +1,20 @@ +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +# tasks file for bluefield + +- name: Check prerequisites + ansible.builtin.include_tasks: check_prerequisites.yml + diff --git a/provision/roles/bluefield/vars/main.yml b/provision/roles/bluefield/vars/main.yml new file mode 100644 index 000000000..87830fc5f --- /dev/null +++ b/provision/roles/bluefield/vars/main.yml @@ -0,0 +1,20 @@ +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +# vars file for bluefield + +# Usage: check_prerequisites.yml +bluefield_collections: nvidia.dpu_ops:1.0.1 + From 8aa2d46bcbf2ee5b1c0384bd13d9dc32fa6e2b8e Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Thu, 21 Dec 2023 00:15:57 +0200 Subject: [PATCH 012/309] feat(provisioning): bluefield set boot order Signed-off-by: Boris Glimcher --- .../bluefield/tasks/configure_pxe_boot.yml | 29 +++++++++++++++++++ provision/roles/bluefield/tasks/deploy_os.yml | 21 ++++++++++++++ provision/roles/bluefield/tasks/main.yml | 2 ++ provision/roles/bluefield/vars/main.yml | 2 ++ 4 files changed, 54 insertions(+) create mode 100644 provision/roles/bluefield/tasks/configure_pxe_boot.yml create mode 100644 provision/roles/bluefield/tasks/deploy_os.yml diff --git a/provision/roles/bluefield/tasks/configure_pxe_boot.yml b/provision/roles/bluefield/tasks/configure_pxe_boot.yml new file mode 100644 index 000000000..3efc0fd9a --- /dev/null +++ b/provision/roles/bluefield/tasks/configure_pxe_boot.yml @@ -0,0 +1,29 @@ +# Copyright 2023 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +- name: Get power status + ansible.builtin.include_role: + name: nvidia.dpu_ops.bf_bmc + vars: + - bmc_action: "-C 17 chassis power status" + bmc_host: "tbd" + bmc_user: "root" + bmc_password: "tbd" + +- name: Configure boot order for PXE booting + ansible.builtin.include_role: + name: nvidia.dpu_ops.bf2_boot + vars: + - pxe_boot_dev: "{{ bluefield_pxe_boot_dev }}" diff --git a/provision/roles/bluefield/tasks/deploy_os.yml b/provision/roles/bluefield/tasks/deploy_os.yml new file mode 100644 index 000000000..4669f1f7f --- /dev/null +++ b/provision/roles/bluefield/tasks/deploy_os.yml @@ -0,0 +1,21 @@ +# Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +- name: Configure PXE booting + ansible.builtin.include_tasks: configure_pxe_boot.yml + +- name: Provision OS + ansible.builtin.debug: + msg: "tbd" diff --git a/provision/roles/bluefield/tasks/main.yml b/provision/roles/bluefield/tasks/main.yml index 1692c5e25..444929437 100644 --- a/provision/roles/bluefield/tasks/main.yml +++ b/provision/roles/bluefield/tasks/main.yml @@ -18,3 +18,5 @@ - name: Check prerequisites ansible.builtin.include_tasks: check_prerequisites.yml +- name: Deploy OS + ansible.builtin.include_tasks: deploy_os.yml diff --git a/provision/roles/bluefield/vars/main.yml b/provision/roles/bluefield/vars/main.yml index 87830fc5f..be7624681 100644 --- a/provision/roles/bluefield/vars/main.yml +++ b/provision/roles/bluefield/vars/main.yml @@ -18,3 +18,5 @@ # Usage: check_prerequisites.yml bluefield_collections: nvidia.dpu_ops:1.0.1 +# Usage: configure_pxe_boot.yml +bluefield_pxe_boot_dev: NET-OOB-IPV4 From 2bd2d74bb3b36e857635a62d33f3c4283f1182db Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Fri, 22 Dec 2023 09:57:54 +0530 Subject: [PATCH 013/309] Update .all-contributorsrc Added Boris as contributor to Omnia Signed-off-by: Sujit Jadhav --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index b1d072f5e..9a8541dc8 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -623,6 +623,15 @@ "test" ] } + { + "login": "glimchb", + "name": "Boris Glimcher", + "avatar_url": "https://avatars.githubusercontent.com/u/36732377?v=4", + "profile": "https://github.com/glimchb", + "contributions": [ + "code" + ] + } ], "contributorsPerLine": 7, "projectName": "omnia", From 71f0d352f3587ee5de112893bbc517db38850509 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Dec 2023 12:21:05 +0530 Subject: [PATCH 014/309] Updating documentation Signed-off-by: cgoveas --- README.md | 2 +- .../DiscoveryMechanisms/index.rst | 1 + .../InstallationGuides/RunningInit/index.rst | 2 +- .../SupportMatrix/OperatingSystems/Ubuntu.rst | 2 ++ .../SupportMatrix/OperatingSystems/index.rst | 1 + docs/source/Tables/bmc.csv | 14 +------------- docs/source/Tables/mapping.csv | 14 +------------- docs/source/Tables/snmpwalk.csv | 14 +------------- docs/source/Tables/switch-based.csv | 13 ------------- docs/source/conf.py | 2 +- docs/source/index.rst | 4 ++-- 11 files changed, 12 insertions(+), 57 deletions(-) create mode 100644 docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst diff --git a/README.md b/README.md index 14041065b..3564f1fa1 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ -![GitHub](https://img.shields.io/github/license/dell/omnia) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/dell/omnia?include_prereleases) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/dell/omnia/main) ![GitHub commits since tagged version](https://img.shields.io/github/commits-since/dell/omnia/v1.5/main) +![GitHub](https://img.shields.io/github/license/dell/omnia) ![GitHub release (latest by date including pre-releases)](https://img.shields.io/github/v/release/dell/omnia?include_prereleases) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/dell/omnia/main) ![GitHub commits since tagged version](https://img.shields.io/github/commits-since/dell/omnia/v1.6/main) ![All contributors](https://img.shields.io/github/all-contributors/dell/omnia) ![GitHub forks](https://img.shields.io/github/forks/dell/omnia) ![GitHub Repo stars](https://img.shields.io/github/stars/dell/omnia) ![GitHub all releases](https://img.shields.io/github/downloads/dell/omnia/total) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index a4dec0ef4..47c1d9e5c 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -87,5 +87,6 @@ Omnia can query known switches (by IP and community string) for information on t - Servers require a manual PXE boot if iDRAC IPs are not configured. - PXE NIC ranges should contain IPs that are double the iDRACs present (as NIC and iDRAC MACs may need to be mapped). - LOM architecture is not supported (including cloud enclosures: C6420, C6520, C6620). + - Ubuntu cannot be provisioned using this method For more information regarding snmpwalk, `click here `_ diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index dd6f01650..6c209bc69 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -1,7 +1,7 @@ Running prereq.sh ================= -``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.8), Ansible (2.12.10). :: +``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.12.10). :: cd omnia sh prereq.sh diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst new file mode 100644 index 000000000..d6270a116 --- /dev/null +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst @@ -0,0 +1,2 @@ +Ubuntu +====== \ No newline at end of file diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/index.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/index.rst index 06734a206..e569779d0 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/index.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/index.rst @@ -4,3 +4,4 @@ Operating Systems .. toctree:: RedHat Rocky + Ubuntu \ No newline at end of file diff --git a/docs/source/Tables/bmc.csv b/docs/source/Tables/bmc.csv index 41b85a1a2..b322bdb86 100644 --- a/docs/source/Tables/bmc.csv +++ b/docs/source/Tables/bmc.csv @@ -31,6 +31,7 @@ Choices: * ``rhel`` <-default * ``rocky`` +* ``ubuntu`` .. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** " @@ -248,19 +249,6 @@ Sample value: :: " -"**primary_dns** - -``string`` - -Optional","* The primary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing). -* Currently, the ``primary_dns`` value stored in ``input/provision_config.yml`` cannot be part of any of the subnets (``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet``) also defined in ``input/provision_config.yml``. - -Ex: If the ``primary_dns`` is set to 10.15.0.7, the subnet ``10.15.0.0`` cannot be used for ``admin_nic_subnet``, ``ib_nic_subnet`` or ``bmc_nic_subnet``." -"**secondary_dns** - -``string`` - -Optional",The secondary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing) "**disk_partition** ``JSON list`` diff --git a/docs/source/Tables/mapping.csv b/docs/source/Tables/mapping.csv index f45ad0e68..8b7a9e2e8 100644 --- a/docs/source/Tables/mapping.csv +++ b/docs/source/Tables/mapping.csv @@ -31,6 +31,7 @@ Choices: * ``rhel`` <-default * ``rocky`` +* ``ubuntu`` .. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** " @@ -223,19 +224,6 @@ Sample value: :: " -"**primary_dns** - -``string`` - -Optional","* The primary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing). -* Currently, the ``primary_dns`` value stored in ``input/provision_config.yml`` cannot be part of any of the subnets (``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet``) also defined in ``input/provision_config.yml``. - -Ex: If the ``primary_dns`` is set to 10.15.0.7, the subnet ``10.15.0.0`` cannot be used for ``admin_nic_subnet``, ``ib_nic_subnet`` or ``bmc_nic_subnet``." -"**secondary_dns** - -``string`` - -Optional",The secondary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing) "**disk_partition** ``JSON list`` diff --git a/docs/source/Tables/snmpwalk.csv b/docs/source/Tables/snmpwalk.csv index 40656ce33..4c51ab850 100644 --- a/docs/source/Tables/snmpwalk.csv +++ b/docs/source/Tables/snmpwalk.csv @@ -31,6 +31,7 @@ Choices: * ``rhel`` <-default * ``rocky`` +* ``ubuntu`` .. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** " @@ -230,19 +231,6 @@ Sample value: :: " -"**primary_dns** - -``string`` - -Optional","* The primary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing). -* Currently, the ``primary_dns`` value stored in ``input/provision_config.yml`` cannot be part of any of the subnets (``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet``) also defined in ``input/provision_config.yml``. - -Ex: If the ``primary_dns`` is set to 10.15.0.7, the subnet ``10.15.0.0`` cannot be used for ``admin_nic_subnet``, ``ib_nic_subnet`` or ``bmc_nic_subnet``." -"**secondary_dns** - -``string`` - -Optional",The secondary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing) "**disk_partition** ``JSON list`` diff --git a/docs/source/Tables/switch-based.csv b/docs/source/Tables/switch-based.csv index d7167ecc3..323e1aeb7 100644 --- a/docs/source/Tables/switch-based.csv +++ b/docs/source/Tables/switch-based.csv @@ -264,19 +264,6 @@ Sample value: :: " -"**primary_dns** - -``string`` - -Optional","* The primary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing). -* Currently, the ``primary_dns`` value stored in ``input/provision_config.yml`` cannot be part of any of the subnets (``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet``) also defined in ``input/provision_config.yml``. - -Ex: If the ``primary_dns`` is set to 10.15.0.7, the subnet ``10.15.0.0`` cannot be used for ``admin_nic_subnet``, ``ib_nic_subnet`` or ``bmc_nic_subnet``." -"secondary_dns - -``string`` - -Optional",The secondary DNS host IP queried to provide Internet access to cluster Node (through DHCP routing) "**disk_partition** ``JSON list`` diff --git a/docs/source/conf.py b/docs/source/conf.py index c67032aa0..c216a656d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,7 +10,7 @@ project = 'Omnia' copyright = '2023, Dell Technologies' author = 'dell/omnia' -release = '1.5' +release = '1.6' rst_epilog = "If you have any feedback about Omnia documentation, please reach out at `omnia.readme@dell.com `_." import sys diff --git a/docs/source/index.rst b/docs/source/index.rst index 4c0c1a9a5..8ba129b34 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -6,7 +6,7 @@ Omnia: Everything at once! ---------------------------------- -|Omnia version| |Downloads| |Last Commit| |Commits Since 1.4.3| |Contributors| |Forks| |License| +|Omnia version| |Downloads| |Last Commit| |Commits Since 1.6| |Contributors| |Forks| |License| Ansible playbook-based deployment of Slurm and Kubernetes on servers running an RPM-based Linux OS. @@ -66,7 +66,7 @@ For a better understanding of what Omnia does, check out our `docs Date: Fri, 29 Dec 2023 11:01:16 +0530 Subject: [PATCH 015/309] Update .all-contributorsrc Signed-off-by: Sujit Jadhav --- .all-contributorsrc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 9a8541dc8..8c9d2e88c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -622,7 +622,7 @@ "contributions": [ "test" ] - } + }, { "login": "glimchb", "name": "Boris Glimcher", From 0daefa3352277c8fd4b82a1fc92cf027d7165d68 Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Fri, 29 Dec 2023 11:07:23 +0530 Subject: [PATCH 016/309] Update README.md Signed-off-by: Sujit Jadhav --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14041065b..8a55527e0 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,8 @@ Our thanks go to everyone who makes Omnia possible ([emoji key](https://allcontr Subhankar-Adak
    Subhankar-Adak

    💻 priti-parate
    priti-parate

    💻 Lavanya Adhikari
    Lavanya Adhikari

    💻 - preeti-thankachan
    preeti-thankachan

    ⚠️ + Preeti Thankachan
    preeti-thankachan

    ⚠️ + Boris Glimcher
    Boris Glimcher

    💻 From 34cbed4787e74a4f20539f667c154fa287e85596 Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Tue, 2 Jan 2024 03:44:57 +0200 Subject: [PATCH 017/309] feat(dpu): add fw update role Signed-off-by: Boris Glimcher --- .../roles/bluefield/tasks/update_firmware.yml | 32 +++++++++++++++++++ provision/roles/bluefield/vars/main.yml | 6 ++++ 2 files changed, 38 insertions(+) create mode 100644 provision/roles/bluefield/tasks/update_firmware.yml diff --git a/provision/roles/bluefield/tasks/update_firmware.yml b/provision/roles/bluefield/tasks/update_firmware.yml new file mode 100644 index 000000000..2b96f669b --- /dev/null +++ b/provision/roles/bluefield/tasks/update_firmware.yml @@ -0,0 +1,32 @@ +# Copyright 2022 Dell Inc. or its subsidiaries. All Rights Reserved. +# +# 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. +--- + +- name: Update BMC firmware of DPU + ansible.builtin.include_role: + name: nvidia.dpu_ops.manage_bf_bmc_fw + vars: + - bmc_url: "{{ bmc.url }}/{{ bmc.file }}" + +- name: Update CEC firmware of DPU + raw: "wget --no-check-certificate {{ bmc.url }}/{{ bmc.cec }} -O /tmp/images/{{ bmc.cec }}" + +- name: Update DPU NIC firmware + ansible.builtin.include_role: + name: nvidia.dpu_ops.manage_bf2_fw + vars: + - bmc_host: "tbd" + bmc_user: "root" + bmc_password: "tbd" + diff --git a/provision/roles/bluefield/vars/main.yml b/provision/roles/bluefield/vars/main.yml index be7624681..8474139e1 100644 --- a/provision/roles/bluefield/vars/main.yml +++ b/provision/roles/bluefield/vars/main.yml @@ -20,3 +20,9 @@ bluefield_collections: nvidia.dpu_ops:1.0.1 # Usage: configure_pxe_boot.yml bluefield_pxe_boot_dev: NET-OOB-IPV4 + +# Usage: update_firmware.yml +bmc: + url: https://content.mellanox.com/BlueField/BMC/23.10-1-oct-2023 + file: bf3-bmc-23.10-5_opn.fwpkg + cec: cec1736-ecfw-00.02.0152.0000-n02-rel-prod.fwpkg From 5050f1f4ddad9d8fb8f1e722e2a60a0bb4ffd953 Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Wed, 3 Jan 2024 02:04:05 +0200 Subject: [PATCH 018/309] feat(dpu): add force pxe task Signed-off-by: Boris Glimcher --- provision/roles/bluefield/tasks/configure_pxe_boot.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/provision/roles/bluefield/tasks/configure_pxe_boot.yml b/provision/roles/bluefield/tasks/configure_pxe_boot.yml index 3efc0fd9a..c4cbfcea9 100644 --- a/provision/roles/bluefield/tasks/configure_pxe_boot.yml +++ b/provision/roles/bluefield/tasks/configure_pxe_boot.yml @@ -22,6 +22,15 @@ bmc_user: "root" bmc_password: "tbd" +- name: Force PXE boot + ansible.builtin.include_role: + name: nvidia.dpu_ops.bf_bmc + vars: + - bmc_action: "-C 17 chassis bootdev pxe options=efiboot" + bmc_host: "tbd" + bmc_user: "root" + bmc_password: "tbd" + - name: Configure boot order for PXE booting ansible.builtin.include_role: name: nvidia.dpu_ops.bf2_boot From 29965af849a1536762b7191c6e8622c3eaedbefb Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Wed, 3 Jan 2024 02:18:16 +0200 Subject: [PATCH 019/309] feat(dpu): use redfish for CEC update Signed-off-by: Boris Glimcher --- provision/roles/bluefield/tasks/update_firmware.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/provision/roles/bluefield/tasks/update_firmware.yml b/provision/roles/bluefield/tasks/update_firmware.yml index 2b96f669b..e83a959f5 100644 --- a/provision/roles/bluefield/tasks/update_firmware.yml +++ b/provision/roles/bluefield/tasks/update_firmware.yml @@ -20,7 +20,13 @@ - bmc_url: "{{ bmc.url }}/{{ bmc.file }}" - name: Update CEC firmware of DPU - raw: "wget --no-check-certificate {{ bmc.url }}/{{ bmc.cec }} -O /tmp/images/{{ bmc.cec }}" + community.general.redfish_command: + category: Update + command: SimpleUpdate + baseuri: "tbd" + username: "root" + password: "tbd" + update_image_uri: "{{ bmc.url }}/{{ bmc.cec }}" - name: Update DPU NIC firmware ansible.builtin.include_role: From 9c457053508f1f2b75ec936a067cab76afcc77b6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 3 Jan 2024 17:46:18 +0530 Subject: [PATCH 020/309] Updating documentation Signed-off-by: cgoveas --- .../DiscoveryMechanisms/index.rst | 2 +- .../installprovisiontool.rst | 5 ----- .../provisionprereqs.rst | 21 ++++++++++++++++--- .../InstallationGuides/RunningInit/index.rst | 4 ++-- docs/source/InstallationGuides/index.rst | 15 ++++++++++--- .../Overview/NetworkTopologies/Hybrid.rst | 2 -- .../SupportMatrix/OperatingSystems/RedHat.rst | 1 + .../SupportMatrix/OperatingSystems/Ubuntu.rst | 9 +++++++- docs/source/Tables/snmpwalk.csv | 4 ++-- 9 files changed, 44 insertions(+), 19 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index 47c1d9e5c..6df8e2d9b 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -87,6 +87,6 @@ Omnia can query known switches (by IP and community string) for information on t - Servers require a manual PXE boot if iDRAC IPs are not configured. - PXE NIC ranges should contain IPs that are double the iDRACs present (as NIC and iDRAC MACs may need to be mapped). - LOM architecture is not supported (including cloud enclosures: C6420, C6520, C6620). - - Ubuntu cannot be provisioned using this method + For more information regarding snmpwalk, `click here `_ diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index b299dc11b..7fa832989 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -62,11 +62,6 @@ Omnia now supports deploying different versions of the same OS. With each run of * While Omnia deploys the minimal version of the OS, the multiple version feature requires that the Rocky full (DVD) version of the OS be provided. * The multiple OS feature is only available with Rocky 8.7 when xCAT 2.16.5 is in use. [Currently, Omnia uses 2.16.4] - -**DHCP routing for internet access** - - Omnia now supports DHCP routing via the control plane. To enable routing, update the ``primary_dns`` and ``secondary_dns`` in ``input/provision_config.yml`` with the appropriate IPs (hostnames are currently not supported). For cluster nodes that are not directly connected to the internet (ie only PXE network is configured), this configuration allows for internet connectivity. - **Disk partitioning** Omnia now allows for customization of disk partitions applied to remote servers. The disk partition ``desired_capacity`` has to be provided in MB. Valid ``mount_point`` values accepted for disk partition are ``/home``, ``/var``, ``/tmp``, ``/usr``, ``swap``. Default partition size provided for ``/boot`` is 1024MB, ``/boot/efi`` is 256MB and the remaining space to ``/`` partition. Values are accepted in the form of JSON list such as: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index c8f181ec0..633b2e13a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -1,7 +1,7 @@ Before you run the provision tool --------------------------------- -* (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.12.10 `_ and `Python 3.8 `_ are installed on the system. SELinux should also be disabled. +* (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14.13 `_ and `Python 3.9 `_ are installed on the system. SELinux should also be disabled. * If the control plane is running on the minimal edition of the OS, ensure that ``chrony`` and ``podman`` are installed before running ``provision.yml``. @@ -32,7 +32,7 @@ Before you run the provision tool 2. `RHEL 8.x `_ -.. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** + 3. `Ubuntu `_ .. note:: Ensure the ISO provided has downloaded seamlessly (No corruption). Verify the SHA checksum/ download size of the ISO file before provisioning to avoid future failures. @@ -40,7 +40,7 @@ Note the compatibility between cluster OS and control plane OS below: +---------------------+--------------------+------------------+ | | | | - | Control Plane OS | cluster Node OS | Compatibility | + | Control Plane OS | Cluster Node OS | Compatibility | +=====================+====================+==================+ | | | | | RHEL [1]_ | RHEL | Yes | @@ -51,6 +51,21 @@ Note the compatibility between cluster OS and control plane OS below: | | | | | Rocky | Rocky | Yes | +---------------------+--------------------+------------------+ + | | | | + | Ubuntu | Ubuntu | Yes | + +---------------------+--------------------+------------------+ + | | | | + | Rocky | Ubuntu | No | + +---------------------+--------------------+------------------+ + | | | | + | RHEL | Ubuntu | No | + +---------------------+--------------------+------------------+ + | | | | + | Ubuntu | RHEL | No | + +---------------------+--------------------+------------------+ + | | | | + | Ubuntu | Rocky | No | + +---------------------+--------------------+------------------+ .. [1] Ensure that control planes running RHEL have an active subscription or are configured to access local repositories. The following repositories should be enabled on the control plane: **AppStream**, **Code Ready Builder (CRB)**, **BaseOS**. For RHEL control planes running 8.5 and below, ensure that sshpass is additionally available to install or download to the control plane (from any local repository). diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index 6c209bc69..a011adad6 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -1,10 +1,10 @@ Running prereq.sh ================= -``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.12.10). :: +``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.14.13). :: cd omnia - sh prereq.sh + ./prereq.sh .. note:: diff --git a/docs/source/InstallationGuides/index.rst b/docs/source/InstallationGuides/index.rst index 49a11df94..530a060ec 100644 --- a/docs/source/InstallationGuides/index.rst +++ b/docs/source/InstallationGuides/index.rst @@ -5,13 +5,22 @@ Choose a server outside your intended cluster to function as your control plane. The control plane needs to be internet-capable with Github and a full OS installed. -.. note:: Omnia can be run on control planes running RHEL and Rocky. For a complete list of versions supported, check out the `Support Matrix <../Overview/SupportMatrix/OperatingSystems/index.html>`_ . +.. note:: Omnia can be run on control planes running RHEL, Rocky, and Ubuntu. For a complete list of versions supported, check out the `Support Matrix <../Overview/SupportMatrix/OperatingSystems/index.html>`_ . + +For RHEL and Rocky installations: :: dnf install git -y -.. note:: Optionally, if the control plane has an Infiniband NIC installed, run the below command: +For Ubuntu installations: + +:: + + apt install git -y + + +.. note:: Optionally, if the control plane has an Infiniband NIC installed on RHEL or Rocky, run the below command: ``yum groupinstall "Infiniband Support" -y`` @@ -23,7 +32,7 @@ Once the Omnia repository has been cloned on to the control plane: :: Change directory to Omnia using: :: cd omnia - sh prereq.sh + ./prereq.sh Run the script ``prereq.sh`` to verify the system is ready for Omnia deployment. diff --git a/docs/source/Overview/NetworkTopologies/Hybrid.rst b/docs/source/Overview/NetworkTopologies/Hybrid.rst index e539937ce..2e1f0e9d2 100644 --- a/docs/source/Overview/NetworkTopologies/Hybrid.rst +++ b/docs/source/Overview/NetworkTopologies/Hybrid.rst @@ -15,8 +15,6 @@ The first time the provision tool is run (to discover the dedicated BMC ports), * Leave the variables ``bmc_nic_subnet``, ``bmc_static_start_range`` and ``bmc_static_end_range`` blank in ``input/provision_config.yml``. Entering these variables will cause IP reassignment and can interfere with the availability of ports on your target servers. * Do not use the following methods to discover nodes in a Hybrid setup: snmpwalk, switch-based. -.. note:: For users who don't want internet access routed to target nodes, keep ``primary_dns`` and ``secondary_dns`` blank in ``input/provision_config.yml``. - Once all the dedicated NICs are discovered, re-run the provisioning tool (to discover the shared LOM ports) with the following variables in ``input/provision_config.yml``: * ``network_interface_type``: ``lom`` diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst index 1dab2a10b..631ef04cb 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst @@ -11,6 +11,7 @@ OS Version Control Plane Cluster Nodes 8.5 Yes Yes 8.6 Yes Yes 8.7 Yes Yes +8.8 Yes Yes ========== ============= ============= .. note:: diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst index d6270a116..53c8890b5 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst @@ -1,2 +1,9 @@ Ubuntu -====== \ No newline at end of file +====== + +========== ============= ============= +OS Version Control Plane Cluster Nodes +========== ============= ============= +20.04 Yes Yes +22.04 Yes Yes +========== ============= ============= \ No newline at end of file diff --git a/docs/source/Tables/snmpwalk.csv b/docs/source/Tables/snmpwalk.csv index 4c51ab850..d27a68581 100644 --- a/docs/source/Tables/snmpwalk.csv +++ b/docs/source/Tables/snmpwalk.csv @@ -31,10 +31,10 @@ Choices: * ``rhel`` <-default * ``rocky`` -* ``ubuntu`` + .. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** -" +.. note:: Ubuntu cannot be provisioned using the ``snmpwalk`` method." "**provision_os_version** ``string`` From 61272c29e2f3f87ff1ef8969a16ae1357b3ac68b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 4 Jan 2024 11:01:20 +0530 Subject: [PATCH 021/309] Updating documentation Signed-off-by: cgoveas --- .../installprovisiontool.rst | 2 +- .../InstallingProvisionTool/provisionparams.rst | 8 -------- docs/source/Overview/NetworkTopologies/Hybrid.rst | 2 +- .../source/Overview/NetworkTopologies/dedicated.rst | 9 --------- docs/source/Troubleshooting/FAQ.rst | 13 ------------- 5 files changed, 2 insertions(+), 32 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 7fa832989..3be0808c2 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -138,7 +138,7 @@ After successfully running ``provision.yml``, go to `Building Clusters <../Build * If the target nodes were discovered using switch-based, mapping or snmpwalk mechanisms, manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_. - * If the cluster does not have access to the internet, AppStream will not function. To provide internet access through the control plane (via the PXE network NIC), update ``primary_dns`` and ``secondary_dns`` in ``provision_config.yml`` and run ``provision.yml`` + * If the cluster does not have access to the internet, AppStream will not function. * All ports required for xCAT to run will be opened (For a complete list, check out the `Security Configuration Document <../../SecurityConfigGuide/ProductSubsystemSecurity.html#firewall-settings>`_). diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 9552199ea..e2c550435 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -169,14 +169,6 @@ Fill in all provision-specific parameters in ``input/provision_config.yml`` | ``string`` | | | Required | **Default values**: ``public`` | +----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| primary_dns | The primary DNS host IP queried to provide Internet access to Compute Node (through DHCP routing) | -| ``string`` | | -| Optional | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| secondary_dns | The secondary DNS host IP queried to provide Internet access to Compute Node (through DHCP routing) | -| ``string`` | | -| Optional | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | disk_partition | * User defined disk partition applied to remote servers. | | ``JSON list`` | * The disk partition desired_capacity has to be provided in MB. | | Optional | * Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. | diff --git a/docs/source/Overview/NetworkTopologies/Hybrid.rst b/docs/source/Overview/NetworkTopologies/Hybrid.rst index 2e1f0e9d2..814556a59 100644 --- a/docs/source/Overview/NetworkTopologies/Hybrid.rst +++ b/docs/source/Overview/NetworkTopologies/Hybrid.rst @@ -20,4 +20,4 @@ Once all the dedicated NICs are discovered, re-run the provisioning tool (to dis * ``network_interface_type``: ``lom`` * ``discovery_mechanism``: ``bmc`` -To assign BMC NICs and route internet access to your target nodes, populate the values of ``bmc_nic_subnet``, ``bmc_static_start_range``, ``bmc_static_end_range``, ``primary_dns`` and ``secondary_dns`` in ``input/provision_config.yml`` during the second run of the provision tool. \ No newline at end of file +To assign BMC NICs and route internet access to your target nodes, populate the values of ``bmc_nic_subnet``, ``bmc_static_start_range``, and ``bmc_static_end_range`` in ``input/provision_config.yml`` during the second run of the provision tool. \ No newline at end of file diff --git a/docs/source/Overview/NetworkTopologies/dedicated.rst b/docs/source/Overview/NetworkTopologies/dedicated.rst index 3d6532e0d..62125b932 100644 --- a/docs/source/Overview/NetworkTopologies/dedicated.rst +++ b/docs/source/Overview/NetworkTopologies/dedicated.rst @@ -8,18 +8,9 @@ Depending on internet access for host nodes, there are two ways to achieve a ded 1. Dedicated Setup with dedicated public NIC on cluster nodes - - -When all cluster nodes have their own public network access, ``primary_dns`` and ``secondary_dns`` in ``provision_config.yml`` become optional variables as the control plane is not required to be a gateway to the network. The network design would follow the below diagram: - - - 2. Dedicated Setup with single NIC on cluster nodes - -When all cluster nodes rely on the control plane for public network access, the variables ``primary_dns`` and ``secondary_dns`` in ``provision_config.yml`` are used to indicate that the control plane is the gateway for all cluster nodes to get internet access. Since all public network traffic will be routed through the control plane, the user may have to take precautions to avoid bottlenecks in such a set-up. - **Recommended discovery mechanism** * `mapping <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mapping.html>`_ diff --git a/docs/source/Troubleshooting/FAQ.rst b/docs/source/Troubleshooting/FAQ.rst index 29e95611c..4794be76f 100644 --- a/docs/source/Troubleshooting/FAQ.rst +++ b/docs/source/Troubleshooting/FAQ.rst @@ -129,14 +129,6 @@ If ``enable_omnia_nfs`` is true in ``input/omnia_config.yml``, follow the below **Resolution**: Bring the target node up and re-run the script. -⦾ **Why does the 'Verify primary_dns is reachable' task fail during provision.yml?** - -.. image:: ../images/primarydns_verify_failure.png - -Currently, the ``primary_dns`` value stored in ``input/provision_config.yml`` cannot be part of any of the subnets (``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet``) also defined in ``input/provision_config.yml``. - -Ex: If the ``primary_dns`` is set to 10.15.0.7, the subnet ``10.15.0.0`` cannot be used for ``admin_nic_subnet``, ``ib_nic_subnet`` or ``bmc_nic_subnet``. - ⦾ **Why is the node status stuck at 'powering-on' or 'powering-off' after a control plane reboot?** **Potential Cause**: The nodes were powering off or powering on during the control plane reboot/shutdown. @@ -214,11 +206,6 @@ Omnia does not validate the input of ``rhel_repo_local_path``. Changing the ``breakout_value`` on a split port is currently not supported. Ensure the port is un-split before assigning a new ``breakout_value``. -⦾ **How to enable DHCP routing on Compute Nodes:** - -To enable routing, update the ``primary_dns`` and ``secondary_dns`` in ``provision_config.yml`` with the appropriate IPs (hostnames are currently not supported). For compute nodes that are not directly connected to the internet (ie only host network is configured), this configuration allows for internet connectivity. - - ⦾ **What to do if the LC is not ready:** From 302dd3879e38850dd0d4cdcde646df25be086859 Mon Sep 17 00:00:00 2001 From: Boris Glimcher Date: Tue, 2 Jan 2024 21:23:26 +0200 Subject: [PATCH 022/309] feat(inventory): fetch bmc ip using ipmitool instead of racadm This is to accomodate for DPUs and unsupported racadm OSes Signed-off-by: Boris Glimcher --- .../roles/post_provision/tasks/provisioned_node_inventory.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/provision/roles/post_provision/tasks/provisioned_node_inventory.yml b/provision/roles/post_provision/tasks/provisioned_node_inventory.yml index be308a766..6d1aeb8d8 100644 --- a/provision/roles/post_provision/tasks/provisioned_node_inventory.yml +++ b/provision/roles/post_provision/tasks/provisioned_node_inventory.yml @@ -39,13 +39,13 @@ - name: Fetch BMC IP ansible.builtin.shell: > set -o pipefail && \ - racadm get iDRAC.IPv4.Address | grep Address + ipmitool lan print 1 | grep "IP Address :" register: fetch_bmc_ip changed_when: false - name: Set BMC IP ansible.builtin.set_fact: - bmc_ip: "{{ fetch_bmc_ip.stdout.split('=')[1] }}" + bmc_ip: "{{ fetch_bmc_ip.stdout.split(':')[1] }}" when: fetch_bmc_ip.stdout is defined - name: Check IP and service tag already present in node_inventory From 1ef8c8f6dd58cf37c696a48b5ff3cbb2930fdb70 Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Tue, 9 Jan 2024 21:46:27 +0530 Subject: [PATCH 023/309] Update provision/roles/post_provision/tasks/provisioned_node_inventory.yml Co-authored-by: Boris Glimcher <36732377+glimchb@users.noreply.github.com> Signed-off-by: Sujit Jadhav --- .../roles/post_provision/tasks/provisioned_node_inventory.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provision/roles/post_provision/tasks/provisioned_node_inventory.yml b/provision/roles/post_provision/tasks/provisioned_node_inventory.yml index 6d1aeb8d8..c46d76516 100644 --- a/provision/roles/post_provision/tasks/provisioned_node_inventory.yml +++ b/provision/roles/post_provision/tasks/provisioned_node_inventory.yml @@ -39,7 +39,7 @@ - name: Fetch BMC IP ansible.builtin.shell: > set -o pipefail && \ - ipmitool lan print 1 | grep "IP Address :" + ipmitool lan print 1 | grep -E "IP Address\s+:" register: fetch_bmc_ip changed_when: false From 16d95d3ae018f5aa38e099257c9380c9e4f9996e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 10 Jan 2024 14:30:21 +0530 Subject: [PATCH 024/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Tables/security_config_ldap.csv | 99 +++++++++++++-------- 1 file changed, 64 insertions(+), 35 deletions(-) diff --git a/docs/source/Tables/security_config_ldap.csv b/docs/source/Tables/security_config_ldap.csv index 775d1736e..2f1b552c5 100644 --- a/docs/source/Tables/security_config_ldap.csv +++ b/docs/source/Tables/security_config_ldap.csv @@ -1,44 +1,19 @@ Parameter,Details -"ldap_required - ``boolean`` [1]_ - Optional ","Boolean indicating whether ldap client is required or not. +"authentication_setup + ``string`` + Optional ","Indicates whether FreeIPA or OpenLDAP is setup. Choices: - * ``false`` <- Default - * ``true`` " + * ``openldap`` <- Default + * ``freeipa`` " "domain_name ``string`` - Optional ","Sets the intended domain name. - - **Default values**: ``omnia.test``" -"ldap_server_ip - ``string`` - Optional ",LDAP server IP. Required if ``ldap_required`` is true. There should be an explicit LDAP server running on this IP. -"ldap_connection_type - ``string`` - Optional ","For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. - - **Default values**: ``TLS`` " -"ldap_ca_cert_path - ``string`` - Optional ","This variable accepts Server Certificate Path. Make sure certificate is present in the path provided. The certificate should have .pem or .crt extension. This variable is mandatory if connection type is TLS. - - **Default values**: ``/etc/openldap/certs/omnialdap.pem`` " -"user_home_dir - ``string`` - Optional ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. - - **Default values**: ``/home`` " -"ldap_bind_username - ``string`` - Optional ","If LDAP server is configured with bind dn then bind dn user to be provided. If this value is not provided (when bind is configured in server) then ldap authentication fails. Omnia does not validate this input. Ensure that it is valid and proper. - - **Default values**: ``admin`` " -"ldap_bind_password - ``string`` - Optional ","* If LDAP server is configured with bind dn then bind dn password to be provided. If this value is not provided (when bind is configured in server) then ldap authentication fails. Omnia does not validate this input. Ensure that it is valid and proper. -* The first character of the string should be an alphabet." + Required ","* Sets the intended domain name. +* If dc=omnia,dc=test, Provide ``omnia.test`` +* If dc=dell,dc=omnia,dc=com Provide ``dell.omnia.com`` + + **Default values**: ``omnia.test`` " "enable_secure_login_node ``boolean`` [1]_ Optional ","Boolean value deciding whether security features are enabled on the Login Node. @@ -47,3 +22,57 @@ * ``false`` <- Default * ``true`` " +"ldap_connection_type + ``string`` + Optional ","For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. + + Choices: + + * ``TLS`` <- Default + * ``SSL`` " +"tls_ca_certificate + ``string`` + Optional","File path pointing to the Certificate Authority (CA) issued certificate path. Certificate files should be saved with a .pem or .crt extension. If not provided, a self-signed certificate is generated by Omnia." +"tls_certificate + ``string`` + Optional",File path pointing to the certificate used to authorize the LDAP server. Certificate files should be saved with a .pem or .crt extension. +"tls_certificate_key + ``string`` + Optional ",The private key that matches the LDAP certificate. +"user_home_dir + ``string`` + Optional ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. + + **Default value**: ``/home`` " +"openldap_db_username + ``string`` + Optional "," The username used to manage the LDAP database. + + **Default value**: ``""admin""``" +"openldap_db_password + ``string`` + Optional "," The password used to configure and manage the LDAP database. Ensure that this value is 8 characters long. +" +"openldap_config_username + ``string`` + Optional "," The username used to configure the LDAP database. + + **Default value**: ``""admin""``" +"openldap_config_password + ``string`` + Optional "," The password used to configure the LDAP database. Ensure that this value is 8 characters long. +" +"openldap_monitor_password + ``string`` + Optional "," The password used to monitor the LDAP database. Ensure that this value is 8 characters long. +" +"openldap_organization + ``string`` + Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. + + **Default value**: ``""omnia""``" +"openldap_organizationational_unit + ``string`` + Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. + + **Default value**: ``""People""``" From 75d2ab98a131e7ae53735f1578663528c713b9f1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 10 Jan 2024 17:52:49 +0530 Subject: [PATCH 025/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Roles/Security/index.rst | 76 ++++------------------------ 1 file changed, 10 insertions(+), 66 deletions(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 04332dd88..12142eaff 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -13,72 +13,16 @@ ________________________________ Enter the following parameters in ``input/security_config.yml``. -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+============================+=================================================================================================================================================================================================================================================================+ -| freeipa_required | Boolean indicating whether FreeIPA is required or not. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``true`` <- Default | -| | * ``false`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| realm_name | Sets the intended realm name. | -| ``string`` | | -| Optional | **Default values**: ``OMNIA.TEST`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| directory_manager_password | Password authenticating admin level access to the Directory for system management tasks. It will be added to the instance of directory server created for IPA.Required Length: 8 characters. The password must not contain -,, ‘,” | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| kerberos_admin_password | “admin” user password for the IPA server on RockyOS. | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_required | Boolean indicating whether ldap client is required or not. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | * ``true`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| domain_name | Sets the intended domain name. | -| ``string`` | | -| Optional | **Default values**: ``omnia.test`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_server_ip | LDAP server IP. Required if ``ldap_required`` is true. There should be an explicit LDAP server running on this IP. | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_connection_type | For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. | -| ``string`` | | -| Optional | **Default values**: ``TLS`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_ca_cert_path | This variable accepts Server Certificate Path. Make sure certificate is present in the path provided. The certificate should have .pem or .crt extension. This variable is mandatory if connection type is TLS. | -| ``string`` | | -| Optional | **Default values**: ``/etc/openldap/certs/omnialdap.pem`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| user_home_dir | This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. | -| ``string`` | | -| Optional | **Default values**: ``/home`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_bind_username | If LDAP server is configured with bind dn then bind dn user to be provided. If this value is not provided (when bind is configured in server) then ldap authentication fails. Omnia does not validate this input. Ensure that it is valid and proper. | -| ``string`` | | -| Optional | **Default values**: ``admin`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ldap_bind_password | If LDAP server is configured with bind dn then bind dn password to be provided. If this value is not provided (when bind is configured in server) then ldap authentication fails. Omnia does not validate this input. Ensure that it is valid and proper. | -| ``string`` | | -| Optional | | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| enable_secure_login_node | Boolean value deciding whether security features are enabled on the Login Node. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | * ``true`` | -+----------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -.. note:: When ``ldap_required`` is true, ``freeipa_required`` has to be false. Conversely, when `freeipa_required`` is true, ``ldap_required`` has to be false. +.. csv-table:: Parameters for FreeIPA + :file: ../../Tables/security_config_freeipa.csv + :header-rows: 1 + :keepspace: + +.. csv-table:: Parameters for LDAP + :file: ../../Tables/security_config_ldap.csv + :header-rows: 1 + :keepspace: + From 394c294175e946b7b6e69a91932608750397541d Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Thu, 11 Jan 2024 11:46:46 +0530 Subject: [PATCH 026/309] Update README.md Signed-off-by: Sujit Jadhav --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 8a55527e0..9422f6844 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,12 @@ Current Status: ![GitHub](https://readthedocs.org/projects/omnia-doc/badge/?vers Omnia is made available under the [Apache 2.0 license](https://opensource.org/licenses/Apache-2.0) +## Contributing To Omnia + +We encourage everyone to help us improve Omnia by contributing to the project. Contributions can be as small as documentation updates or adding example use cases, to adding commenting and properly styling code segments all the way up to full feature contributions. We ask that contributors follow our established [guidelines](https://omnia-doc.readthedocs.io/en/latest/Contributing/index.html) for contributing to the project. + +Contributions to Omnia are made through Pull Requests (PRs) to "[devel](https://github.com/dell/omnia/tree/devel)" branch. "[devel](https://github.com/dell/omnia/tree/devel)" is the bleeding edge branch of Omnia packed with experimental and untested features". + ## Omnia Community Members: Dell Technologies Intel Corporation From a10704079e234d0a72bd8880a5f935e3cbb9b971 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 12 Jan 2024 11:16:13 +0530 Subject: [PATCH 027/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Roles/Security/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 12142eaff..bfa9da12d 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -23,8 +23,7 @@ Enter the following parameters in ``input/security_config.yml``. :header-rows: 1 :keepspace: - - +.. [1] Boolean parameters do not need to be passed with double or single quotes. Configuring login node security ________________________________ From bf18f45ccf2838db472298c2b8f0d7ce56205362 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 12 Jan 2024 11:45:45 +0530 Subject: [PATCH 028/309] Updating documentation Signed-off-by: cgoveas --- .../BuildingClusters/schedulerinputparams.rst | 9 ++------- docs/source/Roles/Security/index.rst | 11 +++-------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst index 0c7f321e1..cbf64ef5f 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst @@ -19,13 +19,8 @@ These parameters are located in ``input/omnia_config.yml``, ``input/security_con **security_config.yml** -.. csv-table:: Parameters for FreeIPA - :file: ../../Tables/security_config_freeipa.csv - :header-rows: 1 - :keepspace: - -.. csv-table:: Parameters for LDAP - :file: ../../Tables/security_config_ldap.csv +.. csv-table:: Parameters for Authentication + :file: ../../Tables/security_config.csv :header-rows: 1 :keepspace: diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index bfa9da12d..520deace2 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -13,13 +13,8 @@ ________________________________ Enter the following parameters in ``input/security_config.yml``. -.. csv-table:: Parameters for FreeIPA - :file: ../../Tables/security_config_freeipa.csv - :header-rows: 1 - :keepspace: - -.. csv-table:: Parameters for LDAP - :file: ../../Tables/security_config_ldap.csv +.. csv-table:: Parameters for Authentication + :file: ../../Tables/security_config.csv :header-rows: 1 :keepspace: @@ -86,7 +81,7 @@ Enter the following parameters in ``input/login_node_security_config.yml``. Installing LDAP Client ________________________ -Manager and compute nodes will have LDAP client installed and configured if ``ldap_required`` is set to true. The login node does not have LDAP client installed. +Manager and compute nodes will have LDAP client installed and configured if ``authentication_system`` is set to "openldap". The login node does not have LDAP client installed. .. caution:: No users/groups will be created by Omnia. From edd5488e96430354e5a76c2f3cdcf4ade97c9de2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 12 Jan 2024 11:47:20 +0530 Subject: [PATCH 029/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Tables/security_config.csv | 93 ++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 docs/source/Tables/security_config.csv diff --git a/docs/source/Tables/security_config.csv b/docs/source/Tables/security_config.csv new file mode 100644 index 000000000..0bf45d660 --- /dev/null +++ b/docs/source/Tables/security_config.csv @@ -0,0 +1,93 @@ +Parameter,Details +"authentication_setup + ``string`` + Required ","Indicates whether FreeIPA or OpenLDAP is setup. + + Choices: + + * ``openldap`` <- Default + * ``freeipa`` " +"domain_name + ``string`` + Required ","* Sets the intended domain name. +* If dc=omnia,dc=test, Provide ``omnia.test`` +* If dc=dell,dc=omnia,dc=com Provide ``dell.omnia.com`` + + **Default values**: ``omnia.test`` " +"realm_name + ``string`` + Required ","* Sets the intended kerberos realm name. +* It is required for FreeIPA setups. +* A realm name is often, but not always the upper case version of the name of the DNS domain over which it presides. + * **Default value**: ``""OMNIA.TEST""`` + **Default values**: ``omnia.test`` " +"directory_manager_password + ``string`` + Required"," +* The directory server operations require an administrative user. This user is referred to as the Directory Manager and has full access to the Directory for system management tasks and will be added to the instance of directory server created for IPA. +* The password must be at least 8 characters long. +* The password must not contain -,\, ',""" +"kerberos_admin_password + ``string`` + Required","* kerberos_admin_password used by IPA admin user. The IPA server requires an administrative user, named 'admin'. +* The password must be at least 8 characters long. +* The password must not contain -,\, ',""" +"ldap_connection_type + ``string`` + Required ","For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. + + Choices: + + * ``TLS`` <- Default + * ``SSL`` " +"tls_ca_certificate + ``string`` + Optional","File path pointing to the Certificate Authority (CA) issued certificate path. Certificate files should be saved with a .pem or .crt extension. If not provided, a self-signed certificate is generated by Omnia." +"tls_certificate + ``string`` + Optional",File path pointing to the certificate used to authorize the LDAP server. Certificate files should be saved with a .pem or .crt extension. +"tls_certificate_key + ``string`` + Optional ",The private key that matches the LDAP certificate. +"user_home_dir + ``string`` + Required ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. + + **Default value**: ``/home`` " +"openldap_db_username + ``string`` + Required "," The username used to manage the LDAP database. + + **Default value**: ``""admin""``" +"openldap_db_password + ``string`` + Required "," The password used to configure and manage the LDAP database. Ensure that this value is 8 characters long. +" +"openldap_config_username + ``string`` + Required "," The username used to configure the LDAP database. + + **Default value**: ``""admin""``" +"openldap_config_password + ``string`` + Required "," The password used to configure the LDAP database. Ensure that this value is 8 characters long. +" +"openldap_monitor_password + ``string`` + Required "," The password used to monitor the LDAP database. Ensure that this value is 8 characters long. +" +"openldap_organization + ``string`` + Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. + + **Default value**: ``""omnia""``" +"openldap_organizationational_unit + ``string`` + Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. + + **Default value**: ``""People""``" +"enable_secure_login_node + ``boolean`` [1]_ + Required ","* Boolean indicating whether security features are to be enabled on the login node or not. + + **Default value**: ``false``" From 7962a8418aa00daf3dbd0a05134a39d10595cbba Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 12 Jan 2024 12:02:15 +0530 Subject: [PATCH 030/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Tables/security_config.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/Tables/security_config.csv b/docs/source/Tables/security_config.csv index 0bf45d660..1e93ebfb3 100644 --- a/docs/source/Tables/security_config.csv +++ b/docs/source/Tables/security_config.csv @@ -1,5 +1,5 @@ Parameter,Details -"authentication_setup +"authentication_setup ``string`` Required ","Indicates whether FreeIPA or OpenLDAP is setup. @@ -19,8 +19,8 @@ Required ","* Sets the intended kerberos realm name. * It is required for FreeIPA setups. * A realm name is often, but not always the upper case version of the name of the DNS domain over which it presides. - * **Default value**: ``""OMNIA.TEST""`` - **Default values**: ``omnia.test`` " +* **Default value**: ``""OMNIA.TEST""`` +" "directory_manager_password ``string`` Required"," @@ -29,7 +29,7 @@ * The password must not contain -,\, ',""" "kerberos_admin_password ``string`` - Required","* kerberos_admin_password used by IPA admin user. The IPA server requires an administrative user, named 'admin'. + Required","* ``kerberos_admin_password`` used by IPA admin user. The IPA server requires an administrative user, named 'admin'. * The password must be at least 8 characters long. * The password must not contain -,\, ',""" "ldap_connection_type From 9809d54d9d25438c67c58b8867b0c856656cadd4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 12 Jan 2024 17:58:14 +0530 Subject: [PATCH 031/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Roles/Security/index.rst | 10 +++ docs/source/Tables/security_config.csv | 72 ------------------- .../source/Tables/security_config_freeipa.csv | 42 +++++------ docs/source/Tables/security_config_ldap.csv | 40 +++-------- 4 files changed, 36 insertions(+), 128 deletions(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 520deace2..7d653bf35 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -18,6 +18,16 @@ Enter the following parameters in ``input/security_config.yml``. :header-rows: 1 :keepspace: +.. csv-table:: Parameters for OpenLDAP configuration + :file: ../../Tables/security_config_ldap.csv + :header-rows: 1 + :keepspace: + +.. csv-table:: Parameters for FreeIPA configuration + :file: ../../Tables/security_config_freeipa.csv + :header-rows: 1 + :keepspace: + .. [1] Boolean parameters do not need to be passed with double or single quotes. Configuring login node security diff --git a/docs/source/Tables/security_config.csv b/docs/source/Tables/security_config.csv index 1e93ebfb3..efe476480 100644 --- a/docs/source/Tables/security_config.csv +++ b/docs/source/Tables/security_config.csv @@ -14,78 +14,6 @@ * If dc=dell,dc=omnia,dc=com Provide ``dell.omnia.com`` **Default values**: ``omnia.test`` " -"realm_name - ``string`` - Required ","* Sets the intended kerberos realm name. -* It is required for FreeIPA setups. -* A realm name is often, but not always the upper case version of the name of the DNS domain over which it presides. -* **Default value**: ``""OMNIA.TEST""`` -" -"directory_manager_password - ``string`` - Required"," -* The directory server operations require an administrative user. This user is referred to as the Directory Manager and has full access to the Directory for system management tasks and will be added to the instance of directory server created for IPA. -* The password must be at least 8 characters long. -* The password must not contain -,\, ',""" -"kerberos_admin_password - ``string`` - Required","* ``kerberos_admin_password`` used by IPA admin user. The IPA server requires an administrative user, named 'admin'. -* The password must be at least 8 characters long. -* The password must not contain -,\, ',""" -"ldap_connection_type - ``string`` - Required ","For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. - - Choices: - - * ``TLS`` <- Default - * ``SSL`` " -"tls_ca_certificate - ``string`` - Optional","File path pointing to the Certificate Authority (CA) issued certificate path. Certificate files should be saved with a .pem or .crt extension. If not provided, a self-signed certificate is generated by Omnia." -"tls_certificate - ``string`` - Optional",File path pointing to the certificate used to authorize the LDAP server. Certificate files should be saved with a .pem or .crt extension. -"tls_certificate_key - ``string`` - Optional ",The private key that matches the LDAP certificate. -"user_home_dir - ``string`` - Required ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. - - **Default value**: ``/home`` " -"openldap_db_username - ``string`` - Required "," The username used to manage the LDAP database. - - **Default value**: ``""admin""``" -"openldap_db_password - ``string`` - Required "," The password used to configure and manage the LDAP database. Ensure that this value is 8 characters long. -" -"openldap_config_username - ``string`` - Required "," The username used to configure the LDAP database. - - **Default value**: ``""admin""``" -"openldap_config_password - ``string`` - Required "," The password used to configure the LDAP database. Ensure that this value is 8 characters long. -" -"openldap_monitor_password - ``string`` - Required "," The password used to monitor the LDAP database. Ensure that this value is 8 characters long. -" -"openldap_organization - ``string`` - Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. - - **Default value**: ``""omnia""``" -"openldap_organizationational_unit - ``string`` - Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. - - **Default value**: ``""People""``" "enable_secure_login_node ``boolean`` [1]_ Required ","* Boolean indicating whether security features are to be enabled on the login node or not. diff --git a/docs/source/Tables/security_config_freeipa.csv b/docs/source/Tables/security_config_freeipa.csv index 6be5248dd..38c5b68d8 100644 --- a/docs/source/Tables/security_config_freeipa.csv +++ b/docs/source/Tables/security_config_freeipa.csv @@ -1,31 +1,21 @@ Parameter,Details -"freeipa_required - ``boolean`` [1]_ - Required ","Boolean indicating whether FreeIPA is required or not. - - Choices: - - * ``true`` <- Default - - * ``false`` " -"realm_name +"realm_name ``string`` - Required ","Sets the intended realm name. - - **Default value**: ``OMNIA.TEST``" + Required ","* Sets the intended kerberos realm name. +* It is required for FreeIPA setups. +* A realm name is often, but not always the upper case version of the name of the DNS domain over which it presides. +* **Default value**: ``""OMNIA.TEST""`` +" "directory_manager_password - ``string`` - Required ","* Password authenticating admin level access to the Directory for system management tasks. -* It will be added to the instance of directory server created for IPA. -* Required Length: 8 characters. -* The password must not contain -,, �,� -* The first character of the string should be an alphabet." + ``string`` + Required"," +* The directory server operations require an administrative user. This user is referred to as the Directory Manager and has full access to the Directory for system management tasks and will be added to the instance of directory server created for IPA. +* The password must be at least 8 characters long. +* The password must not contain -,\, ',""" "kerberos_admin_password - ``string`` - Required ","* ""admin"" user password for the IPA server on RockyOS. -* The first character of the string should be an alphabet." -"domain_name ``string`` - Required ","Sets the intended domain name - - **Default value**: ``omnia.test``" + Required","* ``kerberos_admin_password`` used by IPA admin user. The IPA server requires an administrative user, named 'admin'. +* The password must be at least 8 characters long. +* The password must not contain -,\, ',""" +, +, diff --git a/docs/source/Tables/security_config_ldap.csv b/docs/source/Tables/security_config_ldap.csv index 2f1b552c5..359ad7f61 100644 --- a/docs/source/Tables/security_config_ldap.csv +++ b/docs/source/Tables/security_config_ldap.csv @@ -1,30 +1,7 @@ Parameter,Details -"authentication_setup - ``string`` - Optional ","Indicates whether FreeIPA or OpenLDAP is setup. - - Choices: - - * ``openldap`` <- Default - * ``freeipa`` " -"domain_name - ``string`` - Required ","* Sets the intended domain name. -* If dc=omnia,dc=test, Provide ``omnia.test`` -* If dc=dell,dc=omnia,dc=com Provide ``dell.omnia.com`` - - **Default values**: ``omnia.test`` " -"enable_secure_login_node - ``boolean`` [1]_ - Optional ","Boolean value deciding whether security features are enabled on the Login Node. - - Choices: - - * ``false`` <- Default - * ``true`` " "ldap_connection_type ``string`` - Optional ","For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. + Required ","For a TLS connection, provide a valid certification path. For an SSL connection, ensure port 636 is open. Choices: @@ -41,30 +18,30 @@ Optional ",The private key that matches the LDAP certificate. "user_home_dir ``string`` - Optional ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. + Required ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. **Default value**: ``/home`` " "openldap_db_username ``string`` - Optional "," The username used to manage the LDAP database. + Required "," The username used to manage the LDAP database. **Default value**: ``""admin""``" "openldap_db_password ``string`` - Optional "," The password used to configure and manage the LDAP database. Ensure that this value is 8 characters long. + Required "," The password used to configure and manage the LDAP database. Ensure that this value is 8 characters long. " "openldap_config_username ``string`` - Optional "," The username used to configure the LDAP database. + Required "," The username used to configure the LDAP database. **Default value**: ``""admin""``" "openldap_config_password ``string`` - Optional "," The password used to configure the LDAP database. Ensure that this value is 8 characters long. + Required "," The password used to configure the LDAP database. Ensure that this value is 8 characters long. " "openldap_monitor_password ``string`` - Optional "," The password used to monitor the LDAP database. Ensure that this value is 8 characters long. + Required "," The password used to monitor the LDAP database. Ensure that this value is 8 characters long. " "openldap_organization ``string`` @@ -76,3 +53,6 @@ Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. **Default value**: ``""People""``" +, +, +, From 9b19c61a542ad42def2082f485ea152591a791df Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 12 Jan 2024 18:27:32 +0530 Subject: [PATCH 032/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Tables/security_config.csv | 4 ++-- docs/source/Tables/security_config_freeipa.csv | 2 -- docs/source/Tables/security_config_ldap.csv | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/docs/source/Tables/security_config.csv b/docs/source/Tables/security_config.csv index efe476480..83368cf1a 100644 --- a/docs/source/Tables/security_config.csv +++ b/docs/source/Tables/security_config.csv @@ -1,7 +1,7 @@ Parameter,Details -"authentication_setup +"authentication_system ``string`` - Required ","Indicates whether FreeIPA or OpenLDAP is setup. + Required ","Indicates whether FreeIPA or OpenLDAP is setup. Choices: diff --git a/docs/source/Tables/security_config_freeipa.csv b/docs/source/Tables/security_config_freeipa.csv index 38c5b68d8..53525a8ff 100644 --- a/docs/source/Tables/security_config_freeipa.csv +++ b/docs/source/Tables/security_config_freeipa.csv @@ -17,5 +17,3 @@ Parameter,Details Required","* ``kerberos_admin_password`` used by IPA admin user. The IPA server requires an administrative user, named 'admin'. * The password must be at least 8 characters long. * The password must not contain -,\, ',""" -, -, diff --git a/docs/source/Tables/security_config_ldap.csv b/docs/source/Tables/security_config_ldap.csv index 359ad7f61..298d2d338 100644 --- a/docs/source/Tables/security_config_ldap.csv +++ b/docs/source/Tables/security_config_ldap.csv @@ -53,6 +53,3 @@ Required ","LDAP server is configured using organizations. They are necessary for user creation and group mapping. **Default value**: ``""People""``" -, -, -, From b06547a4d1bf4505f29eb9297ed1547e6d64ec25 Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Fri, 12 Jan 2024 22:03:00 +0530 Subject: [PATCH 033/309] Update README.md Signed-off-by: Sujit Jadhav --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9422f6844..7d800d95f 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Our thanks go to everyone who makes Omnia possible ([emoji key](https://allcontr priti-parate
    priti-parate

    💻 Lavanya Adhikari
    Lavanya Adhikari

    💻 Preeti Thankachan
    preeti-thankachan

    ⚠️ - Boris Glimcher
    Boris Glimcher

    💻 + Boris Glimcher
    Boris Glimcher

    💻 🚧📖 From b16b898a40fe69fd9bedd9eadf014a65ab89089b Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Fri, 12 Jan 2024 22:06:00 +0530 Subject: [PATCH 034/309] Update .all-contributorsrc Signed-off-by: Sujit Jadhav --- .all-contributorsrc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 8c9d2e88c..12bd721e2 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -629,7 +629,9 @@ "avatar_url": "https://avatars.githubusercontent.com/u/36732377?v=4", "profile": "https://github.com/glimchb", "contributions": [ - "code" + "code", + "maintenance", + "doc" ] } ], From dc03f6bbd78e0b7ddb41a32397792f8628a1c96a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 17 Jan 2024 15:28:14 +0530 Subject: [PATCH 035/309] Updating documentation Signed-off-by: cgoveas --- docs/source/samplefiles.rst | 78 +++++++++++++++++++++++++++++++++---- 1 file changed, 70 insertions(+), 8 deletions(-) diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index e3c9eb40f..102e89186 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -9,15 +9,75 @@ inventory file :: - [manager] - 10.5.0.101 + #Batch Scheduler: Slurm - [compute] - 10.5.0.102 - 10.5.0.103 + [slurm_control_node] - [login] - 10.5.0.104 + # node1 + + [slurmdbd] + + #node2 + + [slurm_node] + + #node3 + + #node4 + + [login] + + #node5 + + + + #General Cluster Storage + + #NFS node + + [nfs] + + #node10 + + + + [auth_server] + + #node12 + + #AI Scheduler: Kubernetes + + [kube_control_plane] + + # node1 + + [etcd] + + # node1 + + # node2in + + # node3 + + + + [kube_node] + + # node2 + + # node3 + + # node4 + + # node5 + + # node6 + + + + [calico_rr] + + #node7 pxe_mapping_file.csv @@ -59,8 +119,10 @@ NFS Server inventory file :: + #General Cluster Storage + #NFS node [nfs] - 10.5.0.104 + #node10 From 3bf15f7ea0d8d4bb709d018b7be9c860b70e5cb5 Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Thu, 18 Jan 2024 19:26:03 +0530 Subject: [PATCH 036/309] Update .all-contributorsrc Signed-off-by: Sujit Jadhav --- .all-contributorsrc | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 12bd721e2..0f02a6fee 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -633,6 +633,16 @@ "maintenance", "doc" ] + }, + { + "login": "MoshiBin", + "name": "Moshi Binyamini", + "avatar_url": "https://avatars.githubusercontent.com/u/1297388?v=4", + "profile": "https://github.com/MoshiBin", + "contributions": [ + "code", + "maintenance" + ] } ], "contributorsPerLine": 7, From d0eb197defc7f1b8ec58cfbe676a35e94b409b83 Mon Sep 17 00:00:00 2001 From: Sujit Jadhav Date: Fri, 19 Jan 2024 22:58:05 +0530 Subject: [PATCH 037/309] Update README.md Signed-off-by: Sujit Jadhav --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 7d800d95f..7a64b882a 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,8 @@ Our thanks go to everyone who makes Omnia possible ([emoji key](https://allcontr Lavanya Adhikari
    Lavanya Adhikari

    💻 Preeti Thankachan
    preeti-thankachan

    ⚠️ Boris Glimcher
    Boris Glimcher

    💻 🚧📖 + Moshi Binyamini
    +Moshi Binyamini

    💻🚧 From 438ad9f1b34b64e8971027b19f381d42bf2f371a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 23 Jan 2024 09:00:32 +0530 Subject: [PATCH 038/309] Updating documentation Signed-off-by: cgoveas --- .../source/Roles/Security/ReplicatingLDAP.rst | 52 +++++++++++++++++++ docs/source/Roles/Security/index.rst | 4 ++ 2 files changed, 56 insertions(+) create mode 100644 docs/source/Roles/Security/ReplicatingLDAP.rst diff --git a/docs/source/Roles/Security/ReplicatingLDAP.rst b/docs/source/Roles/Security/ReplicatingLDAP.rst new file mode 100644 index 000000000..59a49891b --- /dev/null +++ b/docs/source/Roles/Security/ReplicatingLDAP.rst @@ -0,0 +1,52 @@ +How to replicate LDAP +---------------------- +Once Omnia has set up an LDAP server for the cluster, external LDAP servers can be replicated onto the cluster LDAP server using the following steps. + +**[Optional]Create a replication user** + +1. Create an LDIF file (eg: ``replication_user.ldif``) containing the following information: + + * DN: The distinguished name that indicates where the user will be created. + * objectClass: The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. Here, the values are ``simpleSecurityObject``, ``account``, and ``shadowAccount``. + * UID: The username of the replication user. + * Description: A user-defined string describing the account. + * UserPassword: The SHA encrypted value of the intended user password. This can be obtained using ``slappasswd`` + +Below is a sample file: :: + + dn: uid=replicauser,dc=orchid,dc=cluster + objectClass: simpleSecurityObject + objectclass: account + objectClass: shadowAccount + uid: replicauser + description: Replication User + userPassword: {SSHA}BL5xdrUvHQ8GPvdvHhO/4OmKHYoXQlIK + +2. Run the command ``ldapadd -D -w < bind_password > -f replication_user.ldif`` to execute the LDIF file and create the account. + +**Initiate the replication** + +1. Create an LDIF file (eg: ``Replication.ldif``) containing the following information: + + * Provider: The IP address of the source LDAP server. + * binddn: The distinguished name of the replication user/admin user being used to authenticate the replication. + * searchbase: The groups of users to be replicated. + +Below is a sample file: :: + + dn: olcDatabase={1}mdb,cn=config + changetype: modify + add: olcSyncRepl + olcSyncRepl: rid=001 + provider=ldap://10.5.0.4:389/ + bindmethod=simple + binddn="uid=replica,dc=orchid,dc=cluster" + credentials=sync1234 + searchbase="dc=orchid,dc=cluster" + scope=sub + schemachecking=on + type=refreshAndPersist + retry="30 5 300 3" + interval=00:00:05:00 + +2. Run the command ``ldapadd -D cn=,cn=config -w < config_password > -f Replication.ldif`` to execute the LDIF file and initiate the replication. \ No newline at end of file diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 7d653bf35..3c76b4e5d 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -141,3 +141,7 @@ The inventory should contain compute, manager, login as per the inventory file i .. caution:: No users/groups will be created by Omnia. + +.. toctree:: + + ReplicatingLDAP From 8144104f93b7c1349b4a7c76e32ace4c69438cb5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 24 Jan 2024 11:15:44 +0530 Subject: [PATCH 039/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Roles/Security/ReplicatingLDAP.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/source/Roles/Security/ReplicatingLDAP.rst b/docs/source/Roles/Security/ReplicatingLDAP.rst index 59a49891b..00377f601 100644 --- a/docs/source/Roles/Security/ReplicatingLDAP.rst +++ b/docs/source/Roles/Security/ReplicatingLDAP.rst @@ -19,7 +19,7 @@ Below is a sample file: :: objectclass: account objectClass: shadowAccount uid: replicauser - description: Replication User + description: Replication User userPassword: {SSHA}BL5xdrUvHQ8GPvdvHhO/4OmKHYoXQlIK 2. Run the command ``ldapadd -D -w < bind_password > -f replication_user.ldif`` to execute the LDIF file and create the account. @@ -28,8 +28,9 @@ Below is a sample file: :: 1. Create an LDIF file (eg: ``Replication.ldif``) containing the following information: - * Provider: The IP address of the source LDAP server. + * Provider: The IP address of the source LDAP server. It is routed over the LDAP protocol and via port 389. * binddn: The distinguished name of the replication user/admin user being used to authenticate the replication. + * credentials: The corresponding password of the user indicated in ``binddn``. * searchbase: The groups of users to be replicated. Below is a sample file: :: @@ -38,7 +39,7 @@ Below is a sample file: :: changetype: modify add: olcSyncRepl olcSyncRepl: rid=001 - provider=ldap://10.5.0.4:389/ + provider=ldap://xx.xx.xx.xx:389/ bindmethod=simple binddn="uid=replica,dc=orchid,dc=cluster" credentials=sync1234 From dbd84555a987a3119354fa60a06831bdaf6805bf Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 24 Jan 2024 11:17:05 +0530 Subject: [PATCH 040/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Roles/Security/ReplicatingLDAP.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Security/ReplicatingLDAP.rst b/docs/source/Roles/Security/ReplicatingLDAP.rst index 00377f601..2488183c7 100644 --- a/docs/source/Roles/Security/ReplicatingLDAP.rst +++ b/docs/source/Roles/Security/ReplicatingLDAP.rst @@ -29,7 +29,7 @@ Below is a sample file: :: 1. Create an LDIF file (eg: ``Replication.ldif``) containing the following information: * Provider: The IP address of the source LDAP server. It is routed over the LDAP protocol and via port 389. - * binddn: The distinguished name of the replication user/admin user being used to authenticate the replication. + * binddn: The distinguished name of the dedicated replication user or admin user being used to authenticate the replication. * credentials: The corresponding password of the user indicated in ``binddn``. * searchbase: The groups of users to be replicated. @@ -41,7 +41,7 @@ Below is a sample file: :: olcSyncRepl: rid=001 provider=ldap://xx.xx.xx.xx:389/ bindmethod=simple - binddn="uid=replica,dc=orchid,dc=cluster" + binddn="uid=replicauser,dc=orchid,dc=cluster" credentials=sync1234 searchbase="dc=orchid,dc=cluster" scope=sub From 8448180b20ae4ec86f2ee26a688cf45b96195029 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 29 Jan 2024 10:55:18 +0530 Subject: [PATCH 041/309] Updating documentation Signed-off-by: cgoveas --- docs/source/Roles/Security/ReplicatingLDAP.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Security/ReplicatingLDAP.rst b/docs/source/Roles/Security/ReplicatingLDAP.rst index 2488183c7..dc20209d2 100644 --- a/docs/source/Roles/Security/ReplicatingLDAP.rst +++ b/docs/source/Roles/Security/ReplicatingLDAP.rst @@ -4,7 +4,7 @@ Once Omnia has set up an LDAP server for the cluster, external LDAP servers can **[Optional]Create a replication user** -1. Create an LDIF file (eg: ``replication_user.ldif``) containing the following information: +1. Create an LDIF file (eg: ``replication_user.ldif``) on the external LDAP server (source) containing the following information: * DN: The distinguished name that indicates where the user will be created. * objectClass: The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. Here, the values are ``simpleSecurityObject``, ``account``, and ``shadowAccount``. @@ -26,7 +26,7 @@ Below is a sample file: :: **Initiate the replication** -1. Create an LDIF file (eg: ``Replication.ldif``) containing the following information: +1. Create an LDIF file (eg: ``Replication.ldif``) on the auth server on the cluster (destination) containing the following information: * Provider: The IP address of the source LDAP server. It is routed over the LDAP protocol and via port 389. * binddn: The distinguished name of the dedicated replication user or admin user being used to authenticate the replication. From 6ee4337aeb998238dd8e64664853cc6e4840ab18 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 1 Feb 2024 11:02:55 +0530 Subject: [PATCH 042/309] Updating documentation Signed-off-by: Goveas --- docs/source/Overview/NetworkTopologies/dedicated.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/Overview/NetworkTopologies/dedicated.rst b/docs/source/Overview/NetworkTopologies/dedicated.rst index 6a7c723e1..0a0d8c5bf 100644 --- a/docs/source/Overview/NetworkTopologies/dedicated.rst +++ b/docs/source/Overview/NetworkTopologies/dedicated.rst @@ -23,4 +23,5 @@ When all compute nodes have their own public network access, ``primary_dns`` and When all compute nodes rely on the control plane for public network access, the variables ``primary_dns`` and ``secondary_dns`` in ``provision_config.yml`` are used to indicate that the control plane is the gateway for all compute nodes to get internet access. Since all public network traffic will be routed through the control plane, the user may have to take precautions to avoid bottlenecks in such a set-up. - +* `mapping <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.html>`_ +* `snmpwalk <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/snmp.html>`_ From fa88c92628b6513bb47e6ee1f1238922b545f9c0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 1 Feb 2024 11:32:38 +0530 Subject: [PATCH 043/309] Updating documentation Signed-off-by: Goveas --- docs/source/Overview/NetworkTopologies/lom.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Overview/NetworkTopologies/lom.rst b/docs/source/Overview/NetworkTopologies/lom.rst index ebc20b43a..e7e078ae4 100644 --- a/docs/source/Overview/NetworkTopologies/lom.rst +++ b/docs/source/Overview/NetworkTopologies/lom.rst @@ -10,7 +10,7 @@ A LOM port could be shared with the host operating system production traffic. Al **Recommended discovery mechanism** -* `mapping <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mapping.html>`_ +* `mapping <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.html>`_ * `bmc <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.html>`_ * `switch-based <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.html>`_ From 7e5c721e95a0994231041bbfd4985fc5cca4f4c3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 2 Feb 2024 13:59:32 +0530 Subject: [PATCH 044/309] Updating documentation Signed-off-by: Goveas --- .../Roles/Platform/InstallJupyterhub.rst | 37 +++++++++++++++++++ docs/source/Roles/Platform/index.rst | 2 + 2 files changed, 39 insertions(+) create mode 100644 docs/source/Roles/Platform/InstallJupyterhub.rst diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst new file mode 100644 index 000000000..2acfcde0f --- /dev/null +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -0,0 +1,37 @@ +Using Jupyterhub +----------------- + +Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jupyterhub is deployed, log into the UI to create your own notebook servers. For more information, `click here `_. + +**Prerequisites** + +* Ensure the kubernetes cluster is setup and working. If NVidia or AMD GPU acceleration is required for the notebook, install the Kubernetes NVidia or AMD GPU device plugin during Kubernetes deployment. +* Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. +* Review the ``omnia/tools/roles/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. +* Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. + + +**Deploying Jupyterhub** + +1. Change directories to the ``tools`` folder: :: + + cd tools + +2. Run the ``jupyterhub.yml`` playbook using: :: + + ansible-playbook jupyterhub.yml -i inventory + +.. note:: The default namespace for deployment is ``jupyterhub-omnia-ns``. + + +**Accessing the Jupyterhub UI** + +1. Verify that the Jupyterhub service is running using metallab loadbalancer. +2. Find the IP address of the Jupyterhub service using: :: + + kubectl get svc -n jupyterhub-omnia-ns + +The IP address is listed against ``proxy-public-service``. + +3. For the first log in, use the Login Node. Ensure the login node has an OS installed with GUI support. Use any browser to log in with user credentials. +4. Choose your preferred notebook server option and click on **Start**. A pod will be created for the user. Available server options will depend on the user logging in. diff --git a/docs/source/Roles/Platform/index.rst b/docs/source/Roles/Platform/index.rst index 6947dca54..fcb8ea622 100644 --- a/docs/source/Roles/Platform/index.rst +++ b/docs/source/Roles/Platform/index.rst @@ -16,3 +16,5 @@ Commands to install JupyterHub and Kubeflow: :: * Run the Kubernetes and Kubeflow playbooks. +.. toctree:: + InstallJupyterhub \ No newline at end of file From 705bb47541b269b0de7aaa2228adff8de6f3d5ff Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 2 Feb 2024 15:00:04 +0530 Subject: [PATCH 045/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/Roles/index.rst b/docs/source/Roles/index.rst index 068c7cd5e..309ef3d94 100644 --- a/docs/source/Roles/index.rst +++ b/docs/source/Roles/index.rst @@ -13,6 +13,7 @@ Below is a list of all Omnia's features: Storage/index Accelerator/index Airgap/index + Platform/index Utils/index Telemetry/index From 2ea9130d78b95827e3142d4cc8f36e28f8dfee2b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 2 Feb 2024 18:25:41 +0530 Subject: [PATCH 046/309] Updating documentation Signed-off-by: Goveas --- docs/source/Appendices/BeeGFSServer.rst | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/source/Appendices/BeeGFSServer.rst b/docs/source/Appendices/BeeGFSServer.rst index d9da45379..618b09627 100644 --- a/docs/source/Appendices/BeeGFSServer.rst +++ b/docs/source/Appendices/BeeGFSServer.rst @@ -1,13 +1,19 @@ Setting up the BeeGFS server ----------------------------- -1. Download and install the required BeeGFS version using the below command: :: +1. Download and install the required BeeGFS version for Rocky and RHEL servers using the below commands: :: wget -O /etc/yum.repos.d/beegfs_rhel8.repo https://www.beegfs.io/release/beegfs_7.3.2/dists/beegfs-rhel8.repo yum install beegfs-mgmtd -y beegfs-meta libbeegfs-ib beegfs-storage -y -.. note:: These steps can safely be used on Rocky and RHEL servers. +For an Ubuntu server, use these additional steps: + + i. Configure the repo ``sources.list.d``. Ensure that the version of the repository matches the Ubuntu OS in use (Jammy or Focal). For more information, `click here `_. + ii. Add `a GPG key `_. + iii. Update the apt cache. :: + + apt-cache update 2. Create a directory for BeeGFS storage configuration: :: @@ -19,9 +25,11 @@ Setting up the BeeGFS server dd if=/dev/random of=/etc/beegfs/connauthfile bs=128 count=1 4. Setup the BeeGFS services: + - Manager: ``/opt/beegfs/sbin/beegfs-setup-mgmtd -p /data/beegfs/beegfs_mgmtd`` - Meta: ``/opt/beegfs/sbin/beegfs-setup-meta -p /data/beegfs/beegfs_meta -s 2 -m `` - Storage: ``/opt/beegfs/sbin/beegfs-setup-storage -p /root/test_beegfs -s 3 -i 301 -m `` + 5. Append ``connAuthFile = /etc/beegfs/connauthfile`` in the following files: _ ``/etc/beegfs/beegfs-mgmtd.conf`` From 6282be576dd1858bd303aacf96c8554e5d9b8cc6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Sun, 4 Feb 2024 12:45:47 +0530 Subject: [PATCH 047/309] Updating documentation Signed-off-by: Goveas --- docs/source/Appendices/BeeGFSServer.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/Appendices/BeeGFSServer.rst b/docs/source/Appendices/BeeGFSServer.rst index 618b09627..ad95f35da 100644 --- a/docs/source/Appendices/BeeGFSServer.rst +++ b/docs/source/Appendices/BeeGFSServer.rst @@ -39,6 +39,7 @@ For an Ubuntu server, use these additional steps: _ ``/etc/beegfs/beegfs-meta.conf`` 6. Start BeeGFS services by running the following commands: + - Manager: ``systemctl start beegfs-mgmtd`` - Meta: ``systemctl start beegfs-meta`` - Storage: ``systemctl start beegfs-storage`` From 19f54cb964b87d3f5a423d2567e2166864840b49 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 5 Feb 2024 07:27:15 +0530 Subject: [PATCH 048/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/InstallJupyterhub.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 2acfcde0f..c2fb5b849 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -8,6 +8,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Ensure the kubernetes cluster is setup and working. If NVidia or AMD GPU acceleration is required for the notebook, install the Kubernetes NVidia or AMD GPU device plugin during Kubernetes deployment. * Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. * Review the ``omnia/tools/roles/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. +* Update the ``omnia/input/software_config.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. @@ -26,7 +27,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup **Accessing the Jupyterhub UI** -1. Verify that the Jupyterhub service is running using metallab loadbalancer. +1. Verify that the Jupyterhub service is running using metallb loadbalancer. 2. Find the IP address of the Jupyterhub service using: :: kubectl get svc -n jupyterhub-omnia-ns @@ -35,3 +36,10 @@ The IP address is listed against ``proxy-public-service``. 3. For the first log in, use the Login Node. Ensure the login node has an OS installed with GUI support. Use any browser to log in with user credentials. 4. Choose your preferred notebook server option and click on **Start**. A pod will be created for the user. Available server options will depend on the user logging in. + +**Stopping the Notebook server** + +1. Click **File > Hub Control Plane**. +2. Select **Stop Server**. + +**Note:** Stopping the notebook server only terminates the user pod. The users data persists and can be accessed by loggin in and starting the notebook server again. From 2c3af334e6d34327baae9d523c87bee92253d64b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 5 Feb 2024 07:32:57 +0530 Subject: [PATCH 049/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/InstallJupyterhub.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index c2fb5b849..21773a828 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -35,11 +35,11 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup The IP address is listed against ``proxy-public-service``. 3. For the first log in, use the Login Node. Ensure the login node has an OS installed with GUI support. Use any browser to log in with user credentials. -4. Choose your preferred notebook server option and click on **Start**. A pod will be created for the user. Available server options will depend on the user logging in. +4. Choose your preferred notebook server option and click **Start**. A pod will be created for the user. Available server options will depend on the user logging in. **Stopping the Notebook server** 1. Click **File > Hub Control Plane**. 2. Select **Stop Server**. -**Note:** Stopping the notebook server only terminates the user pod. The users data persists and can be accessed by loggin in and starting the notebook server again. +.. note:: Stopping the notebook server only terminates the user pod. The users data persists and can be accessed by loggin in and starting the notebook server again. From db57ea08137578a7b2db149b142b0e25c6e43a0d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 5 Feb 2024 10:38:38 +0530 Subject: [PATCH 050/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/Roles/index.rst b/docs/source/Roles/index.rst index 309ef3d94..b6c696ec9 100644 --- a/docs/source/Roles/index.rst +++ b/docs/source/Roles/index.rst @@ -12,6 +12,7 @@ Below is a list of all Omnia's features: Security/index Storage/index Accelerator/index + Platform/index Airgap/index Platform/index Utils/index From 59d4e851253334bc98899bf140f1997bcea4734b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 5 Feb 2024 15:18:47 +0530 Subject: [PATCH 051/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Security/index.rst | 41 ++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 3c76b4e5d..058c4af84 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -140,8 +140,45 @@ The inventory should contain compute, manager, login as per the inventory file i * If a subsequent run of ``security.yml`` fails, the ``security_config.yml`` file will be unencrypted. -.. caution:: No users/groups will be created by Omnia. +.. caution:: No users will be created by Omnia. + +Create a new user on OpenLDAP +----------------------------- + +1. Create an LDIF file (eg: ``create_user.ldif``) on the auth server containing the following information: + + * DN: The distinguished name that indicates where the user will be created. + * objectClass: The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. Here, the values are ``inetOrgPerson``, ``posixAccount``, and ``shadowAccount``. + * UID: The username of the replication user. + * sn: The surname of the intended user. + * cn: The given name of the intended user. + * + +Below is a sample file: :: + + dn: uid=testuser1,ou=People,dc=orchid,dc=cluster + objectClass: inetOrgPerson + objectClass: posixAccount + objectClass: shadowAccount + cn: testuser1 + sn: testuser1 + loginShell: /bin/bash + uidNumber: 2000 + gidNumber: 2000 + homeDirectory: /home/testuser1 + shadowLastChange: 0 + shadowMax: 0 + shadowWarning: 0 + + dn: cn=testuser1,ou=Group,dc=orchid,dc=cluster + objectClass: posixGroup + cn: testuser1 + gidNumber: 2000 + memberUid: testuser1 + +2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. +3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``testuser1,ou=People,dc=orchid,dc=cluster``) -.. toctree:: +.. toctree:: ReplicatingLDAP From f280f2b5c2ca8df16b5af5a46f2c1fc01c68ddb5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 5 Feb 2024 16:10:08 +0530 Subject: [PATCH 052/309] Updating documentation Signed-off-by: Goveas --- .../source/Roles/Platform/InstallJupyterhub.rst | 13 ++++++++++--- docs/source/Roles/Security/index.rst | 1 - docs/source/images/Jupyterhub_Login.png | Bin 0 -> 71873 bytes docs/source/images/Jupyterhub_UI.png | Bin 0 -> 89286 bytes docs/source/images/Jupyterhub_UI_2.png | Bin 0 -> 82806 bytes 5 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 docs/source/images/Jupyterhub_Login.png create mode 100644 docs/source/images/Jupyterhub_UI.png create mode 100644 docs/source/images/Jupyterhub_UI_2.png diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 21773a828..093cc8315 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -7,7 +7,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Ensure the kubernetes cluster is setup and working. If NVidia or AMD GPU acceleration is required for the notebook, install the Kubernetes NVidia or AMD GPU device plugin during Kubernetes deployment. * Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. -* Review the ``omnia/tools/roles/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. +* Review the ``omnia/tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. * Update the ``omnia/input/software_config.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. @@ -22,7 +22,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup ansible-playbook jupyterhub.yml -i inventory -.. note:: The default namespace for deployment is ``jupyterhub-omnia-ns``. +.. note:: The default namespace for deployment is ``jupyterhub``. **Accessing the Jupyterhub UI** @@ -30,13 +30,20 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup 1. Verify that the Jupyterhub service is running using metallb loadbalancer. 2. Find the IP address of the Jupyterhub service using: :: - kubectl get svc -n jupyterhub-omnia-ns + kubectl get svc -n jupyterhub The IP address is listed against ``proxy-public-service``. 3. For the first log in, use the Login Node. Ensure the login node has an OS installed with GUI support. Use any browser to log in with user credentials. + +.. image:: ../../images/Jupyterhub_Login.png + 4. Choose your preferred notebook server option and click **Start**. A pod will be created for the user. Available server options will depend on the user logging in. +.. image:: ../../images/Jupyterhub_UI.png + +.. image:: ../../images/Jupyterhub_UI_2.png + **Stopping the Notebook server** 1. Click **File > Hub Control Plane**. diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 058c4af84..5e9c68998 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -152,7 +152,6 @@ Create a new user on OpenLDAP * UID: The username of the replication user. * sn: The surname of the intended user. * cn: The given name of the intended user. - * Below is a sample file: :: diff --git a/docs/source/images/Jupyterhub_Login.png b/docs/source/images/Jupyterhub_Login.png new file mode 100644 index 0000000000000000000000000000000000000000..3a140507aba81238e97b0c83b18988a379dd3a6b GIT binary patch literal 71873 zcmeFZbySpH_dhJ%Dcvd3pmcXi*N{Vql$3N1-JwV+NQ%@*iGcKw3P^{7GK9d;T?5Sg z25;~0b3ga*{qOzbUF%)nwJsKG;yUN-y+3Dv_TFb-lc=w&PJ~Z~f9K8}B25hy!#j5{ zOz+%5C&a}@y>liftBd-F=3}U?bf;#NVH5QN(@9ZB@y?z4bb@O;EYxc}FAZ~_J9o%^ zZ~xF1pD+jBxq~dzR8cezwAr}{@MZX(Ri3;x);8O=-61U-5X@mx`8H#F&!yA_U$ z=G)v_maSzdSsz+o1yI%NiN2#qV=*4$c_)}aD&h_iYzcNpDsaC;d;ji5M~B|yJ9t6{ z#E)NSK6MV`eaNoMKn)p3Y~@QFzGuEZ7^H!ui`bZ6$6QqI8#zg&+MgU24#FI|?iE@V z)+!ZAVXt^IQa>-$w@^ZcVrm_m-~zD8gajAQjF=IQX;Ir^nd#v_oKM0Km|EvC`hM5w zolm9S)Mj*n=EvB_>w(x(XO1ge@(7plqgCb`vha&uc`{5z(wM<+<|(ASA^0%m0fRb- zEI9u?O=% z8wkkV7lzIR9=2VG37=eXA_zlw=A3rmDbyZ%MZ1NAbCOSJJcdg{op6E7S7Z`}f>Fn1 zdVV#&o$=J51B`h@n3SjS?0FomHM4BtvIFgIsC-oTUYF*D)YRpJg+VrbxWYo`NasXo zR-;t-V7tP`@)~nHL*w<*TFzmZA}OX~AYuE-gF!)r_vnX5MJ-xf`f$&J!@*YwnF9YC z76raTzGDaS9?v&pa_M7SyxmQ94Y}Ipy;dVi_m;bMugkgz@ex)By>qpNy`_U7O_-JQ z#+u9n!N<#w)UYQ%T(nykx%XnqWG}5=kMS4os~^UZ}pz5tR@TvQ-@58_+pA9eB4JrSfZ;_sgh#J{QUfmR7gK0C!$jr7ltoWLamTb1Bt7D3$)i~;xTqCUv|aRb z^&G1g`5?d#BqS0>MjnN_-G?ES@+rPuF73npDGyQ?H=3b)SH>6nNPL-$fP)n}c+Gh{ zVslc?#4?B;D)fWHI6P|gmpi+oQ;X+msIS@{Jx|WjlS(={Pve>)v*Em{3cbY|xsUEr z0&spA**FCM?ZiDQgMxBo1Lw1-k2C?nsSd59ofZfIY4Ol#7-Sl{+QKDc1qP9KWL^Gcbo?Q{#P zF4ZIoiIDoT&@LYV~ zp|Zgc^x8!3#3(T<6}~WPbS8u0)q*fPCSpD5?85$@7ZhTx6yM~+^8z#Vi_wl72X z4a-bivV9ZnRy|V^1!CH*d+32bAX!na@I$ra*S)|(suUxA-33VgY0fWxJ@OrKySc9GgYWiAnm~p6LOxJFO9t1518zH5wF~jEi zw0gVpm!;|e^%a*zz82P(uXv=)GD%j~eU0Oy=LgtLLu(}U-WOgUuGJP2ELSdpYOqj_ zz>e)914>5rKQcNbQR2)#sirk;!@^+r{6d2Ey=krtMjcT^R0ug=hCtp|;^d!1$zO0^ zeu)XMCQzGWY4ACE-Y7)Y=D(}p?oPQQMu4?7fB*CN2kGFV3r;DWmuRwKOCnlYaYu7B zyq>Zo{5Klh1{av0fmJ8%KRm?SnQGy(zI>LVH)pkZRmZR+lTNv5F{;;gfo;)OG!b9y zW7?|8VU-aJ^R;R(jf2ZW?gKx1C6FMWowQcKTN=sKvDU^6KW|KbMW2BZxdjl&#QDSB z4K`GU_2i#`5mTdi2fnzzx+ss0lCxw`y60FEwUPPA^}#zboT(g<>RA@^mgAmVI5!c! zPwz#tO{|a+IdCzgstU=EL>0sM2+tdAYg_R{oH$3G@Dftdk2*QAv+*ztXA3Hu2XXJn zq^2I1Kbs!%x5CTj=;<<4w(oPS+NTSS#V7|+AVnOC%V!F?={kNgcRWq*M^7JAezwBo z{R0-fDP!p5k%tVAQXOQ*(d%Uo`XKf*_VU6CFv=g(QA#H;zmD21Z5SQ`IqF%Nn8NJG zjO1)mKwa_O0AYb|fFVH5jwygp*30@E{%~<+9fi|`oK!Q%lt51E&`RsohWJRSBOVI8 zw@#!lcJ+qLe(jkXL?Zq3wCJ?M!l=8(_nf3r4-9PVJ2{mE>(>~tpYk{z)!}G^lZB9u zUwTUxM-Nv(JsmfU5&|_5Wy@&u7O$V1=||)*sKR!{39*o_-k90%ij(wT8Iy6|=~S>O zb1W{_>u69;!9RAuHUsBI;WU&J$YOZIg#f5()jSRl_#)P$^-0h zvn`4aeAQ~}a;z?TIoUV#zCeA|C8TM{O$dyXgd57my#JIr#H3$p!Dlj0AwLu!lQ_|r zIOJ%|c>P${J)p9m2LNt)n)4Oi$P;HLzQ@k`a877Z;_W-S*A-8*mzINFcV`#iLGDzy zhDWh=;%9dIGBtaRsz3)L?T2C>-xJ*10*WiE32Ndjy%-33ZCCV`h%fc(;=^$Yo_qGv zpRvi1LF2{YT|JbiICTSI%mX^L-63xBe6ox%A2d@z4H^lB@}m5*Audy8MJW@NFIdTM z$hq);nJA21H72D|@u<-oOkjZAjT5)WDptb=8y=avn~Hv%P%Csb)@4*5^kG6fV&<8` z*|7UyF)=@zWIfI0HuqlD$md}@h7IRa9{H{lnXI%zgAV}yx=C+WVO*fBAH;Aoljcy^ zib>ILLsjla<5!DU7*p?%5spZTZWB#y7^eJ}t|{ zw1B$YKusmEvvY-_wFAFY@))G)bfb7nq6X7SnAP zuHAB9B7xti5O_a$5mf8PZp*N3Haq%=oTxByYOVXlhEZiY1dofyRh4tdPpzKkgOVZG@zPY}W1UbL@s3bDw&c!j4%+b|%7`J- z4~Fj@O3j3T1HG}zza;I|@U%P&fP`>R%;MuuzY)v*(as=U=1rI$=nQGa;4I_J?P8&7 z^WRr-Q|HZRq9z;&-_iUT-S<}IN2iZvnZu!->(|jx<^HLjr>?$gAp`LbS6!Sax)ZWSK&qg;s~$k4!&Ryk*v|B$BY@hoLljRlnX06?9&J&vmX6b+{jspz#Q}y@TX^bZ zhRlUph?KN+y_Yw+4Hx9g*I|<&ujmFrCx;;l@`6_nNy%u_vZ~Eix{EQsH8>DF8GV&# z7JlXS^n24Ql?t;|CPqE!G+@UO@6#Xc2C24(33v4_w|BO>TTizSAiqew;3M2LnT?JP zmr0M?k4L2g&u`9+7p2d4`eKu*Gw+*ocM*Kw5Dpr8+$WF#seH)gy}siDHgCh;fBxe= zw2^7|&F*WKjJM#07OH){@WROfwqP3(Dt?=o;|;;?M?sP}?LsCL-A!kp-VQkPMB5qB z$x&u^ilY!is?vE$S1d0=&u&;U!bbYb>s}0XGxijEn^>PiB!SZ@BTxKjv=59DlSj`QobN1UG5UMdH;vu zgMq1&Cu0TCpDQ#nv$Lz*`OMa`9CPnV;gA`SRd`mIu{-klWto^HB&8T`@>cV5cUXq_ z5ASyOX5i#fOOtrxc~?}|mhDc5m#03iBH}gUAKa1r@FJ&>Bz^xof3_r5ugk-CtB=&A zT7z3BoH#1kHrZ;UJ|0o=@gljv+6eL+C$sJ!CW&Y{L`*(7@DH;Pvf~FMSLMCqgHw1N zUcTbJb%#U}IS4@sw>_TvhL-^I&Coz8t%)2dB3W$&-RvYmU2A(CZL6&mBbwz3iJc9S zmuAng`_V?C8FAx5XTEiv(f0wJuE@%=l)famT0t%Op8!dHsVgNVMZG_%o?EivrG8ik z8U76|kNaD8uh)X?rZ2hlh*?Y-0WBPOFBf0MMCD;=c>uy|tlQ$mLCAL&wj~W!hO*+0 zBJ^2HH2i9!9}iyY$s3dcWcbHyg=~-4zi#FFX3$fKgi~z|o$|VhxcrRsbIr4`jT(Ai z0aiiz-q%q8OS9@pp899sz0ZD_bGoaiG0q-|(Q5?qxdz)lS(oJWtE{Z#(7~vx*%q%E zbn|R~Cnp`!y2Qv3@v~nL=~r>rp|&#;Au6xF0f%<~@M0F2e^Tdqvsv{{Oz?)Drnw6* zz@eC&&CQH4#d0ym=es<_Tv`h(HEb&-gb}8Vq@pSWydvrlD*GBOdg&zegukp))IdH+ zGo`Yly-?+A!?tWLHG-QkmTUUzV}3hBXvFdT+t?a)-K9m)8-e5c?ss<%_RmpP6O&iJ zRpl`C)T5)TU)ccFSdT$0_uEs;hO>K|A5@s21tl@*DL0bIxQecQ(5rj$)AfY@N?74R z?-ULfNQAc9v{r>0k63VcwBh)BeF9`&?SdLFmFflXZq7t-@5!ZMe*ykF7 z*f?tO=HHN74BNLpwR&kWpFf@>()?|tB|C(OIsAk*yY`W(;N@BuJWh(wyb1He#;B5} zxp38Xm9X^VCW}X5I)7^L|Z##b$@{QNW&b!TS$31DCo^vhAS4M5eF8LvY@b%RC3&0J*NI)7yObMK?1t!c9?`}Hk>J7G& zOf>0A_^a*|#ex}uENB6QEmq_Rn4a%L&FuTxjrmO5e@GH&JbTtaSKk_Zy7e4zn4rg% zX!76-Su$Zd&*9bEADJY{GbnV=_Sin?dHS(pqZ*JDsI|0tGUcj>AKqCxHeRmQ`iP31 zm{~R^01BesXc%3-?&llH6=g*2I)gFyLnS)6ba|D=J0(r@@`$Nu~Dq_eMf53c?JAf`n{O@_Y^Z|ASJ4xcR;wczsN@W zwjn=S#@^)4a2&9w^Bm)w#qbhG{m}s%D~EV?T)a>XGT_8Lh^U~IUTA?q$oFGW$o7H| zCz2$0>zN&+FGMZs$vyL{g2L6S33k&~z@Z%R ziMYp)ioUI1UtaR?;~?5=!R>@ECSGV|9N`~ngfi4+P0_A=cayz;X&er;0sZkJrA#WxJIq};=54DCg->2PVC{MuITSvrccOur@maeRux`a zm7Fp0QFpl|r!C(wiVE!n60LKBh#bB-xe01O|6>b`z zV@}fE0CkpN?2VMDz4!U@fFKN`Y^Hx}u_I(lRu^upusCS%f3{;DdH}&mNJ}%VKJ)YQ ztIWD?a$k5?pcjmcK98fSUE*9m#y>iQ=Xoxjirc7fb#`dg1k#?qo4uDW7lQBEbtPuM zK3Mb?tb#|DOgXHl2TTvXm!$rFG5DOH5BQ0J(V9`~*~KMKwpjJoB=`Wfl$l(@{Hdr+d4LE6;wfuX_=>`=?{|`4;Mdu^{E~+o6+<6#iOX|6?_J&@VF6zsaKE5 ztGi-PojJfW0poK&u^dj_bM?4-Xp!o5d~n(kP8musQd0-*16M)zp1e z6V>$-*^YBID{iGSDLR}&vp?dZW7x)TokPI>qRD>zWWUx}ZA}gF;o)K6T9%oR!vLXZ ziDLlciRtB` zU>k;!>a#;OO8*>d9UPHdLJ81eyTwd;j)Ht%xLPWY%b31Psa;AU#|z;4@Y+#ZgDKb| zQTuz&v=WVs^>g(xxi@fbO=xvOQsO}Nu4TRZhJW8czy0aFsI#kwp%Im=O)dOp7j5D0gx~Fg=K6PbV*ZXm=)H9wM1GmK89Js-4i*YW))n2ln zBT|RN+t7@@i{^^o&^5)#M+IGR9#T-?!@iZ_O!yfAi9I!>64~USxQa*BB&_R-1`2ZwYc}?v~fEh zVe-wSPw;E_ugR^-)jKvmt7V+r7nt9V%aY^&nJV=2Tl(UMLm|_(mm-9EtMo*}CI$v% z;m9i}Z@sIVn~`C^5gMxcT5#{P5qfD!2`N2&b+&p}0Fp@n_z7H4)~XGaWM(oL`tr5k z(zEM*6ZP}Q@2#74`BOVt!qLP$<`a6_V&`%1>J74!*`Htucu+46OuHCq&X*Wi0;^Tx z)pG+mG&?AA(w5Jy4)1>(wU!o^7a-PtnX|l7rmZz{5yVFYjG{U*I#Nz4&6 zJ?1Zkvo~syJDJn%>w)!@!&*kkx&GzFw_v;bas&&J<_CNEm>V?#wvV(Us&{w@#r3*1 zN*viHKDM>jy@K1dHqZ_ve-WC7#&Qc{t%ospH=Uo??S&Dnp9JP^Cu!Wjylkj1_xYdT z!08bxVk!Y-kCA0kRfGS>UU7+u@!?ns9z9`)!>_XRh4a&Zq%xcDH38c8{bLfR`twOc_#$GWRVH`Lvo8RmC2COfia=4t zf|_Q(1=DuqGLA&h7RLzH2d!$*kuYBbAHb^l-TIUFavbLEELff!QU?_B@7ii{bl!ix zUt6ORM41Iu%FwdkIt`w2rfg15cbM2>pIF7>{c%m0y+u!69;p~;P1Q1AwY*ssH3u=m z?eJ=o)v9Y3yKBYY?-d|EAtq>L6F!@q#(2`bBhouDLl}VZrhK05yvQ02}#$QN2)pQskiq4LAfE?>IGPXMJS! zE&C=QcTBLfs3R3UTzu`k0(H!AphWoQ&6{tne!PpJ$2ttM!NzzQ1!~lMh!b^G*^CKp zeAHj6)hH`2PQBl8USpy2T)hn&2gd|;bmOnvD~Q=tVR8wGdFl$cHPaJMD`Om-cA0wK zB7~RvRmVb-L)(fvtTAbOxYRI|Z{w@q65OZrI*&6|y-`9IDfa5?mN;`Sy9M8UnO*OQ zw_j8TT_&APHiHcC1>{&o_i z2zsAGd>w)N-Ro-|)t)`RfpiRsg1z*Y$k>NF$SBDZ`Cf)29HCeQ7oZ1uryv2zY$XiB zU4R$%J_}2yBU-kV)wdm0vKOJt!ack{^H%dEDH&Ph(a|&hrSq4(aiHzG=LcfCgV0?L z5WEr6-Y%0hHVt&5P?@Fv43AxIZbxM;eSc_F}Y{Zgo zZ2e%o={K=GczIZn4nHY#P&8z>v=Rr>saXz%KDNn^17d?2xAn(#KLJ)?Q=3ORSF5X8 zp%cQ5soQIYr8>s%zACxEUY;LTWWDT9p&nq7(4*JPnNe}BCOWF$k^owpFovB@fv(Q$ z3v_=6SBj(s*siv#++-DU4v#87!fzA;-|8O^TS8(~gdB z%t{~SlcYb{yu8Z!0$aElUfYFhdcC|;`4Zv+Fx1$}=QHVC^=-Tkh57-&p;uXeO?GuY zBm7+&KX5JMyckd3WP@*|OL+SmOvAF(ewDyJq3(*}zcz2JY%KtF&YQfQ4ioa+0_U}mDTo&XFa-`K5@BK7kEGr;rX+* zOf8X)jxJ73JFaXsd4e-`*~MRGCLJhdWnviayap2xBb5IAnvi2dQQc%1EVq3 z{#0Mm@sa!a?wm?$nbxqG{NHwq8B|xOpX@JcX`yKg*dNH|x18oeu5Z)?nka-L;?<1- zD$`=&gBiossdf6K@=6SynE8lmtt=Zoxj4@F^bM!Vi%&dM_c;yFwn~Qa1Vcun9EIpU zxncL{2Zfqa=tn@PS*J7@0b)5*RUyeYjnyFBB4Q6jfCLmO0&52`m@gO?lF zs|M8(KHwqgf)i$aSs17&|69*!6RU{&C6Vi#f&!*M9$Ot9qRGk0=NTDMM&-Jd0a}}- z^6huf<(YpqzI^`elF?)yH@)C6CvvJ`+z6=fYNOXurl~(w;s%1G+k^cJQqHI-@%wYdU5+wnNplA5;y3XmBF`i3;=K@qfO(8Ym0tfYElDSm%%8N^W#B?)`R_&70 zbKl4#hel&zU~?Lf85ovH=;CK!SVmJrpohgkey^r9gJ;0=inR29Jj;Q^QkO7wtu4Ux zgse>As_qMcoOa5kAN(g~4D`pNV3w~A zEe3d(aIw;-V~F02c^Dl8oGys9^R+dlHy`7N$V|Qqn=2rgI(MsBHKBtZTa=!GWF?q^ zmxa+hQzSLzre?br-9b1}3+ryojI}xPjj5BcDaJoZ)UtW}>T!7@RSwDEE?r|f?R>3l zS}*9;t5+AvwqPn)PPImLvEI%vZt&oOqhHa|7D|T1DOo^KUk>!te zwU4O_hCF8U?W}mzVN;q;pDOqU#Qb*%@Nfu5bD6j98jVW6FTi(^<%#};tWj&zN3FclY)Jc@e3E2 z8ot%6aC2!QoJ$B3pX%rM`|bpV!=0(}xqYM3v2O(XMbw`zB`>H14Va8uWW9o|d(8UQ zh{kh(7~-^_+#-(t*?*lLcr zxuoY~trBwE+ZgR(#CWOYVKhu-%A zN`ZK=Hm3i2Llyjswz_t3L)L-Q{&#~%&%@Y+nHVm8nX5*;`=(4`JVmINihWwYkBy5I z`&@hO-Y*E7zet`L_eV_~|DUPMu%e?R&ElMXt`WPmRef>3T<1`GYCb}S2uDgJhiV>ppfaa>8{oG45v zjg!M{crek}O#k+i!E(6w<@Ip6G_zhtXBc4OTjeUapu)KVsZja5Q6&Eb9rB{V#3^a` z^)vmI2saA&S^ZfX41fZYQ{;4cx$JNdpE3(iATgkAQ6xb;~OSf%Qk(?G=++ZHL zT^~V8OD!JcmX!av;Q|tLyoptXmsJxR+3Ka&=$UBD$_u{rM^GwE*zN(Bz7%RT1ZsY5* zoJ;)o3L(y{!TE$a%J!nR>^r`lKfPLIy*_oEgxwJke5ldolBeAkelhj6!mY3LAVmo( zH;YgRojGwhG&v4raKw)~*jWORP@=^Bv)NNPO@WkT)#chOtaO5E)e5aCweRY4hkoEtoqnP*o+3IDMg1%)V3Yz9Cjt$Es>^1~E36K>Qx)+a zUgTBQ5}jR@FMs}tt_|^^@z_yCe!YQh==JD7uWGtv~O%kV{8XA3ehbWnE)6sJ`kLh-1RyW?UB6y?DP?e;{GsO^+vRUy@-wRqFnvT z{vH|^HVm}4$CIl!&|80jjFjGy_EPD@w46RqWG1vb=gJ8BPU4>DP8e9&drq66uqk?f zzd~?;igai=-p2E$ttsp=T;UQwiqt9>)@he=9d6qLjB$Y!_7-$%yyT_*6zq@U<9}d7 zm`+gHu*|D_xyfbfI%(9f`_Sk_wLPKpASW?rTu)I0bU`3AUe06F3Hpe|k8d|4}u7Ya_Cw_nlgPnMIA zM=lMUA?{xW*Y1}g1UZZ`=={?${Nq)zsNZdK zQ+Vl*lO4*Qs6RJWZC402vnzsP&(|DgsJ%@u-iI>V_f6B!%X1j}w!>u`3%lHC*kFL3 z&*PnBmsdl3BoUxD#*0#!@!VTDLWf*y4kco_s6L2n;i#s&R#cu-TV;nD(pZYPJm^E2 z@>@11VE~_iWPmL10U>@i50t`BF>sdbcZh=`398aVg$MmgWxYtQ^+t%cIIiWM4WI`g zVWR}1(A0j5%K9+N3RP4Gg`#pOZzkkpAn`9=sgH*{wA|Cd#&;z&fFp9^4;gEV8LPwQ zj`q`68V1$Mj!E)ifV&U()rAafw%W+~Tnp#b7b+RTuAajx+eNMycu*P>QYt}bwLjgt z#VPIY2n>bO?q?@{6Yr2Nf>`&ke^^Kg@c!_PuKQKiL$14`NZv;-Dg!^s*l)WhsEpo= zHbUBK__i;hlSI>qqgbuy0)T3E4(d{pE;wf3@lomQb%d94j19uV5QD^7iVIoB-rpZ# z&P<$J-xZMmG)XIk+B-#2`xu4s2{RuOHU8osul5`yKs@PD3{12S?+4-+inaa%W_QWB z$nco7W^S?rEa>>(n9ecxs2DmHwbBIg6wS-U0Vd>-aMVuXBZP{hv!No=9*O_43i;dG zVdu(cA+lb_mz?!0mNDG&sv&!yxl9>~2ovvWzlds@+8Fom*}0mIrpu1Li}t& zNc|>Z=!W}deWUQcAak(L;}V6>BZlvm+{67!qRl18wKa+q{r?DlZQk;$UCR3 zNUoXVt2!fVu(15B+I;BXgzEKo#3hWj-SN&E3A`Cgvs~BM}Nk7^UJ3lO;*v^Qauegt_B)3`aWjVokQ!A3d$wlT9;FVxpyf3R-@0FK?^|E8UmBwYWcpd8mKf7^U2#lWDVqSk)w7XN&g*d^zGC7tE_nU=GaALPF^oVcL!vUk#6VWGp3S*S zaw{H26h!;eSQnWV*uwL{Rxc#FZyzh;VMap&vy00nAl%%GBx_22%|*N0hY3aY0k;{G zknUfJ5h@VD+}u8fRYkbA>48UrD%q)O$D>I(O;QB-(u>k9IxuY62z-Pd0=`SSw#2vSsN# z5KUL%fnxz2I^#!!-XlHR!gB|SN*RKiz0@GuxJ$tv@+5qtce&mJqTLn}?DGH0Dho)MvPut2w6o%Rw-4@CcW{`>;J;1GLgY_A2M9Z0 z3G$gTfa?IUFLQUSFtvfwggH><{d^>btPkR03M;5ctuMH#CgvlIB3~UCDY{b*gUT^B zft>+4NUYW;sJ3k4tB1KwgAi|Toc7DMB?(IO<3!BdG5$Et%P~9rE6bKM_lVtJGT$D~ z_IR&KFf{A-zUaV@J4LFTu2a*0urdhKXbF4`1Wu>lM~d6(C9@Y_L0ub%n%o4eHmjE; zni$r3xrJoD;S8Q;2{Eu-vK<Z_5DlVY{h6SF#hv~~er zmRTS5#$8Qg0V#qWr>Ln7E~o{jBj0s+4vpQCRdYHNNitpU8T`wt z=))6%G_?TlrIm9_#ldl|+JiY}1o{_3M&|P_yHCDMqi1R-%~lbggs_?#B>=PSS{bM1 zLWjm}6-e||uzcj^Qg}&v9zyEA9QBOD_zoYJ_43&hSTB?9n6v!fERWzg}pO z^p2C)kDw)VX_IZFWL9Uxm~euT!nnJ-5?*02UFaK`a63CbS+mFOCAygX6qsn zDp{o-md%XZFyeic2(x_`_SgMgEn1XjH>0JOJ ze(dynRTMPT2s{)sDDVU9G`|yuh$fnBbs0%_#v>}I?b6^(d@}fA8;<1Fn1NM3cG7U| zlM$9>sX{C_9K89au6VlvBoXfGc)b?DE6LJL0>g%f}QD4``H!qSa8S0!q4AD{NIwvVAoI5&LbM=gjY6R zKO%#&Ph39CZ61xh*|DObzQJu8XRcJ`X;touZyJ}6@VlWPf30=0_FfSxlTp}c?KR67 zA2cXm;x_C-UTye|1WCS56E3%fjN?2Jw37=VO`DId17FcH(A)fR5WrDkKRh%S-y-^lU3hN1~?>26$=c2KOQvve_4e$Gz{?lp@iz`vNr6 zY+|@iNG8O$kr=C!U%ZSndn{ULZYBhKf}e{2Fp0N=o*;_?G$p{NYjwZ^{Oxum{%Q)6 zQ2R%%U3(B#+WOr(_Y3Wl*c*O^%Z;VhF2d}$g~d7Qc}gI{jYU7NS*PB7c&+O)o=x0O ziqi&i-r=YAmTXpjpX%P;pm%(z2&3IRn7uVM{mDpB@x;jIj{#WrZ?| z)b|4V0Tr0x3qW_?G4G)w9u>-_U|7Q@t9kW3Qe{j7TrW zg&lLWoQ=e8t_Ml9;oHd^5}bSuM{8ma5e9_cDL4hiBNC8kMvEpbuLU7NPalA*f$=xf zy5Cw~FL_83E)2-42V6kA4ZWCZ;(6_~uOFU#z1D*fT%zrSh(o3_F?tt4aooS8>oV?} zmtJCZPrs9d#=CFZOSt(=fL1nOg_rDrQ78MlL);NJWVXuoLfuzRF%^il5urA`O(-S_ zfTyHSzQiPoep~z;NJNEvn5>bg-6TU>Z^*7ZA=oR0ir}Z}*X!ifkn8&2_HE+J>gk&1 zE$e0}yXT*o>0Ety^9I|ghq;#le)og{8jUzwg_$FBgkr;R_STqt13598)^X|@e{~11 z;%ZKdO1L%kv?InU(vSq7hof(F$qAE@G#&L&cGeKQY*{zE_g`W;*EZ^6k8r06U?f3k z9R?sw<&iPl?_?MOno^J2kVLbR@-e7x#GM%&TWjrSYUqy12<{!XcfAI$305n`HAf$R z@>9gsLjO^!c3bzp4X6J$6c@W`N>d;f4xb=|L9x(Iu%`i5IR0tZh=zD1>Tv1N$quUV ziV{iacA~eGa81VdLSFU!2wD=h;5p8SRHjh^B^CI+w0#sry`Fh)D}8{MQY{}R%f(oO zvu$gkmO*j0;pOof{kRDfZ70Y0aNn_Nby$cm80+VPT!i-_C_1(r?I;AS6qMD&457JE z7ZOC6ee>@mIcCcMKW8rSJf(;IM7ZUyf*zeBS-&i&+i6`e!xj)|t=TuRQvND+_fRo8 z=@LTZ-)8#l^hkgtv_m*&uGw;dSfaOQK7kH~sFL^Eo1p#f&I;ecGp6(<%XHXRNprxpv6$rrWie|mw8 zomV$h9X$3Okn`JVwo5Dttt4T>`-XbH{4D4flPLbb!G>K=$7+^Y(4W+KZd5d>jozzW zlUM32UB2p+DUrZR`=H_E`LDX}x`e}U)B|8FMtuPlPs!_Z<$D#j&;$2vVk>KCetuN- z68QxQmc_Fk*8E(eIdWeQBRzo|^*~^n;MLJeWr$T;6ZGwwTT1S%y5ZpFqZd$54R7j4*c zz_Kuo4i;R+=zZvM?%xg{lNA>a6=ShJ2bilR&S*O%&)~+DX?@XUxt<~{JC!al+hNbl zRQ1+ZS?CRPg_78=Pm~H3Ob$+}95i;pm|eXV+0iTOCm!p?uW1SvF122)c8$q{6iK6S zkf6cH+Y^%8kQGmflpK)ODZpnK*{8)^uZ2o1i=x%Raag|&6SMYdIE6ah$>iVa#Wioc zNC?3T#FA9eo+qm4g=7zjKUi~URKSXxa&bRYht}Y7pgQDay8dhN8o-6-TL8fBJ;K64@;B>MvP6qF3``sDMRErk? z?k{Z9pe!Z=q!jU8{VJLcU56$kR5kCPa7iDU2)qcbZ$K$Y13bcE+H2VV;Md)f2}oiO zmxl7@^~Cv=+^KtTXXnfXg~2s~7jex>*w`fw58*H~CV`JGWCqq-#fIq>Q}qYF6#zyT z!!K|%)lhQ~`~#A|=U}VXGC(y~oAQY$qrbg-U*Qs!PF~5OL;brZP%RFNqmJjimGDlj z;V~ob3K^#NlLf^zA&DOTwrlLttI=s~SI3pyjJ zO65fggEszqyrsLmJ(|z@?aPJ^3h^}z9r44+Zk7dmiUJkGsuW_%mtO>8#guQziUqbp zb6CggQ4jV9qJPQ!=P2j|lYuP7bmY8fj{2mStbs*W-#3<{s6VC>IXioxiXWKE zZnu$$q6Uj19SIN68jPz02765*w_elfo0}1}&0$n8V9?`be_f62Uq#r%Xl^U_Xznix zmakyWRu}@)vvVbpdqKCz3T6C$OURGmzmz`eSBuS)CyY= zm3V`)-G^@2)s)8Xq(Tri0BKB0_N&7Onc@U5Ehxt|?H!FEs$oX_Jk`U?oXhsufjuKd zcMH%4NjZe8+KIm91Yf z$>C98*X@LTFx0C5IU%ZKS+Yj20dBAGtWn2G%woz9tp~Uu9RVmcEc-zs_D_Syr%Q@4s-loET}$@gO-cykmvG|lW_Li&?WG%&_#b-h-rYF z*M_og&n-F2A)y=X1!`fdEaNvD2G>)6CFzH^r9(xHq9Qw)6g_a@72uTo79n^grkpp= z&ef2{u%K_aTKf8?{=nT-lZc4SV0N2OYH|ptpr*=@H_wi z$Iyg0oP82~uD(Bw$9o}TMd@hs1F$aCSw|;k4cWJNgJ=EcEL5zm;+K2si1Xs*tBH+& zi{a~H7|LI7uQuzAYyI}(*oWtibwiNhQJD0Eg7s%tT!(i(3mI80I&2y+Hi>{YK$Hr`L) zJjq=Snfd1uR7fb8sM&wPyc4sKpDA#pt`}UQdcUg`?gDYkL$dLVolxZ+ifc~~)K8cg zwd8FsDlKT#<$GlCGIgw6r50KdL96AMf3rmL?RrE6>Rc$a3*i_Qg@jq)>5Eilcl&FSSo zfHzUL?k%j8#?%H7ZcH!Vlz?+9xLz2xFz9$K^(>qBv*3i#hDm$(T4)g?ZWt^pL}7>m?jIp`oN2wYIExyYPbB79i3XnBnp5 z!hx1xlpz3BH1qOGV7jmr;)1wW0Q<7@K>()IdUa`H_qU*}hNWKyk{`cz5l04!q<3%n zwm?tzBh$jDXlp(gO^E!^3&)i6r`i2x>wLcPhItY7`!-Fx)o1^Qt#|N_`;FRuo1|$P zH@1_;w(Z86SdDEoHX7TuCXH=3_QbaBclvwRS?4*=I)A~;nz_IG-rs9q*Jt;+PX)=O z(C{GBsoP@GKA*FM|EtM!|D9&Bl=PtiAU=w|Ecn9}P!uZ>w3x*Fm$9zsA~DcPCybf# zD}7M#>yLl0Vo~X5OZTMf~!9sU1cozovzBC!K6~uVgzuLvexm+P{ zhc;PRXcoWXq{T#kIDnZ=cs~%Dj87YVSs$hG^>gSn{*?kg(f^*heA)3Gk(BQPJKri$ zW&Y~Z{##|;TG{}vi1SvaQ;PC{Lidzs&yjfeV)FrutMl(rO zJ0l2{UnnCwHq?b!fFodA`nM!Z9qXg>W~eK>RS_`~8f^1o9Dc|n;=F#`GJf@iA)sS< z?$Uo#X~?;hBbuLj;J1}XVkTF=)%|zbnt|;B;Cky^=AnZijlrr{J5v-PK1!*fFH`B> zM)ZoWLY(KJ{&gvYc`DGlEgE<4>a3)Zhe`;ap78IX7u###m|;kCftL#xKg>HFoEFbJ zKOIb;$>W7xP{xcs4?X?-7#3R_mjY4w?>ytTV#pcSl!`R>dj9uP$0wbWjT|_w4L-<* z6r~CwW!_XF#{qMrJ>T|D1zFzJn7*OU6kd8qP5>nD#ot|uPrgJl56x3Icl^c!EC2m= zga2LX{~e%MRb~a9N-8R4h*Ux*CHsDe#w@5J!)(slKTn2koZaUZ#QqjRp;)~JU?pAr zNK@z0>BsFSCu|B@Iu>%a<5@XxnakmXp^2G-aAcwy*#I7itsJa_$sU@fnBC#fHFcQK z4kX+1rpUr6{mMk=WpX#vyjH3Y^UNQ=c2PB=Bp9ILmNy3b7`>I#bnPz?paAi1~l z=f9!)9WD+gr{y``E1JWl7pvvSp)X#gzlnwI>Qovet!fw&$grQ?s?fN)YGSf${#_fB z4FB&F8Ben>9f<*5q4jOB2NmWL9pAz4Cz%vW=7f5)EfXwSIF~)JR8FG z{i9DhiFyj045dHZc)w70a4_3fN-Y@uar(Xf)NqL9qqjX5gJ2>$NM5oaXw z!PYkTb#H`!O5Uskia`M$oJz{|T&5#OaOP{jyKJT=fL#DLSYT95kA#tRu_y1BGF|fm zC($7#tz;>0^3Y&0?{bcB$GGki23tQpHWfN0%ElS2_`j4A*v8a!mFCzuS82hX^H#m5 zD=ufce7-|_$O{E2cykFI^!6<#T<{QCy2W-cVl*ua-yK+4*~eCEFn+*5B;)DYL!xkX zUF98ArO5vO9gmGtfYMa4gr>W5V1PT)58i7$hk=3|mm zb&!Oz$w_C-Os_0e6@9Tm)1K_e6rfqky8WJJE?GyyVZa;PI*|xgJhz@F=8F&6G_**l zWI3Q3|6Ibo-R01-H6&kqaS9|JFLh>CJ1r6Dg#aD@W0U3ftsG%KhF(>koj_l*hYyzW z4n8Iwq2nd=SqHCnnOVlSwk}NfFZ=N`A&fAzo0!ycpY zLZ9CAASeo6qf5~?^vLC8M(@c)X+42o_Nul~c#?2&#visXrk)t=+Qj4-etJE55fl#0LoBl0Fi6rWO-3aSHOWkLZ);T_gkirO$UZWyR z@k?YG>Zzt*+J=PIp>DZfCPKA=t`je*T{oXW)@Prf6}>&IE|;~tdRN(DrWY1vnyMJ; z*X6~Hme{QMexYD0;C+#bhJ>9e_$;&dW$B!h%mvytXILyF?RsZAU2^6r?`IfAZ~$LU zB?7cp(05fWrg8I05L@4g&6oE1W?xU7`~pmpib{WwDC%~3ND8@_T%F30IYisNS3+`$ zK$OBuRaCXP$~0F82aQoJdM_v~FjRvvuf2%SJ5X2V>ni%~iy#r}tB3|+aNcGjq`5nu z!`_r*Kci;kuP8ZHBDivXJ{~8W5;vcSk*f^FndPquMOiZmUzG)(X#zG~(+EkOWVu8* zv&9p_LE@0G@jRT7Sqd_$%d6k-v}+R98Ej+TwPkA}H|;@&bFBKJL&qCO2`}PzQP~TO zf<(`5P1%C5f`Tdo8&#|OJ)VGP_$%TI(g>^b9O)qbRmKo{_9TQqBkGzX&6*Zp4<0;9Ke?y+N zycb`zDt0c}D;_9)QOg-RuU})_nvA-Y5FY}o0CCtM-Wm}G4sI3ouS6oNojm48Wm!HZ zh&B(RNjp|eH2U*O8#VI^6)D;BlahA-qgefRmoga=U&;FMaH!ecHZ2f)e&m2!JBfw-*yG4-^ZL_G0U|bd%(;2RADSoAO8P;A`!ay4PH#^hRPG65p(rB@GH%S|FZD*>yc3g;<$CH? z*1n`<{QQ=MoonL?6TYpuSvG>eh{%6f-CKnQkAfQKR|&_1NkBvF#%*O#vN<<)SH!oP zjj6msNE5g+@81KF48%n6)S{+`ZqS3Xg#k$gNb9)6Z3^)g(Zhi1fbN!GUE|Pi{l%l7 zAtb7*EP1f*VsN)em59ss%6{2e!t*`Y+qki9W7>5Gs>jP_V@kap9gX!JvClGvPe?l` zVBnWW=>l6a42wRk@pjLCle9rKHPlD} zyX5-J_sp%&bFuEP$1^m?am=f@;W0NS+v-|oO#zIiVKc3fe0@zCwkgf`YPrzVIsy?Z z8I)~X8OKhvWE>aIS7c4F3r?z4fO;lZma9OeQ=bSX7yVLh@?5#9)PR7KQr!+`9l>eX z1LCZY9hg3;OFt z_&J^z*v$inEAjr(_Xw*RLd<9LsPONF5TR-1Eeebo@f#eJm|IZp#xnTO2o%8xwQ%pJ z{DuSj_PMarGgU?MJmrBrpzF1yvSlJeG zBgtWS6N0f+YX$Si4zqjHGPG=u=emZlZ=SZqert+Qr_BjG2cxv-e!-R}(us7bNT?M& z`#g$QE}cHA==Fx}Xor>CQ1=xYN7DZ8n&fn&1r=|hX5i>X)0~sd*zdZ*Wwk%)Zxx`+ zf*px)CG^y(&Ef4G5pY&i$|w-L6B@JWvj-K=MOZamIJ#e$n-w5L2muM*+%$tpO5;h* zpgvd7woS)yperKk#tnTQWnR^a>rHyA}>^L!syhcU!a!wtO6rs&jN=#;p!^ zE?eMBPrjq%dO9!a4GtL7)>;g)Sn~tnAFLwhhfCJvXD0Ws&vSQwkeasN(X8imqGOF- zC~J=?IlB@`oA$gxZ8ZOleWS^zY? zfveQQjsT_xbLlVoRlmU03LJa?K#Uw1r00#(NDb~AQDNSjjR6{%uyE9bOWtOt0a`BT ze&2f)QiK{jO^8yJDGa4sTx|7C?vtkdw3*-j`WF_q@BQRq^Sg9Qry!04^G&V$n=+j~ z8=76m8*cu6RzY_qO4QQ}&}W=Rhk;&&44M#0VE(qq6D};H9)%Px*DebXJoT zo%>wF6P7Pe2nHLtoJ;gGriRw-aW^-zqjtT8`u3PzZ7p@WQY?i06_eW5(xKrCL>x0C zF?^6N|Am|>R|2HHVx?QF#jr3_H$1k}6aHI%Mpa2G+S76u7LgXcm!WQO5@P;W_D63X zp2wk0%Wr;%3qu(x^mq=NzCGT9xZ21dc25BYbgcZcGfc~4$0^nH=(kA9ohlD2#reBW zSdBG+)tW^jJ&?Y^WN3K376jmv#VC2X(UVt@M6j{sGy83N1a+xh$ntE(=L&i|ep5Lg7^2C@ z0uH*tnL?%@`qUWKri)(V*6`ao6F@T+YDObtUu#lrs=}SzWLG$cDF28@7H--$%GCAE z2@2jFHD=Y1eo&zzDqib%!iBh7we8z#KtDrjAYw*}(ay0uos3qD6Eb5#H94ZJS!cvD z{5H_gjD|s1FFLqxqc?qS?9d61c`7~BxZ=C<@o@(gHD9={)xL30FZStrdeHopL)e-R zwH!b?Uh|y^01vR+Sr}3K3Y!zf9hq#X z`N~EI0DhvZ#@u|*``X%Q6z3E3>;#0MU)KJ{Z1v^-r+#mhQ$-w*3zxRZw!eHAn@%dM zck30#zFu#jGdSV$eH9u|Z$!XiXI8MX22l}MxVXkar%I|W92}O!r1XDf{Hc!-KG;r= zT1%3r!+@tP61teoXcw4SB_9t0(_s36fp%G`4e6fUWMgp6LC?q+?D_MiNe|V1t9{9 za2uZRP@c9j!emFpYB~r9-$TuGTw{i^l>j64W{IbOekx4I=|kKCOEXT z;+h=Qe${S45g#X~F&9(mVIUu(*iv;MoUls^-{|DQcyV$vJZ2O(KK~-t&JSB5U$V8d zP9??&@>3S2#jRU35;kI+z})Lu_x>_w8brd*h^#xVxy0eiLb_16EiX=DISS6j@)0DY zR14c)VOYm}d}2ji*z`1JKFtmtR)`wp?E(Xof@1N-$3>iPfAmkheZJ_rw`#}if}dX# zZ|-y>*iLBLi7t|8sM#l-r*`14#@y(Cs;awEmx5%#SPNWJ4*qpClFDhubFVinPL!pu z*Ka(v5>mYl1t8?asB6p;^FGi;-{6jfKakHaI79lwIZnbYFSKx$VQ$$HfoCE86&_i1 zbdPm-Jt0gJC0uHZR!HRyQAZH?)sSeSJFd-xN=iSf^hnm>*%imyd(qzDuH=!+k(yyX zrJ&&oyO9n_czZp;yg4Nx$w{!ceVkHBO(m>V+d_&rDLO)nFe%?@c&wrTrm+>lT0cFk z>PW+oO=oE0G6rZrCcJ7{CagbXg1^Cs=#-yKR#JyW+qnq(?Q19lVGSvKc{x7g?v!nvOQd(JADoIdNanTP4HOxSMR!TLvP_+y7=>8Y)d zb{`H;a&-oUs-7(krnqki0hVpIHI-OT^5?$@`Z1@nyg=J&bTK6Yq6I-AmmUawsaNbe z%yS`4agIhtuar)^-mLf+re&)+^AgYdh>|#-$25-T2Xe4B0hTn;p#KvUA>VTTCTwP4 z(dr3Tp#`pK*c*)eAdj`iU&jrP#rUN-tr{JQGlr5?k3KY`PUR&8<7CgC z6;Q`-Rm*kE3Z@#u0DK$15ClusIto*96zTU7KX09O1fx}$8uu(1A2QuRLM1hOSVPBy z=PbXZE7ipfD8kj4q32FSrB7L?iJkHMCQi6INVK5$pmAuw;pGH5C1E(fSO>Q4(J7;e z0C$BjK|jb<%$49(oAF(MD^}Es#jZ-5W*1d{4K>j63drGVi07GFzop=G>MUs$lW{_U zCRPq@_au9op^e%vKpG#M=#94Mn-wzy^+%S~B0A$Y()XSE3X*31Vjnu6wiMf>I_TadC|}Hw((-0q+3m@HWL2Z?q;Po9^Bu zUi&_E*ornJi~|i~+Y#K|q&+extFNSs_+o)^Ikm@w1}`|3k=fB0p{&zq)}f(=CiXxu zD}`1{mjx!r>k%ipS}S1Zs6=UcHEiOZuki1?Tl@R@PcK|%43aG(gZ;#&%V$cb+M`Fp z!v4-s{f~XDuhO|Eq_3=h)9=3M`JNbCw!uHebOrSMH46aa-At4*qTj#Yia6CEFZ zsIm}%j;`OAHa{ENe!@gEI$=0@-4e#{gM(aCCECC1J7Bl*{w;26E+n<(@o~24YC503 z+2exLl|oMPdY$!f$E^PgZdswX9kt?~SF+Z0iw`d3hDoRg*l~avhhso$LoV@qg)FpruFONz2S+X%_~~6{;p)_W(<=qPtdx^~ZONEY-iV zR_-6^HL3$}Rca$XTOOQ|Chnd~UP~s_em}z}RM!`_ST;dl9~E=(U{BY&2HG7-0y11t z-r9%#4iIyVH^16SJa* z0)i`IRkC8>$<+$95oS&4y(r{&zHdf9i#80 zy~RdIu(lIX1ybQY$aNZL{o|o2ifUejO_38jgB{wXjJ%N@4n$<}6N?Rh@Tff9QCpfO zwx8GV>u)#2mdl=`v=V>w5~xN;9=Fq?%eoOrc0_@uByEbE1f3onoVjSH^;2RZEnsSW z*OcR<)7&|kaiEim$ffu!L0_;Me&q@f@NSdU?mt@G&YcZqmZ{XzQo?v!I>aHVVpaBU zYdXbh0uW<5A_Ck{;T7mX4AsJ3=5!1k>jlo_spm2}f|+4cj}1#5PSlv&<8Hz20xZ6~re9$Y^&_1Zp{w5T&{-we6wDUA ziy>TUC?P&yqL7HpUI&5i@GbfC_#@+I;D6Zus5)YIRH(OX5p% z1H%Abv^pt}qg{5NZuwZ2_A=GqwlEmv2P56XAt^4sAVL_%N~Q4ol?oIr{*3-(LTPy2 zjeFeqEP?t}!Dtsl@@;gfW<}Ar_3+TNNM@@i$XzwH-1DEP+dEi0yUR9GQkl_xNyyUx zAYwQQE6{k-XD-pSpz;}4hL&-MK^J*#??5VB6!>iZ9oCwCKIdm$cg!sr!zqVmQOG1D+H*( zlR*!w-_gnNmRDDb9hS@jcb;vUD~p=zSut}4=z0d8Jymmli~m$+xwfK;y-nOa&wENG zKnXNPuGzVsuy4ORW-DByE$D7Y1Jz^PP~|!Fn0f{`9PW_C3Cp8rO*kK z19F`A|Djg>(55i2;SW@ekE8g-GG9j%c>k-}lMd%s9lYX3Vx%{1vC+|$?4j!|#WWHw+ri~?W($}8^6%|yV&21F36`2a_mNypLS`1)FiU@ z9orlXHtEsSPAS_zTwt?qkl6GCgf_ zjD5`xM}&Nh*lYY9)v0BV-yOrm+1H*wiEMKj(oC&44hA+~^B;1=bjNXi7F+ks^O^wh zXzdw|nZI|uGvDiu7C0@GgX=-vxA`Jt*;lVhE(au2QI3Vs_Lye57bUafkg?d9$|%-v zme&vWy4YJ|#@5NgIvbi!S zJ4PDZx%RCj1Xj*PNlkY7)3oku1p7o}Y1sA2ydk506l!iYNyw1j0deq^z)zjdjE4Y5%@T+DMA@Z~IwQLLtw>6LHcuw#zJFn7;O4NEp z-%=|%Y6a4C7f$(y(1-5N9G%FsG%TscNyEk7G=SG7si(AZ53LQ42el_EO*Y)2D80eI z@%ItSbV<~C45|7gDVTKeA5|hCHm>)2*Imnqee)>b$QEu}@D=NI(#?n}ci$}LdGn|x z>ePj3lksCipV(3o^GBnp^BO3;@DfK#s|(R=_JP#IhFrkofc@`UW=Q_Yuh`6Q{^Mya zmLrzGCgt$;nW4gY<#WLR7HUUihJn|@JF1hG=!6mUunVprm3n_#wXF@Vd*c_m^KRH2~|0u*ofe(EkHdD4$M7;anJ4I6-bhZtm+i5 z`ZQ*!P`@+y5@SSaE$jDL;XpbeOGL~KGPORH`>G?9%>Z^h5R9Pd4@qAoox6?3@v{F`-0l3b}9;SHv(y3Fyq-}N0W zrFo-a#vAL&cpKzGEL7wFj5lW_7GC*dL)&N@)rWdqKupeR; z!Cx|qv*3cRPdIG}-%tsnU3k?EXVcyL|7Ju6YS{J6IiQri5(!4@inldDGgu{{s-JO- zgVPpAV^y@Z@hBB$I4HD+`Ttzm!oyOA9*%tUwc8I0SEIfuNY&kgffnW`d*VbOW`hbb z-5$b9KpiTMTf~-&qMw<2*e@(sqrN|YO06zT%E_Xw)jSM9moeV8U6$zcNJq2dg+M#G zm3$x6>c~>`tcK&1-S;?qwY>ICZ23%{sO0yy=B!$H9F6MS+OsbcL`%_Q50Qp0u7Bp-9T&^o9E)r;L$gY1a+Aacb}1~F)$;G}rSX?oh@?ltm+CK= zWUSn!-C3=RNp&XmxM_>5s$7ic|BbA06{A2<+hF7Q$=VORAcb>YMPoCnI?6qP*Lqkn8 zhC6(r(N5+sj}-mIt>EJR6NX`(I)BBC5(MvNqH+ zX$A!dr%Tzm4$zo8%pqSJm7ULY^_Z?gSB62OdO4fxXrH(+XV>Q?@p$&`?LIPD^xwaZ zxG1HOx^@?3U7V5Qv9Hj@Im5|ocBTB=#sLx=xoROjgQt zd^{SDp?D_pnOZ-w*(HHj*Hn|1B{Y|+!|{JfGivX9# z53FA;nq+DpkGiO8(ZQaJH=|m|1i%$d1h~lq`@eg|{6GE~x`(l; z=@g<%Xw(rDqHyEO4Y@Ai>*ad7yf-9Erl$)nPd6ey?fnUA0o^#*N}{5op#eQ+X)1q& z_0L3=xlf7oLX2%pxQ^>!J7q~)28|iE`L5^u$2$>LtV?o#8m!|XSGTk5S z+|Q2#zHwm5HeE>aj^Hr9ZsjV#9Eisc6)>3k9MM68@PFP!cS|Mbjk?FQpg z*_$kHQL7_8+myI!QMosi+q{ZwSfcV+<^=Z(K{q63f9~EnB`-6Apcu(lNWsk`OUv`y z=;`fdY%>vdN|;-c+N5G~Rm?_!8F8JE+*9Zkf;`RV<07c}JM?Fhq6ItGSd(i_<{DSp zfQqZgWb4qs1&Te@djLFHHqztpUye1WD}*Ss8Zcxt$C6*6>~1@ zL{#3UBj-M6x{A-i|q?5}8B3Q@{7(No7#deeKev@(~>i z(lHDsD>AHqD7oKcnWuW#By7W)$k}zXw3IFg^^Ai@0aKQJgz^EF(QgJ4zNksblXHG? ztiT2A?8sSlqa&f?x5a9h*Mlmk(n&xRs9``wf14o%l3KOqvy>2Kur8wNazTJ$omHCAk$~`|{(+u) zuYF=b3h_sY{|sN}MwJ?_o}aLsDCVn@{du7?ekP9vUW`$*MH?;#u{HTOI#o<7`bu&x z{JB4TmsEinfm(3yRrN7YI!K#q2(n1zwRj@TBWp&C%DT3_1QSYuG%ltA-sy1 z-XW3maPol;?q(clzEK|KdzbsrFjncwQ&`i9)JH+O;l+H4Bj=K4LP(}LMvF%tHH#g^ zRkR^9bWqOHG%Edp$yD7nP8rYlJU|vAZ_E3@TvYpqPdUq-1PoFz#4)bjGR~xvRArEj z3Vz-g1k;E086-Q*(_j2fq=s&&azdXoC6`Y*;<2karDH8w$4GOm)HwDOy#Ky!?+Tbv z`JT%Xwru;@Py1Bolv6e+r5M;^+MdB(DsU zd64(bJ+ue4ujy4yFkUp>G)TBOtE?qDKRrw7T6vw9jT5dlyB1jYjRaL%Gry_D4v)g)^ID8uKDx;@q z-XqqF;%G>~zH;Iw|Iug(XWu}a2xUjup$I_*UFeF5CxZ5szFVV*#?IJ5iL?;9iB1Q9 zj#cZ^WDmVG{Fxcolu7tDUp)qh3lSa_rrnD#W@)N~5t*KN;dp?|4402*tAY}Gl+KVw zFiD+vaOA0+hjqN1KqlGCqih;8sl>H<{z=`!`^DQvW3QssVx!^tnxpCmMx~QBcZW;? zkwVU^c0=6QG^hY1_EPUy->!*Tzf+3*c3dJ`*f^OvQj+yV6(VBzZ>}M zFFA_u_3mv$V96*Aum3ce7oA+!S^4 z_o>v=VI2(MZS-1E6DTLpTKCldqjOXsd;H3r*(Ea+D;Ag9QmW9vap|#t68cf#$H7yU zRFU_Px4@{?0@lxZ7BOj&x9+{8L6l$&W+eC-6#2%Y49Lds`L0g0soayoNUY+|?XCO? zlgj&2_^ftu%8Z?E!WFQpORn8uAE)ZTbei`mZ8}&i3Rmfcn@ioEcuctUq75_m8B!nP zH5%@x+GY93Z%kDc0(1fJaz$>xMTyjA9kp!KZ%- z*1`e7K>>Hn|Kb`y|4EYp3YGN+a>$p722ALF&@x0`irQ4)_6|}rqg~-dc&Q(&3;fhF z1P(5tC;2+$__h0IyQsdJIBZh;;1l1l%D!4`QJZqWC2P`ICk_rmFhk!sBPhtJ6zI>T zSju3_qTc1LVLdu_*L2h;&DwvOoLsxC=S4;3i7pAXcxspuC{MWXqMDw~+YklwhFJG% zqD&pM=-t&_9`d3L96Yr2UUm8LiVoyf*r&Ii9dm$mN4>kWlN#q?x0!>S`9jh*q5S$R`VfL8A5Kx^&tyq@JZ*xsjgTsGo2?K&5*?Pz#GF^v;hWB z5J2DA+B_2|SnVEUe6gNmbUtrDp{3WKkd(_HdsKN_cyRLex|Lsa_FV9 zK>IThmp*8cG3`#-gF}|UTD_chgov>?H}Z?1$cn~)-wLoYlka4%cC*_RQEUIH$NJB(sv(_jsZ&7d%8nx1k+E^?FKlDVf|{YwHj zu_f~kt<&L!py4=?m%q(JxGFpJbXwQ!xkq<>Qx}&q^fGJD`~WGlB5PRM6|kbAKo&Z4 zpeGn*<&oB`=T0#G7KKfmc6l9^T7hV*#~l;s2{*-U-$bo>Eu9nqWo3y6i`ex`hF+}a zAnM-1Q_rt&B2tvgJ&70T(nB!j(42Ou7Eq=nO@Zu%zc&s~H+AL3e|d;2`#Yg1V7B&? zy?{(Ffc#O5N7b)+fe}1IdF-=Eh`uRd81I+YLenwB$Ul zU-GGl*k{BX`wsk{BgPaxZe03B1|f$IauFb zZj`eQ+pnmwBQqPN!Y($-kmV|yCnZ=iC3rPFwZ$s~VE&hQWm7woLV?_l&vP+*f3i{^ zhlJE#uLMa6?fKEWfEBO z;Kh_*vK(8sSi?mm0cyPziK}N?Jmy98P_v5yD8gozsFx_8w&Di(eOX-KV?bd^|gSTeCdtq=_9RNiq6hdz~M&p2t85mz*%7G{iSwsd9 zvE~~cx==b9?e`C|_`2+j&OS)kK%?K+fll7Z537>!khdgZv`^)KB}{`k37)OPFy^mM zm3MUg78@>q4tR+Ijd>4)p^IB)r`@zr@j7KnKTxR~hQ%gzol{Km8iT7*d@iuvgZ^k% zy_&OV%sdgJ6hC`ft12YZS_Vc2CtfR($#NW1g0~x{XVp+MB;1(zZ}UtwST^1Kd5Lm9 zm)>q?XTq!$0^sY~nGDz~6M44JI};x2%+y*gyJ6Dm`#S1d6lknwPm2s39*I>3p!~06 z1=d8BaL!Cx`!3=2G>hlpy*(%d)-PmPU-Nb0n%#NOM0*;r>a$7&sB0~iJj&}6V?33B z*)hI2ok@?kHZQYu1JRn!yXQR6-k##X`~xf7V}R+LoL*1>^ySf19%X^;z)jZHAsxNcx! z8j;~q4_T>AYfNh~%;7m>?|fEXDsC$}HS&3GRa`VJPn1)J+2)&@>9)ZH0S`=)j5Ys+ z?J@YrwsDr0V30|Ud$%p~=;Z&M&p zTDbGbuQA6-&fd<}lmhAM<6m`ejU%f`kd+{Ta2-2{q@H2Ad{1d(I<^T$Vk{l#U%Fc75Xp)sz6B_ zgnI1Ul@u;)#K%_z*%VaX(IG?X-Xn~UX&C|OABrO zW5%k!`iJ$tmK48!iy;Sobu%*Ss-q|?@KFi z_Ug77-z3uRxo*_J%d_)^Wp-^!XY z5)Dd1?{fpA`oMoI+kbCE|H!tmBC*W>`fvsDN+~{_5M|ZfobK=rZJ^nrYoUorerHwy zj|#gbQTEV4q*-i23tn53U3c8hkRnJCE+Zkp3=UGwPok%>;Dkqh-gsgQkuCLU-ZyRb!A4w zI7cBMIaj1SH)5G?_Qnw`HT~jeVaSs7)`tR(%>aG&D;~iv4*V`hBsI55;tYWd`Z?cZ zWwuqp@cO`tTDJ#=Ouk=)F5aspq1kUXrXX zD6ftRM)bWLrSmy_Uc9-;t?81^LMANQxhW1R{2;L;RBR2TwLk1e`l-_uA|Z;X1vZnn zBfsO=1^ty&?@?n*{JAY-`@LF^FXXi1VA`ZyXs<(MSY{&-Dpc9w_yz& zVwEr0N<)5oZaoS-^5%piTo;b1h@nD>U~!2R-V!o)1Ed7tpvwpvnE zhi}G_VP|1}r`hKLbHp6Jz0omokEo{zFJ;TsEIFPCN~gLZ++WQHU+Q7Tz6x5`d1h<2pyJ<6{t269tN8c7|a`;zpfY=-4+U@VE%k14PR@i$+sUmIoK*{ zHU-j*+UE@g(%2&9qs0UH1U@t0U=q_md`Z7qFj{{V`?=nwaCaP7yNlj9;2RQ{0ypLC zjb^m(6Lu6Qy;SSX2q$a1CBJV;E*5GeeN9@f@j2fJ%|7*-8TWkaIU74j(kH}YM7GxF z3gPebCHoI)P_WT2BIw{M`^$RHUx=+v8phW!v$dR@$m9GNhbIjF1Bzi8lH1Ibjso)Q zW;m94@0KD8d(4$tf>?a@!OUIt;3pP3>;4r z9+sC>{I`gpC-Ow*JV2TUtb`rwIlk2Y;p(j)qI#fjQKh6yq(i#9Yv@K&I)`os>45?1 zE@=Ug2I=k`7?AFk8j$Xietf?7#l7#B^9P)BcCEeE+I#(D?!Md9!y%e6juIO|+3C@U%1J zs>s!H9v{8G97ChVkI)q2N_z9h2em#AQ}7nHQNOs;qBZqX*G+q74Q0i=N;qr|t-j{T zpBjZ+{OrEpVQ!7Lw4x*0+1(7f?R$7uQ$~7o6SJt+hhP8vQTg;(X0^gzKgmn!)8?<= zqOtIj2@Q$ut^R{0)XZ*#=7V46$B;-r1q&``8%#A*mBIZnAgYRSg5Ovp7oRCCiXEe7 zb5b+K*fiwsTnTES1ODFc@QXoLIE(8cM-Q*{9Q8ZcaZ=lj^iW0uwv{qtcT#L#e@&y6 z43M$wv)Q&eg$5@wE2@e|s%gLfBc^ntDKDoK5{;u z95-`&E;DAF{~pW`zNGa(``Zoo)}{sB2apuG2K`z2T7~|pB8{RIp}aBem54fLPoqQ| zBrOOYxi#N8BGJ!E!Xk5q&%N1X>D9q6UkE&B?T~xxW3|mTdgp<^7VyL`%g#7;XzpwG zQIob-TKu|Knod^Ma(8KkOJ7+tr<3q7nGn8uteU;9y6ZYmW6ahSQPrhoyhIU%Q!KkV zopb1u(e=jll>;qc(ynx;^OMe=a zJ{xNjHJ2>RvFP?ynE`{cmX`(0)bPUDUU{IvQAp41znaq7L>S&~KKcc*MBU^#zg&Yl&3LO$YD z^Ih+T3;|eq=PHT1#-Y#g2&*DuRNA(TThi9Z2h}dnSi$w4M~K1Ro?qmeXnUcPIl*H1u{FN%fO(E-1Q0*DEMtl8a zzV|ER>p>%HVQ&we$&JaQ`5(rA=0Bo)4XVNNp#+#KzF>VkHTnr?@SLBfX5fd1wDG># z*1W|QcN`Am_Rxbg@S?+nrRCn?zd0i+S`Ie=A;SO-;7Hs5-;}D8SObRRmaWCiz9TX5 z5ps9#(4t9j+PqeSu|d${KUpiRs5uh!j1ss;lYj-kyDqU-wfIkw=AZ0=?`=As(E&e5 zqGiz=h#2Ikx04sR`E8K31nGdLeHO+QRe25aJzhAw^9sQEzBr~`+X^v)Y;YM4g*Df1 z_289vvE@{_vruXP!LAxr?|yQ7t<5umzYr~{?Wyi$>kb|VVL5FBL?CKTN8gDbb?TKjvP{!PoMY%bD=@VbPZ%P`>~o?K2evy3Ni%w zF`0MkHGC|DrD=#Z3 z%d2eE=(RR5=v{ ztb1XyKiwt<@=>C>k%77|*u2;?LXgWy_O@-;HNxima`btuNpE(|22Q%C4~f(uTqe(NdEqGS zX8MdKU_&=$$ZCZ62--P!^Y2e|WuH$zbcn)v*%UM4KE(XBT;6Wx_M0*!SeP}RTvGcY z_2rmJ{yHpG|Lk?}=EPnZKOQXFaw7J5o3uurtq({YcNb}k+hJ192_kVj1SL8gY)g*BC zPE5!9wOe5nY(-3}W-DOted>{S(x;5rt1-}T0dk_d<_`SL zNZ@7%QgHmW%KONPD6FTx>2PAbI{wPscH^yK7AFe%!O^%8Jfnr<9!RlVUDea^FKh^W zh8sfQLprQxA+zd1KHBw~d6N36u@x?q-=Jd~eQEw^b-}0~uu*E*B_^@U#$j7R-5t4- zBbi@AtT%F^J*0qO!7eP#wkzyl8)2`l0x7q@UzQ16qbLZ92O$>Kd>8rU1 z5i03$suKKM`D9&_S#B<{CN&?g$hPW>PmvZeB$4?wWAU1aMYZIR6BCV*qfc_-1Lwyn zLoo608HwKb@^rWBZG1MvPDF1JAGZh>k&?q&b3oMGAAkH5`L>g?T#^Hv=L8f7DU4z0 zlv!j}1QBp}R*@|xGj1p@VyYLznBcf~co8RwK!idQ7?WuFg~}P{2DsE<$ELOvTjA*E z1|PQHHtP<~Dhk^>%{%;YKQ1?YLRtE?;Fy8(hj1uFG~MDnnrjpr2ReS0wMUmUVl4Wq z#>i(MA%;Ax3^xY{hrl1$}_N*G>sjveB;$#@c$L&{I^p+ zAB)z(5F_xw;j;yLKQd;tTM<$6r4%%my|Mi!@v(L}Ec&}YeymTfeq$N4u8f6_^xNWg z!w1fF#N)l{k)F0td;J`*oY0Xs-ZN-)5gj3gDaoZ5QF8~{$lvu13@Uv3S&(n-*L~3s ze5sKv7fg&L+Hg1BWk6?-B;@*p;i%~HtoQrG-(s7x9%^rgG*_92d)Bs>BL93LFtPcD zNQ?Zpq}gKkT-yf(WY4#RgMOWLeb3iVm+Ac*n^60r_4d2F05uy6wt_(gQ_m5LXt1@r z1oRhgE0;*y8*T0j_2a(USWK~w8fgcp4_MVttF+HxA{)NW^geWk{81XVSDzsS2Bd~&HSc@i^} zLxAB+U2pD;t4ugcIbDg7vvic{?l}hfAe3b-Y@q*kSiWe@=mKFxiyW5yNVRKkBAqFg z+t7bTUR5!RuR$Ksw6fQjNNhA+uaK{prV^7JYehyili$)Fq4l{gWnPThE<_&c@T4Fr zbJ28T)tKy`A;~iTB^J`ze!Ib;w27k1Rh{Lh-y`i5YpB>DO+ZZ#8gDvNl6-{jSOQ{MI;_y$lUrNV4Oj=wv50;=psh$+a0>dLS6~!*t z87KKHr?~OC?V-Qo@%aR@p&tl5{^uI-J}V776`JRG>XHcM*!((d1tArl#;^B&6Z6 zr{EAED!)A27{yo3A&f`VbM4b@z{b~Y@a10gt5h^0bMdAy zacy+?pzdrBHmUN+o5rg}xB35LlO9uHkxM$ zx3mHn#!oXM_T3IOPu`c;%|vBT)}!u5GuPZU^~kSuT>{(+tJQ?8o zfuWn9V(|1&P*iSr-d9S*xfVYQG@G%^h=OLSZ+x1PfXT?4g93e0@%Ku8^}srR;Cg!|_0 ziZIoh``YD+qb;Lbl4G{j;F5iljQ;LjU%;LAVzCZYh@#)eDe)r(&4`G>gJAT!9KI}#xoT!|mIdb8hT>n`Ae8^#KKrx%^m4CKUcia^Q23JF%nQA64V!JoTK+9PdYHkPa z?L`&bF#k%>i@{~yiui%=Wt&YF7P>ik>^HP1h%K{avuR`Vi;Wg%Km9#dz^LL;cP1UR zH z`jA(vu-L)Eb=dF5DWBukb&HKUPo`R;yw(f+`N0Spk4Ge@MR#J+1y%Xai@0n69|Soy zNN9T(Eh|p^vZGL~Jwx~nMRe++9`N+UhmB%}DtX=ox)WW#$lWO+|H&|%SBc0?NqW2n zjWy9w^EE8qw>~h^+MK0lbeNN1yBfuEQ&Rym9{m){$7PL#@ysydn?Bd` zy9^ScOxD3Dw^5XFUHcj^@h{?vHX;<(`_tgw=%HXrEVkautJB(VuWPW0>22AHY{KBg znxu?2J7l%fgux?w%NiR!nsEjWxyQE3p;XC2&atuX8vGdD%D$Zk-x@)^z7rPddIgMo z0)n+a!M<>r$4JQ?a z<@13I5r>amvJ{h#QgYX#SZlJq}DAeFbSvErf90k`^Y2Rr=Hp4n%MwgP_ zLk_<)#cRt$24G49ubA?@??{lQ=mv3^x&Y{J9!UH7BA@s%>q+4qJt2 z0KOL*P|dXrsgPXgnAy&LSO(%n)5I1HZK}7`+%1=Ok1;*Sh;r8RQ_r)X;nL z*~c(Nmg!qFYg+gt%cw~+#Vr{fTRVLNU1e|Gj=LK_9H7j>U_Kw+h~HC~i;sWG=-T^z zj@NA`;H_atW@$&)hY?13^U26w)J%S=i25p$bm6`Lqnl0RrLHF~uq+#4g?_>|PiKE6 zLFO)@xwI;h&Ct20*Naw#VJjBNv_kWf$jNcChM)s6fP^wQ%Kbg)w9AwwGbStIFD-D2 zurTG|NlzHGY813np1v7;RsL@rdz6x0>gJyRv!7Lan`iqFAPx8UCQSvmEjaly!s2n( zXO($8)x7BRfJM4Dt}#Pgl#rD(H+;r~b&q9Z@Z~m*z;l z3)ta!bP_d}K}HtcvKXb`>cbWei-#3oE^H{Sgd$_?Zpn|Epy{T9Y$zljH%v2Hc5u;G zJ!^hV!Kjz9N`b}ZsurKS_UoCg(^;7C}!P&Gpps(%s8PG_r&fmF=67^23@h`)$KU# zs@0rW^MJz<$RD0@(-QdAXj0Q3k?|xPBWDJdVJ!`lEKYb~Lfa9{U&y0XUgGhvG8gt_ zPZ!u>!>rBl4v^2Et*YMBb0`(O4E(PDd2(W?FLJ(lWLqeajH>(q}w4dC-#J<~#n z<=dQ2t!8H#3QU7b%jMQzQdkfDs2V-*xAgCf9%ztTWa8hpAK@hMQs~rS9gtdgph&Mk z_=W&(ibChZ+>utR4uIBs_eu z9ge3t?Pu0Bm{z1FIChjWMrAw25$A5mXAhfF0s9!?WQX6Ze|Tg9%n&-sOUB7R&y^_G za$XKKRhOrLSXV~yP*GqvNnG10@MT)^{b`&`vjEp`)(6(XE(U^GpW+SB*iDyQ*?-^% zg3_Lx%O_-W*bA=9V(J1tbL~r0)r-VPyN`2b&D$MWN6gb#f z50_cCON6W(rCMspO8e$_m)DS6^{EJJ zTPIl**}{gQR~6DZ0o^fi#L(|cH!mhNui4W}6q`)K2p1(c7g3>rHI= z6h%7EOW*XKUfh`*QdH$BM6;nG-J7*Her*<1Zb@9fuH9nSN;!CxC!224LySK6%d$RL zuRJEjnM$;7-n%IJ7iiVi1Yf?QoeU4m<~W=J+%L$bQ_K0AFTuco^qPBB?k7UBH~;7z0396!rSW>aeS*Q`nqYN^iVu3<2H&8 zkxJ9=3?q&Xvmev#Ls_u6pZgjKC`qal3>LP`Vn7j2X6o)`=fS}0g}`EEaa3J=IzD3i z#F?MP$6!9bJ?)FDJQ5z$hvO*(gTFH)k5`-6E_#HM#uj2cW-;DaAHbYh3ik)IeMZ3+ z^`V%@F+Z%&4-81zA3d{LN36x^KEDB&uz>k{>)Df##p^<*afgP0LQd{sol z{@hpQ6}kBl_J<|ldwlQ}{wRY9r=^L9QOc0l`#SNB%0z)H32ZABP1XnF;F=TnW&m41 z>x1rX=GE9s&o`dCiWEo|BYgYc^akyBI&8Y8iqG_}&}f6&j9M#f zUDu4r^IBTGZehF~eC1AddKk&%{lRCtT(zF7DH%KwAW7A3$;fRGd3#;eJrzqspgc$b zVODSIxRSUcvh>iRhNkZ0<;L{62&?{+HJ|=|U}O5$IujxNS4F8`fWf9HCp?Xst)-+fYSmxe}6 zCl=T;KISRMnAmHhd*%{ckp_r?b>;ppnEwR!Fe0}A_Iju)9)o&c2m~{m`He|V8NZ#k zaW)Vyq~kQ_n3l}BkrKz%Tj4WZ#b#g&O2@Me(mpgOEg1D>>OsRQ5`Gk240X*x{?M(+ zQ8}K>Oww+Qc1O}vMEJH;$*^Go$w?1 zY7`|_+ptLk3SIBxIp9UzJQW5_QuPhHNzQY0QlB4ekZ6}o!7s^GGf?MWR!hspN8L7P zKBib^b>qW}P19*r?FtdU>pVoTXymD^?!e(1h&lx(xBJlJQ&&Bi^l%5D6K7|F(#o8D z;Y8IuF2i7QEhbt6OvqWUIR_~){l;V>fMjJtqC;u$w+C2$ylODvs&>E^r^ZC?JO{Ga z1{C?rpbEX0dC=5Nwp?|!x!wLbo*5N>zoOXQMtIo7)@yyoQPzC8q}3UrzTzs5?I8>U z+_CV)1@%TpwsD}a(qQo5a8OJb_9{mkvNsi?Vi8z^@=MPIzQY&)g*r|UJ-pa zoOFzw?laCEwH1?<20X3EVz}fKk6nqVl_YJF;>Vul&k#fDJcy~sUNc=-H({ez=*Z)< z`IhTQMsp)YL8kzmGViVOO@x_acjygtQK4@y8FPl03Fo$``=7wjI?RCE^2s{)-96Le z;fZa9>(?8Vg)t#*MrY!~!XTD)A>KKrV=~*sSOl|&UvQ%pKdYR_5x%qs^OkU`Ox=h> z>+DZ*7wzLE&?5FfHZGl`S}QlMj4#hqyb3%ywN-7Vl_LuQ4nL=wJgJ6uWh!S#9-*-S zV&F(NUVkj)#H`9~erD0D&DdUMu<-;ZEgoVjDCP4OlV${mr&@HwB}-Rnv;*zueFgCy{Kvrl0+AqeX~536kj8_s68 zmdvsNm`0VCB(L0It|yaaj8QUFY{LvPTfV}d{K2WF0>!p{RsnFQq^Y!A%_A1}4l3I# zO_;q|=!{Uv7U#D(UMHTo?m&^8KwmIb62~AF=A#Fo;AL8(LRJ@`QHR~V^!{Gxh?E5NbPsayw_9j=ZL%8 zm@ke#$!^ZKaT5CbUp&n00v~O!JaS^|tzaa)fqp@_H|9&rx{iMGSvd1LX+;kPD}qSH z=dLm@7e<3hqBtR`Ro+=Q%c>=VJ}aFRh) z%OJPh?>|Upd2PTj{fUPCx+Bd)0^Tz7Rl00=Kyj;P&3EMdP2lN3!Z@C zL`MS_6-=l=;vN+0g!UesnbS~k3skD%S_>?CN(`|7TAmKFSh!AlCbJ#&$mChIlUcr6 zH{0$$(&WsVQCa+sIqholqpAR)FO%-5s{L`$BMJ{a_Vp9s2Xb+9c+UQ$xg-vfU3OPC zdVa%vXop0fxn`%Ae)=-|{1B4hGSlOO#q~U)fDm%t94JbXr_MRzG@8H;t2uXcp5(MND0OC?Kns`t}1$ozxddUti9xFt#3@zswur#xr- z^=+Y)-ISwY_+Vj0@iOjt$MosmAY*`ub#=m6y!nh{ex7VYEFQZFP z;NJ#`=>Ic`fM1gc2Ro&aOzN7)`ZjaYdZlMVD!^Yd7ir<9mly?2H|QZhwq9A{vC2mqyBhO(f$wMRYhH3@;VJo zMdb1Q_5eW46=D)Wf4>|;IX(XHCH`xcD?kDKx#2NBb>l$~q&;gup}I3#IgcR03Ilhi zJH10=A-##kEwK%_>S7WPVR*uD(hfX3kI0oAnh|)CYT=h1Sr5|K@vx3kh2KghUaWf; z4@NbWKqjC6$uyzp!uP*c9{#%3ZyX9(ICetPE$9~MWLwa75(Ajz-t2lPKD3<{ivJ-b zZR0oI7xy=X=g}<-cG{|*dd@okS$-!jZ`EQnNOl{4_i)NMBPLZW_%GpuWrmB{f0;}A ze@#mNHI(&+HPbIFE(9*}L1oBBWq9~k+?z0ZZ5}m}Thsj#?3pe7;#);(S0tVSpA?`x z(^TK57**y5*$uXcr8?2*g`|Y=Xaa%{B~Y6{He3hP$!9z2O5{?_S3`ME@fizaQ=9BR zQvrk+F9K73{;|9$%ibpHcYNbqijnpWCDfePG`}2YtVq%DUjGV$aY{%>Gb5rk@`9%R zcSJuK5%l_Rng>i=9QzjzTvPVf73Su`@)A}{2U0&T-n}V$;u{~@gOYydnbH7%7@#l1 z4;Xp6RO-Ik|ElA=t7)8tX|$tLxGEBp9%K>*;=BHZ+#EI?;YHFs0`gu=m zfT!&Xi%g^q=bcy8S|e8kaW(>ApJwN5^SLewP6~4d{>)-1DghE6>;*M7lCVqGaJJdf z-!QKHyyBU5&6Qm~9#Q<%9VZRx7az9v`>XtMvTNjCiP+9BpV?tT|>UX&nt55Ke zzExRHwBCPau4YcL9PSo-*-5C2m8_WtAR$;CHu(*8k5OLS#{HKIc>bS;qMA1(^_&R= zzXY~Su0M?yr|%c`@caNUhNTlmQ8J@;-j{-^$jfbFVe{f8pxZ5*QSuKlmUn`h z<+h<#B0?ip?TSG5nRapTjmkv)5Rd1d!i`%rctxTM@7*jUA1CTeAiZZHBNkq6^N~$} z@-BXQ{(4Bx`5Mb9Q?2!U@8jjAJB@HH@S0LO7bW*spZt>vJzGZ9tt8;-T7N5~b$BMA!Rjzm6yFo@Zm zaPx~Py0Pb7sVd;Bvx)+>lOk0p4n=rm4eF?VJ%N&ecWe!UFh{IHhv+HPsFrFl{nZ9= zuT~#&N15Hl(qip*uoDKJR|=^(zXCkX*5nOlp{UUhrn;eJJ7A%TaEk26Qq0Zv>U($B7T*2)B6hD{~?1ZLKRL6M= z)r3$eG^xIxsBctcol_V)#K^~p1BhAyu*Q}Z{O0IKqYe`IMQ;km>0jbKvLD;OkZiKz zRy?lkP@7DAZG!5Uga4-q`~One>ujt;2kZ-E&h8pv#+7`8DjV&$|1?BQC%C|Y@sD@_ z*juiqmb6e+dP~xs8|~cK;2o6glMP@o6}HVLfn*tIYZtSw+gmWD{8yhR&h-};(~ z$J0pd+i@rNjg({6A1LwdHE@ChYMY&!zUIwhN(0RuL3@@Hxw!IN4vl;Drp)TQewp5+ffGlU_jPJBn`>=o`%ZEA_d@UoZhkc%Fxwba3&V-@;@l=Q=HS!BG z9S8B(XYTW%w6lXrNv4M}JwN33l3VDRy(5VBlJKH#f|hoN;D$Xx_T|~k;(T0OQKj>% zU*_`j5Q9{in zC+u~1zzyEJ=l3zu+RU~adKK^FVgmRZ8Xh$01Iu8gXGMU0}}ZX zjK@qRCX~{Q@S=*|{4v%*D1h}7LS@&PUK;bIz+s@%B&4!eSvuZmexl^CU?lMg%@5zD z3SDL~!$3$on;Lq#kz(052f}!5OZ(H4-zORvGYnQVP(vJ3HtZK}?WNLIXrL?;mM1*{ z8I4{z4q|i90V-to!GC)K2_|cbaE{NqQ6!tOLO$RbWW5?%;~B*Ig7$sXUpwy1Y&NTP z@hC?k^^N;fh>+Ja-!BIYjVyOUMw}{Wab>yN_Nsk~uCmZK$u0X)DYpY=@}*7$qo#`f z%q%@kx&cTG!I!mgf>p70JR^Y#Xj4B{%lD*kc|SZ-$K*sW7vAw~iCDyTUEtyPC!xSw z26QWuh*vKDiHRSGn^p&XN{pc76#5$;wdie5uUj28_=8s=F$eNN$@cXsMDd&u_!)D! zD3B6z?gAk_F^*V*$#I9sTJq`ir)FCN+s647o73myC3z^@od z9uwLbCFF1S!RyE<2BWzuuTFlx%%3+c79E<8sGyU3Vlmu3tUhVDwTv@$3;>A2+9-8f~$+B>`Kc1zWE#Xj0q{Jkkh&k z7>#=%z(b2-^7gaxXYb%A0=cV*;m3Fq1cdLxm7giL*M;Io1Ud7y2K~NhW_sb;PMF99>{ArdI}c{MM+pVm@#DW= z*qCfh9%4`B()K_iil>mbNpg}w0|JcjPfR5~UOErlAX9Cm-U1|7zjY2VcjMR|i?533 zMw*Bc0#9pYjn!M}N0^hZ0Z}pOH}HcwS|L9NqLacOgFC4}VnSZTL6!Qrhw<2So`v<^ zA9qkLt7(hvG%H$#_(RrxaI1Nl6C6LKB)6}%F!@UdIdnM*%H?-%aRjI(Y`>|3ZoX#( zb$4mS2O*&O2;0qXERohd+FtN!AS1mBd|X5a{+lY(|F^Ic)!!$f@^Rfzlx9P@If-!N zg;~s1L5AAvi5!a+%xCwQR7t6VN+t?ekgLwX(C4&O3i!pJ&LV`fBq`~hG6`6}TkayS6P`6Fu_rm0~C~_9ZN!s}SC$#pv zZmbhGC|4`fPHYE?HtiBOI152SS)6+>&W{4i%>v1|y(y zL-er~3~qrd8UIxY1YS#8Jc=o@JZ?*n@HMFueR{3^Z&^%Yl5l3rh>!l;sIeLKAH0Wo zCKKD=x<5eT0niA`i&^5(IFjJJO*bL`8yeD>Cg4;HDw|jUW^*;eN5iItsUww^I$sWy zz*USV25jlo(6^B(cZ2M!Q4L!Upjp$Nq*S-aD3ahIv`u31Bi;@PF49A_oN$Z}_$8yH zZQ|YMn`5!O!mrj1N`5d}1{y+z8JFH&R)rX(@;0(8ZhAg~6^?cO=Lt1LeW0?~7D{(C z04_jN{||c}77#VjjXC&BTp{sCGFxw8o&=ZO{hk`N+Q_XD*w z!&rZr=%Cx_KZ{tb{kWl0PA>WQu-?3annQjC1_rd@oVPY$fx2+6q~Le? z)3wYwE3N(a%tUK*{}nW7WGQ*%oajl8v;o0S9M^8H_ng-27L&fRzT zC<`>SFXZD?`ZO;L;nWs=iv95vLFd{wa78V2W8ZRIGG5{kdQ5g>v3Cm9CjCWoQ>YZ| zuT{`0*~zt&t+8lJ1e=32{%n6F@rNg+(O(4`mp^KJd!Rls&w=lAT+XT z@9wT-Pw=lw|Et&KW=KAl=b=H$l5%W4h`sLR>YMBfB%bugD{wZn{C_lVsi6gE)O*)b zffd3Yr2IR-TWb72hRekd)*cE1tJ~su9rL;E_Fh-m4NdT$~%9Q3$mpS?mE--Xy$bJzEYPcOHpt+e@Usz-A%@Q}md@;$eD-{>O0 zXkxM#CM&$FXUM=YkpoioTOx99>a^hH2+4RD5S9wR-z=yRGUnt6uHPcoO~8;k>PQ{x zY(}}1d1rn#3~A9!i5_K*;jZ0v<>vFko_46;JWnM~pKZ+{84?vG%L7vDx7}hYAMzxD zJ>uP#mPa9an(pr0uxkhgP-P*%;T$kr&8e_Dq+auQ=DV%@w!>zL+)32)t(O9d*6nDI z?bD$7ZX7Gq@M>s=x`g~Xnif;~-+VrA96~w&@C*Z1H_>Axe3(4&E(xO8PB-w7o~NiP z5tE!{ad!9aiR)pKUx@5<6P8v>4DcsaD_)ZvZyi7-6F@(lpp^Uc#DA12_{OzkorrAQ zIH^Y~n$Ww*jXA62g6oEpII?-|AMVuq0kY z$7wiC0K=SfDekToZ_)R!fJ02Y`DSSXF2AcdPjs^8w?;(wcU=j4VOfcWVC0gth>glF zncDL{9KIo-UgZrGw6+4lQ4#29Y6!GVWUK;_|CIqHtL2{bZ#PoxvcTbfW0%z|rNhRKS zV`y(WwS*L2L(h~ZaHb?Ya2eEN`}?D6GsM8S;Q`MKV0FWo)dyQQE&wK6@JLQBq~iUw zn=jNS)}#h=p)MYH_mk2GK2j?L+Q&X%9k`k9(~7UbzNd>~E*2lim29#5hi(WwsYvh4l1k%+dwjtn7(l zPi@d@a5~}o98b~`_pvSH1oqaW%75BwxyqCn7z*=1tLz8(u=(D?2 zsZSWEDxIh=|Vdq@-p$s}?Eujt3dWk>Vg@t?KTCHgr4EC$D6=LBf^hqQS7ZfGt# z`v&>w1i400k$XUW_ls}ji1@n3)?bWMdyF6`euUTq?NlQHtKYw38Ew^Cn~2S`lO@z} zf-Q!Qu!fjYpH7*-nWr-JDo^Mu)wD79Dx=#&UhT%wO>*xe|N0xR2%{&_TGHv$lk^V% z$&P6&+=;x~f?%Rj#r%_-skJj@)8#M=?|d~_h3PQMK|~H5T?-nvc{qOj3CChBF<)N9 z#eDq2#W27r<&qOBXg{(!rSkUDoOP9Lg^wUh%}nkhb&h!DMY}>Y9lg1k(C&9%rOp&; z4j)m;H}zpaY)?;=dy+9Tbx-DhIil!RZeLvK<}+H(?WR+ejEXi32T3}D8nkl@j$e__ z4IKVb*m|%d^jivc0>aFyL)~>b;yrnXk=2e*Ux&qSJkMASYe~fIr&>#x5iO>+fqgOl zBpwEhL7{f}i(R-t`0@0SCNw@L9P#&WMNu)zQ^+JDv}9bm@1jh<<|9EKA^@5}a;~Uu z7`224)Nk1(|CLp~X|LLMrz11@FcU!BZ6(m;ViG;}>Vi8rY)>pwLj?HIvGxy#AOgPA zV%m+9+Js;!kz*!-U5lYh!+gk=hVzK)HX=|kr0Gb$BD`z!(FMdwm)#joy5xF4tM+n; zcm=4e#?bj6v>ost!UpDP5F0-B3{(+OH*#UtGCphMBa@S#hd>fT0<%lT_;7ZeXVP}L zox}aU9{@Wlnw4@L^v;N}bhQ=_i@vHrxxKcu=oSc|I^HObP=KWVsI1d^J0hd{DRjy* z3-oUhdsVdkHGyE^Da#uE9l#L>8gCW3@ghMm9=@WQ z>1qrGz6jw-cZ^6U(e90dDlso+z1mt@b-(}TKl%|viBUq?Zp!F4%#oz8=Cq`I`t+Ma zTS*zj-FWu&7v9&tPG(%F$=*lMfteVtqCkoMishK(5`4FVGx?+SW@Lpb6M2JsH>dBs z-ZWMwQ#R+}7!YCO;_h^l+1I+Jlfe29mad2ifU_t|!blNrH2dcbt)Qf){DuVv6R zs(Ih1&-+Jp(Mk;7%dCJl7vG{;`++X@yt2m?W!ge}N#F{Ww_~6ARDQaplK0frB68cl zaBo{v!eC2D#Dc!)X%z<1&KNXjOGKNCU*ISwC3NO$K78}0tyo!tI!!MWt7_Rnk+t{@UsBfPejmg-*Fh@ zYf*F|@Qnn32##bsoZyX&uUA96X)HZzCl@*qMUOmX8_wZ0mKnG5HS`Q_qg2 zsb@*kaW25U$To&^gjbHKrb>uI%jf zKF;exav&qDtf?XLpMWs{P3x_e@g7&i3Ug5yj&NA3;)q%x*V>;WU#>Bz@5`IhT8hOg$MGsO#}aMP z?|>ls)T|%o3&gKb8v^U*4S15hOH&<433E)O2|MjiLahDw4{P!2kMdkeO<>=y*3XIF zoahI9MOHe+l;0v&n`=pE!~_&^+9U>b6i0TXfc!Y>ZTT^!jon zy$4O9+)JkT3l6T8a;uSe`T>s!tL)cb#74MF1~V0+ebCB3yprf0u0U)65JD>0Mm4u^ zfsWc`;q%ooRkX9Wmerl`m!mboHO~2rM#M`C1&iz7BTTBx@nJH6-cd-p#(JT;hblBr zIE3rVFoN-DTdYcXA8w})qB2=@T>A6D%;{>A|37kkfIz<@DCeunfbdsQlEGcf-kO&E zAr?Sb2!4+xW0h3Xh)sv!;bJi7x#p;Gc1s(XQAuFbTlgy%v+_|Cw41lpk1vafJ@}os zS<}#qoQyFrs27T2u@Q+TWcJhcvM$jb%+m)`?K^L1FYWA*Zc@PXGF3{3mtdE6N4qOD zTfC&Il#Uq1?9&$1C^hLMhyG^p!ym7Vm7ZN(YSB-NB6Q{OuUqfH@=k1_!=p;z#oGQ2Uc8gSJ}HfWn@u(67?6bRx&}f zDRat3N7z$LIMCzBVznv-VKpaewLXUX%LZdcmkl>QPUS$p+bbe9ENwj09?lvuXsI!T zs%p?kIe5#_yEycmQ4{c9`PaDR-RxUbD$x(`)G7NnO=hNEiQD+aVb2C96?{=w2U0IB~ zR#(0#_N3ikxe~KAy|T!OY`ZQcQ**FqL%zsQ^Q;Sqzp7ie>eqiz<+yiu@73L_pY^P@x?!&8_RMb!%v`Q09~oB?8(j2N`On{u zPUE9vC$3+aOi_yPMp&PKMCt63iA#Nxd-DeuiA&k`O1p*{WGMMwvc=}iS!9Y*QVY?u z>@Pi7>oJI+9g3M%f**BAA;p-U?g5EV{tJ{l0H@A*@JuYA8F@_^vI(6AxJC$hOAgnkd@$R+S+D*ZY&@ZQwWda3|H1ATGz?-({mDMP~K z%+^nR6wD^hq69Z3b)mMtreftg5puHuydp`@)Td4BsBkpFJ|qhGG?D2ngk3*5!)G`L zZ5s)5gmFzaqgsy0Q`Dk54-!x-z5AZgN`Ay{IvY|P>L20t*n4KByNOC}^~99Ox13Mg zx}qa9jY!`UdUuQ2Yv+wP9s^N+l`-TD?li&kV}d@ddIc*|*=1#NE0>bThI7FF&ZC#7 zRhx6YbA3PGKeF0Q4;?i(Piub0`(-bSsZR;3mviyeYpA$L6B{*AS69`>x2Lpo{1jSk z=S)j<^l`_+1Qy3Xq`X#8Mc+>|f9ns#e;7d%w30}%qW#`ceMTqK7%sZxyDQi%Xic}b zaQZ57^PZTrI#h(5ACh_Bctxi44Si4tFG=P05Z8`Ab?__VUOiA-?3+oiN7!*4c;a*}J+*bDFSoTJI`gGVOH4_q7p>yFL@w)8Ak)`}~DC7hPKH zN=|D?Ab-k=2XMf~))~3~*)$KwQYEThELYDDw_qNxBVVf|=2iGq){)D_t)r3?-m8mB z!A;BEwk^kGAQ~~RJnlN?wNu+LaP(MJ5=&?614fCEe3CfGIh-^&hP9!_fjWhIAzeW^U@`h>o;caIT8(2>NwN-wuS6t}Q`q%$ws;awK3cA>LkXJ&3h zBvlaW#9c=J3l0v$Pbi_a2CiF8wKegRo@k#v2Ab>0jtgVt&WmIs(naY@)G`I$e`u*C zexAw&Kp_qls^URz%hVI=?Tf^FY|R0%K}AMJ-&;?=yos&dwy}Ji=~!W{;<`31o`qP77%Y5Jo>!8|uvj@^qR#QN+%26+^%B~J>{wU zLLI^_+xMB56M0$T%4c;#>ZGP zFG}uuhWD*v?a|=mRy=K7rj{RtSk9i`+O)TEHDRGz#>0|HI`48@c_|2}_K5a+A89Au z&28YpE?~B+RKhw|uG(=Lkhd&*Wa>q7@o7fGfEm4*G+-F|?1>GRy^0Hy^g167j&oik zLtg_+|5(zit?`Vak|CMIN2~Tj58P|bro??#`$%P*F|$A7FnGxJs6;AJESHw8WG z_bn>}v9c0PD0i1V`~KU!yAutWW9zR`s`w0`UL@!RpNZ?LVP~Q z(`xJPlC6<#x+>q?aTrRu{Q{F&-c#dAO6<`VUee6F{G}}1CKh#wJbmT^(2sA`Hu->C zQ7%REu?MCO{+xnOIR>`K_Lr%fk2HW2sh4sS<2zSxPwy z+KtD(m^1bMkXc$tPg70jG{ss}o_vshxtM=smg=v&!D~LTTeyGn+I@2HrZv4J>eCW+ zMY{{tNtOH09Rd<87B>6ur#t4)zu{=etj1&QJ}pf+v~|Hhr=EZJ)}>TU_QM{(sKQay zeqJ$Liu#?gANAYTcQd=wYh)@u&y13o2O;tBZB))X98)@9<<0kWuq*2C$bIHz%$19R z&2QZ?5XRQ3E>)O|>zxy9nN$UlaPQ7)LW=X-4bLrz!;$ zD+4yi>fMu9VZACJtea-~C9IR-u+`U)k{`>DO{N8{Y?kh)mul%ay+K=}73hbvRm5A? zo=_j*u6ZR|E|e1%yV>ODZjnc>d6gww_A^{+BC@2Z-_aNP9f73*2fwBsuzIXyo|+ez z-QT!)Panc|N*a{haW93wN$5`Gq_dS#& zMmY}S((j=x{3tT^7BI25qm>=J+DHy@6(X<2X>;hw4o5`^<;ZwlGHcFN7Y!N>jN zh2g_nNkPV_VTvGeE~gCx@+^hRiP8n-u0k~Z7GJf6vxb7UYJ&T@rFv9vVtg!Lm|Qd& zK$#c%7a6y2FOH)e zs$J9gQMZJ}P(JFG%9>bbpQuJ2-o+*&F8vzIH>X?en?t_c=wuCc$mLj&g z9EzUVZ5(V^&KGbi^pE8|iDO#)Njz_+=p$Wdr7<28)wa?l)& z-5_k#X)hV}E#cxcvGnc9`$DCrY^Ag1oT7q8s?gQ$c^nnp`k~Sx7wouk&`SDY!}K6}jC-<&yXnRu zA1GLaJb4__$D+&i|VF~JuVi+Qv^R#$`1R3=acZy zQi4!c`8q?0`?lBOQ|RW@{o=mxx{3wU`BC>7ci#6vRPD$cy92(uWLoy#gK4{~OVt^j z@QcfmK;_GCNvne*Bu_)I@x2@AKPg~MIaxdA=qlV!I`qD)R{wD#7dGnp-bQZi+^N9H z!Irl!!;xF>LiL@|atz7l2iy4jThAVvz4jOK8CWT9deuFpRcSRPc4rfnS0Gx6hG33f z_2|RkF^GL!anU8v{k1h^Uvftq%-xX6Z|bF0gIkK~`ow08rR;uq;{Cf_wQ=<6Uqq&@ zVOa!rGXU^~2|;4MFu~&MU<+T`ID$D8&tCD>scw7ayQpK81|z(9!#1nhk)}1)AACUn z^6EmE*ek?4AcQ%tDHv4Gb-cAY9TU{7v#?w{>UVIN7_C^deR5N*`P9=7GiBlJ#KpyW zVi3h+kKy~c9Dw{1lRHAvXdm`*?|j~p`r@}IX+yYT#d22 zny5WJfAQo8rayRA8qs)h5iXgjxNs2XQ*GunXnM7^PZ+sbVSyGCjw1iDE;p6Y+wbw$ z?Lsts@WVrjUU++&UH>qTH5e9X=1awBJN%#Plh2kdYQ z8&7yS%<28q2~R9}Q?fxDTR-td?|52p`TuH)AfI4 zs|o49{N^F7L^Sy@>oe2Jw3hm0i`Uw$&_(%`5Hhc=-qP)-iX^8#R7j@(L@2NN||=giVWf`|xEgtfomFWFE> zyV(>hjZR$-$tUghUGMGa&v|(C-KC%Qkr43$J-h_|7{nWN(Bk3gF2?;IRg1=?fAPjJ znmaq?DX6)utJwq;oy*C2@G>VeTrBplnt$tPpc^k={P^lHfGJH@JyeJ#`Y0* zfDkLDycVCae+X{rY4Ec>KV#aNTK>LfGA5E~>f+0L!Asy`^RZVX=g|WFoZ^ zq!qABms?fe1&$1Zb##^(x=*~YT~1&1R6S@4q2RV3#EH*-M&Y@)B>U8#%25ql%>?v@ zxwK)6Jt5Jbuzvpz6H`5@P%0+pu!(>!IU_$4s;E3!5f`VNrV^2IuU_0%v7EQ zSx562lRBgfvhdc_gs3A7mSz(J;Y~eRYohVJ#on?e)&^7U(7W||&r-|Ve5p3STkRNAhr@Fq4=UokSC4af^}WA|71OEx0HufDY+3GFXX>@^eTem*Lq8~4MPYT3 zzJ*u99#4Vb91H9Z<&RFUyYc*P%!B>2rS_a97>Zj4*W0&WVh46g^m&=v9@l zZ)YQI(F|_KmDXL4`hC5#+D5`tvG~_evZfyrH3u~lOxt=D&DG}TMcE= zL=l=^NSa)Ep%4H^Ir|+lY#c7JP<|94Y7*kO@3riC(EH6mBxC#jb4zB(qYJ!>)(fe- z``kej6ED@J1^!IyzZR00SjRwk@zwpxH@7>s$O(qFgAwOF`v->+hx&DP{JLcZ!QK2y z4LN>vG>R>urf>+eFO?*w3dP8S9~3St6o@O8kh__kpNyZ6ZO2fIG4b6@7o@KdIdZer zyazvDIO8#27Zl0xyC=d!2WmZJX_j2MF~El7wmGZjsNY5)PV8yn0g$ZcO$fOhDoh}@ zIjYO8;(O1GbbD!+ylwfzu9PvC6_Cj}txDYc+;RqVT+Fu6R8vsInoqsugJtPeLhiPx z11fBNDX;{_=@p4TyyT4M?8V)!W`eJxb=WGzx~mVL2^vXQ%1^E#O(UPb6eS&f=@T|L ziGcJnu}r;@jM^RGi*2f|!Ju z;CtuPM}3JaW{Jxt={%b@o@iRC$cTu0-O;fNhxWGJ3a$NjIO{oY068 z=Q8AC#U=U2aQ?MX{PrjUyUJ))#{f$~B;AZqUv6IoT-ZC- zAbk76!^`-zUxF6|YB?7_p%frnuRcz2UloX@mwv@x7;8BKMW;Of3I1NseI|1S$=4Tb zWbwa*uBWv~<6iW9YVbRxtaF?TRN1_EsFoRPvfmmi6Q!2>nPu7eiv+mRd*%6%cs3(y zbCF0bR?fq7sM);#9aEz?c!hM_S(sW+g3p}DM>{qt-_!bYi=Q%9G#y(y%~xM+^!-~g zioUehRqcN>U80OFqbNA2E@1NSZt_|yW6-aXCQ7_KYj^Nttb{pJMdI?gZcfTL&b!_E zEI)PN-D3Mppwqd&Ywq*@Cf`4%{>G@;+Gz*VuFmpe6f4ZMutanSK zbTj0p1+iKl2Z9Uo1r%#yir3ZsaLyfl#r1pyMGoV$HFR*LJzINKauuMjcR~yzSaQ=&dT;LOE8q=2 zzbQpU97UC=sM6$;uQ!BaG<>i7l>unAOG>s1@{IF|eRY-16VTORqUOV9-5d3iG$jgW z9hfb7mE2{w$k3H$1(;}aAikI&2$T{Pnby*SH``LJZO9B6J|}i*IU{;c$MGOh5j5gl z=NB}x4t9qJzZ)jKn0y9d|p6=Rp5;8H_ z@es_d%X|2q^Zv`M<5x~c0_pz%jsU`=YL=?;%M6Cs*cRE-Rixre@tU9}^DeR9EOj^A zjtir(Y;8YC37^2orpevCEX1z)$^r8dF#$iBzbbcD2byPf{UuSDIS}GUi9~xr}vn zFWtZnGecvqm~m*{NCmE0mWQBf3g-p(@Aw=oTtn4s(EqWW7_S3MHzp>gsG_1!?Xg1% z^Omlo8qJ$#)%VNE%NR(U{wrx5J;iLJ->kr<*ik5BOxN36jE|46h~%A30f{@!hx8Bq zUj`MjTFMt~%8@YZx1G>{v=d6ItNEC;b@cS|>*`V>Hn?^548ynP?cZ4!|}ZWB5Ey zl1>T(6FVw18S{Um^b;s`ygQ6ih{GV{{M?J^iuMp z+YbC{(6i)Klw+l|1HnrK#M@d7|9;tOi;FZDDqa2zT2!?=wK)bU`$RMY6EE)~Iu=h*j{KYV+H`UB6 zR=wf8Q18VLPdXdLmM<);Mq+AVqE=~TV>es0NAiycMVjEdZuv^^Iu##}aFfUHb{kgW z4;vjbsvNP^sNa5tuZWpyX_36i zv**OfeBVXU{<;|5uWs6tf8@>z7VTf=ww56=$> zrTdnp&qO^6NLR+|M4F*HIYf1Pc-4D53UU<`hda0xtE(fI--A=Z!Rt#`D94b3c1WyB!(`$Z}|y53vfd}Me*q|QTN$!Alv`2c!(ex7)CF#f!)y-i{UccRWH%(!m3 zEXH!QVrGG|{*aoDj?;E5{6(5$PGQeqkm3(WW4PDB#(+|RxRh2Bf!^}NB!_`P{B}~X^j?nWCwOpTi^kZ2v@TIItH{#`y=8$4;EmHqX1b%RZnO1Wc9&}7*1;;o zsM-+S1yT0pB2Aj70NI7S=)*==Jn{O{uFlOW%E?Q*<}0XAS|yCHT6w^2yAyk7sha$_ zFs`R^WVsW!!Y}9p%}8G37KU!OZ-jI+j6e$dj<9!lF=Q$cb7l8Ts?$eusdscvTvIb6 z+I@8iFsCK(GPo(IO=HWeKT^UDL1Tcog|_X5X3$j0`6;I6?DKqDTeo~jGX^^q=o5xr zE%aR^U#5W=)`-;d1gMn$rJbHiVK|%hABO7RG`I}5?x4c=Dexseqh5~UtG;uB*C1>i zsAfi}aiVm`GVI7b+MpU_6X&cjX;ZO6(Y6^VulU;asVU0$-k82|DxObX?R4r$Ok=hI(M5=t8B(@T2Q^E4lYKpp9l4!2+{6^H6=yP=;mxTtJOmG_L>bNzf= z4^4=uGnxzxHmxL}Q@r*y?`0;r=GN31UGu^G!udgBw%6sb^eXJ8W!3&u zp*_>3Kwj8#k3&UUXq?p5t^Jlmz9l*ydU39`4s6g->`>Qb8$uL*I_$dBlo*q@J$L}< zlQ5fQy4X`awrDfGjORC1`h3G?O#QJdn&CFhCw=RO9hI!JFUx3`UT5e_et&s&xsW^S zUMu(BIdG6Q(CJjf7Y+d(Uap&Vic3njXH>LBAiN-wkLF*DHS}#A<#8VlxWLg-DYE3# zji0Vc0;``Gx%z)66C=5PI_lCB`4$tJYG>Nsun;ub7B^5W7afGhwt?Adj{UjY+5vf~ zaXtNIoN0Rj$z_%Q6yMILw9tWKHmfC(&@$j)P~KX)d3g8*&s%zNu8;pksM#=!)%KOYu%1y;85gU%QsIe zaM$LPL>hfibvaDK1T#q7Hcc3)jrq!RNoNRMx{r4I;&t^Mnl<#7OQ!S_;s#kD7K`(O zv#tBL)v_caPPgk;t`=!Uto)8D=(>Npm$-iOrl)@6n+5MQ`-_+UWwRkEcs$*k)Mh84 zpN5IWhW13qDfWa0z5J@mx!OJ%_!B;=ShdnOGy100WngAxC>kGEIOd;8J4hHoX5Jny{2B^VI%Y&i|J@ zJIwlmL&qG6UZf?ApYK4c4 zd+lfHxAoBlYA;|Ve-Ta^3pYp}0WuvZ9*BRF5E;~oLP|zKl#op7E*Tmc`cOqh*1#a$ zu5$c7*}=Kz`08I4bCFX3_WM`@U3qKy{(<43kDp)N)gvJ?P|})7%F1#=EA0zTCMs$M zdU|pKv}N$8naIJY1ids&^^ei1LE#alUAvp!XZm(&1A~M7Urf?5N_3ZhNUTqr7IAZ=H9qeLnw|0(q0jRH4#xlBR_+&Kmh{!)>-L}%1|?4{ zSb3e$={ha^w+GkJN?0WEbiH3y(Yy>aTeCwFDQbV?Y3}P`>t5%cAxSq}K6dXQTKm7pdgMqAdhe!3AECGyUaAiOe=bT9^UlCkHsd zYg>`mgYs8{Un$V){SnC7L(zLpwEXGxItDxQG8m|6G88$j;thUNRimF$QIvVc?=!ba z6PF9v=W7G_w#Ozq{=GK=7*vJzA12T`lQ1Nhw6WDc0w-KYG~)eD3@6p% zsUdM+-rwx!3>=uqYwj%w04M-g@ACs3#x0{iLIfmN1^_rD)8r*!5_u<2<2#)TRXPtZY zI})mdf{nDcFT^z*N@R7Ng>Y1&T8};i5Oz%^E*Jcp4nw{VCu1)Tuc|5v#+H)JoZjI&$6aPqKZlU`S`z>I8_11< za+!jYpEWI3&N&u+_#ort#7SfzA5%mD5d+v;nbQ4Q*_$ zbKgh+b1Ipe?BDv1CEN$_R0ijvVVKE-^UU>CHr(j z`Z{LeZyKO|0$cZ~`Icrm=8wzDGR)Hs;GcLrj7xomAkX_*jno2W(BzeOwrdYu`$};7A(9FMM{;h?HGmdt=9q9 zN4B6FHz*5~dLIc@v7}~DiJhMaQu(?T zk#o}$=VfN!6;N(?Ca^unzM0?JK6@VPc!X;tbUu5wt_O@_9^|j}8bn;$Yyu3cO#{X%$phDz4P`s(lUqe+h+JKj>{&aPkbM zIxZei3uzoFURK8f^aFF$$5X9vrPOcy{w{$dyJ0ii39dg9_aEYGQJ2s2e6dIe=U`lK zyuUqvVJWwfUa#X01LNq%331I92khcAjzUCTN;=;5{a1IpiWcojQuFp$KY+XWR<*)s z?sCb*`0DPO#2zhT7cIBoefik5!odkRP`GIv165GQ6PGi9UXuC(f5@$YPtyM^Y(%ur-8CO9*=l=FsAIa6srnVU9l> zQxExZ*E@3jORr5YI`YyJdi;y(4^qtp=pckTX{b^M9n^0N&6){(KmlDLQC5UwF&`N) zuIe22+u$)XWy=@@T+w~Yfhh6~$HlxouX)5+pM~y zn^enUJDT&o`4f^qK;&tV4uSF3@imD|2xjkkzLRIG{T$@!WjC8W6F6i(qP&3ZDjYa( zmu_;$gaBxe$o<#piTK3%N&ebdV zwi*gJ>WZm)))#5N07&8SMq}D8Nr`O)RA$?ML(JYvnjaV#z3c7e{R%S{a92qV2J0Tp zyW23xi`D?pxjgLQ{1vt%FC(|?-gH` z%zUcdizgX}tnVZ<>MCBePOo^tCgBe??BZRmNoV&ZcRFk37meDTJ z7vi(lnbKHxqle*i;P$awKV14i5&}H6VLZVE4*9#T_&VMgY(`y4@hk3mCey>q!kgh7 zBiuYKwhP(m)2I0K7$vd54lieneXV$aVK)P!)U%mXqter&9DPL4)@(^wy=% zB&QcTq)IwW^2#Nq(y}J^%%V1o0b#&`txVjx73%i$!zqXMw`gs@ccoEqDJVtd@Jmeh z34doJYTFq*3;%$|wCT&%6Ble<_}hZx&xPf|b7B}&!8(1{A%h{vkikb?Dz}iqY=lAb zO?H(>(gJyRzf(=(!4P?3Cq6|PV>H7o9$gtVxV3sSdFKQE0!D_omtlGHhHS zF;xnH(r>Yx1^6J8C(971)Uy5&cYzSDe5=MP>BNz?M4q<{8kZ$9!{AqWhi9uDeQ9?a zC`-iv@JHnS3nx;W1O;>yUvAEtouX)?g6`@m%}iw_^H>`XU;J zFogQ7!b2bGnmePDO81JQ&RfT9ENLWq?vnxGgNI0nzJ_&0Zsv@U9{Guc!^s>!UUt^HQ&O`anArN@H|yMC-_nj~ zu*KTshQFSDlMuVuUrdlMS`fxQrCCy34FU7+Z5R7V=u1|q z(bYQ*0W(7aiKmsXQLR8T+D#xva$>BbST{&H2BUPNP0?>wI`3&0p0M?>0@(N-29-%l%h+x-N+YJvpadPDZ(?ATEG(7#-UCnvFD%QVcxS)2FXV(zlCbZSB zMeF~BHWGs-K>H?mtI1~6%U{S*3yv*lKGIHfN?3%S8st6y(YArXoU2Nh+9o{r5UMKj z*t5e!ggj=w?k%r1ssyfSD3dnm+2Nz@f)G4iFw!*3tGKpM{^-A00z!A-eD69ct{kS; zxUEC(T<7o}(HbB0oe$47#n)_# zK*zL>;T~NHAMwA;fgix;KiLk<;{#_2u)!gh zU$I3zAabf#JhLuY;m58Z0fj5Xw~TpAhzh3JGK7B10$zCNio1G~>U~GC`#DpW82Nu) zoq>JvV4uhRb$&)K*;fxYpaBtSIi2)yEs;Dh-dRyjo?EAjCO?8{w!T84E33ryor{9j zRaE5&Ey2vLj_s2}W}`mOF861Y0}AlvBEky-YGLN~^lJ20QSMylQ@qLdT#8erZL+KF zZ9$gK_Z)3zy0Q<%C&ML~24U%kl~G5tdSkvvcc?wv;=UPZBE6F4cY$pZm_2`tx8Evx2nX(>fHT+E zncS*1;DykhRM(_Adp=v}7tovKb}$4N7kL23v=8?q%#H`k!J5Zxn?3Qe1%VG8zyEF8 zzM(Fp!|mdRL^x)?_W=SIl8ZpacS!9@sKFV2o-Mn(m0qN761hbs9p-m{2=UXz+v0W% z@e4&`_jB~=UIvKHfmM^x{UO#_5}&-M9rq`*mSf-4g5}n3U_W-_R&o`;c}9<~i-%xmbME1V?KdC1|c#ME$UP&t3U6@BuEnxKg)yDyRR;X!Y0idzC_DioPZVN zPo(o0PHb$I(;^yu#LY}EF}C``+mmakmINiu#nW!glzC}Kzr^St1`&+{Jxw~LD7EhS|g za6p;t$q9mCuhDW76E!`(B;LFp$!B%pG&=T=3rn70eyA#cnw0Y}9!i6)t66DkgxMFl z+(phP-^$S>baYviePSb`_VD%sr;O9s{mC4|80aZ?9@`aWQO1=REsJMYeGAK$A_9NM zTsqNg%DZ>#P@~7})D(d8jMvs30Cs=v0le(z2tK%(brgVRh@|iDwj+e?F%hQ3W^giy z;OaM#I}8sWs4ezv+Rjc9)@p$Ri#5TheM4s&ZPL{EZiv_|UPKsFkZH{I8HqhXU*5_A zTLYJRs8cUO;j|fEv~(g$t$@IDXF^cdZAzLgP~-Gvn!e?IgyYM46w}wz2gA_W?(J+n zVNU-ksO3h z#M%{MMdjvx?y`*W##ywd%9Nr*$0e$E>{U6haTaNNa_-1mF>MI!U_X!1DDp&8T5++O z;eeJpv{6$!#SR=k@0amST#z8fZG`f8TG`eC>q2U)vlZ1a%~t_NIYnL6dFPJO!w-ob z#f)(BDP9CxlN75)D#bCO?I;Urm~=3P!F#94<$MLG7W>4Tun%?g2KBLh|84V%YwJ(V zJ2CX(yGPmMloY~_ErG8oozQm5Cyp(h01mb{&~=)WZYP7BxrQR>cE+UTTSD@omHX6j zlJ)Wk{$h%lu0Ey{Ff7X3K*1^Q`g!;DrEd;JT)(1 zw;&O1iJRF8*4XLqr_*#%?x%%FQ20)`kb0$5ra0faCQI$BaQUGgWxNMRrC1s-ggmBJ}HV+J!RP+#({g5 zv_|BVZs4F%OD1X;o;|RueC^g-SZ7&tfjY}9AgBPxs|B){9_s)Lk(yb5u6B_JTZM@F z{fT2*h!8BP4#d^uexU#YY)Nvbu5l)m)p@=QF07gnq-FF^l@I@JR`5ht)leY~C!|;r zpmU9=Qg@YZUftGawcB2qW2OSZ{U*b}gtbJ=f_tGyIb-8))TK|lk`FI<^d*0|XhrQ{ z?v}7X;ig``P$aDXC&FIm#?gJ;4wa<0M?qPIb!>Gk1NI9X7@m)AamL?muHaq_i+A-U z)AkRAnz;N}tLCJtkZj@KaRLbJ%FF#2;ouZB!Zfdzzp}Nm9EVXEP&Xm1yf4eQkzR7I z#dL6gWzC;3b)l}MFTHkg?nTxRV2lD-{|{*i7=FmK5ea(z)|UGlb|t&#AnBv}>;gNQ zu;{j!6@RC~)5~HHQ0!U#*nsVsc`hvAk;9U|jYZ{_?cdCXpl@g;Z3;2u_PoTU7AJ|> z#kQP#r;?AstXXZzQXSj}q-|+JtZDw z1K^$lOi20lHI>L!0Yo5@`2mIx&ZXh(i3~c?a&BR%|Bo{b&`~P1^>Za+z?5&Ko@fUm z-j78Dm7HZ9K8qrwjO!-!d9U(;>cWro^vVJ7f&$}PG;z(D0_IH+;1^mVe+!3dlHy+w zCPCna+9xl=#AFWFr5~)UODkwLT@~SfJVb6oJ*3SV&dStBz$ zd1~KJKdGL*(rIYf6=#~9x_<0h9KR^!#kj$Rkh@!?T>BH3^)$%v$G=h4TmCieo{tM{ zfe{}^O7h&zg{ z;D3+O1cJ-Zr6uX`bd72L#f$u|GHvlvRvmM{Y76Pi_gDj)#cB!-;PR4>Y3iB^{DeQo@FY9#uC)58-VI{JiW| z=Bu`nZ2VAjBJhLa2hH+JZ-cjUp4mzA1;u0vZp&p#Eq!Y4UXNTE=-U;lN{m76tgKu7%%7 zS;~Rr$bf>pm9HA>_b`@6{cm1)5Uj(K#uv1j?8pZ@=o#1Upm b)HwoG#?t$!GMzH|22hmb)#S<_m<9bW`m4$s literal 0 HcmV?d00001 diff --git a/docs/source/images/Jupyterhub_UI.png b/docs/source/images/Jupyterhub_UI.png new file mode 100644 index 0000000000000000000000000000000000000000..f62bf963289d9b9e0fed4bfcde23d060064e2e25 GIT binary patch literal 89286 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

    dtM6Ma&rwQ1X1@&px&3nE`+{#PFL17xkjQRS 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 R-?JEiz|+;wWt~$(698=!w#@(l literal 0 HcmV?d00001 diff --git a/docs/source/images/Jupyterhub_UI_2.png b/docs/source/images/Jupyterhub_UI_2.png new file mode 100644 index 0000000000000000000000000000000000000000..b379b7c1594535df99436ca54b4dcde9ea36bea5 GIT binary patch literal 82806 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 S>YP`=A3|DDs#3z}-Twgth-fDO literal 0 HcmV?d00001 From a77a62162415578fe2998589e8afd40024721f49 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 5 Feb 2024 16:18:48 +0530 Subject: [PATCH 053/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/InstallJupyterhub.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 093cc8315..0b438b65e 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -30,9 +30,14 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup 1. Verify that the Jupyterhub service is running using metallb loadbalancer. 2. Find the IP address of the Jupyterhub service using: :: - kubectl get svc -n jupyterhub - -The IP address is listed against ``proxy-public-service``. + root@omnianode0000x:/usr/local# kubectl get svc -A + NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + default kubernetes ClusterIP xx.xx.xx.xx 443/TCP 2d2h + jupyterhub hub ClusterIP xx.xx.xx.xx 8081/TCP 2d2h + jupyterhub proxy-api ClusterIP xx.xx.xx.xx 8001/TCP 2d2h + jupyterhub proxy-public LoadBalancer xx.xx.xx.xx xx.xx.xx.xx 80:31134/TCP 2d2h + +The IP address is listed against ``proxy-public``. 3. For the first log in, use the Login Node. Ensure the login node has an OS installed with GUI support. Use any browser to log in with user credentials. From eaba8b06a9a72c1c3b629c22daccd3ced9159223 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 6 Feb 2024 17:28:47 +0530 Subject: [PATCH 054/309] Updating documentation Signed-off-by: Goveas --- .../InstallingProvisionTool/SetupvLLM.rst | 47 +++++++++++++++++++ .../InstallingProvisionTool/index.rst | 1 + docs/source/Roles/Security/index.rst | 2 + 3 files changed, 50 insertions(+) create mode 100644 docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst b/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst new file mode 100644 index 000000000..5b714e859 --- /dev/null +++ b/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst @@ -0,0 +1,47 @@ +Setup vLLM +----------- +Using ansible playbooks, Omnia can install vLLM on the kube_node, and the kube_control_node. Once vLLM is deployed, log into the UI to create your own notebook servers. For more information, `click here `_. + +**Pre requisites** + +* Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. +* Ensure the system has enough available space (Over 55GiB). +* Ensure the passed inventory file has a kube_control_plane listing all cluster nodes. +* Review the ``omnia/tools/vllm_config.yml`` file to ensure the deployment meets your requirements. If not, modify the file. +* Update the ``omnia/input/software_config.json`` file with the correct vllm version required. The default value is vllm-v0.2.4 for AMD container and vllm latest for NVidia. +* Omnia deploys the vLLM pip installation for NVidia GPU, or embeddedllminfo/vllm-rocm:vllm-v0.2.4 container image for AMD GPU. To use a custom image, modify the ``omnia/tools/roles/vllm_config.yml`` file. While updating the custom image, ensure all additional pre-requisites are met. +* Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl.NVidia + +**Deploying vLLM** + +1. Change directories to the ``tools`` folder: :: + + cd tools + +2. Run the ``vllm.yml`` playbook using: :: + + ansible-playbook vllm.yml -i inventory + +The default namespace is for deployment is ``vLLM``. + +**Accessing the vLLM (AMD)** + +1. Verify that the vLLM image is present in the container engine images: :: + + nerdctl images | grep vllm + +2. Run the container image using modifiers to customize the run: :: + + nerdctl run -it --network=host --group-add=video --ipc=host --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --device /dev/kfd --device /dev/dri/card0 --device /dev/dri/card1 --device /dev/dri/renderD128 -v /opt/omnia/:/app/model embeddedllminfo/vllm-rocm:vllm-v0.2.4 + +3. To enable an endpoint, `click here `_. + +**Accessing the vLLM (NVidia)** + +1. Verify that the vLLM package is installed: :: + + python3.9 -c "import vllm; print(vllm.__version__)" + +2. Use the package within a python script as demonstrated: :: + +3. To enable an endpoint, `click here `_. \ No newline at end of file diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index bae3ce391..e1741f654 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -22,4 +22,5 @@ This playbook achieves the following tasks: installprovisiontool ViewingDB provisionservers + SetupvLLM diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 5e9c68998..deef89d3d 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -155,6 +155,7 @@ Create a new user on OpenLDAP Below is a sample file: :: + # User Creation dn: uid=testuser1,ou=People,dc=orchid,dc=cluster objectClass: inetOrgPerson objectClass: posixAccount @@ -169,6 +170,7 @@ Below is a sample file: :: shadowMax: 0 shadowWarning: 0 + # Group Creation dn: cn=testuser1,ou=Group,dc=orchid,dc=cluster objectClass: posixGroup cn: testuser1 From 03a768a0b424b3579ca41e05163ba0c621c7738d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 6 Feb 2024 19:05:48 +0530 Subject: [PATCH 055/309] Updating documentation Signed-off-by: Goveas --- .../InstallingProvisionTool/SetupvLLM.rst | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst b/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst index 5b714e859..4b5df242c 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst @@ -42,6 +42,27 @@ The default namespace is for deployment is ``vLLM``. python3.9 -c "import vllm; print(vllm.__version__)" -2. Use the package within a python script as demonstrated: :: +2. Use the package within a python script as demonstrated in the sample below: :: + + from vllm import LLM, SamplingParams + + prompts = [ + "Hello, my name is", + "The president of the United States is", + "The capital of France is", + "The future of AI is", + ] + + sampling_params = SamplingParams(temperature=0.8, top_p=0.95) + llm = LLM(model="mistralai/Mistral-7B-v0.1") + + outputs = llm.generate(prompts, sampling_params) + + # Print the outputs. + for output in outputs: + prompt = output.prompt + generated_text = output.outputs[0].text + print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}") + has context menu 3. To enable an endpoint, `click here `_. \ No newline at end of file From 21f3becc663b59ebe5be2fb281004777e6dc7b6d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 7 Feb 2024 09:01:39 +0530 Subject: [PATCH 056/309] Updating documentation Signed-off-by: Goveas --- .../InstallationGuides/InstallingProvisionTool/index.rst | 1 - .../Platform}/SetupvLLM.rst | 7 +++---- docs/source/Roles/Platform/index.rst | 3 ++- 3 files changed, 5 insertions(+), 6 deletions(-) rename docs/source/{InstallationGuides/InstallingProvisionTool => Roles/Platform}/SetupvLLM.rst (87%) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index e1741f654..bae3ce391 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -22,5 +22,4 @@ This playbook achieves the following tasks: installprovisiontool ViewingDB provisionservers - SetupvLLM diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst similarity index 87% rename from docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst rename to docs/source/Roles/Platform/SetupvLLM.rst index 4b5df242c..6226795ef 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -8,9 +8,9 @@ Using ansible playbooks, Omnia can install vLLM on the kube_node, and the kube_c * Ensure the system has enough available space (Over 55GiB). * Ensure the passed inventory file has a kube_control_plane listing all cluster nodes. * Review the ``omnia/tools/vllm_config.yml`` file to ensure the deployment meets your requirements. If not, modify the file. -* Update the ``omnia/input/software_config.json`` file with the correct vllm version required. The default value is vllm-v0.2.4 for AMD container and vllm latest for NVidia. -* Omnia deploys the vLLM pip installation for NVidia GPU, or embeddedllminfo/vllm-rocm:vllm-v0.2.4 container image for AMD GPU. To use a custom image, modify the ``omnia/tools/roles/vllm_config.yml`` file. While updating the custom image, ensure all additional pre-requisites are met. -* Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl.NVidia +* Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. +* Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. To use a custom image, modify the ``omnia/tools/roles/vllm_config.yml`` file. While updating the custom image, ensure all additional pre-requisites are met. +* Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. **Deploying vLLM** @@ -63,6 +63,5 @@ The default namespace is for deployment is ``vLLM``. prompt = output.prompt generated_text = output.outputs[0].text print(f"Prompt: {prompt!r}, Generated text: {generated_text!r}") - has context menu 3. To enable an endpoint, `click here `_. \ No newline at end of file diff --git a/docs/source/Roles/Platform/index.rst b/docs/source/Roles/Platform/index.rst index fcb8ea622..b639a5e55 100644 --- a/docs/source/Roles/Platform/index.rst +++ b/docs/source/Roles/Platform/index.rst @@ -17,4 +17,5 @@ Commands to install JupyterHub and Kubeflow: :: * Run the Kubernetes and Kubeflow playbooks. .. toctree:: - InstallJupyterhub \ No newline at end of file + InstallJupyterhub + SetupvLLM \ No newline at end of file From e33f1cd91e3bc63037c56a85249e6b58a0e637a1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 7 Feb 2024 09:03:21 +0530 Subject: [PATCH 057/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index 6226795ef..3d9ac1c8a 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -40,7 +40,7 @@ The default namespace is for deployment is ``vLLM``. 1. Verify that the vLLM package is installed: :: - python3.9 -c "import vllm; print(vllm.__version__)" + python3.9 -c "import vllm; print(vllm.__version__)" 2. Use the package within a python script as demonstrated in the sample below: :: From abc3a2b0234b19f824c67d50b2127a284b4ecab7 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 7 Feb 2024 09:56:43 +0530 Subject: [PATCH 058/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Security/index.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index deef89d3d..3503b11cd 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -156,29 +156,29 @@ Create a new user on OpenLDAP Below is a sample file: :: # User Creation - dn: uid=testuser1,ou=People,dc=orchid,dc=cluster + dn: uid=ldapuser,ou=People,dc=orchid,dc=cluster objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount - cn: testuser1 - sn: testuser1 + cn: ldapuser + sn: ldapuser loginShell: /bin/bash uidNumber: 2000 gidNumber: 2000 - homeDirectory: /home/testuser1 + homeDirectory: /home/ldapuser shadowLastChange: 0 shadowMax: 0 shadowWarning: 0 # Group Creation - dn: cn=testuser1,ou=Group,dc=orchid,dc=cluster + dn: cn=ldapuser,ou=Group,dc=orchid,dc=cluster objectClass: posixGroup - cn: testuser1 + cn: ldapuser gidNumber: 2000 - memberUid: testuser1 + memberUid: ldapuser 2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. -3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``testuser1,ou=People,dc=orchid,dc=cluster``) +3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=orchid,dc=cluster``) .. toctree:: From ba033da859e86801ad5a48f4cd4bc4df46b0da45 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 7 Feb 2024 14:48:33 +0530 Subject: [PATCH 059/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index 3d9ac1c8a..de2cdb39d 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -7,7 +7,6 @@ Using ansible playbooks, Omnia can install vLLM on the kube_node, and the kube_c * Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. * Ensure the system has enough available space (Over 55GiB). * Ensure the passed inventory file has a kube_control_plane listing all cluster nodes. -* Review the ``omnia/tools/vllm_config.yml`` file to ensure the deployment meets your requirements. If not, modify the file. * Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. * Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. To use a custom image, modify the ``omnia/tools/roles/vllm_config.yml`` file. While updating the custom image, ensure all additional pre-requisites are met. * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. From a49bb49f47ebb36cc59564d21b96c10cb8e38467 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 7 Feb 2024 16:54:29 +0530 Subject: [PATCH 060/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index de2cdb39d..a67512fb2 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -8,7 +8,8 @@ Using ansible playbooks, Omnia can install vLLM on the kube_node, and the kube_c * Ensure the system has enough available space (Over 55GiB). * Ensure the passed inventory file has a kube_control_plane listing all cluster nodes. * Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. -* Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. To use a custom image, modify the ``omnia/tools/roles/vllm_config.yml`` file. While updating the custom image, ensure all additional pre-requisites are met. +* Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. +* For nodes using AMD, ensure nerdctl is available. * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. **Deploying vLLM** From 91cb2552604995b41b2965c1d6dd70ad74676601 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 7 Feb 2024 17:22:38 +0530 Subject: [PATCH 061/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index a67512fb2..03972e8ef 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -11,6 +11,7 @@ Using ansible playbooks, Omnia can install vLLM on the kube_node, and the kube_c * Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. * For nodes using AMD, ensure nerdctl is available. * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. +* For nodes using NVidia, ensure that the GPU has a compute capacity that is higher than 7 (Eg: V100, T4, RTX20xx, A100, L4, H100, etc). **Deploying vLLM** From 714b317110a5837feb0d0fbd116fe1c84abd7c04 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 9 Feb 2024 10:49:13 +0530 Subject: [PATCH 062/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 10 +++++++--- docs/source/Roles/Security/index.rst | 2 ++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index 03972e8ef..f4e6dd21b 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -1,12 +1,16 @@ Setup vLLM ----------- -Using ansible playbooks, Omnia can install vLLM on the kube_node, and the kube_control_node. Once vLLM is deployed, log into the UI to create your own notebook servers. For more information, `click here `_. +vLLM 0.2.4 onwards supports model inferencing and serving on AMD GPUs with ROCm. At the moment AWQ quantization is not supported in ROCm, but SqueezeLLM quantization has been ported. Data types currently supported in ROCm are FP16 and BF16. + +For NVidia, vLLM is a Python library that also contains pre-compiled C++ and CUDA (12.1) binaries. + +With an Ansible script, user can deploy vLLM on both kube_node and kube_control_node. After the deployment of vLLM, users gain access to the vllm container (AMD GPU) and can import the vLLM Python package (NVIDIA GPU). For more information, `click here `_ **Pre requisites** * Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. -* Ensure the system has enough available space (Over 55GiB). -* Ensure the passed inventory file has a kube_control_plane listing all cluster nodes. +* Ensure the system has enough available space (Over 55GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) +* Ensure the passed inventory file has a kube_control_plane and kube_node_group listing all cluster nodes. * Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. * Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. * For nodes using AMD, ensure nerdctl is available. diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 3503b11cd..937d0e296 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -177,6 +177,8 @@ Below is a sample file: :: gidNumber: 2000 memberUid: ldapuser +.. note:: Avoid whitespaces when using an LDIF file for user creation. Any extra space can affect the input data ,which might be misunderstood by OpenLDAP encryption mechanism. + 2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. 3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=orchid,dc=cluster``) From 213994e50fec68f097784998816bc065a70b8088 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 9 Feb 2024 12:13:32 +0530 Subject: [PATCH 063/309] Updating documentation Signed-off-by: Goveas --- .../BuildingClusters/KubernetesAccess.rst | 16 ++++++++++++++++ .../BuildingClusters/index.rst | 1 + docs/source/Roles/Security/index.rst | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst new file mode 100644 index 000000000..0d3f29ef1 --- /dev/null +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -0,0 +1,16 @@ +Granting Kubernetes access +--------------------------- + +Omnia grants cluster node access to users defined on the manager node using the ``k8_access.yml`` playbook. + +**Prerequisites** + +* Ensure the Kubernetes cluster is up and running. +* Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma separated list of users. +* Verify that all intended users have a home directory set up on the manager node. +* Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. If this file is not updated, root access will be provided to the users.Kubernetes +* The passed inventory should contain a defined ``kube_control_plane``. + +To run the playbook, use the below command: :: + + ansible-playbook -i inventory k8s_access.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/BuildingClusters/index.rst b/docs/source/InstallationGuides/BuildingClusters/index.rst index 3fad1c792..3f60a8102 100644 --- a/docs/source/InstallationGuides/BuildingClusters/index.rst +++ b/docs/source/InstallationGuides/BuildingClusters/index.rst @@ -22,6 +22,7 @@ Configuring the cluster schedulerprereqs installscheduler Authentication + KubernetesAccess BeeGFS NFS OneAPI diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 937d0e296..c78584f57 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -177,7 +177,7 @@ Below is a sample file: :: gidNumber: 2000 memberUid: ldapuser -.. note:: Avoid whitespaces when using an LDIF file for user creation. Any extra space can affect the input data ,which might be misunderstood by OpenLDAP encryption mechanism. +.. note:: Avoid whitespaces when using an LDIF file for user creation. Extra spaces in the input data may be encrypted by OpenLDAP and cause access failures. 2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. 3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=orchid,dc=cluster``) From 6230459d85d7ca3108a62f6b0831ed1efacfd935 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 9 Feb 2024 12:16:21 +0530 Subject: [PATCH 064/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Security/index.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index c78584f57..f745fd3c3 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -133,8 +133,9 @@ Run: :: cd security ansible-playbook security.yml -i inventory -The inventory should contain compute, manager, login as per the inventory file in `samplefiles <../../samplefiles.html#inventory-file>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. +The inventory should contain auth_server as per the inventory file in `samplefiles <../../samplefiles.html#inventory-file>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. + * Do not include the IP of the control plane or local host in the auth_server group in the passed inventory. * To enable security features on the login node, ensure that ``enable_secure_login_node`` in ``input/security_config.yml`` is set to true. * To customize the security features on the login node, fill out the parameters in ``input/login_node_security_config.yml``. * If a subsequent run of ``security.yml`` fails, the ``security_config.yml`` file will be unencrypted. From fa7eb1b6d565d29f0ea6ececb3fb6256c7eb0b49 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 9 Feb 2024 12:26:49 +0530 Subject: [PATCH 065/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index f4e6dd21b..ff27766e2 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -8,14 +8,17 @@ With an Ansible script, user can deploy vLLM on both kube_node and kube_control_ **Pre requisites** -* Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. -* Ensure the system has enough available space (Over 55GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) -* Ensure the passed inventory file has a kube_control_plane and kube_node_group listing all cluster nodes. -* Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. -* Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. +* Only AMD GPUs from the MI200s (gfx90a) are supported. * For nodes using AMD, ensure nerdctl is available. -* Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. * For nodes using NVidia, ensure that the GPU has a compute capacity that is higher than 7 (Eg: V100, T4, RTX20xx, A100, L4, H100, etc). +* Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. + + **[Optional]** + * Ensure the system has enough available space. (Over 55GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) + * Ensure the passed inventory file has a kube_control_plane and kube_node_group listing all cluster nodes. + * Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. + * Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. + * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. **Deploying vLLM** From 30c982fa398ff4b187d70877cc7589e95d7b4a20 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 9 Feb 2024 12:33:02 +0530 Subject: [PATCH 066/309] Updating documentation Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index ff27766e2..8b58067fb 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -14,10 +14,15 @@ With an Ansible script, user can deploy vLLM on both kube_node and kube_control_ * Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. **[Optional]** + * Ensure the system has enough available space. (Over 55GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) + * Ensure the passed inventory file has a kube_control_plane and kube_node_group listing all cluster nodes. + * Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. + * Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. + * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. **Deploying vLLM** From 9b080db1785aafea3da080cf33d4e222c261a96c Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 12 Feb 2024 12:35:30 +0530 Subject: [PATCH 067/309] Updating vLLM docs Signed-off-by: Goveas --- docs/source/Roles/Platform/SetupvLLM.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index 8b58067fb..026b43281 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -4,22 +4,22 @@ vLLM 0.2.4 onwards supports model inferencing and serving on AMD GPUs with ROCm. For NVidia, vLLM is a Python library that also contains pre-compiled C++ and CUDA (12.1) binaries. -With an Ansible script, user can deploy vLLM on both kube_node and kube_control_node. After the deployment of vLLM, users gain access to the vllm container (AMD GPU) and can import the vLLM Python package (NVIDIA GPU). For more information, `click here `_ +With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. After the deployment of vLLM, access the vllm container (AMD GPU) and import the vLLM Python package (NVIDIA GPU). For more information, `click here `_ **Pre requisites** * Only AMD GPUs from the MI200s (gfx90a) are supported. * For nodes using AMD, ensure nerdctl is available. * For nodes using NVidia, ensure that the GPU has a compute capacity that is higher than 7 (Eg: V100, T4, RTX20xx, A100, L4, H100, etc). -* Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7) GPU drivers during provisioning. +* Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7.0) GPU drivers during provisioning. **[Optional]** - * Ensure the system has enough available space. (Over 55GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) + * Ensure the system has enough available space. (Approximately 100GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) * Ensure the passed inventory file has a kube_control_plane and kube_node_group listing all cluster nodes. - * Update the ``omnia/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. + * Update the ``/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. * Omnia deploys the vLLM pip installation for NVidia GPU, or ``embeddedllminfo/vllm-rocm:vllm-v0.2.4`` container image for AMD GPU. From da739bfca5674c0d06d979cddb079545381eab32 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 12 Feb 2024 17:05:58 +0530 Subject: [PATCH 068/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 116 +++++++++++------------ docs/source/Tables/local_repo_config.csv | 1 + 2 files changed, 55 insertions(+), 62 deletions(-) create mode 100644 docs/source/Tables/local_repo_config.csv diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index f10746c9c..44b045b8c 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -1,69 +1,61 @@ -Offline repositories for the cluster +Local repositories for the cluster ===================================== -* The airgap feature will help create offline repositories on control plane which all the cluster nodes will access. This will remove the overhead of subscribing all the cluster nodes to RHEL. -* Currently, ``airgap.yml`` only updates RHEL repositories. - -``airgap.yml`` runs based on the following parameters in ``input/provision_config.yml``: - -+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+====================================+===========================================================================================================================================================================+ -| **update_repos** | * Indicates whether ``provision.yml`` will update offline RHEL repos (applicable from the second run of ``provision.yml``) | -| | | -| | * In the first execution of ``provision.yml``, Omnia updates the BaseOS, Appstream and CRB repos. | -| | | -| | * If ``update_repos``: false, none of the repos required for cluster nodes will be updated provided the repos are already available. | -| ``boolean`` | | -| | * If ``update_repos``: true, BaseOS, Appstream and CRB repos created for cluster nodes will be updated | -| | | -| Required | Choices: | -| | | -| | | -| | * ``false`` <- Default | -| | | -| | | -| | * ``true`` | -+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **rhel_repo_alphabetical_folders** | * Indicates whether the packages in the local repos or subscription repos are ordered in alphabetical directories. | -| | | -| | * For RHEL 8, when subscription is activated, this variable should be set to true. | -| | | -| | | -| ``boolean`` | Choices: | -| | | -| | | -| Required | * ``false`` <- Default | -| | | -| | | -| | * ``true`` | -+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **rhel_repo_local_path** | * The repo path and names of the software repository to be configured on the cluster nodes. | -| | | -| | * Provide the repo data file path, which ends with .repo extension in repo_url parameter. | -| | | -| | * Provide a **valid** url for BaseOS and AppStream repositories. | -| ``JSON list`` | | -| | * This variable should be filled if control plane OS is RHEL and subscription is not activated. | -| | | -| Optional | * This variable should be filled if the control plane OS is Rocky and the ``provision_os`` is rhel. | -| | .. note:: Omnia does not validate the ``repo_url`` provided. Invalid entries will cause ``provision.yml`` to fail. | -| | | -| | Sample value: :: | -| | | -| | | -| | - { repo: "AppStream", repo_url: "http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-appstream.repo", repo_name: "RHEL-8-appstream-partners" } | -| | | -| | - { repo: "BaseOS", repo_url: "http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-baseos.repo", repo_name: "RHEL-8-baseos-partners" } | -| | | -+------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - - -``airgap.yml`` is internally called when ``provision.yml`` is executed. +* The local repository feature will help create offline repositories on control plane which all the cluster nodes will access. + +``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: + +1. Enter the required values in the ``input/software_config.json`` file: + + * ``cluster_os_type``: The operating system provisioned on the cluster. Accepted values are ``rhel``, and ``ubuntu``. + * ``cluster_os_version``: The version of the operating system provisioned on the cluster. + * ``repo_config``: This variable specifies how many of the listed software are to be downloaded offline (versus configured as online repositories). Possible values include ``always`` (all images and RPMs will be downloaded and configured), ``partial`` (all images specified under ``input/local_repo_config.yml/user_registry`` are omitted), and ``never`` (No images or RPMs are configured locally). + .. note:: This variable configures how many RPMs and images are configured as offline repositories or online subscriptions. All other repository types like tarballs etc. will be downloaded and maintained offline by default. + * ``softwares``: A JSON list of required software and (optionally) the software revision. + +Below is a sample version of the file: :: + + { + "cluster_os_type": "rhel", + "cluster_os_version": "8.6", + "repo_config": "always", + "softwares": [ + {"name": "slurm", "version": "20.11.9"}, + {"name": "amd_benchmarks"}, + {"name": "k8s", "version":"1.26.9"}, + {"name": "jupyter", "version": "3.2.0"}, + {"name": "kubeflow", "version": "1.8"}, + {"name": "openldap"}, + {"name": "freeipa"}, + {"name": "beegfs", "version": "7.2.6"}, + {"name": "nfs"}, + {"name": "kserve"}, + {"name": "custom"}, + {"name": "amdgpu", "version": "5.4.6"}, + {"name": "rocm", "version": "5.4.6" }, + {"name": "nvidiagpu", "version": "latest"}, + {"name": "telemetry"}, + {"name": "network", "version": "5.4-2.4.1.3"}, + {"name": "utils"} + ], + + "amdgpu": [ + {"name": "rocm", "version": "5.4.6" } + ] + } + +2. Enter the required values in the ``input/local_repo_config.yml`` file: + + .. csv-table:: Parameters for Local Repositories + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :keepspace: + +``local_repo.yml`` is internally called when ``provision.yml`` is executed. Alternatively, run the following commands: :: - cd airgap - ansible-playbook airgap.yml + cd local_repo + ansible-playbook local_repo.yml diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv new file mode 100644 index 000000000..e02abfc9b --- /dev/null +++ b/docs/source/Tables/local_repo_config.csv @@ -0,0 +1 @@ + From 0274e2f0016cf8c7e6a8f69bbee4f228ed3800cf Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 12 Feb 2024 17:11:31 +0530 Subject: [PATCH 069/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 44b045b8c..5bae3d5e9 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -1,9 +1,7 @@ Local repositories for the cluster ===================================== -* The local repository feature will help create offline repositories on control plane which all the cluster nodes will access. - -``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: +The local repository feature will help create offline repositories on control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: 1. Enter the required values in the ``input/software_config.json`` file: From 78494dc83be7947cb0e955564db4a9c636874271 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 12 Feb 2024 17:16:37 +0530 Subject: [PATCH 070/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Tables/local_repo_config.csv | 73 +++++++++++++++++++++++- 1 file changed, 72 insertions(+), 1 deletion(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index e02abfc9b..6067d82b9 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -1 +1,72 @@ - +Parameter,Details +"**repo_store_path** + +``string`` + +Required","* The intended file path for offline repository data. +* Ensure the disk partition has enough space. + +**Default value**: ""/omnia_repo""" +"**user_repo_url** + +``JSON List`` + +Optional","* The code ready builder URL required for downloading packages to a RHEL control plane. +* This value is required on RHEL clusters. +* 'url' defines the baseurl for the repository. +* 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. +* **Sample value**: ``- {url: ""http://crb.com/CRB/x86_64/os/"",gpgkey: ""http://crb.com/CRB/x86_64/os/RPM-GPG-KEY""}``" +"**user_registry** + +``JSON List`` + +Optional","* Lists external user configured mirror registries. +* For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. +* 'host' defines the host for registry along with port where registry will be accessible. +* 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. +* **Sample value**: :: + + - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } + - { host: registryhostname.registry.test, cert_path: """" }" +"**os_repo_url** + +``string`` + +Optional","* URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. +* When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. +* When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. + +* **Sample value**: ``http://in.archive.ubuntu.com/ubuntu``" +"**omnia_registry** + +``string`` + +Mandatory","* A list of registries from where images will be downloaded for Omnia features. +* All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. +* This value is not validated by Omnia. Any errors can cause Omnia to fail. + +**Default value**: :: + + - ""registry.k8s.io"" + - ""quay.io"" + - ""docker.io""" +"**omnia_repo_url_rhel** + +``JSON List`` + +Mandatory","* A list of all the repo urls from where rpms will be downloaded for Omnia features. +* 'url' defines the baseurl for the repository. +* 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository +* This value is not validated by Omnia. Any errors can cause Omnia to fail. + +**Default value**: :: + + - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } + - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"" } + - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } + - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} +" From 870c8cfbfa33c21dcada56f5f0ce4290267c9d82 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 12 Feb 2024 17:20:37 +0530 Subject: [PATCH 071/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Tables/local_repo_config.csv | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 6067d82b9..1e03b6e15 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -27,7 +27,8 @@ Optional","* Lists external user configured mirror registries. * **Sample value**: :: - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } - - { host: registryhostname.registry.test, cert_path: """" }" + - { host: registryhostname.registry.test, cert_path: """" } + " "**os_repo_url** ``string`` @@ -49,12 +50,14 @@ Mandatory","* A list of registries from where images will be downloaded for Omni - ""registry.k8s.io"" - ""quay.io"" - - ""docker.io""" + - ""docker.io"" + + " "**omnia_repo_url_rhel** ``JSON List`` -Mandatory","* A list of all the repo urls from where rpms will be downloaded for Omnia features. +Required","* A list of all the repo urls from where rpms will be downloaded for Omnia features. * 'url' defines the baseurl for the repository. * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository * This value is not validated by Omnia. Any errors can cause Omnia to fail. @@ -69,4 +72,6 @@ Mandatory","* A list of all the repo urls from where rpms will be downloaded for - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"" } - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} + + " From 487b1d21ecdd9a05c533edccda0167b30d4cc748 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 12 Feb 2024 17:24:59 +0530 Subject: [PATCH 072/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Tables/local_repo_config.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 1e03b6e15..95b69313e 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -15,7 +15,7 @@ Optional","* The code ready builder URL required for downloading packages to a R * This value is required on RHEL clusters. * 'url' defines the baseurl for the repository. * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. -* **Sample value**: ``- {url: ""http://crb.com/CRB/x86_64/os/"",gpgkey: ""http://crb.com/CRB/x86_64/os/RPM-GPG-KEY""}``" +* **Sample value**: - {url: ""http://crb.com/CRB/x86_64/os/"",gpgkey: ""http://crb.com/CRB/x86_64/os/RPM-GPG-KEY""}" "**user_registry** ``JSON List`` @@ -37,7 +37,7 @@ Optional","* URL to a list of repositories to be configured for Ubuntu clusters. * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. -* **Sample value**: ``http://in.archive.ubuntu.com/ubuntu``" +* **Sample value**: http://in.archive.ubuntu.com/ubuntu" "**omnia_registry** ``string`` From 13b88aac094c2f5dfc3858e06a4c829c39ea4858 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 13 Feb 2024 16:50:40 +0530 Subject: [PATCH 073/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 11 ++++---- docs/source/Tables/local_repo_config.csv | 33 ++++++++++------------ docs/source/Tables/software_config.csv | 35 ++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 25 deletions(-) create mode 100644 docs/source/Tables/software_config.csv diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 5bae3d5e9..71712a23c 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -5,11 +5,10 @@ The local repository feature will help create offline repositories on control pl 1. Enter the required values in the ``input/software_config.json`` file: - * ``cluster_os_type``: The operating system provisioned on the cluster. Accepted values are ``rhel``, and ``ubuntu``. - * ``cluster_os_version``: The version of the operating system provisioned on the cluster. - * ``repo_config``: This variable specifies how many of the listed software are to be downloaded offline (versus configured as online repositories). Possible values include ``always`` (all images and RPMs will be downloaded and configured), ``partial`` (all images specified under ``input/local_repo_config.yml/user_registry`` are omitted), and ``never`` (No images or RPMs are configured locally). - .. note:: This variable configures how many RPMs and images are configured as offline repositories or online subscriptions. All other repository types like tarballs etc. will be downloaded and maintained offline by default. - * ``softwares``: A JSON list of required software and (optionally) the software revision. + .. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: Below is a sample version of the file: :: @@ -49,7 +48,7 @@ Below is a sample version of the file: :: :header-rows: 1 :keepspace: -``local_repo.yml`` is internally called when ``provision.yml`` is executed. + Alternatively, run the following commands: :: cd local_repo diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 95b69313e..64344af59 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -25,10 +25,9 @@ Optional","* Lists external user configured mirror registries. * 'host' defines the host for registry along with port where registry will be accessible. * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. * **Sample value**: :: - - - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } - - { host: registryhostname.registry.test, cert_path: """" } - " + - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } + - { host: registryhostname.registry.test, cert_path: """" } +" "**os_repo_url** ``string`` @@ -47,11 +46,9 @@ Mandatory","* A list of registries from where images will be downloaded for Omni * This value is not validated by Omnia. Any errors can cause Omnia to fail. **Default value**: :: - - - ""registry.k8s.io"" - - ""quay.io"" - - ""docker.io"" - + - ""registry.k8s.io"" + - ""quay.io"" + - ""docker.io"" " "**omnia_repo_url_rhel** @@ -63,15 +60,13 @@ Required","* A list of all the repo urls from where rpms will be downloaded for * This value is not validated by Omnia. Any errors can cause Omnia to fail. **Default value**: :: - - - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } - - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } - - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } - - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"" } - - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} - + - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } + - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"" } + - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } + - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} " diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv new file mode 100644 index 000000000..af1d1ccec --- /dev/null +++ b/docs/source/Tables/software_config.csv @@ -0,0 +1,35 @@ +Parameter,Details,, +"**cluster_os_type** + +``string`` + +Required","* The operating system running on the cluster. + +**Accepted values**: rocky, rhel, and **ubuntu**.",, +"**cluster_os_version** + +``string`` + +Mandatory","* The OS Version that will be provisoned on compute nodes. +* For RHEL, the accepted values are 8.6, 8.7, and 8.8. +* For Rocky, the accepted values are 8.6, 8.7, and 8.8. +* For Ubuntu, the accepted values are 20.04, 22.04. +* **Default value**: 22.04",, +"**repo_config** + +``string`` + +Mandatory","* The type of offline configuration user needs. +* When the value is set to ``always``, all repositories specified in the ``softwares`` list will be configured. +* When the value is set to ``partial``, all repositories specified in the ``softwares`` list will be configured except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. +* When the value is set to ``never``, no images or RPMs will be configured locally. +.. note:: All local repositories that are not available as images or RPMs will be configured locally. +* **Accepted values**: always, **partial**, and never. + ",, +"**softwares** + +``JSON list`` + +Mandatory",A JSON list of required software and (optionally) the software revision.,, +,,, +,,, From 45333a04c075dc4c75354df10634b2ef7e36589f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 13 Feb 2024 16:59:47 +0530 Subject: [PATCH 074/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Tables/local_repo_config.csv | 2 ++ docs/source/Tables/software_config.csv | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 64344af59..4cd4f0765 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -46,6 +46,7 @@ Mandatory","* A list of registries from where images will be downloaded for Omni * This value is not validated by Omnia. Any errors can cause Omnia to fail. **Default value**: :: + - ""registry.k8s.io"" - ""quay.io"" - ""docker.io"" @@ -60,6 +61,7 @@ Required","* A list of all the repo urls from where rpms will be downloaded for * This value is not validated by Omnia. Any errors can cause Omnia to fail. **Default value**: :: + - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index af1d1ccec..f4df0b320 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -1,11 +1,11 @@ -Parameter,Details,, +Parameter,Details "**cluster_os_type** ``string`` Required","* The operating system running on the cluster. -**Accepted values**: rocky, rhel, and **ubuntu**.",, +**Accepted values**: rocky, rhel, and **ubuntu**." "**cluster_os_version** ``string`` @@ -14,7 +14,7 @@ Mandatory","* The OS Version that will be provisoned on compute nodes. * For RHEL, the accepted values are 8.6, 8.7, and 8.8. * For Rocky, the accepted values are 8.6, 8.7, and 8.8. * For Ubuntu, the accepted values are 20.04, 22.04. -* **Default value**: 22.04",, +* **Default value**: 22.04" "**repo_config** ``string`` @@ -25,11 +25,9 @@ Mandatory","* The type of offline configuration user needs. * When the value is set to ``never``, no images or RPMs will be configured locally. .. note:: All local repositories that are not available as images or RPMs will be configured locally. * **Accepted values**: always, **partial**, and never. - ",, + " "**softwares** ``JSON list`` -Mandatory",A JSON list of required software and (optionally) the software revision.,, -,,, -,,, +Mandatory",A JSON list of required software and (optionally) the software revision. From 4c982c01019101ad44ffa93f4c650ab40cac051d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 13 Feb 2024 17:25:08 +0530 Subject: [PATCH 075/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/InstallationGuides/RunningInit/index.rst | 1 + docs/source/Tables/local_repo_config.csv | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index a011adad6..80860771c 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -6,6 +6,7 @@ Running prereq.sh cd omnia ./prereq.sh +To install local repositories on the control plane, `click here. <../../Roles/Airgap/index.html>`_ .. note:: * If SELinux is not disabled, it will be disabled by the script and the user will be prompted to reboot the control plane. diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 4cd4f0765..a8121e501 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -67,8 +67,7 @@ Required","* A list of all the repo urls from where rpms will be downloaded for - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } - - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"" } + - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} - " From f4f060be75f0e5f15b1af4b9775c555557562fad Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 08:10:12 +0530 Subject: [PATCH 076/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Tables/local_repo_config.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index a8121e501..c7d1b698e 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -25,6 +25,7 @@ Optional","* Lists external user configured mirror registries. * 'host' defines the host for registry along with port where registry will be accessible. * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. * **Sample value**: :: + - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } - { host: registryhostname.registry.test, cert_path: """" } " From 7bed6f0ecb4d1d4412ef9d5701ffdc61f2345843 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 08:29:26 +0530 Subject: [PATCH 077/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 71712a23c..b23342a30 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -5,10 +5,10 @@ The local repository feature will help create offline repositories on control pl 1. Enter the required values in the ``input/software_config.json`` file: - .. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: Below is a sample version of the file: :: @@ -43,10 +43,10 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: - .. csv-table:: Parameters for Local Repositories - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :keepspace: +.. csv-table:: Parameters for Local Repositories + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :keepspace: Alternatively, run the following commands: :: From ebcc691a9abe7b499a87ef5fdfea735bf84319d1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 08:40:53 +0530 Subject: [PATCH 078/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 64 ++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index b23342a30..546f7fbaf 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -43,10 +43,66 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: -.. csv-table:: Parameters for Local Repositories - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :keepspace: ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Parameter | Details | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **repo_store_path** | * The intended file path for offline repository data. | +| | * Ensure the disk partition has enough space. | +| ``string`` | | +| | **Default value**: "/omnia_repo" | +| Required | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | +| | * This value is required on RHEL clusters. | +| ``JSON List`` | * 'url' defines the baseurl for the repository. | +| | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | +| Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **user_registry** | * Lists external user configured mirror registries. | +| | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | +| ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | +| | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | +| Optional | * **Sample value**: :: | +| | | +| | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | +| | - { host: registryhostname.registry.test, cert_path: "" } | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | +| | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | +| ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | +| | | +| Optional | * **Sample value**: http://in.archive.ubuntu.com/ubuntu | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | +| | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | +| ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | +| | | +| Mandatory | **Default value**: :: | +| | | +| | - "registry.k8s.io" | +| | - "quay.io" | +| | - "docker.io" | +| | | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | +| | * 'url' defines the baseurl for the repository. | +| ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | +| | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | +| Required | | +| |**Default value**: :: | +| | | +| | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | +| | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | +| | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | +| | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | +| | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | +| | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | +| | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | +| | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Alternatively, run the following commands: :: From d7d10924efd51be4cc0cf570c94bc4048b4b3484 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 08:45:41 +0530 Subject: [PATCH 079/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 121 ++++++++++++++--------------- 1 file changed, 60 insertions(+), 61 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 546f7fbaf..add119da9 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -43,67 +43,66 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **repo_store_path** | * The intended file path for offline repository data. | -| | * Ensure the disk partition has enough space. | -| ``string`` | | -| | **Default value**: "/omnia_repo" | -| Required | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | -| | * This value is required on RHEL clusters. | -| ``JSON List`` | * 'url' defines the baseurl for the repository. | -| | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | -| Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **user_registry** | * Lists external user configured mirror registries. | -| | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | -| ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | -| | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | -| Optional | * **Sample value**: :: | -| | | -| | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | -| | - { host: registryhostname.registry.test, cert_path: "" } | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | -| | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | -| ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | -| | | -| Optional | * **Sample value**: http://in.archive.ubuntu.com/ubuntu | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | -| | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | -| ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | -| | | -| Mandatory | **Default value**: :: | -| | | -| | - "registry.k8s.io" | -| | - "quay.io" | -| | - "docker.io" | -| | | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | -| | * 'url' defines the baseurl for the repository. | -| ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | -| | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | -| Required | | -| |**Default value**: :: | -| | | -| | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | -| | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | -| | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | -| | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | -| | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | -| | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | -| | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | -| | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+======================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: "/omnia_repo" | + | Required | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | + | | * This value is required on RHEL clusters. | + | ``JSON List`` | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * Lists external user configured mirror registries. | + | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | + | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | + | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | + | Optional | * **Sample value**: :: | + | | | + | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | + | | - { host: registryhostname.registry.test, cert_path: "" } | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | + | | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | + | ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | + | | | + | Optional | * **Sample value**: http://in.archive.ubuntu.com/ubuntu | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Alternatively, run the following commands: :: From 5f23ed630488f575d2439458cad72daf27d8580a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 09:06:45 +0530 Subject: [PATCH 080/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 127 +++++++++++++----------- docs/source/_static/sphinx-argparse.css | 1 + 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index add119da9..8abbd5e24 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -43,66 +43,73 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+======================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: "/omnia_repo" | - | Required | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | - | | * This value is required on RHEL clusters. | - | ``JSON List`` | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * Lists external user configured mirror registries. | - | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | - | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | - | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | - | Optional | * **Sample value**: :: | - | | | - | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | - | | - { host: registryhostname.registry.test, cert_path: "" } | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | - | | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | - | ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | - | | | - | Optional | * **Sample value**: http://in.archive.ubuntu.com/ubuntu | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Parameters for Local Repo configuration + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Parameter | Details | ++=========================+======================================================================================================================================================================================================+ +| **repo_store_path** | * The intended file path for offline repository data. | +| | * Ensure the disk partition has enough space. | +| ``string`` | | +| | **Default value**: "/omnia_repo" | +| Required | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | +| | * This value is required on RHEL clusters. | +| ``JSON List`` | * 'url' defines the baseurl for the repository. | +| | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | +| Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **user_registry** | * Lists external user configured mirror registries. | +| | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | +| ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | +| | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | +| Optional | * **Sample value**: :: | +| | | +| | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | +| | - { host: registryhostname.registry.test, cert_path: "" } | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | +| | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | +| ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | +| | | +| Optional | * **Sample value**: http://in.archive.ubuntu.com/ubuntu | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | +| | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | +| ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | +| | | +| Mandatory | **Default value**: :: | +| | | +| | - "registry.k8s.io" | +| | - "quay.io" | +| | - "docker.io" | +| | | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | +| | * 'url' defines the baseurl for the repository. | +| ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | +| | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | +| Required | | +| | **Default value**: :: | +| | | +| | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | +| | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | +| | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | +| | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | +| | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | +| | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | +| | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | +| | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Alternatively, run the following commands: :: diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index c0e04ee40..0196e7b0e 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -13,3 +13,4 @@ overflow: visible !important; max-width: 800px; } + From 51bc0aa4c9b0524719cb53cf9f0c8f5f7ca60b12 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 09:18:15 +0530 Subject: [PATCH 081/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 8abbd5e24..891f10991 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -43,13 +43,6 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: -.. csv-table:: Parameters for Local Repo configuration - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Parameter | Details | +=========================+======================================================================================================================================================================================================+ From a513940c8052e4e56e42f7fb7cc85a8198617bf1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 09:26:26 +0530 Subject: [PATCH 082/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 891f10991..242c503e4 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -78,7 +78,7 @@ Below is a sample version of the file: :: | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | | | | -| Mandatory | **Default value**: :: | +| Required | **Default value**: :: | | | | | | - "registry.k8s.io" | | | - "quay.io" | @@ -103,7 +103,6 @@ Below is a sample version of the file: :: | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | | | | +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - Alternatively, run the following commands: :: cd local_repo From 6788a99533ea721ca051579c140013297b14ab9a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 10:33:24 +0530 Subject: [PATCH 083/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 65 +++--------------------------- 1 file changed, 5 insertions(+), 60 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 242c503e4..72a049563 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -43,66 +43,11 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+=========================+======================================================================================================================================================================================================+ -| **repo_store_path** | * The intended file path for offline repository data. | -| | * Ensure the disk partition has enough space. | -| ``string`` | | -| | **Default value**: "/omnia_repo" | -| Required | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | -| | * This value is required on RHEL clusters. | -| ``JSON List`` | * 'url' defines the baseurl for the repository. | -| | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | -| Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **user_registry** | * Lists external user configured mirror registries. | -| | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | -| ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | -| | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | -| Optional | * **Sample value**: :: | -| | | -| | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | -| | - { host: registryhostname.registry.test, cert_path: "" } | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | -| | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | -| ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | -| | | -| Optional | * **Sample value**: http://in.archive.ubuntu.com/ubuntu | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | -| | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | -| ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | -| | | -| Required | **Default value**: :: | -| | | -| | - "registry.k8s.io" | -| | - "quay.io" | -| | - "docker.io" | -| | | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | -| | * 'url' defines the baseurl for the repository. | -| ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | -| | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | -| Required | | -| | **Default value**: :: | -| | | -| | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | -| | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | -| | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | -| | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | -| | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | -| | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | -| | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | -| | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Parameters for Local Repo Configuration + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :keepspace: + Alternatively, run the following commands: :: cd local_repo From ca85efd220130d0c381081bcf933f2b2d890accd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 10:49:49 +0530 Subject: [PATCH 084/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/_static/sphinx-argparse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 0196e7b0e..58464dc57 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -1,5 +1,5 @@ .wy-table-responsive table td { - white-space: normal !important; + white-space: pre-line !important; word-break: break-all; !important; } .wy-table-responsive table th { From 6694b44771192e75e43438f59d3e8d3e4dcc799e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 11:08:43 +0530 Subject: [PATCH 085/309] Updating Local Repository docs Signed-off-by: Goveas --- docs/source/Roles/Airgap/index.rst | 1 + docs/source/_static/sphinx-argparse.css | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/Airgap/index.rst index 72a049563..3fdf1a5db 100644 --- a/docs/source/Roles/Airgap/index.rst +++ b/docs/source/Roles/Airgap/index.rst @@ -48,6 +48,7 @@ Below is a sample version of the file: :: :header-rows: 1 :keepspace: + Alternatively, run the following commands: :: cd local_repo diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 58464dc57..810c3f3df 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -1,6 +1,7 @@ .wy-table-responsive table td { - white-space: pre-line !important; - word-break: break-all; !important; + word-wrap: break-word !important; + overflow-wrap: break-word !important; + word-break: break-all !important; } .wy-table-responsive table th { background-color: #2980b9; From 4e927457a77a149e8b42bbde020906b2bdc87e60 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 12:00:20 +0530 Subject: [PATCH 086/309] Updating KubernetesAccess.rst docs Signed-off-by: Goveas --- .../InstallationGuides/BuildingClusters/KubernetesAccess.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 0d3f29ef1..d6a96c249 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -8,7 +8,7 @@ Omnia grants cluster node access to users defined on the manager node using the * Ensure the Kubernetes cluster is up and running. * Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma separated list of users. * Verify that all intended users have a home directory set up on the manager node. -* Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. If this file is not updated, root access will be provided to the users.Kubernetes +* Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. * The passed inventory should contain a defined ``kube_control_plane``. To run the playbook, use the below command: :: From 93e29d29f5efcaafd3b216c4491afcc50d78c80f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 12:37:20 +0530 Subject: [PATCH 087/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/Roles/{Airgap => LocalRepo}/index.rst | 0 docs/source/Tables/software_config.csv | 8 +++++--- docs/source/conf.py | 5 ++++- docs/source/samplefiles.rst | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) rename docs/source/Roles/{Airgap => LocalRepo}/index.rst (100%) diff --git a/docs/source/Roles/Airgap/index.rst b/docs/source/Roles/LocalRepo/index.rst similarity index 100% rename from docs/source/Roles/Airgap/index.rst rename to docs/source/Roles/LocalRepo/index.rst diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index f4df0b320..ca1ee30b7 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -21,13 +21,15 @@ Mandatory","* The OS Version that will be provisoned on compute nodes. Mandatory","* The type of offline configuration user needs. * When the value is set to ``always``, all repositories specified in the ``softwares`` list will be configured. -* When the value is set to ``partial``, all repositories specified in the ``softwares`` list will be configured except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. +* When the value is set to ``partial``, all repositories specified in the ``softwares`` list will be configured except those listed in the ``user_registry`` or ``user_repo_url`` in ``input/local_repo_config.yml``. * When the value is set to ``never``, no images or RPMs will be configured locally. .. note:: All local repositories that are not available as images or RPMs will be configured locally. -* **Accepted values**: always, **partial**, and never. +* **Accepted values**: ``always``, ``**partial**``, and never. " "**softwares** ``JSON list`` -Mandatory",A JSON list of required software and (optionally) the software revision. +Mandatory","A JSON list of required software and (optionally) the software revision. + +.. note:: The accepted names for software is taken from " diff --git a/docs/source/conf.py b/docs/source/conf.py index c216a656d..87ea93a80 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -15,6 +15,9 @@ import sys import os +from datetime import datetime +from sphinxawesome_theme.postprocess import Icons + # If extensions (or modules to document with autodoc) are in another directory, @@ -92,7 +95,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "sphinx_rtd_theme" +html_theme = "sphinxawesome_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index 102e89186..706b5bb2d 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -1,7 +1,7 @@ Sample Files ============= -.. caution:: All the file contents mentioned below are case sensitive. The casing of words like ``[manager]``, ``[compute]``, etc should be consistent with the samples below when creating inventory or mapping files. +.. caution:: All the file contents mentioned below are case sensitive. inventory file ----------------- From d349d6bf7f1a7157a28e79792e0a447b750b410a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 12:43:25 +0530 Subject: [PATCH 088/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/_static/sphinx-argparse.css | 2 +- docs/source/conf.py | 6 +++++- docs/source/requirements.txt | 11 +++++++++-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 810c3f3df..10eebb1ac 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -12,6 +12,6 @@ width: fit-content; block-size: fit-content; overflow: visible !important; - max-width: 800px; + max-width: 750px; } diff --git a/docs/source/conf.py b/docs/source/conf.py index 87ea93a80..2c1bcd0e2 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,7 +33,11 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [] +extensions += [ + "sphinxawesome.highlighting", + # To help you with the upgrade to version 5: + # "sphinxawesome.deprecated", +] html_css_files = ["theme.css"] html_js_files = [ diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt index dbf9ee22b..7476c448d 100644 --- a/docs/source/requirements.txt +++ b/docs/source/requirements.txt @@ -1,2 +1,9 @@ -sphinx-tabs -sphinx-rtd-theme==1.2.2 \ No newline at end of file +sphinx >=3 +sphinxcontrib-napoleon +sphinx-argparse +docutils +myst-parser +configargparse +appdirs +immutables +sphinxawesome-theme \ No newline at end of file From 17fc0d164eb290395edfdfd7fd0ed6c36afa4b19 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 12:46:16 +0530 Subject: [PATCH 089/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/conf.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2c1bcd0e2..93b5a1ea4 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,12 +33,17 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions += [ - "sphinxawesome.highlighting", - # To help you with the upgrade to version 5: - # "sphinxawesome.deprecated", +extensions = [ + "sphinx.ext.mathjax", + "sphinx.ext.viewcode", + "sphinx.ext.napoleon", + "sphinxarg.ext", + "sphinx.ext.autosectionlabel", + "myst_parser", + "sphinxawesome_theme.highlighting", ] + html_css_files = ["theme.css"] html_js_files = [ 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js', From 299315f95ca9660756b8e5344b0853f1ca3f47cc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 12:48:12 +0530 Subject: [PATCH 090/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/conf.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 93b5a1ea4..e564a197c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -33,15 +33,15 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = [ - "sphinx.ext.mathjax", - "sphinx.ext.viewcode", - "sphinx.ext.napoleon", - "sphinxarg.ext", - "sphinx.ext.autosectionlabel", - "myst_parser", - "sphinxawesome_theme.highlighting", -] +#extensions = [ +# "sphinx.ext.mathjax", +# "sphinx.ext.viewcode", +# "sphinx.ext.napoleon", +# "sphinxarg.ext", +# "sphinx.ext.autosectionlabel", +# "myst_parser", +# "sphinxawesome_theme.highlighting", +#] html_css_files = ["theme.css"] From 23f75ddba6c68c632d14417e9ff65248e65d0959 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 12:52:43 +0530 Subject: [PATCH 091/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/conf.py | 23 ++++------------------- docs/source/requirements.txt | 4 ++-- 2 files changed, 6 insertions(+), 21 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index e564a197c..e44e62ae9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,14 +10,11 @@ project = 'Omnia' copyright = '2023, Dell Technologies' author = 'dell/omnia' -release = '1.6' +release = '1.5' rst_epilog = "If you have any feedback about Omnia documentation, please reach out at `omnia.readme@dell.com `_." import sys import os -from datetime import datetime -from sphinxawesome_theme.postprocess import Icons - # If extensions (or modules to document with autodoc) are in another directory, @@ -33,16 +30,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -#extensions = [ -# "sphinx.ext.mathjax", -# "sphinx.ext.viewcode", -# "sphinx.ext.napoleon", -# "sphinxarg.ext", -# "sphinx.ext.autosectionlabel", -# "myst_parser", -# "sphinxawesome_theme.highlighting", -#] - +extensions = [] html_css_files = ["theme.css"] html_js_files = [ @@ -104,7 +92,7 @@ # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. -html_theme = "sphinxawesome_theme" +html_theme = "sphinx_rtd_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the @@ -187,7 +175,4 @@ def setup(app): - app.add_css_file("sphinx-argparse.css") - - - + app.add_css_file("sphinx-argparse.css") \ No newline at end of file diff --git a/docs/source/requirements.txt b/docs/source/requirements.txt index 7476c448d..62ee86d1d 100644 --- a/docs/source/requirements.txt +++ b/docs/source/requirements.txt @@ -1,4 +1,5 @@ -sphinx >=3 +sphinx-tabs +sphinx-rtd-theme==1.2.2 sphinxcontrib-napoleon sphinx-argparse docutils @@ -6,4 +7,3 @@ myst-parser configargparse appdirs immutables -sphinxawesome-theme \ No newline at end of file From cf1b765e98926a6bdf51afee0d05316b61eac8e8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 13:00:41 +0530 Subject: [PATCH 092/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/_static/sphinx-argparse.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 10eebb1ac..5a0a2f8bf 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -2,10 +2,12 @@ word-wrap: break-word !important; overflow-wrap: break-word !important; word-break: break-all !important; + white-space: normal !important; } .wy-table-responsive table th { background-color: #2980b9; color: white; + overflow : visible !important; } .wy-table-responsive { display: block; From 64cf3b65eead046f01d1e66a9d9d25e01398b8bc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 13:01:59 +0530 Subject: [PATCH 093/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/Roles/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/index.rst b/docs/source/Roles/index.rst index b6c696ec9..8934de085 100644 --- a/docs/source/Roles/index.rst +++ b/docs/source/Roles/index.rst @@ -13,7 +13,7 @@ Below is a list of all Omnia's features: Storage/index Accelerator/index Platform/index - Airgap/index + LocalRepo/index Platform/index Utils/index Telemetry/index From f85b666efd3e86ee0f6d1732ad450235013ba9fd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 13:07:19 +0530 Subject: [PATCH 094/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/_static/sphinx-argparse.css | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 5a0a2f8bf..3fc0ff481 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -1,8 +1,6 @@ .wy-table-responsive table td { - word-wrap: break-word !important; - overflow-wrap: break-word !important; - word-break: break-all !important; white-space: normal !important; + word-break: break-all; !important; } .wy-table-responsive table th { background-color: #2980b9; From 72b53d9ffa24b93cd04fe09546316a1ce333143a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 13:16:35 +0530 Subject: [PATCH 095/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/Roles/LocalRepo/index.rst | 5 ++++- docs/source/_static/sphinx-argparse.css | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 3fdf1a5db..1bd9d2c83 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -9,6 +9,9 @@ The local repository feature will help create offline repositories on control pl :file: ../../Tables/software_config.csv :header-rows: 1 :keepspace: + :class: longtable + + Below is a sample version of the file: :: @@ -47,7 +50,7 @@ Below is a sample version of the file: :: :file: ../../Tables/local_repo_config.csv :header-rows: 1 :keepspace: - + :class: longtable Alternatively, run the following commands: :: diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 3fc0ff481..efe657b81 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -1,5 +1,5 @@ .wy-table-responsive table td { - white-space: normal !important; + white-space: inherit !important; word-break: break-all; !important; } .wy-table-responsive table th { From ca00bb17dfb694e59c4f2652fbf8b310220c7553 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 13:58:05 +0530 Subject: [PATCH 096/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/Roles/LocalRepo/index.rst | 73 +++++++++++++++++++++++++-- 1 file changed, 68 insertions(+), 5 deletions(-) diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 1bd9d2c83..900436194 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -46,11 +46,74 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: -.. csv-table:: Parameters for Local Repo Configuration - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :keepspace: - :class: longtable ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Parameter | Details | ++=========================+======================================================================================================================================================================================================+ +| **repo_store_path** | * The intended file path for offline repository data. | +| | * Ensure the disk partition has enough space. | +| ``string`` | | +| | **Default value**: ``"/omnia_repo"`` | +| Required | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | +| | * This value is required on RHEL clusters. | +| ``JSON List`` | * 'url' defines the baseurl for the repository. | +| | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | +| Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **user_registry** | * Lists external user configured mirror registries. | +| | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | +| ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | +| | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | +| Optional | * **Sample value**: :: | +| | | +| | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | +| | - { host: registryhostname.registry.test, cert_path: "" } | +| | | +| | | +| | | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | +| | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | +| ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | +| | | +| Optional | * **Sample value**: ``http://in.archive.ubuntu.com/ubuntu`` | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | +| | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | +| ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | +| | | +| Mandatory | **Default value**: :: | +| | | +| | - "registry.k8s.io" | +| | - "quay.io" | +| | - "docker.io" | +| | | +| | | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | +| | * 'url' defines the baseurl for the repository. | +| ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | +| | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | +| Required | | +| | **Default value**: :: | +| | | +| | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | +| | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | +| | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | +| | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | +| | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | +| | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | +| | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | +| | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | +| | | +| | | +| | | +| | | ++-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + Alternatively, run the following commands: :: From eba5d2a41edd6f92d5fb341777bbd5c1c5dc6783 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 14:01:40 +0530 Subject: [PATCH 097/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/Roles/LocalRepo/index.rst | 134 +++++++++++++------------- 1 file changed, 67 insertions(+), 67 deletions(-) diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 900436194..a61a23b5f 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -46,73 +46,73 @@ Below is a sample version of the file: :: 2. Enter the required values in the ``input/local_repo_config.yml`` file: -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+=========================+======================================================================================================================================================================================================+ -| **repo_store_path** | * The intended file path for offline repository data. | -| | * Ensure the disk partition has enough space. | -| ``string`` | | -| | **Default value**: ``"/omnia_repo"`` | -| Required | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | -| | * This value is required on RHEL clusters. | -| ``JSON List`` | * 'url' defines the baseurl for the repository. | -| | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | -| Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **user_registry** | * Lists external user configured mirror registries. | -| | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | -| ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | -| | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | -| Optional | * **Sample value**: :: | -| | | -| | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | -| | - { host: registryhostname.registry.test, cert_path: "" } | -| | | -| | | -| | | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | -| | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | -| ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | -| | | -| Optional | * **Sample value**: ``http://in.archive.ubuntu.com/ubuntu`` | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | -| | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | -| ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | -| | | -| Mandatory | **Default value**: :: | -| | | -| | - "registry.k8s.io" | -| | - "quay.io" | -| | - "docker.io" | -| | | -| | | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | -| | * 'url' defines the baseurl for the repository. | -| ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | -| | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | -| Required | | -| | **Default value**: :: | -| | | -| | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | -| | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | -| | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | -| | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | -| | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | -| | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | -| | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | -| | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | -| | | -| | | -| | | -| | | -+-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+======================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | + | | * This value is required on RHEL clusters. | + | ``JSON List`` | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * Lists external user configured mirror registries. | + | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | + | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | + | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | + | Optional | * **Sample value**: :: | + | | | + | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | + | | - { host: registryhostname.registry.test, cert_path: "" } | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | + | | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | + | ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | + | | | + | Optional | * **Sample value**: ``http://in.archive.ubuntu.com/ubuntu`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ Alternatively, run the following commands: :: From 4d9cc37b4fc11068968c631a23a7cb07463e086f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 15:19:24 +0530 Subject: [PATCH 098/309] Updating formatting docs Signed-off-by: Goveas --- docs/source/Roles/LocalRepo/index.rst | 6 +++--- docs/source/_static/sphinx-argparse.css | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index a61a23b5f..8fe395240 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -94,9 +94,9 @@ Below is a sample version of the file: :: | | | +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | | Required | | | | **Default value**: :: | | | | diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index efe657b81..bdda09736 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -5,7 +5,7 @@ .wy-table-responsive table th { background-color: #2980b9; color: white; - overflow : visible !important; + } .wy-table-responsive { display: block; From 645ba234ad8efa2ccf04536d0be090a27563a7ed Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 16:00:28 +0530 Subject: [PATCH 099/309] Updating LDAP FAQ docs Signed-off-by: Goveas --- docs/source/Troubleshooting/FAQ.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/source/Troubleshooting/FAQ.rst b/docs/source/Troubleshooting/FAQ.rst index 4794be76f..bdd332ab1 100644 --- a/docs/source/Troubleshooting/FAQ.rst +++ b/docs/source/Troubleshooting/FAQ.rst @@ -68,6 +68,17 @@ Re-run the playbook whose execution failed once the issue is resolved. Run ``kinit admin`` on the node and provide the ``kerberos_admin_password`` when prompted. (This password is also entered in ``input/security_config.yml``.) + +⦾ **Why am I unable to login using LDAP credentials after successfully creating a user account?** + +**Potential Cause**: + + Whitespaces in the LDIF file may have caused an encryption error. Verify whether there are any whitespaces in the file by running ``cat -vet ``. + + **Resolution:** + + Remove the whitespaces and re-run the LDIF file. + ⦾ **Why are the status and admin_mac fields not populated for specific target nodes in the cluster.nodeinfo table?** **Causes**: From ea5ead77603aa4b476f876052465c7bf01efba92 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 14 Feb 2024 18:06:15 +0530 Subject: [PATCH 100/309] Updating LDAP FAQ docs Signed-off-by: Goveas --- docs/source/Roles/Security/index.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index f745fd3c3..cc49703ed 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -157,13 +157,13 @@ Create a new user on OpenLDAP Below is a sample file: :: # User Creation - dn: uid=ldapuser,ou=People,dc=orchid,dc=cluster + dn: uid=ldapuser,ou=People,dc=omnia,dc=test objectClass: inetOrgPerson objectClass: posixAccount objectClass: shadowAccount cn: ldapuser sn: ldapuser - loginShell: /bin/bash + loginShell:/bin/bash uidNumber: 2000 gidNumber: 2000 homeDirectory: /home/ldapuser @@ -172,7 +172,7 @@ Below is a sample file: :: shadowWarning: 0 # Group Creation - dn: cn=ldapuser,ou=Group,dc=orchid,dc=cluster + dn: cn=ldapuser,ou=Group,dc=omnia,dc=test objectClass: posixGroup cn: ldapuser gidNumber: 2000 From b8606e443360c41feca01b0e0a03805ecb2c7a46 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 11:04:22 +0530 Subject: [PATCH 101/309] Updating mapping file provisioning Signed-off-by: Goveas --- .../DiscoveryMechanisms/mappingfile.rst | 22 ++++---- .../installprovisiontool.rst | 27 +++++----- docs/source/Roles/Security/index.rst | 2 +- docs/source/Tables/Provision_creds.csv | 52 +++++++++++++++++++ docs/source/Tables/local_repo_config.csv | 2 +- docs/source/samplefiles.rst | 8 ++- 6 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 docs/source/Tables/Provision_creds.csv diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index 501695207..0f99d49c1 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -1,21 +1,19 @@ mapping -------------- -Manually collect PXE NIC information for target servers and manually define them to Omnia using a mapping file using the below format: +Manually collect PXE NIC information for target servers and define them to Omnia using a mapping file using the below format: **pxe_mapping_file.csv** :: - MAC,Hostname,IP - - xx:yy:zz:aa:bb:cc,server,10.5.0.101 - - aa:bb:cc:dd:ee:ff,server2, 10.5.0.102 + SERVICE_TAG,HOSTNAME,ADMIN_MAC,ADMIN_IP,BMC_IP + 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 + V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 .. note:: - * All the file contents mentioned above are case sensitive. The casing of words like ``[manager]``, ``[compute]``, etc should be consistent with the samples below when creating inventory or mapping files. - * The hostnames listed in the above file should be exclusively lower-case with no special characters. + * All the file contents mentioned above are case sensitive. + * The service tags listed in the above file should be exclusively upper-case with no special characters. * The MAC address provided in ``pxe_mapping_file.csv`` should refer to the PXE NIC on the target nodes. .. caution:: @@ -23,14 +21,18 @@ Manually collect PXE NIC information for target servers and manually define them * **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** * ``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet`` should have the same subnet mask (Omnia only supports /16 subnet masks currently). -The following parameters need to be populated in ``input/provision_config.yml`` to discover target nodes using a mapping file. +The following parameters need to be populated in ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` to discover target nodes using a mapping file. -.. csv-table:: Parameters +.. csv-table:: Parameters for Mapping file configuration :file: ../../../Tables/mapping.csv :header-rows: 1 .. [1] Boolean parameters do not need to be passed with double or single quotes. +.. csv-table:: Credentials for Mapping file configuration + :file: ../../../Tables/Provision_creds.csv + :header-rows: 1 + .. caution:: The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. .. note:: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 3be0808c2..5cec02cad 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -97,20 +97,10 @@ To deploy the Omnia provision tool, run the following command :: To call this playbook individually, ensure that ``input/provision_config.yml`` is updated and then run:: + cd Prepare_cp ansible-playbook prepare_cp.yml -**Creating/updating the repositories** - - * Creates and updates all repositories required locally. - - * This playbook also invokes the ``airgap.yml`` playbook for creating offline repositories. For more information on this, `click here <../../Roles/Airgap/index.html>`_. - - * To call this playbook individually, ensure that ``prepare_cp.yml`` has run at least once and then run:: - - ansible-playbook repo_manipulate.yml - - -**Discovering/provisioning the nodes** +**Discovering the nodes** * Discovers all target servers based on specifications in ``input/provision_config.yml``. @@ -118,13 +108,22 @@ To deploy the Omnia provision tool, run the following command :: * Configures the control plane with NTP services for cluster node synchronization. - * Provisions all discovered servers. + * Encrypts the file ``input/provision_config_credentails.yml``. + - To call this playbook individually, ensure that ``repo_manipulate.yml`` has run at least once and then run:: + To call this playbook individually, run:: + cd Discovery ansible-playbook discovery_provision.yml +**Provisioning the nodes** + + * The intended operating system and version is provisioned on the nodes. + + To call this playbook individually, run:: + cd Provision + ansible-playbook provision.yml ---- After successfully running ``provision.yml``, go to `Building Clusters <../BuildingClusters/index.html>`_ to setup Slurm, Kubernetes, NFS, BeeGFS and Authentication. diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index cc49703ed..c8323439b 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -181,7 +181,7 @@ Below is a sample file: :: .. note:: Avoid whitespaces when using an LDIF file for user creation. Extra spaces in the input data may be encrypted by OpenLDAP and cause access failures. 2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. -3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=orchid,dc=cluster``) +3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=omnia,dc=test``) .. toctree:: diff --git a/docs/source/Tables/Provision_creds.csv b/docs/source/Tables/Provision_creds.csv new file mode 100644 index 000000000..5fcc2d566 --- /dev/null +++ b/docs/source/Tables/Provision_creds.csv @@ -0,0 +1,52 @@ +Parameter,Details +"**provision_password** + +``string`` + +Required","* Password set for the root account of target nodes during provisioning. +* Length >= 8 characters +* Password must not contain -,\, ',""" +"**postgresdb_password** + +``string`` + +Required","* Password set for the postgresDB on target nodes during provisioning. +* Length >= 8 characters +* Password must not contain -,\, ',""" +"**bmc_username** + +``string`` + +Required","* The username set on target iDRACs. +* Username must not contain -,\, ',""" +"**bmc_password** + +``string`` + +Required","* The password set on target iDRACs. +* The username must not contain -,\, ',""" +"**switch_snmp3_username** + +``string`` + +Optional","* Non-admin SNMPv3 credentials of the PXE switch. +* If multiple switches are provided, ensure the credentials are same across switches. +* Username must not contain -,\, ',""" +"**switch_snmp3_password** + +``string`` + +Optional","* Non-admin SNMPv3 credentials of the PXE switch. +* If multiple switches are provided, ensure the credentials are same across switches. +* Password must not contain -,\, ',""" +, +, +, +, +, +, +, +, +, +, +, diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index c7d1b698e..559a347a0 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -6,7 +6,7 @@ Required","* The intended file path for offline repository data. * Ensure the disk partition has enough space. -**Default value**: ""/omnia_repo""" +**Default value**: ``""/omnia_repo""``" "**user_repo_url** ``JSON List`` diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index 706b5bb2d..a66063b79 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -85,11 +85,9 @@ pxe_mapping_file.csv :: - MAC,Hostname,IP - - xx:yy:zz:aa:bb:cc,server,10.5.0.101 - - aa:bb:cc:dd:ee:ff,server2, 10.5.0.102 + SERVICE_TAG,HOSTNAME,ADMIN_MAC,ADMIN_IP,BMC_IP + 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 + V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 .. note:: * To skip the provisioning of a particular node in the list, simply append a '#' to the beginning of the line pertaining to that node. From 0f3d7d2d0982bf8cb34c26e3bac92d9ab01dceba Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 12:45:51 +0530 Subject: [PATCH 102/309] Updating mapping file provisioning Signed-off-by: Goveas --- .../BuildingClusters/Authentication.rst | 15 +-------- .../BuildingClusters/NFS.rst | 2 +- .../BuildingClusters/installscheduler.rst | 5 +-- .../DiscoveryMechanisms/mappingfile.rst | 6 ++-- .../installprovisiontool.rst | 12 +++---- docs/source/Tables/mapping.csv | 33 +++++-------------- 6 files changed, 20 insertions(+), 53 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index 92306021b..6115c8baa 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -127,7 +127,7 @@ Where inventory follows the format defined under inventory file in the provided Using LDAP client ------------------ -To add the cluster to an external LDAP server, Omnia enables the installation of LDAP client on the manager, compute and login nodes. +To add the cluster to an external LDAP server, Omnia enables the installation of LDAP client on all cluster nodes. To customize your LDAP client installation, input parameters in ``input/security_config.yml`` @@ -233,19 +233,6 @@ Use the below command to enable passwordless SSH: :: ansible-playbook user_passwordless_ssh.yml -i inventory -Where inventory follows the format defined under inventory file. :: - - [manager] - 10.5.0.101 - - [compute] - 10.5.0.102 - 10.5.0.103 - - [ldap_server] - 10.5.0.105 - - .. caution:: Do not run ssh-keygen commands after passwordless SSH is set up on the nodes. diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index ef2208db4..eb9a8895a 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -5,7 +5,7 @@ NFS bolt on * Fill out the ``nfs_client_params`` variable in the ``input/storage_config.yml`` file in JSON format using the samples provided below. -* This role runs on manager, compute and login nodes. +* This role runs on all nodes. * Make sure that ``/etc/exports`` on the NFS server is populated with the same paths listed as ``server_share_path`` in the ``nfs_client_params`` in ``input/storage_config.yml``. diff --git a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst index 50624be5a..659930ff3 100644 --- a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst +++ b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst @@ -9,10 +9,7 @@ Building clusters 2. Create an inventory file in the *omnia* folder. Check out the `sample inventory for more information <../../samplefiles.html>`_. - * *[Manager]* group should contain the manager node IP address. [1]_ - * *[compute]* group should contain all compute node IP addresses. - * *[login]* group should contain the login node IP. -.. [1] In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, don't include the manager node IP address in the compute group. In a single node setup, the compute node and the manager node must be the same. +.. [1] In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, do not include the manager node IP address in the compute group. In a single node setup, the compute node and the manager node must be the same. .. include:: ../../Appendices/hostnamereqs.rst diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index 0f99d49c1..8971cef8c 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -12,8 +12,10 @@ Manually collect PXE NIC information for target servers and define them to Omnia V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 .. note:: - * All the file contents mentioned above are case sensitive. - * The service tags listed in the above file should be exclusively upper-case with no special characters. + * The header fields mentioned above are case sensitive. + * The service tags provided are not validated. Ensure the correct service tags are provided. + * The hostnames provided should not contain the domain name of the nodes. + * All fields mentioned in the mapping file are mandatory. * The MAC address provided in ``pxe_mapping_file.csv`` should refer to the PXE NIC on the target nodes. .. caution:: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 5cec02cad..dff7b0505 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -80,22 +80,20 @@ Running the provision tool To deploy the Omnia provision tool, run the following command :: cd provision - ansible-playbook provision.yml + ansible-playbook discovery_provision.yml ``provision.yml`` runs in three stages that can be called individually: **Preparing the control plane** - * Verifies pre-requisites such as SELinux and xCAT services status. * Installs required tool packages. * Verifies and updates firewall settings. * Installs xCAT. - * Configures xCAT databases basis ``input/provision_config.yml``. - * Configures a docker registry to pull images from the internet and store them locally. These images will then be pulled by cluster nodes locally. For more information, `click here. <../Benchmarks/hpcsoftwarestack.html>`_ + * Configures Omnia databases basis ``input/provision_config.yml``. - To call this playbook individually, ensure that ``input/provision_config.yml`` is updated and then run:: + To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` is updated and then run:: cd Prepare_cp ansible-playbook prepare_cp.yml @@ -108,13 +106,11 @@ To deploy the Omnia provision tool, run the following command :: * Configures the control plane with NTP services for cluster node synchronization. - * Encrypts the file ``input/provision_config_credentails.yml``. - To call this playbook individually, run:: cd Discovery - ansible-playbook discovery_provision.yml + ansible-playbook discovery.yml **Provisioning the nodes** diff --git a/docs/source/Tables/mapping.csv b/docs/source/Tables/mapping.csv index 8b7a9e2e8..bee17e6bb 100644 --- a/docs/source/Tables/mapping.csv +++ b/docs/source/Tables/mapping.csv @@ -1,14 +1,4 @@ Parameter,Details -"**network_interface_type** - -``string`` - -Required","The network type used on the Omnia cluster. - -Choices: - -* ``dedicated`` <- default -* ``lom``" "**discovery_mechanism** ``string`` @@ -86,20 +76,6 @@ Required","Language to be used during OS provisioning. Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 **Default values**: ``86400``" -"**provision_password** - -``string`` - -Required","* Password set for the root account of target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',""" -"**postgresdb_password** - -``string`` - -Required","* Password set for the postgresDB on target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',""" "**node_name** ``string`` @@ -253,3 +229,12 @@ Optional","Absolute path to local copy of .rpm file containing CUDA packages. Th Required","* Indicates whether apptainer will be installed on the cluster to enable execution of HPC benchmarks in a containeraized environment. * If ``apptainer_support``: false, apptainer will not be installed on the cluster. * If ``apptainer_support``: true, apptainer will be installed on the cluster." +"**admin_static_start_range** + +``string`` + +Required","**admin_static_start_range** + +``string`` + +Required" \ No newline at end of file From e427c5843a67bba1df14616a42688e2289ffda0d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 12:46:35 +0530 Subject: [PATCH 103/309] Updating mapping file provisioning Signed-off-by: Goveas --- docs/source/samplefiles.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index a66063b79..a45fa690e 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -1,11 +1,10 @@ Sample Files ============= -.. caution:: All the file contents mentioned below are case sensitive. - inventory file ----------------- +.. caution:: All the file contents mentioned below are case sensitive. :: From 8677c169c1f792445d90ac99945726732454c2d8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 13:07:20 +0530 Subject: [PATCH 104/309] Updating mapping file provisioning Signed-off-by: Goveas --- .../InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index 8971cef8c..fcfb57541 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -17,6 +17,7 @@ Manually collect PXE NIC information for target servers and define them to Omnia * The hostnames provided should not contain the domain name of the nodes. * All fields mentioned in the mapping file are mandatory. * The MAC address provided in ``pxe_mapping_file.csv`` should refer to the PXE NIC on the target nodes. + * If the fields ``bmc_static_start_range`` and ``bmc_static_end_range`` are not populated, manually set the nodes to PXE mode and start provisioning. If the fields are populated, Omnia will take care of provisioning automatically. .. caution:: * Do not remove or comment any lines in the ``input/provision_config.yml`` file. From 4bd3fd10cc0f30889176614fb6a5d134b52b50a7 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 13:47:40 +0530 Subject: [PATCH 105/309] Updating mapping file provisioning Signed-off-by: Goveas --- .../InstallingProvisionTool/ViewingDB.rst | 22 +++++++------------ 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index f61f83961..3103a515a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -31,20 +31,14 @@ Via omniadb 4. To view the contents of the ``nodeinfo`` table: ``select * from cluster.nodeinfo;`` :: - id | serial | node | hostname | admin_mac | admin_ip | bmc_ip | ib_ip | status | bmc_mode | switch_ip | switch_name | switch_port - ----+---------+--------------------+--------------------------------+-------------------+--------------+--------------+--------------+------------+----------+---------------+-------------+------------- - 1 | XXXXXXX | control_plane | control_plane.omnia.test | ec:2a:72:34:f7:26 | 10.5.255.254| 10.19.255.254| | | | | | - 2 | XXXXXXX | omnia-node00002 | omnia-node00001.omnia.test | | 10.5.0.102 | 10.19.0.102 | 10.10.0.102 | booted | | 10.96.28.132 | switch1 | 3 - 3 | XXXXXXX | omnia-node00003 | omnia-node00002.omnia.test | | 10.5.0.103 | 10.19.0.103 | 10.10.0.103 | | | 10.96.28.132 | switch1 | 4 - 4 | XXXXXXX | omnia-node00004 | omnia-node00003.omnia.test | 2c:ea:7f:3d:6b:98 | 10.5.0.104 | 10.19.0.104 | 10.10.0.104 | installing | | 10.96.28.132 | switch1 | 5 - 5 | XXXXXXX | omnia-node00005 | omnia-node00004.omnia.test | | 10.5.0.105 | 10.19.0.105 | 10.10.0.105 | | | 10.96.28.132 | switch1 | 6 - 6 | XXXXXXX | omnia-node00006 | omnia-node00005.omnia.test | | 10.5.0.106 | 10.19.0.106 | 10.10.0.106 | | | 10.96.28.132 | switch1 | 7 - 7 | XXXXXXX | omnia-node00007 | omnia-node00006.omnia.test | 4c:d9:8f:76:48:2e | 10.5.0.107 | 10.19.0.107 | 10.10.0.107 | booted | | 10.96.28.132 | switch1 | 8 - 8 | XXXXXXX | omnia-node00008 | omnia-node00007.omnia.test | | 10.5.0.108 | 10.19.0.108 | 10.10.0.108 | | | 10.96.28.132 | switch1 | 1 - 9 | XXXXXXX | omnia-node00009 | omnia-node00008.omnia.test | | 10.5.0.109 | 10.19.0.109 | 10.10.0.109 | failed | | 10.96.28.132 | switch1 | 10 - 10 | XXXXXXX | omnia-node00010 | omnia-node00009.omnia.test | | 10.5.0.110 | 10.19.0.110 | 10.10.0.110 | | | 10.96.28.132 | switch1 | 12 - 11 | XXXXXXX | omnia-node00011 | omnia-node00010.omnia.test | | 10.5.0.111 | 10.19.0.111 | 10.10.0.111 | failed | | 10.96.28.132 | switch1 | 13 - 12 | XXXXXXX | omnia-node00012 | omnia-node00011.omnia.test | | 10.5.0.112 | 10.19.0.112 | 10.10.0.112 | | | 10.96.28.132 | switch1 | 14 + id | service_tag | node | hostname | admin_mac | admin_ip | bmc_ip | status | discovery_mechanism | bmc_mode | switch_ip | switch_name | switch_port + ----+-------------+---------------+-------------------+-------------------+-----------+-----------+--------+---------------------+----------+-----------+-------------+------------- + 1 | | control_plane | control.omnia.test| 2c:ea:7f:b4:6e:ed | 10.27.0.1 | 10.29.0.1 | | | | | | + 2 | 6T2R6Z2 | node1 | node1.omnia.test | 4c:d9:8f:76:48:2e | 10.27.0.3 | 10.29.0.3 | | mapping | | | | + 3 | C2KP643 | node2 | node2.omnia.test | 2c:ea:7f:3d:6b:98 | 10.27.0.2 | 10.29.0.2 | | mapping | | | | + 4 | 6TDL6Z2 | login | login.omnia.test | 20:04:0f:fa:88:d4 | 10.27.0.4 | | | mapping | | | | + (4 rows) + Possible values of node status are powering-off, powering-on, bmcready, installing, booting, post-booting, booted, failed. From e9ddbf4e20b6524ad7f4a447a6883a7abd03cad4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 15:17:51 +0530 Subject: [PATCH 106/309] Updating local repo docs Signed-off-by: Goveas --- .../InstallingProvisionTool/ViewingDB.rst | 1 - .../Roles/LocalRepo/CustomLocalRepo.rst | 105 ++++++++++++++++++ docs/source/Roles/LocalRepo/index.rst | 82 +++++++++++++- 3 files changed, 185 insertions(+), 3 deletions(-) create mode 100644 docs/source/Roles/LocalRepo/CustomLocalRepo.rst diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index 3103a515a..82206b5e4 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -43,7 +43,6 @@ Via omniadb Possible values of node status are powering-off, powering-on, bmcready, installing, booting, post-booting, booted, failed. .. note:: - * Nodes discovered via mapping file will not have a service tag listed against them under serial. * Nodes are listed as failed when the IB NIC or OFED did not get configured. They are still reachable via the admin IP. Correct any underlying connectivity issue on the IB NIC and `re-provision the node <../reprovisioningthecluster.html>`_. * Information on debugging nodes stuck at 'powering-on', 'bmcready' or 'installing' for longer than expected is available `here. <../../Troubleshooting/FAQ.html>`_ Correct any underlying issue on the node and `re-provision the node <../reprovisioningthecluster.html>`_. * A blank node status indicates that no attempt to provision has taken place. Attempt a manual PXE boot on the node to initiate provisioning. diff --git a/docs/source/Roles/LocalRepo/CustomLocalRepo.rst b/docs/source/Roles/LocalRepo/CustomLocalRepo.rst new file mode 100644 index 000000000..b9bd4e8e7 --- /dev/null +++ b/docs/source/Roles/LocalRepo/CustomLocalRepo.rst @@ -0,0 +1,105 @@ +Configuring custom repositories +------------------------------- + +Use the local repository feature to create a customized set of local repositories on the control plane for the cluster nodes to access. + +1. Ensure the ``custom`` entry is included in the ``software_config.json`` file. :: + + { + "cluster_os_type": "rhel", + "cluster_os_version": "8.6", + "repo_config": "always", + "softwares": [ + {"name": "slurm", "version": "20.11.9"}, + {"name": "amd_benchmarks"}, + {"name": "k8s", "version":"1.26.9"}, + {"name": "jupyter", "version": "3.2.0"}, + {"name": "kubeflow", "version": "1.8"}, + {"name": "openldap"}, + {"name": "freeipa"}, + {"name": "beegfs", "version": "7.2.6"}, + {"name": "nfs"}, + {"name": "kserve"}, + {"name": "custom"}, + {"name": "amdgpu", "version": "5.4.6"}, + {"name": "rocm", "version": "5.4.6" }, + {"name": "nvidiagpu", "version": "latest"}, + {"name": "telemetry"}, + {"name": "network", "version": "5.4-2.4.1.3"}, + {"name": "utils"} + ], + + "amdgpu": [ + {"name": "rocm", "version": "5.4.6" } + ] + } + +2. Create a ``custom.json`` file in the following directory: ``input/config//`` to define the repositories. For example, For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and create the file there. The file is a JSON list consisting of the package name, repository type, URL (optional), and version (optional). Below is a sample version of the file: :: + + { + "custom": { + "cluster": [ + { + "package": "ansible==5.3.2", + "type": "pip_module" + }, + { + "package": "docker-ce-24.0.4", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + + { + "package": "gcc", + "type": "rpm", + "repo_name": "appstream" + }, + { + "package": "community.general", + "type": "ansible_galaxy_collection", + "version": "4.4.0" + }, + + { + "package": "perl-Switch", + "type": "rpm", + "repo_name": "codeready-builder" + }, + { + "package": "prometheus-slurm-exporter", + "type": "git", + "url": "https://github.com/vpenso/prometheus-slurm-exporter.git", + "version": "master" + }, + { + "package": "ansible.utils", + "type": "ansible_galaxy_collection", + "version": "2.5.2" + }, + { + "package": "prometheus-2.23.0.linux-amd64", + "type": "tarball", + "url": "https://github.com/prometheus/prometheus/releases/download/v2.23.0/prometheus-2.23.0.linux-amd64.tar.gz" + }, + { + "package": "metallb-native", + "type": "manifest", + "url": "https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yaml" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + } + + ] + } + } + +2. Enter the parameters required in ``input/local_repo_config.yml`` as explained `here `_. + +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 8fe395240..211547f85 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -1,7 +1,7 @@ Local repositories for the cluster ===================================== -The local repository feature will help create offline repositories on control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: +The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: 1. Enter the required values in the ``input/software_config.json`` file: @@ -44,6 +44,81 @@ Below is a sample version of the file: :: ] } + +For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: + +:: + + amdgpu.json + k8s.json + openldap.json + rocm.json + +For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: + + { + + "k8s": { + + "cluster": [ + { + "package": "containerd.io-1.6.16-3.1.el8", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + { + "package": "kubelet", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" + }, + { + "package": "kubeadm", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" + }, + { + "package": "helm", + "type": "tarball", + "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" + }, + { + "package": "registry.k8s.io/kube-apiserver", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "registry.k8s.io/kube-controller-manager", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "quay.io/coreos/etcd", + "version": "v3.5.9", + "type": "image" + }, + { + "package": "quay.io/calico/node", + "version": "v3.25.2", + "type": "image" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + }, + { + "package": "docker.io/kubernetesui/dashboard", + "version": "v2.7.0", + "type": "image" + } + ] + + } + + } + +.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. + 2. Enter the required values in the ``input/local_repo_config.yml`` file: +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -115,10 +190,13 @@ Below is a sample version of the file: :: +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -Alternatively, run the following commands: :: +3. Alternatively, run the following commands: :: cd local_repo ansible-playbook local_repo.yml +.. toctree:: + CustomLocalRepo + From 02e4d5e75c452bdf1792c782f17bccc8b4cb68cd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 16:14:56 +0530 Subject: [PATCH 107/309] Updating local repo docs Signed-off-by: Goveas --- docs/source/samplefiles.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index a45fa690e..fa50e694c 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -88,10 +88,6 @@ pxe_mapping_file.csv 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 -.. note:: - * To skip the provisioning of a particular node in the list, simply append a '#' to the beginning of the line pertaining to that node. - * Hostnames listed in this file should be exclusively lower-case with no special characters. - switch_inventory ------------------ From 15d643dad2a0a91ebdc9b66280eab8dafe4973f5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 15 Feb 2024 16:20:21 +0530 Subject: [PATCH 108/309] Updating mappingfile.rst Signed-off-by: Goveas --- .../DiscoveryMechanisms/mappingfile.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index fcfb57541..19337dc4b 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -15,9 +15,9 @@ Manually collect PXE NIC information for target servers and define them to Omnia * The header fields mentioned above are case sensitive. * The service tags provided are not validated. Ensure the correct service tags are provided. * The hostnames provided should not contain the domain name of the nodes. - * All fields mentioned in the mapping file are mandatory. + * All fields mentioned in the mapping file are mandatory except ``bmc_ip``. * The MAC address provided in ``pxe_mapping_file.csv`` should refer to the PXE NIC on the target nodes. - * If the fields ``bmc_static_start_range`` and ``bmc_static_end_range`` are not populated, manually set the nodes to PXE mode and start provisioning. If the fields are populated, Omnia will take care of provisioning automatically. + * If the field ``bmc_ip`` is not populated, manually set the nodes to PXE mode and start provisioning. If the fields are populated, Omnia will take care of provisioning automatically. .. caution:: * Do not remove or comment any lines in the ``input/provision_config.yml`` file. From 51673443608a90c3e0233b6c816864039e4ba2eb Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 07:59:53 +0530 Subject: [PATCH 109/309] Updating mappingfile.rst Signed-off-by: Goveas --- .../DiscoveryMechanisms/mappingfile.rst | 4 +- docs/source/Tables/mapping.csv | 41 +++++++++++++++---- 2 files changed, 35 insertions(+), 10 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index 19337dc4b..d1b351a44 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -17,7 +17,9 @@ Manually collect PXE NIC information for target servers and define them to Omnia * The hostnames provided should not contain the domain name of the nodes. * All fields mentioned in the mapping file are mandatory except ``bmc_ip``. * The MAC address provided in ``pxe_mapping_file.csv`` should refer to the PXE NIC on the target nodes. - * If the field ``bmc_ip`` is not populated, manually set the nodes to PXE mode and start provisioning. If the fields are populated, Omnia will take care of provisioning automatically. + * If the field ``bmc_ip`` is not populated, manually set the nodes to PXE mode and start provisioning. If the fields are populated and IPMI is enabled, Omnia will take care of provisioning automatically. + * Target servers should be configured to boot in PXE mode with the appropriate NIC as the first boot device. + .. caution:: * Do not remove or comment any lines in the ``input/provision_config.yml`` file. diff --git a/docs/source/Tables/mapping.csv b/docs/source/Tables/mapping.csv index bee17e6bb..3ca315d5d 100644 --- a/docs/source/Tables/mapping.csv +++ b/docs/source/Tables/mapping.csv @@ -116,6 +116,22 @@ Required","Admin NIC of Control Plane. This is the shared LOM NIC. Required","* The subnet within which all Admin IPs are assigned. * The value of this variable cannot be changed after successfully running ``provision.yml``. +**Default values**: ``10.5.0.0``" +"**admin_static_start_range** + +``string`` + +Required","* The start IP of the admin NIC provisioning range. +* The value of this variable cannot be changed after successfully running ``provision.yml``. +* Only the last two octects (16 bits) of IPv4 are dynamic. +**Default values**: ``10.5.0.0``" +"**admin_static_start_range** + +``string`` + +Required","* The end IP of the admin NIC provisioning range. +* The value of this variable cannot be changed after successfully running ``provision.yml``. +* Only the last two octects (16 bits) of IPv4 are dynamic. **Default values**: ``10.5.0.0``" "**pxe_mapping_file_path** @@ -144,6 +160,22 @@ Required","* If provided, Omnia will assign static IPs to IB NICs on the cluster * When the PXE range and BMC subnet are provided, corresponding NICs will be assigned IPs with the same 3rd and 4th octets. * The value of this variable cannot be changed after successfully running ``provision.yml``. " +"**bmc_nic_start_range** + +``string`` + +Required","* The start IP of the admin NIC provisioning range. +* The value of this variable cannot be changed after successfully running ``provision.yml``. +* Only the last two octects (16 bits) of IPv4 are dynamic. +**Default values**: ``10.5.0.0``" +"**bmc_nic_start_range** + +``string`` + +Required","* The end IP of the admin NIC provisioning range. +* The value of this variable cannot be changed after successfully running ``provision.yml``. +* Only the last two octects (16 bits) of IPv4 are dynamic. +**Default values**: ``10.5.0.0``" "**update_repos** ``boolean`` [1]_ @@ -229,12 +261,3 @@ Optional","Absolute path to local copy of .rpm file containing CUDA packages. Th Required","* Indicates whether apptainer will be installed on the cluster to enable execution of HPC benchmarks in a containeraized environment. * If ``apptainer_support``: false, apptainer will not be installed on the cluster. * If ``apptainer_support``: true, apptainer will be installed on the cluster." -"**admin_static_start_range** - -``string`` - -Required","**admin_static_start_range** - -``string`` - -Required" \ No newline at end of file From 1bfd88b6e9bd2922ce35c1de02d1072006ec6838 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 10:03:59 +0530 Subject: [PATCH 110/309] Updating KubernetesAccess.rst Signed-off-by: Goveas --- .../Benchmarks/OpenMPI_AOCC.rst | 2 +- .../BuildingClusters/Authentication.rst | 4 ++-- .../BuildingClusters/KubernetesAccess.rst | 4 ++-- .../BuildingClusters/installscheduler.rst | 4 ++-- .../BuildingClusters/schedulerprereqs.rst | 2 +- .../InstallationGuides/addinganewnode.rst | 2 +- docs/source/Overview/newfeatures.rst | 2 +- docs/source/Overview/releasenotes.rst | 4 ++-- .../Roles/Utils/freeipa_installation.rst | 4 ++-- .../ProductSubsystemSecurity.rst | 2 +- docs/source/Troubleshooting/FAQ.rst | 2 +- docs/source/Troubleshooting/knownissues.rst | 24 +++++++++---------- .../Troubleshooting/troubleshootingguide.rst | 2 +- docs/source/limitations.rst | 4 ++-- 14 files changed, 31 insertions(+), 31 deletions(-) diff --git a/docs/source/InstallationGuides/Benchmarks/OpenMPI_AOCC.rst b/docs/source/InstallationGuides/Benchmarks/OpenMPI_AOCC.rst index 0c2f68ef3..a104c86e0 100644 --- a/docs/source/InstallationGuides/Benchmarks/OpenMPI_AOCC.rst +++ b/docs/source/InstallationGuides/Benchmarks/OpenMPI_AOCC.rst @@ -58,7 +58,7 @@ This topic explains how to manually update servers for MPI jobs. To automaticall systemctl stop slurmd systemctl start slurmd -3. Once the service restarts on the compute nodes, restart ``slurmctld.service`` on the manager node. :: +3. Once the service restarts on the compute nodes, restart ``slurmctld.service`` on the kube_control_plane. :: systemctl stop slurmctld.service systemctl start slurmctld.service diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index 6115c8baa..7b96a4777 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -62,7 +62,7 @@ Enter the following parameters in ``input/security_config.yml``. If a subsequent run of ``security.yml`` or ``omnia.yml``, all configuration files that have been encrypted by the playbook will be unencrypted. -Omnia installs a FreeIPA server on the manager node and FreeIPA clients on the cluster and login node using one of the below commands: :: +Omnia installs a FreeIPA server on the kube_control_plane and FreeIPA clients on the cluster and login node using one of the below commands: :: ansible-playbook security.yml -i inventory @@ -196,7 +196,7 @@ Once user accounts are created, admins can enable passwordless SSH for users to .. note:: * Ensure that the control plane can reach the designated LDAP server. * If ``enable_omnia_nfs`` is true in ``input/omnia_config.yml``, follow the below steps to configure an NFS share on your LDAP server: - - From the manager node: + - From the kube_control_plane: 1. Add the LDAP server IP address to ``/etc/exports``. 2. Run ``exportfs -ra`` to enable the NFS configuration. - From the LDAP server: diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index d6a96c249..22d272b43 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -1,13 +1,13 @@ Granting Kubernetes access --------------------------- -Omnia grants cluster node access to users defined on the manager node using the ``k8_access.yml`` playbook. +Omnia grants Kubernetes node access to users defined on the kube_control_plane using the ``k8_access.yml`` playbook. **Prerequisites** * Ensure the Kubernetes cluster is up and running. * Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma separated list of users. -* Verify that all intended users have a home directory set up on the manager node. +* Verify that all intended users have a home directory set up on the kube_control_plane. * Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. * The passed inventory should contain a defined ``kube_control_plane``. diff --git a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst index 659930ff3..4a644bdc8 100644 --- a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst +++ b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst @@ -5,11 +5,11 @@ Building clusters .. note:: * Use the parameter ``scheduler_type`` in ``input/omnia_config.yml`` to customize what schedulers are installed in the cluster. - * Without the login node, Slurm jobs can be scheduled only through the manager node. + * Without the login node, Slurm jobs can be scheduled only through the kube_control_plane. 2. Create an inventory file in the *omnia* folder. Check out the `sample inventory for more information <../../samplefiles.html>`_. -.. [1] In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, do not include the manager node IP address in the compute group. In a single node setup, the compute node and the manager node must be the same. +.. [1] In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, do not include the kube_control_plane IP address in the compute group. In a single node setup, the compute node and the kube_control_plane must be the same. .. include:: ../../Appendices/hostnamereqs.rst diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst index 0ef2fb805..98d34f32a 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst @@ -17,7 +17,7 @@ Before you build clusters .. note:: * The inventory file accepts both IPs and FQDNs as long as they can be resolved by DNS. - * In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, don't include the manager node IP address in the compute group. In a single node setup, the compute node and the manager node must be the same. + * In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, don't include the kube_control_plane IP address in the compute group. In a single node setup, the compute node and the kube_control_plane must be the same. * Users should also ensure that all repos are available on the cluster nodes running RHEL. diff --git a/docs/source/InstallationGuides/addinganewnode.rst b/docs/source/InstallationGuides/addinganewnode.rst index 57b7ab4b9..df4efe41b 100644 --- a/docs/source/InstallationGuides/addinganewnode.rst +++ b/docs/source/InstallationGuides/addinganewnode.rst @@ -103,7 +103,7 @@ Verify that the node has been provisioned successfully by `checking the Omnia no In the above example, nodes 10.5.0.105 and 10.5.0.106 have been added to the cluster as a compute nodes. .. note:: - * Do not change the manager node in the existing inventory. Simply add the new node information in the compute group. + * Do not change the kube_control_plane in the existing inventory. Simply add the new node information in the compute group. * Only the ``scheduler_type`` in ``input/omnia_config.yml`` and the variables in ``input/storage_config.yml`` can be updated while re-running ``omnia.yml`` to add the new node. All other variables in the files ``input/omnia_config.yml`` and ``input/security_config.yml`` must be unedited. 3. To install `security `_, `job scheduler `_ and storage tools (`NFS `_, `BeeGFS `_) on the node, run ``omnia.yml``: :: diff --git a/docs/source/Overview/newfeatures.rst b/docs/source/Overview/newfeatures.rst index be8a486db..5c52c0b14 100644 --- a/docs/source/Overview/newfeatures.rst +++ b/docs/source/Overview/newfeatures.rst @@ -39,7 +39,7 @@ New Features * Host aliasing for Scheduler and IPA authentication. -* Login and Manager Node access from both public and private NIC. +* Login and kube_control_plane access from both public and private NIC. * Validation check enhancements: diff --git a/docs/source/Overview/releasenotes.rst b/docs/source/Overview/releasenotes.rst index 49fae5aa8..33c89d3de 100644 --- a/docs/source/Overview/releasenotes.rst +++ b/docs/source/Overview/releasenotes.rst @@ -47,7 +47,7 @@ Releases * Host aliasing for Scheduler and IPA authentication. -* Login and Manager Node access from both public and private NIC. +* Login and kube_control_plane access from both public and private NIC. * Validation check enhancements: @@ -197,7 +197,7 @@ Releases * Omnia can deploy cluster nodes with a single NIC. -* All Cluster metrics can be viewed using Grafana on the Control plane (as opposed to checking the manager node on each cluster) +* All Cluster metrics can be viewed using Grafana on the Control plane (as opposed to checking the kube_control_plane on each cluster) * AWX node inventory now displays service tags with the relevant operating system. diff --git a/docs/source/Roles/Utils/freeipa_installation.rst b/docs/source/Roles/Utils/freeipa_installation.rst index 1dea23f5d..8945a3088 100644 --- a/docs/source/Roles/Utils/freeipa_installation.rst +++ b/docs/source/Roles/Utils/freeipa_installation.rst @@ -10,11 +10,11 @@ To customize your installation of FreeIPA, enter the following parameters in ``i +=========================+=================================================================+=======================================================================================================================================================+ | kerberos_admin_password | "admin" user password for the IPA server on RockyOS and RedHat. | The password can be found in the file ``input/security_config.yml`` . | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ipa_server_hostname | The hostname of the IPA server | The hostname can be found on the manager node. | +| ipa_server_hostname | The hostname of the IPA server | The hostname can be found on the kube_control_plane. | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ | domain_name | Domain name | The domain name can be found in the file ``input/security_config.yml``. | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ipa_server_ipadress | The IP address of the IPA server | The IP address can be found on the IPA server on the manager node using the ``ip a`` command. This IP address should be accessible from the NFS node. | +| ipa_server_ipadress | The IP address of the IPA server | The IP address can be found on the IPA server on the kube_control_plane using the ``ip a`` command. This IP address should be accessible from the NFS node. | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/SecurityConfigGuide/ProductSubsystemSecurity.rst b/docs/source/SecurityConfigGuide/ProductSubsystemSecurity.rst index 48e39422c..137262a02 100644 --- a/docs/source/SecurityConfigGuide/ProductSubsystemSecurity.rst +++ b/docs/source/SecurityConfigGuide/ProductSubsystemSecurity.rst @@ -22,7 +22,7 @@ Omnia can be installed via CLI only. Slurm and Kubernetes are deployed and confi To perform these configurations and installations, a secure SSH channel is established between the management node and the following entities: -* Manager Node +* kube_control_plane * Compute Nodes diff --git a/docs/source/Troubleshooting/FAQ.rst b/docs/source/Troubleshooting/FAQ.rst index bdd332ab1..37864b26c 100644 --- a/docs/source/Troubleshooting/FAQ.rst +++ b/docs/source/Troubleshooting/FAQ.rst @@ -125,7 +125,7 @@ Re-run the playbook whose execution failed once the issue is resolved. **Resolution**: If ``enable_omnia_nfs`` is true in ``input/omnia_config.yml``, follow the below steps to configure an NFS share on your LDAP server: - - From the manager node: + - From the kube_control_plane: 1. Add the LDAP server IP address to ``/etc/exports``. 2. Run ``exportfs -ra`` to enable the NFS configuration. - From the LDAP server: diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index e5214d832..98aaa3472 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -25,11 +25,11 @@ Omnia does not maintain any order when assigning hostnames to target nodes. **Resolution**: Ensure a control plane IP is assigned to the admin NIC. -⦾ **Kubernetes pods on the manager node are in CreateContainerConfigError and Calico Pods are in CrashLoopBackoff error after running omnia.yml.** +⦾ **Kubernetes pods on the kube_control_plane are in CreateContainerConfigError and Calico Pods are in CrashLoopBackoff error after running omnia.yml.** **Potential Cause:** -Calico pods are configured with the NIC name of the manager node. If the NIC name of the other nodes are not the same, the pods will throw an error and retry later. +Calico pods are configured with the NIC name of the kube_control_plane. If the NIC name of the other nodes are not the same, the pods will throw an error and retry later. **Workaround:** @@ -147,7 +147,7 @@ Alternatively, run the task manually: :: ⦾ **What to do after a reboot if kubectl commands return: ``The connection to the server head_node_ip:port was refused - did you specify the right host or port?``** -On the control plane or the manager node, run the following commands: :: +On the control plane or the kube_control_plane, run the following commands: :: swapoff -a @@ -160,11 +160,11 @@ On the control plane or the manager node, run the following commands: :: Wait for 15 minutes after the Kubernetes cluster reboots. Next, verify the status of the cluster using the following commands: -* ``kubectl get nodes`` on the manager node to get the real-time k8s cluster status. +* ``kubectl get nodes`` on the kube_control_plane to get the real-time k8s cluster status. -* ``kubectl get pods all-namespaces`` on the manager node to check which the pods are in the **Running** state. +* ``kubectl get pods all-namespaces`` on the kube_control_plane to check which the pods are in the **Running** state. -* ``kubectl cluster-info`` on the manager node to verify that both the k8s master and kubeDNS are in the **Running** state. +* ``kubectl cluster-info`` on the kube_control_plane to verify that both the k8s master and kubeDNS are in the **Running** state. ⦾ **What to do when the Kubernetes services are not in the Running state:** @@ -225,7 +225,7 @@ As defined in RFC 822, the only legal characters are the following: **Potential Cause**: Your Docker pull limit has been exceeded. For more information, click [here](https://www.docker.com/increase-rate-limits) -1. Delete Kubeflow deployment by executing the following command in manager node: ``kfctl delete -V -f /root/k8s/omnia-kubeflow/kfctl_k8s_istio.v1.0.2.yaml`` +1. Delete Kubeflow deployment by executing the following command in kube_control_plane: ``kfctl delete -V -f /root/k8s/omnia-kubeflow/kfctl_k8s_istio.v1.0.2.yaml`` 2. Re-execute ``kubeflow.yml`` after 8-9 hours @@ -238,7 +238,7 @@ As defined in RFC 822, the only legal characters are the following: ⦾ **What to do when Slurm services do not start automatically after the cluster reboots:** -* Manually restart the slurmd services on the manager node by running the following commands: :: +* Manually restart the slurmd services on the kube_control_plane by running the following commands: :: systemctl restart slurmdbd systemctl restart slurmctld @@ -287,9 +287,9 @@ Recommended Actions: - slurmctl restart slurmctld on manager node + slurmctl restart slurmctld on kube_control_plane - systemctl restart slurmdbd on manager node + systemctl restart slurmdbd on kube_control_plane systemctl restart slurmd on compute node @@ -461,7 +461,7 @@ The hostnames of the manager and login nodes are not set in the correct format. **Resolution**: -If you have enabled the option to install the login node in the cluster, set the hostnames of the nodes in the format: *hostname.domainname*. For example, *manager.omnia.test* is a valid hostname for the login node. **Note**: To find the cause for the failure of the FreeIPA server and client installation, see *ipaserver-install.log* in the manager node or */var/log/ipaclient-install.log* in the login node. +If you have enabled the option to install the login node in the cluster, set the hostnames of the nodes in the format: *hostname.domainname*. For example, *manager.omnia.test* is a valid hostname for the login node. **Note**: To find the cause for the failure of the FreeIPA server and client installation, see *ipaserver-install.log* in the kube_control_plane or */var/log/ipaclient-install.log* in the login node. ⦾ **Why does FreeIPA installation fail on the control plane when the public NIC provided is static?** @@ -474,7 +474,7 @@ If you have enabled the option to install the login node in the cluster, set the **Potential Cause**: Your Docker pull limit has been exceeded. For more information, `click here `_. -1. Delete Jupyterhub deployment by executing the following command in manager node: ``helm delete jupyterhub -n jupyterhub`` +1. Delete Jupyterhub deployment by executing the following command in kube_control_plane: ``helm delete jupyterhub -n jupyterhub`` 2. Re-execute ``jupyterhub.yml`` after 8-9 hours. diff --git a/docs/source/Troubleshooting/troubleshootingguide.rst b/docs/source/Troubleshooting/troubleshootingguide.rst index b4671ab04..fea9b799f 100644 --- a/docs/source/Troubleshooting/troubleshootingguide.rst +++ b/docs/source/Troubleshooting/troubleshootingguide.rst @@ -40,7 +40,7 @@ Using telemetry information to diagnose node issues :header-rows: 1 :keepspace: -.. [1] This metric is collected from the manager node if a login node is absent. +.. [1] This metric is collected from the kube_control_plane if a login node is absent. .. csv-table:: Health telemetry metrics :file: ../Tables/Metrics_Health.csv diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst index 2a2a82e47..5a6908100 100644 --- a/docs/source/limitations.rst +++ b/docs/source/limitations.rst @@ -7,8 +7,8 @@ Limitations - Omnia supports adding only 1000 nodes when discovered via BMC. - Removal of Slurm and Kubernetes component roles are not supported. However, the scheduler type can be customized by setting ``scheduler_type`` in ``input/omnia_config.yml`` prior to running ``omnia.yml``. -- After installing the Omnia control plane, changing the manager node - is not supported. If you need to change the manager node, you must +- After installing the Omnia control plane, changing the kube_control_plane + is not supported. If you need to change the kube_control_plane, you must redeploy the entire cluster. - Dell Technologies provides support to the Dell-developed modules of Omnia. All the other third-party tools deployed by Omnia are outside From 2dd595ce4828931445c4b8f5dd06bcf13b2a51cb Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 12:06:30 +0530 Subject: [PATCH 111/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/ViewingDB.rst | 1 - .../InstallingProvisionTool/installprovisiontool.rst | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index 82206b5e4..cdddd135f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -46,4 +46,3 @@ Possible values of node status are powering-off, powering-on, bmcready, installi * Nodes are listed as failed when the IB NIC or OFED did not get configured. They are still reachable via the admin IP. Correct any underlying connectivity issue on the IB NIC and `re-provision the node <../reprovisioningthecluster.html>`_. * Information on debugging nodes stuck at 'powering-on', 'bmcready' or 'installing' for longer than expected is available `here. <../../Troubleshooting/FAQ.html>`_ Correct any underlying issue on the node and `re-provision the node <../reprovisioningthecluster.html>`_. * A blank node status indicates that no attempt to provision has taken place. Attempt a manual PXE boot on the node to initiate provisioning. - diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index dff7b0505..5c9c9f603 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -91,6 +91,13 @@ To deploy the Omnia provision tool, run the following command :: * Verifies and updates firewall settings. * Installs xCAT. * Configures Omnia databases basis ``input/provision_config.yml``. + * Creates an inventory of all nodes in the cluster at ``/opt/omnia/omnia_inventory/``. This inventory will list nodes based on whether the type of CPUs and GPUs they have. The inventory files are: + + * ``compute_cpu_amd``` + * ``compute_cpu_intel`` + * ``compute_gpu_amd`` + * ``compute_gpu_nvidia`` + * ``compute_servicetag_ip`` To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` is updated and then run:: From fd1e2ad9e42384b46796f988e0904e7d237a5e61 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 12:19:18 +0530 Subject: [PATCH 112/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/installprovisiontool.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 5c9c9f603..30925489f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -91,7 +91,7 @@ To deploy the Omnia provision tool, run the following command :: * Verifies and updates firewall settings. * Installs xCAT. * Configures Omnia databases basis ``input/provision_config.yml``. - * Creates an inventory of all nodes in the cluster at ``/opt/omnia/omnia_inventory/``. This inventory will list nodes based on whether the type of CPUs and GPUs they have. The inventory files are: + * Creates an inventory of all nodes in the cluster at ``/opt/omnia/omnia_inventory/``. This inventory will list nodes based on the type of CPUs and GPUs they have. The inventory files are: * ``compute_cpu_amd``` * ``compute_cpu_intel`` From 7599c7ab78b54cf326f4402b37ddfd794ae6dcfc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 12:31:52 +0530 Subject: [PATCH 113/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/installprovisiontool.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 30925489f..799d65580 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -100,7 +100,7 @@ To deploy the Omnia provision tool, run the following command :: * ``compute_servicetag_ip`` - To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` is updated and then run:: + To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` are updated and then run:: cd Prepare_cp ansible-playbook prepare_cp.yml From cbecd8fe116633a2616f9e86da51b26579bedb8a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 12:40:08 +0530 Subject: [PATCH 114/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/installprovisiontool.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 799d65580..f9ec13dd8 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -99,6 +99,7 @@ To deploy the Omnia provision tool, run the following command :: * ``compute_gpu_nvidia`` * ``compute_servicetag_ip`` + .. note:: Service tags will only be written into the inventory files after the nodes are booted post provisioning. To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` are updated and then run:: From 63e297bda25006fe0ba6e8f741fdfb7642a6f171 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 12:55:12 +0530 Subject: [PATCH 115/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/installprovisiontool.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index f9ec13dd8..92c3e8e89 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -93,13 +93,13 @@ To deploy the Omnia provision tool, run the following command :: * Configures Omnia databases basis ``input/provision_config.yml``. * Creates an inventory of all nodes in the cluster at ``/opt/omnia/omnia_inventory/``. This inventory will list nodes based on the type of CPUs and GPUs they have. The inventory files are: - * ``compute_cpu_amd``` + * ``compute_cpu_amd`` * ``compute_cpu_intel`` * ``compute_gpu_amd`` * ``compute_gpu_nvidia`` * ``compute_servicetag_ip`` - .. note:: Service tags will only be written into the inventory files after the nodes are booted post provisioning. + .. note:: Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` are updated and then run:: From 6c5e01c447e57dbc0534772abe6c1d0107eb44d0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 16:58:30 +0530 Subject: [PATCH 116/309] Updating localrepo Signed-off-by: Goveas --- docs/source/Roles/LocalRepo/index.rst | 142 ++++++++++++++------------ 1 file changed, 74 insertions(+), 68 deletions(-) diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 211547f85..2b8b603d6 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -121,74 +121,80 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+======================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | - | | * This value is required on RHEL clusters. | - | ``JSON List`` | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * Lists external user configured mirror registries. | - | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | - | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | - | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | - | Optional | * **Sample value**: :: | - | | | - | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | - | | - { host: registryhostname.registry.test, cert_path: "" } | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **os_repo_url** | * URL to a list of repositories to be configured for Ubuntu clusters. This value is required on Ubuntu clusters but ignored when the cluster runs RHEL or Rocky. | - | | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. | - | ``string`` | * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. | - | | | - | Optional | * **Sample value**: ``http://in.archive.ubuntu.com/ubuntu`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+======================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | + | | * This value is required on RHEL clusters. | + | ``JSON List`` | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * Lists external user configured mirror registries. | + | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | + | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | + | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | + | Optional | * **Sample value**: :: | + | | | + | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | + | | - { host: registryhostname.registry.test, cert_path: "" } | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 3. Alternatively, run the following commands: :: From ff14011d687ca2deca572e0ee85a058f788add30 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 18:56:25 +0530 Subject: [PATCH 117/309] Updating KubernetesAccess.rst Signed-off-by: Goveas --- .../BuildingClusters/KubernetesAccess.rst | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 22d272b43..1389e1248 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -7,8 +7,20 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u * Ensure the Kubernetes cluster is up and running. * Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma separated list of users. + + +---------------+--------------------------------------------------------------------------------------------+ + | Parameter | Details | + +===============+============================================================================================+ + | **user_name** | * A comma-separated list of users to whom access must be granted. | + | ``String`` | * Every user defined here must have a home directory configured on the kube_control_plane. | + | Required | | + | | * **Sample values**: ``user1`` or ``user1,user2,user3``. | + +---------------+--------------------------------------------------------------------------------------------+ + * Verify that all intended users have a home directory set up on the kube_control_plane. * Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. + * ``resources`` are a list of kubernetes objects or entities that are used to define, configure, and manage applications or infrastructure within a Kubernetes cluster. Possible values include ``["pods", "services", "deployments", "jobs"]``. + * ``verbs`` are a list of actions that can be taken on the ``resources``. Possible values are ``["create", "get", "list", "update", "delete"]``. * The passed inventory should contain a defined ``kube_control_plane``. To run the playbook, use the below command: :: From bd4a50ca1013ace57be4136c5ed927d4e54e9394 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 19:00:04 +0530 Subject: [PATCH 118/309] Updating KubernetesAccess.rst Signed-off-by: Goveas --- .../BuildingClusters/KubernetesAccess.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 1389e1248..198d92c23 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -12,13 +12,15 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u | Parameter | Details | +===============+============================================================================================+ | **user_name** | * A comma-separated list of users to whom access must be granted. | - | ``String`` | * Every user defined here must have a home directory configured on the kube_control_plane. | - | Required | | + | | * Every user defined here must have a home directory configured on the kube_control_plane. | + | ``String`` | | | | * **Sample values**: ``user1`` or ``user1,user2,user3``. | + | Required | | +---------------+--------------------------------------------------------------------------------------------+ * Verify that all intended users have a home directory set up on the kube_control_plane. * Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. + * ``resources`` are a list of kubernetes objects or entities that are used to define, configure, and manage applications or infrastructure within a Kubernetes cluster. Possible values include ``["pods", "services", "deployments", "jobs"]``. * ``verbs`` are a list of actions that can be taken on the ``resources``. Possible values are ``["create", "get", "list", "update", "delete"]``. * The passed inventory should contain a defined ``kube_control_plane``. From c9135bed0772282dc1a40d777da2daa2cbdb64ae Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 16 Feb 2024 19:05:01 +0530 Subject: [PATCH 119/309] Updating KubernetesAccess.rst Signed-off-by: Goveas --- .../BuildingClusters/KubernetesAccess.rst | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 198d92c23..7ca57a78a 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -25,6 +25,33 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u * ``verbs`` are a list of actions that can be taken on the ``resources``. Possible values are ``["create", "get", "list", "update", "delete"]``. * The passed inventory should contain a defined ``kube_control_plane``. +:: + + [auth_server] + + #node12 + + #AI Scheduler: Kubernetes + + [kube_control_plane] + + # node1 + + + [kube_node] + + # node2 + + # node3 + + # node4 + + # node5 + + # node6 + + + To run the playbook, use the below command: :: ansible-playbook -i inventory k8s_access.yml \ No newline at end of file From 6ecef70b03a5a4e611b113ea969be8e5c13cb705 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Sat, 17 Feb 2024 06:16:42 +0530 Subject: [PATCH 120/309] Updating KubernetesAccess.rst Signed-off-by: Goveas --- .../InstallationGuides/BuildingClusters/KubernetesAccess.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 7ca57a78a..4c8ec133a 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -6,6 +6,9 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u **Prerequisites** * Ensure the Kubernetes cluster is up and running. + +**Input parameters** + * Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma separated list of users. +---------------+--------------------------------------------------------------------------------------------+ @@ -23,6 +26,7 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u * ``resources`` are a list of kubernetes objects or entities that are used to define, configure, and manage applications or infrastructure within a Kubernetes cluster. Possible values include ``["pods", "services", "deployments", "jobs"]``. * ``verbs`` are a list of actions that can be taken on the ``resources``. Possible values are ``["create", "get", "list", "update", "delete"]``. + * The passed inventory should contain a defined ``kube_control_plane``. :: From 8128dff7b8248e70f9dc223ee9431729212d1234 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 26 Feb 2024 12:25:56 +0530 Subject: [PATCH 121/309] Updating localrepo/index.rst Signed-off-by: Goveas --- docs/source/Roles/LocalRepo/index.rst | 150 +++++++++++++------------- 1 file changed, 76 insertions(+), 74 deletions(-) diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 2b8b603d6..0d76089f3 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -121,80 +121,82 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+======================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * The code ready builder URL required for downloading packages to a RHEL control plane. | - | | * This value is required on RHEL clusters. | - | ``JSON List`` | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | Optional | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * Lists external user configured mirror registries. | - | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | - | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | - | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | - | Optional | * **Sample value**: :: | - | | | - | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | - | | - { host: registryhostname.registry.test, cert_path: "" } | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+======================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | + | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded. | + | ``JSON List`` | * When ``repo_config`` is partial or never, the given list will not be downloaded. | + | | * 'url' defines the baseurl for the repository. | + | Optional | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * Lists external user configured mirror registries. | + | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | + | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | + | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | + | Optional | * **Sample value**: :: | + | | | + | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | + | | - { host: registryhostname.registry.test, cert_path: "" } | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Required | **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + 3. Alternatively, run the following commands: :: From 9cac01c36d1eee878506676e6ec90c1a319861f2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 26 Feb 2024 16:29:11 +0530 Subject: [PATCH 122/309] Updating localrepo/index.rst Signed-off-by: Goveas --- .../DiscoveryMechanisms/snmp.rst | 51 ---- .../installprovisiontool.rst | 2 + .../LocalRepo/CustomLocalRepo.rst | 119 ++++++++ .../InstallationGuides/LocalRepo/cuda.rst | 41 +++ .../InstallationGuides/LocalRepo/index.rst | 226 +++++++++++++++ .../InstallationGuides/LocalRepo/ofed.rst | 3 + .../InstallationGuides/RunningInit/index.rst | 2 +- docs/source/InstallationGuides/index.rst | 1 + .../Overview/NetworkTopologies/dedicated.rst | 2 +- .../Roles/LocalRepo/CustomLocalRepo.rst | 42 ++- docs/source/Roles/LocalRepo/index.rst | 42 ++- docs/source/Tables/snmpwalk.csv | 262 ------------------ 12 files changed, 450 insertions(+), 343 deletions(-) delete mode 100644 docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/snmp.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/cuda.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/index.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/ofed.rst delete mode 100644 docs/source/Tables/snmpwalk.csv diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/snmp.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/snmp.rst deleted file mode 100644 index b754e6205..000000000 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/snmp.rst +++ /dev/null @@ -1,51 +0,0 @@ -snmpwalk ----------- - -Omnia can query known switches (by IP and community string) for information on target node MAC IDs. The following parameters need to be populated in ``input/provision_config.yml`` to discover target nodes using SNMP. - -**Pre requisites** - -SNMPv2 should be enabled on the switch specified using ``pxe_switch_ip`` in ``input/provision_config``. - -To enable SNMPv2, log in to the switch and run the following commands: :: - - configure terminal - snmp-server community public ro - exit - -Use ``show snmp community`` to verify your changes. - -.. note:: The commands provided above sets the SNMP community string of the switch to ``public``. Ensure that the community string set above matches the value provided in ``pxe_switch_snmp_community_string`` in ``input/provision_config.yml`` - -.. caution:: - * Target servers with LOM architecture is not supported. - * Do not remove or comment any lines in the ``input/provision_config.yml`` file. - * ``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet`` should have the same subnet mask (Omnia only supports /16 subnet masks currently). - * **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** - - -.. csv-table:: Parameters - :file: ../../../Tables/snmpwalk.csv - :header-rows: 1 - -.. [1] Boolean parameters do not need to be passed with double or single quotes. - -.. caution:: The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. - -.. note:: - - The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: - - To view the encrypted parameters: :: - - ansible-vault view provision_config.yml --vault-password-file .provision_vault_key - - To edit the encrypted parameters: :: - - ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key - - - -To continue to the next steps: - -* `Provisioning the cluster <../installprovisiontool.html>`_ \ No newline at end of file diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 92c3e8e89..a9af890cf 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -151,6 +151,8 @@ After successfully running ``provision.yml``, go to `Building Clusters <../Build * Post execution of ``provision.yml``, IPs/hostnames cannot be re-assigned by changing the mapping file. However, the addition of new nodes is supported as explained `here <../addinganewnode.html>`_. + * Default Python is installed during provisioning on Ubuntu cluster nodes. For Ubuntu 22.04, Python 3.10 is installed. For Ubuntu 20.04, Python 3.8 is installed. + .. caution:: * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. diff --git a/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst new file mode 100644 index 000000000..ab6869147 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst @@ -0,0 +1,119 @@ +Configuring custom repositories +------------------------------- + +Use the local repository feature to create a customized set of local repositories on the control plane for the cluster nodes to access. + +1. Ensure the ``custom`` entry is included in the ``software_config.json`` file. :: + + { + "cluster_os_type": "ubuntu", + "cluster_os_version": "22.04", + "repo_config": "partial", + "softwares": [ + {"name": "k8s", "version":"1.26.12"}, + {"name": "jupyter", "version": "3.2.0"}, + {"name": "kubeflow", "version": "1.8"}, + {"name": "openldap"}, + {"name": "beegfs", "version": "7.2.6"}, + {"name": "nfs"}, + {"name": "kserve"}, + {"name": "custom"}, + {"name": "amdgpu", "version": "6.0"}, + {"name": "cuda", "version": "12.3.2"}, + {"name": "ofed", "version": "24.01-0.3.3.1"}, + {"name": "telemetry"}, + {"name": "utils"}, + {"name": "vllm"}, + {"name": "pytorch"}, + {"name": "tensorflow"} + ], + + "amdgpu": [ + {"name": "rocm", "version": "6.0" } + ], + "vllm": [ + {"name": "vllm_amd", "version":"vllm-v0.2.4"}, + {"name": "vllm_nvidia", "version": "latest"} + ], + "pytorch": [ + {"name": "pytorch_cpu", "version":"latest"}, + {"name": "pytorch_amd", "version":"latest"}, + {"name": "pytorch_nvidia", "version": "23.12-py3"} + ], + "tensorflow": [ + {"name": "tensorflow_cpu", "version":"latest"}, + {"name": "tensorflow_amd", "version":"latest"}, + {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} + ] + + } + +2. Create a ``custom.json`` file in the following directory: ``input/config//`` to define the repositories. For example, For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and create the file there. The file is a JSON list consisting of the package name, repository type, URL (optional), and version (optional). Below is a sample version of the file: :: + + { + "custom": { + "cluster": [ + { + "package": "ansible==5.3.2", + "type": "pip_module" + }, + { + "package": "docker-ce-24.0.4", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + + { + "package": "gcc", + "type": "rpm", + "repo_name": "appstream" + }, + { + "package": "community.general", + "type": "ansible_galaxy_collection", + "version": "4.4.0" + }, + + { + "package": "perl-Switch", + "type": "rpm", + "repo_name": "codeready-builder" + }, + { + "package": "prometheus-slurm-exporter", + "type": "git", + "url": "https://github.com/vpenso/prometheus-slurm-exporter.git", + "version": "master" + }, + { + "package": "ansible.utils", + "type": "ansible_galaxy_collection", + "version": "2.5.2" + }, + { + "package": "prometheus-2.23.0.linux-amd64", + "type": "tarball", + "url": "https://github.com/prometheus/prometheus/releases/download/v2.23.0/prometheus-2.23.0.linux-amd64.tar.gz" + }, + { + "package": "metallb-native", + "type": "manifest", + "url": "https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yaml" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + } + + ] + } + } + +2. Enter the parameters required in ``input/local_repo_config.yml`` as explained `here `_. + +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst new file mode 100644 index 000000000..9f0c1a8f1 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -0,0 +1,41 @@ +Create local CUDA repository +----------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + To install CUDA, include the following line under ``softwares```: :: + + {"name": "cuda", "version": "12.3.2"}, + + + For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: :: + + { + "cuda": { + "cluster": [ + { "package": "cuda", + "type": "iso", + "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-rhel8-12-3-local-12.3.2_545.23.08-1.x86_64.rpm", + "path": "" + }, + { "package": "dkms", + "type": "rpm", + "repo_name": "epel" + } + ] + } + } + + .. note:: If the target cluster runs on RHEL, ensure the "dkms" package is included in ``input/config/rhel/8.x/cuda.json`` as illustrated above. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst new file mode 100644 index 000000000..c25f1378a --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -0,0 +1,226 @@ +Local repositories for the cluster +===================================== + +The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + + +Below is a sample version of the file: :: + + { + "cluster_os_type": "ubuntu", + "cluster_os_version": "22.04", + "repo_config": "partial", + "softwares": [ + {"name": "k8s", "version":"1.26.12"}, + {"name": "jupyter", "version": "3.2.0"}, + {"name": "kubeflow", "version": "1.8"}, + {"name": "openldap"}, + {"name": "beegfs", "version": "7.2.6"}, + {"name": "nfs"}, + {"name": "kserve"}, + {"name": "custom"}, + {"name": "amdgpu", "version": "6.0"}, + {"name": "cuda", "version": "12.3.2"}, + {"name": "ofed", "version": "24.01-0.3.3.1"}, + {"name": "telemetry"}, + {"name": "utils"}, + {"name": "vllm"}, + {"name": "pytorch"}, + {"name": "tensorflow"} + ], + + "amdgpu": [ + {"name": "rocm", "version": "6.0" } + ], + "vllm": [ + {"name": "vllm_amd", "version":"vllm-v0.2.4"}, + {"name": "vllm_nvidia", "version": "latest"} + ], + "pytorch": [ + {"name": "pytorch_cpu", "version":"latest"}, + {"name": "pytorch_amd", "version":"latest"}, + {"name": "pytorch_nvidia", "version": "23.12-py3"} + ], + "tensorflow": [ + {"name": "tensorflow_cpu", "version":"latest"}, + {"name": "tensorflow_amd", "version":"latest"}, + {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} + ] + + } + + +For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: + +:: + + amdgpu.json + k8s.json + openldap.json + rocm.json + +For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: + + { + + "k8s": { + + "cluster": [ + { + "package": "containerd.io-1.6.16-3.1.el8", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + { + "package": "kubelet", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" + }, + { + "package": "kubeadm", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" + }, + { + "package": "helm", + "type": "tarball", + "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" + }, + { + "package": "registry.k8s.io/kube-apiserver", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "registry.k8s.io/kube-controller-manager", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "quay.io/coreos/etcd", + "version": "v3.5.9", + "type": "image" + }, + { + "package": "quay.io/calico/node", + "version": "v3.25.2", + "type": "image" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + }, + { + "package": "docker.io/kubernetesui/dashboard", + "version": "v2.7.0", + "type": "image" + } + ] + + } + + } + +.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. + +2. Enter the required values in the ``input/local_repo_config.yml`` file: + + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+======================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | + | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded. | + | ``JSON List`` | * When ``repo_config`` is partial or never, the given list will not be downloaded. | + | | * 'url' defines the baseurl for the repository. | + | Optional | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * Lists external user configured mirror registries. | + | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | + | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | + | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | + | Optional | * **Sample value**: :: | + | | | + | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | + | | - { host: registryhostname.registry.test, cert_path: "" } | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Required | **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + +.. toctree:: + cuda + ofed + CustomLocalRepo + + + diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst new file mode 100644 index 000000000..ca91b9ce0 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/ofed.rst @@ -0,0 +1,3 @@ +Create local OFED repository +------------------------------ + diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index 80860771c..51496807c 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -6,7 +6,7 @@ Running prereq.sh cd omnia ./prereq.sh -To install local repositories on the control plane, `click here. <../../Roles/Airgap/index.html>`_ +To install local repositories on the control plane, `click here. <../../Roles/LocalRepo/index.html>`_ .. note:: * If SELinux is not disabled, it will be disabled by the script and the user will be prompted to reboot the control plane. diff --git a/docs/source/InstallationGuides/index.rst b/docs/source/InstallationGuides/index.rst index 530a060ec..1f86246f9 100644 --- a/docs/source/InstallationGuides/index.rst +++ b/docs/source/InstallationGuides/index.rst @@ -40,6 +40,7 @@ Run the script ``prereq.sh`` to verify the system is ready for Omnia deployment. .. toctree:: RunningInit/index + LocalRepo/index InstallingProvisionTool/index PostProvisionScript BuildingClusters/index diff --git a/docs/source/Overview/NetworkTopologies/dedicated.rst b/docs/source/Overview/NetworkTopologies/dedicated.rst index 0a0d8c5bf..fd74981e6 100644 --- a/docs/source/Overview/NetworkTopologies/dedicated.rst +++ b/docs/source/Overview/NetworkTopologies/dedicated.rst @@ -24,4 +24,4 @@ When all compute nodes rely on the control plane for public network access, the * `mapping <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.html>`_ -* `snmpwalk <../../InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/snmp.html>`_ + diff --git a/docs/source/Roles/LocalRepo/CustomLocalRepo.rst b/docs/source/Roles/LocalRepo/CustomLocalRepo.rst index b9bd4e8e7..ab6869147 100644 --- a/docs/source/Roles/LocalRepo/CustomLocalRepo.rst +++ b/docs/source/Roles/LocalRepo/CustomLocalRepo.rst @@ -6,32 +6,46 @@ Use the local repository feature to create a customized set of local repositorie 1. Ensure the ``custom`` entry is included in the ``software_config.json`` file. :: { - "cluster_os_type": "rhel", - "cluster_os_version": "8.6", - "repo_config": "always", + "cluster_os_type": "ubuntu", + "cluster_os_version": "22.04", + "repo_config": "partial", "softwares": [ - {"name": "slurm", "version": "20.11.9"}, - {"name": "amd_benchmarks"}, - {"name": "k8s", "version":"1.26.9"}, + {"name": "k8s", "version":"1.26.12"}, {"name": "jupyter", "version": "3.2.0"}, {"name": "kubeflow", "version": "1.8"}, {"name": "openldap"}, - {"name": "freeipa"}, {"name": "beegfs", "version": "7.2.6"}, {"name": "nfs"}, {"name": "kserve"}, {"name": "custom"}, - {"name": "amdgpu", "version": "5.4.6"}, - {"name": "rocm", "version": "5.4.6" }, - {"name": "nvidiagpu", "version": "latest"}, + {"name": "amdgpu", "version": "6.0"}, + {"name": "cuda", "version": "12.3.2"}, + {"name": "ofed", "version": "24.01-0.3.3.1"}, {"name": "telemetry"}, - {"name": "network", "version": "5.4-2.4.1.3"}, - {"name": "utils"} + {"name": "utils"}, + {"name": "vllm"}, + {"name": "pytorch"}, + {"name": "tensorflow"} ], "amdgpu": [ - {"name": "rocm", "version": "5.4.6" } - ] + {"name": "rocm", "version": "6.0" } + ], + "vllm": [ + {"name": "vllm_amd", "version":"vllm-v0.2.4"}, + {"name": "vllm_nvidia", "version": "latest"} + ], + "pytorch": [ + {"name": "pytorch_cpu", "version":"latest"}, + {"name": "pytorch_amd", "version":"latest"}, + {"name": "pytorch_nvidia", "version": "23.12-py3"} + ], + "tensorflow": [ + {"name": "tensorflow_cpu", "version":"latest"}, + {"name": "tensorflow_amd", "version":"latest"}, + {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} + ] + } 2. Create a ``custom.json`` file in the following directory: ``input/config//`` to define the repositories. For example, For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and create the file there. The file is a JSON list consisting of the package name, repository type, URL (optional), and version (optional). Below is a sample version of the file: :: diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 0d76089f3..12a5d7ff9 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -16,32 +16,46 @@ The local repository feature will help create offline repositories on the contro Below is a sample version of the file: :: { - "cluster_os_type": "rhel", - "cluster_os_version": "8.6", - "repo_config": "always", + "cluster_os_type": "ubuntu", + "cluster_os_version": "22.04", + "repo_config": "partial", "softwares": [ - {"name": "slurm", "version": "20.11.9"}, - {"name": "amd_benchmarks"}, - {"name": "k8s", "version":"1.26.9"}, + {"name": "k8s", "version":"1.26.12"}, {"name": "jupyter", "version": "3.2.0"}, {"name": "kubeflow", "version": "1.8"}, {"name": "openldap"}, - {"name": "freeipa"}, {"name": "beegfs", "version": "7.2.6"}, {"name": "nfs"}, {"name": "kserve"}, {"name": "custom"}, - {"name": "amdgpu", "version": "5.4.6"}, - {"name": "rocm", "version": "5.4.6" }, - {"name": "nvidiagpu", "version": "latest"}, + {"name": "amdgpu", "version": "6.0"}, + {"name": "cuda", "version": "12.3.2"}, + {"name": "ofed", "version": "24.01-0.3.3.1"}, {"name": "telemetry"}, - {"name": "network", "version": "5.4-2.4.1.3"}, - {"name": "utils"} + {"name": "utils"}, + {"name": "vllm"}, + {"name": "pytorch"}, + {"name": "tensorflow"} ], "amdgpu": [ - {"name": "rocm", "version": "5.4.6" } - ] + {"name": "rocm", "version": "6.0" } + ], + "vllm": [ + {"name": "vllm_amd", "version":"vllm-v0.2.4"}, + {"name": "vllm_nvidia", "version": "latest"} + ], + "pytorch": [ + {"name": "pytorch_cpu", "version":"latest"}, + {"name": "pytorch_amd", "version":"latest"}, + {"name": "pytorch_nvidia", "version": "23.12-py3"} + ], + "tensorflow": [ + {"name": "tensorflow_cpu", "version":"latest"}, + {"name": "tensorflow_amd", "version":"latest"}, + {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} + ] + } diff --git a/docs/source/Tables/snmpwalk.csv b/docs/source/Tables/snmpwalk.csv deleted file mode 100644 index d27a68581..000000000 --- a/docs/source/Tables/snmpwalk.csv +++ /dev/null @@ -1,262 +0,0 @@ -Parameter,Details -"**network_interface_type** - -``string`` - -Required","The network type used on the Omnia cluster. - -Choices: - -* ``dedicated`` <- default -* ``lom``" -"**discovery_mechanism** - -``string`` - -Required","The mechanism through which Omnia will discover nodes for provisioning. For more information on how the mechanisms work, go to `DiscoveryMechanisms `_. - -Choices: - -* ``switch_based`` -* ``mapping`` <-default -* ``bmc`` -* ``snmpwalk``" -"**provision_os** - -``string`` - -Required","The operating system to be provisioned on target nodes in the cluster. - -Choices: - -* ``rhel`` <-default -* ``rocky`` - - -.. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** -.. note:: Ubuntu cannot be provisioned using the ``snmpwalk`` method." -"**provision_os_version** - -``string`` - -Required","OS version of provision_os to be installed. - -Choices: - -* ``8.0`` -* ``8.1`` -* ``8.2`` -* ``8.3`` -* ``8.4`` -* ``8.5`` -* ``8.6`` <- default -* ``8.7``" -"**iso_file_path** - -``string`` - -Required","Path where user has placed the iso image that needs to be provisioned on target nodes. Accepted files are Rocky8-DVD or RHEL-8.x-DVD (full OS). iso_file_path should contain the provision_os and provision_os_version values in the filename. - -**Default values**: ``""/home/RHEL-8.6.0-20220420.3-x86_64-dvd1.iso""``" -"**timezone** - -``string`` - -Required","Timezone to be used during OS provisioning. Available timezones are provided `here <../../Appendix.html>`_. - -Choices: - -* ``GMT`` <- default -* ``EST`` -* ``CET`` -* ``MST`` -* ``CST6CDT`` -* ``PST8PDT``" -"**language** - -``string`` - -Required","Language to be used during OS provisioning. - -**Default values**: ``en-US``" -"**default_lease_time** - -``integer`` - -Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 - -**Default values**: ``86400``" -"**provision_password** - -``string`` - -Required","* Password set for the root account of target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',"" -* The first character of the string should be an alphabet." -"**postgresdb_password** - -``string`` - -Required","* Password set for the postgresDB on target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',"" -* The first character of the string should be an alphabet." -"**node_name** - -``string`` - -Required","* Prefix for target node names, if dynamically allocated. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Example: servernode00001.Omnia.test , where node_name =servernode, domain_name =Omnia.test , 00001 used by Omnia. - -**Default values**: ``node``" -"**domain_name** - -``string`` - -Required","* Domain name the user intends to configure on the cluster. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Please provide a valid domain name according to the domain name standards. -* Example: servernode00001.Omnia.test , where node_name=servernode, domain_name=Omnia.test , 00001 used by Omnia." -"**public_nic** - -``string`` - -Required","The nic/ethernet card that is connected to the public internet. - -**Default values**: ``eno2``" -"**admin_nic** - -``string`` - -Required","* Admin NIC of Control Plane. This is the shared LOM NIC. -* The value of this variable cannot be changed after successfully running ``provision.yml``. - -**Default values**: ``eno1``" -"**admin_nic_subnet** - -``string`` - -Required","The subnet within which all Admin IPs are assigned. - -**Default values**: ``10.5.0.0``" -"**ib_nic_subnet** - -``string`` - -Optional","* If provided, Omnia will handle and assign static IPs to cluster node's IB network. -* Only the last 16 bits/2 octets of IPv4 are dynamic -* If provided, the DB entry will be in parallel with the pxe_subnet. -* Example: If ``admin_ip``: 10.5.0.50 and ``ib_nic_subnet``: 10.10.0.0, then ``ib_ip``: 10.10.0.50" -"**bmc_nic_subnet** - -``string`` - -Required","* If provided, Omnia will assign static IPs to BMC NICs on the cluster nodes within the provided subnet. -* If ``network_interface_type``: ``lom``, mandatory for discovery_mechanism: mapping, switch_based and bmc. -* If ``network_interface_type``: ``dedicated``, optional for discovery_mechanism: mapping, snmpwalk. -* Note that since the last 16 bits/2 octets of IPv4 are dynamic, please ensure that the parameter value is set to x.x.0.0. -* When the PXE range and BMC subnet are provided, corresponding NICs will be assigned IPs with the same 3rd and 4th octets. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -" -"**pxe_switch_ip** - -``string`` - -Required","* PXE switch that will be connected to all iDRACs for provisioning -* Ensure that SNMP is enabled on the mentioned switch." -"**pxe_switch_snmp_community_string** - -``string`` - -Required","The SNMP community string used to access statistics, MAC addresses and IPs stored within a router or other device. - -**Default values**: ``public``" -"**update_repos** - -``boolean`` [1]_ - -Required","* Indicates whether ``provision.yml`` will update offline RHEL repos. - -* If ``update_repos``: false, the update repos for BaseOS and AppStream will not be updated to the latest versions available. - -* If ``update_repos``: true, the update repos for BaseOS and AppStream will be updated to the latest versions available. - -.. note:: By default, AppSteam and BaseOS repos will be configured from the given ISO file. - -Choices: - -``false`` <- Default - -``true`` " -" **rhel_repo_alphabetical_folders** - ``boolean`` [1]_ - - Required ","* Indicates whether the packages in local or subscription repos should be ordered in alphabetical directories. - - -* This variable should be filled if control plane OS is RHEL and local RHEL repository is available. - - - -Choices: - -``false`` <- Default - -``true`` " -"**rhel_repo_local_path** - -``JSON list`` - -Optional ","* The repo path and names of the software repository to be configured on the cluster nodes. - -* Provide the repo data file path, which ends with .repo extension in repo_url parameter. - -* Provide a **valid** url for BaseOS and AppStream repositories. Omnia does not validate the ``repo_url`` provided. Invalid entries will cause ``provision.yml`` to fail. - -* This variable should be filled if control plane OS is RHEL and subscription is not activated. - -* This variable should be filled if the control plane OS is Rocky and the ``provision_os`` is rhel. - - -Sample value: :: - - - - { repo: ""AppStream"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-appstream.repo"", repo_name: ""RHEL-8-appstream-partners"" } - - - { repo: ""BaseOS"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-baseos.repo"", repo_name: ""RHEL-8-baseos-partners"" } - - - " -"**disk_partition** - -``JSON list`` - -Optional","* User defined disk partition applied to remote servers. -* The disk partition desired_capacity has to be provided in MB. -* Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. -* Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. -* Values are accepted in the form of JSON list such as: , - { mount_point: ""/home"", desired_capacity: ""102400"" } - - -**Default values**: ``- { mount_point: """", desired_capacity: """" }``" -"**mlnx_ofed_path** - -``string`` - -Optional",Absolute path to a local copy of the .iso file containing Mellanox OFED packages. The image can be downloaded from https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/. Sample value: /root/MLNX_OFED_LINUX-5.8-1.1.2.1-rhel8.6-x86_64.iso -"**cuda_toolkit_path** - -``string`` - -Optional","Absolute path to local copy of .rpm file containing CUDA packages. The cuda rpm can be downloaded from https://developer.nvidia.com/cuda-downloads. CUDA will be installed post provisioning without any user intervention. Eg: cuda_toolkit_path: ""/root/cuda-repo-rhel8-12-0-local-12.0.0_525.60.13-1.x86_64.rpm""" -"**apptainer_support** - -``boolean`` [1]_ - -Required","* Indicates whether apptainer will be installed on the cluster to enable execution of HPC benchmarks in a containeraized environment. -* If ``apptainer_support``: false, apptainer will not be installed on the cluster. -* If ``apptainer_support``: true, apptainer will be installed on the cluster." From d3ac884823235ad4841b36be24fa219020c8e81e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 26 Feb 2024 17:32:01 +0530 Subject: [PATCH 123/309] Updating localrepo/index.rst Signed-off-by: Goveas --- docs/source/InstallationGuides/LocalRepo/cuda.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst index 9f0c1a8f1..eed79b0fd 100644 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -9,12 +9,13 @@ Create local CUDA repository :keepspace: :class: longtable - To install CUDA, include the following line under ``softwares```: :: + +To install CUDA, include the following line under ``softwares```: :: {"name": "cuda", "version": "12.3.2"}, - For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: :: +For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: :: { "cuda": { From ba3125e1ffb0243314575c520bc6724c0eef5c3a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 26 Feb 2024 17:51:05 +0530 Subject: [PATCH 124/309] Updating localrepo/index.rst Signed-off-by: Goveas --- docs/source/InstallationGuides/LocalRepo/cuda.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst index eed79b0fd..256bf8d2a 100644 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -33,7 +33,8 @@ For a list of repositories (and their types) configured for CUDA, view the ``inp } } - .. note:: If the target cluster runs on RHEL, ensure the "dkms" package is included in ``input/config/rhel/8.x/cuda.json`` as illustrated above. + +.. note:: If the target cluster runs on RHEL, ensure the "dkms" package is included in ``input/config/rhel/8.x/cuda.json`` as illustrated above. 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: From 458815718a6865551bf3386f1f2523a344c56abe Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 26 Feb 2024 17:53:08 +0530 Subject: [PATCH 125/309] Updating localrepo/index.rst Signed-off-by: Goveas --- docs/source/Tables/software_config.csv | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index ca1ee30b7..bb86c362d 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -10,7 +10,7 @@ Required","* The operating system running on the cluster. ``string`` -Mandatory","* The OS Version that will be provisoned on compute nodes. +Required","* The OS Version that will be provisoned on compute nodes. * For RHEL, the accepted values are 8.6, 8.7, and 8.8. * For Rocky, the accepted values are 8.6, 8.7, and 8.8. * For Ubuntu, the accepted values are 20.04, 22.04. @@ -19,17 +19,17 @@ Mandatory","* The OS Version that will be provisoned on compute nodes. ``string`` -Mandatory","* The type of offline configuration user needs. +Required","* The type of offline configuration user needs. * When the value is set to ``always``, all repositories specified in the ``softwares`` list will be configured. * When the value is set to ``partial``, all repositories specified in the ``softwares`` list will be configured except those listed in the ``user_registry`` or ``user_repo_url`` in ``input/local_repo_config.yml``. * When the value is set to ``never``, no images or RPMs will be configured locally. .. note:: All local repositories that are not available as images or RPMs will be configured locally. -* **Accepted values**: ``always``, ``**partial**``, and never. +* **Accepted values**: always, **partial**, and never. " "**softwares** ``JSON list`` -Mandatory","A JSON list of required software and (optionally) the software revision. +Required","A JSON list of required software and (optionally) the software revision. .. note:: The accepted names for software is taken from " From 0b39e1d41e28c1df9014e3fa3d4efbfa6924e0f7 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 09:56:52 +0530 Subject: [PATCH 126/309] Updating localrepo/index.rst Signed-off-by: Goveas --- .../InstallationGuides/LocalRepo/index.rst | 149 +++++++++--------- docs/source/Roles/LocalRepo/index.rst | 149 +++++++++--------- 2 files changed, 146 insertions(+), 152 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index c25f1378a..bc8ee4046 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -135,82 +135,79 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+======================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | - | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded. | - | ``JSON List`` | * When ``repo_config`` is partial or never, the given list will not be downloaded. | - | | * 'url' defines the baseurl for the repository. | - | Optional | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * Lists external user configured mirror registries. | - | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | - | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | - | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | - | Optional | * **Sample value**: :: | - | | | - | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | - | | - { host: registryhostname.registry.test, cert_path: "" } | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Required | **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+===================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | + | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | + | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | + | Optional | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | | * | + | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * A list of externally available, user-configured mirror repositories. | + | | * When ``repo_config`` is always, the list given in ``user_repo_url`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the ``user_registry``. | + | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | + | Optional | * 'host' defines the URL and path to the repository. | + | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | + | | * | + | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | * **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | * **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 3. Run the following commands: :: diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 12a5d7ff9..43dfbf47a 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -135,82 +135,79 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+======================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | - | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded. | - | ``JSON List`` | * When ``repo_config`` is partial or never, the given list will not be downloaded. | - | | * 'url' defines the baseurl for the repository. | - | Optional | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | * **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * Lists external user configured mirror registries. | - | | * For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. | - | ``JSON List`` | * 'host' defines the host for registry along with port where registry will be accessible. | - | | * 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. | - | Optional | * **Sample value**: :: | - | | | - | | - { host: 10.11.0.100:5001, cert_path: "/home/ca.crt" } | - | | - { host: registryhostname.registry.test, cert_path: "" } | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Required | **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+===================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | + | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | + | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | + | Optional | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | | * | + | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * A list of externally available, user-configured mirror repositories. | + | | * When ``repo_config`` is always, the list given in ``user_repo_url`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the ``user_registry``. | + | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | + | Optional | * 'host' defines the URL and path to the repository. | + | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | + | | * | + | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | * **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | * **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 3. Alternatively, run the following commands: :: From 9f0af2d5edf752dbf0f6a7849f49d20b4cc87507 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 11:38:04 +0530 Subject: [PATCH 127/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/installprovisiontool.rst | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index a9af890cf..f864dce9b 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -99,7 +99,12 @@ To deploy the Omnia provision tool, run the following command :: * ``compute_gpu_nvidia`` * ``compute_servicetag_ip`` - .. note:: Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. + .. note:: + + * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. + * Nodes must be booted and the service tag must be in the DB for nodes to list in the Inventory file. + * To regenerate an inventory file, use the playbook ``omnia/utils/inventory_tagging.yml``. + To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` are updated and then run:: @@ -147,10 +152,10 @@ After successfully running ``provision.yml``, go to `Building Clusters <../Build * After running ``provision.yml``, the file ``input/provision_config.yml`` will be encrypted. To edit the file, use the command: ``ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key`` - * To re-provision target servers ``provision.yml`` can be re-run with a new inventory file that contains a list of admin (PXE) IPs. For more information, `click here <../reprovisioningthecluster.html>`_ - * Post execution of ``provision.yml``, IPs/hostnames cannot be re-assigned by changing the mapping file. However, the addition of new nodes is supported as explained `here <../addinganewnode.html>`_. + * Ensure the `clean up script <../CleanUpScript.html>`_ is run before any subsequent executions of ``provision.yml``. + * Default Python is installed during provisioning on Ubuntu cluster nodes. For Ubuntu 22.04, Python 3.10 is installed. For Ubuntu 20.04, Python 3.8 is installed. .. caution:: From f78fe68c5940550581de39c77e1bcb71169646d5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 11:54:59 +0530 Subject: [PATCH 128/309] Updating NFS Signed-off-by: Goveas --- .../BuildingClusters/NFS.rst | 5 +- docs/source/Roles/Storage/index.rst | 2 +- docs/source/Tables/scheduler_k8s.csv | 85 +++++++------------ 3 files changed, 37 insertions(+), 55 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index eb9a8895a..2059df825 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -1,5 +1,5 @@ NFS bolt on ------------- +------------- * Ensure that an external NFS server is set up using the `linked steps <../../Appendices/NFSServer.html>`_ alternatively, `nfs_sas.yml <../ConfiguringStorage/index.html>`_ can be leveraged. NFS clients are mounted using the external NFS server's IP. @@ -69,4 +69,5 @@ If ``omnia.yml`` is not leveraged to set up NFS, run the ``storage.yml`` playboo ansible-playbook storage.yml -i inventory -.. note:: Once NFS is successfully set up, set ``enable_omnia_nfs`` (``input/omnia_config.yml``) to false and ``omnia_usrhome_share`` (``input/omnia_config.yml``) to an accessible share path in the NFS share to use the path across the cluster for deployments. \ No newline at end of file + + diff --git a/docs/source/Roles/Storage/index.rst b/docs/source/Roles/Storage/index.rst index c586a6580..527dc071c 100644 --- a/docs/source/Roles/Storage/index.rst +++ b/docs/source/Roles/Storage/index.rst @@ -187,7 +187,7 @@ To open the ports required, use the following steps: cd omnia/storage ansible-playbook storage.yml -i inventory -(Where inventory refers to the `inventory file <../../samplefiles.html>`_ listing manager, login_node and compute nodes.) +(Where inventory refers to the `inventory file <../../samplefiles.html>`_ listing kube_control_plane, login_node and compute nodes.) .. note:: If a subsequent run of ``storage.yml`` fails, the ``storage_config.yml`` file will be unencrypted. diff --git a/docs/source/Tables/scheduler_k8s.csv b/docs/source/Tables/scheduler_k8s.csv index 3feb81112..6bbb86507 100644 --- a/docs/source/Tables/scheduler_k8s.csv +++ b/docs/source/Tables/scheduler_k8s.csv @@ -1,24 +1,12 @@ Variables,Details -"**scheduler_type** +"**mariadb_password** ``string`` - Required ","* Job scheduler to be installed across all nodes in the cluster* -* To install slurm provide ``scheduler_type: ""slurm""`` -* To install k8s provide ``scheduler_type: ""k8s""`` -* To install slurm and k8s provide ``scheduler_type: ""slurm,k8s""`` - -**Default value**: ``""slurm""``" -"**k8s_version** - - ``string`` - - Required ","* Kubernetes version. -* Required when ``scheduler_type: ""k8s""`` - Choices: - - * ``""1.19.3""`` <- default - * ``"" 1.16.7""`` " + Required ","* Password used for Slurm database. +* The Length of the password should be at least 8. +* The password must not contain -,\, ',"" +* **Default value**: ""password""" "**k8s_cni** ``string`` @@ -30,30 +18,13 @@ * ``""calico""`` <- default * ``""flannel""`` " -"**k8s_pod_network_cidr** - - ``string`` - - Required ","* Kubernetes pod network CIDR. -* Make sure this value does not overlap with any of the host networks. -* Required when ``scheduler_type: ""k8s""`` - - **Default values**: ``""10.244.0.0/16""`` " -"**docker_username** +"**pod_external_ip_range** ``string`` - Optional ","* Username for Dockerhub account -* A kubernetes secret will be created and patched to service account in default namespace. This kubernetes secret can be used to pull images from private repositories -* This value is optional but suggested avoiding docker pull limit issues. -* The first character of the string should be an alphabet." -"**docker_password** - - ``string`` - - Optional ","* Password for Dockerhub account -* This value is mandatory if docker username is provided. -* The first character of the string should be an alphabet." + Required ","* These addresses will be used by Loadbalancer for assigning External IPs to K8s services +* Make sure the IP range is not assigned to any node in the cluster. +* **Sample values**: ""10.11.0.100-10.11.0.150"" , ""10.11.0.0/16"" " "**ansible_config_file_path** ``string`` @@ -61,26 +32,36 @@ Required ","* Path to directory hosting ansible config file (ansible.cfg file) * This directory is on the host running ansible, if ansible is installed using dnf * If ansible is installed using pip, this path should be set - - **Default values**: ``/etc/ansible`` " -"**enable_omnia_nfs** - - ``boolean`` [1]_ +* **Default value**: ``/etc/ansible`` " +"**slurm_installation_type** - Required ","* Boolean indicating whether a parallel file system is **not** running in the environment and a share file system (NFS/BeeGFS) will be used to create home directory/ Kubernetes share directory on it. + ``string`` -* When this variable is ``true``, Omnia will create its own NFS share and mount ``omnia_usrhome_share`` on all the nodes. + Optional ","* Indicates whether the slurm installation will support configless or nfs mode +* If set to ``nfs_share``, ensure that a ``share_path`` is provided. Choices: - * ``true`` <- default - * ``false`` " -"**omnia_usrhome_share** + * ``nfs_share`` <- default + * ``configless`` " +"**share_path** ``string`` - Required ","* Path to directory which will be shared across all nodes in the cluster. -* If ``enable_omnia_nfs``: true, NFS share will be created at path mentioned below. -* If ``enable_omnia_nfs``: false, set this variable as path to parallel file system(NFS/BeeGFS) running in the system. - + Optional ","* Path to directory which will be shared across all nodes in the cluster. +* If omitted, ``/mnt/share`` is provided. Default value: ""/home/omnia-share""" +"**k8s_service_addresses** + + ``string`` + + Optional ","* Kubernetes internal network for services. +* This network must be unused in your network infrastructure. +* **Default value**: ""10.233.0.0/18"" " +"**k8s_pod_network_cidr** + + ``string`` + + Optional ","* Kubernetes pod network CIDR for internal network. When used, it will assign IP addresses from this range to individual pods. +* This network must be unused in your network infrastructure. +* **Default value**: ""10.233.64.0/18""" \ No newline at end of file From f3b97347ab894a22291619c43ceae3ee0cf9cfcf Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 11:55:55 +0530 Subject: [PATCH 129/309] Updating NFS Signed-off-by: Goveas --- docs/source/Tables/scheduler_slurm.csv | 60 ++++++++++++-------------- 1 file changed, 27 insertions(+), 33 deletions(-) diff --git a/docs/source/Tables/scheduler_slurm.csv b/docs/source/Tables/scheduler_slurm.csv index e142d3b65..dcbb96ff0 100644 --- a/docs/source/Tables/scheduler_slurm.csv +++ b/docs/source/Tables/scheduler_slurm.csv @@ -1,52 +1,46 @@ Variables,Details -"**scheduler_type** +"**mariadb_password** ``string`` - Required ","* Job scheduler to be installed across all nodes in the cluster* -* To install slurm provide ``scheduler_type: ""slurm""`` -* To install k8s provide ``scheduler_type: ""k8s""`` -* To install slurm and k8s provide ``scheduler_type: ""slurm,k8s""`` - -**Default value**: ``""slurm""``" -"**mariadb_password** + Required ","* Password used for Slurm database. +* The Length of the password should be at least 8. +* The password must not contain -,\, ',"" +* **Default value**: ""password""" +"**k8s_cni** ``string`` - Optional ","* Password used for Slurm database. -* The password must not contain -,\, ',"" -* The length of the password should be at least 8. -* Required when ``scheduler_type: ""slurm""``. -* The first character of the string should be an alphabet. + Required ","* Kubernetes SDN network. +* Required when ``scheduler_type: ""k8s""`` + + Choices: + + * ``""calico""`` <- default + * ``""flannel""`` " +"**pod_external_ip_range** + + ``string`` - **Default value**: ``""password""`` " + Required ","* These addresses will be used by Loadbalancer for assigning External IPs to K8s services +* Make sure the IP range is not assigned to any node in the cluster. +* **Sample values**: ""10.11.0.100-10.11.0.150"" , ""10.11.0.0/16"" " "**ansible_config_file_path** ``string`` Required ","* Path to directory hosting ansible config file (ansible.cfg file) * This directory is on the host running ansible, if ansible is installed using dnf -* If ansible is installed using pip, this path should be set - - **Default values**: ``/etc/ansible`` " -"**enable_omnia_nfs** - - ``boolean`` [1]_ +* If ansible is installed using pip, this path should be set +* **Default value**: ``/etc/ansible`` " +"**slurm_installation_type** - Required ","* Boolean indicating whether a parallel file system is **not** running in the environment and a share file system (NFS/BeeGFS) will be used to create home directory/ Kubernetes share directory on it. + ``string`` -* When this variable is ``true``, Omnia will create its own NFS share and mount ``omnia_usrhome_share`` on all the nodes. + Optional ","* Indicates whether the slurm installation will support configless or nfs mode +* If set to ``nfs_share``, ensure that a ``share_path`` is provided. Choices: - * ``true`` <- default - * ``false`` " -"**omnia_usrhome_share** - - ``string`` - - Required ","* Path to directory which will be shared across all nodes in the cluster. -* If ``enable_omnia_nfs``: true, NFS share will be created at path mentioned below. -* If ``enable_omnia_nfs``: false, set this variable as path to parallel file system(NFS/BeeGFS) running in the system. - -Default value: ""/home/omnia-share""" + * ``nfs_share`` <- default + * ``configless`` " From 9af8a7fc6bcc329d734d5569b9f793e14c3b3dc2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 12:24:14 +0530 Subject: [PATCH 130/309] Updating local repo Signed-off-by: Goveas --- docs/source/Tables/software_config.csv | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index bb86c362d..dfae3a788 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -3,9 +3,9 @@ ``string`` -Required","* The operating system running on the cluster. +Required","* The operating system running on the cluster (``rhel``, ``rocky``, and ``ubuntu``). -**Accepted values**: rocky, rhel, and **ubuntu**." +**Default value**: ``ubuntu``." "**cluster_os_version** ``string`` @@ -20,9 +20,9 @@ Required","* The OS Version that will be provisoned on compute nodes. ``string`` Required","* The type of offline configuration user needs. -* When the value is set to ``always``, all repositories specified in the ``softwares`` list will be configured. -* When the value is set to ``partial``, all repositories specified in the ``softwares`` list will be configured except those listed in the ``user_registry`` or ``user_repo_url`` in ``input/local_repo_config.yml``. -* When the value is set to ``never``, no images or RPMs will be configured locally. +* When the value is set to ``always``, Omnia creates a local repository on the Control plane hosting all the packages/images required for the cluster. +* When the value is set to ``partial``, Omnia creates a local repository on the Control plane hosting all the packages/images except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. +* When the value is set to ``never``, Omnia does not create a local repo/registry. All the packages/images are directly downloaded on the cluster. .. note:: All local repositories that are not available as images or RPMs will be configured locally. * **Accepted values**: always, **partial**, and never. " From 2e7cdc49ee0487990659898ce838ed19523f91d0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 12:32:18 +0530 Subject: [PATCH 131/309] Updating local repo Signed-off-by: Goveas --- docs/source/InstallationGuides/LocalRepo/index.rst | 14 +++++++------- docs/source/Roles/LocalRepo/index.rst | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index bc8ee4046..8d543b3a5 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -144,7 +144,7 @@ For a list of repositories (and their types) configured for kubernetes, view the | | **Default value**: ``"/omnia_repo"`` | | Required | | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | + | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | @@ -153,13 +153,13 @@ For a list of repositories (and their types) configured for kubernetes, view the | | * | | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * A list of externally available, user-configured mirror repositories. | - | | * When ``repo_config`` is always, the list given in ``user_repo_url`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the ``user_registry``. | - | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | - | Optional | * 'host' defines the URL and path to the repository. | + | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | + | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | + | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | + | Optional | * 'host' defines the URL and path to the registry. | | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | - | | * | + | | | | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst index 43dfbf47a..6cdaf5381 100644 --- a/docs/source/Roles/LocalRepo/index.rst +++ b/docs/source/Roles/LocalRepo/index.rst @@ -144,7 +144,7 @@ For a list of repositories (and their types) configured for kubernetes, view the | | **Default value**: ``"/omnia_repo"`` | | Required | | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * A list of externally available, user-configured mirror repositories. | + | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | @@ -153,13 +153,13 @@ For a list of repositories (and their types) configured for kubernetes, view the | | * | | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * A list of externally available, user-configured mirror repositories. | - | | * When ``repo_config`` is always, the list given in ``user_repo_url`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the ``user_registry``. | - | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | - | Optional | * 'host' defines the URL and path to the repository. | + | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | + | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | + | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | + | Optional | * 'host' defines the URL and path to the registry. | | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | - | | * | + | | | | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | From 6968d71f2468fc3d0bf7ad2b1d085bbb841848df Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 13:44:18 +0530 Subject: [PATCH 132/309] Updating local repo Signed-off-by: Goveas --- docs/source/InstallationGuides/LocalRepo/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 8d543b3a5..bcaaa055a 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -150,7 +150,7 @@ For a list of repositories (and their types) configured for kubernetes, view the | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | | Optional | * 'url' defines the baseurl for the repository. | | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | * | + | | | | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | From cc7ce508017fa553df4ccc3d87e83422174d8795 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 13:47:25 +0530 Subject: [PATCH 133/309] Updating local repo Signed-off-by: Goveas --- docs/source/Tables/software_config.csv | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index dfae3a788..784821078 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -20,9 +20,9 @@ Required","* The OS Version that will be provisoned on compute nodes. ``string`` Required","* The type of offline configuration user needs. -* When the value is set to ``always``, Omnia creates a local repository on the Control plane hosting all the packages/images required for the cluster. -* When the value is set to ``partial``, Omnia creates a local repository on the Control plane hosting all the packages/images except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. -* When the value is set to ``never``, Omnia does not create a local repo/registry. All the packages/images are directly downloaded on the cluster. +* When the value is set to ``always``, Omnia creates a local repository/registry on the Control plane hosting all the packages/images required for the cluster. +* When the value is set to ``partial``, Omnia creates a local repository/registry on the Control plane hosting all the packages/images except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. +* When the value is set to ``never``, Omnia does not create a local repository/registry. All the packages/images are directly downloaded on the cluster. .. note:: All local repositories that are not available as images or RPMs will be configured locally. * **Accepted values**: always, **partial**, and never. " From 902a7fdf665ad1bea1736821162de91945e77234 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 14:15:24 +0530 Subject: [PATCH 134/309] Updating local repo Signed-off-by: Goveas --- .../InstallationGuides/LocalRepo/bcm_roce.rst | 42 +++++++++++++++++++ .../InstallationGuides/LocalRepo/index.rst | 1 + 2 files changed, 43 insertions(+) create mode 100644 docs/source/InstallationGuides/LocalRepo/bcm_roce.rst diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst new file mode 100644 index 000000000..1dae9024e --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst @@ -0,0 +1,42 @@ +Create local ROCe repository +----------------------------- + +.. note:: The ROCe driver is only supported on Ubuntu clusters. + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install ROCe, include the following line under ``softwares```: :: + + {"name": "bcm_roce", "version": "229.2.9.0"} + + +For a list of repositories (and their types) configured for ROCe, view the ``input/config/ubuntu//cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: :: + + { + "bcm_roce": { + "cluster": [ + { + "package": "bcm_roce_driver_{{ bcm_roce_version }}", + "type": "tarball", + "url": "", + "path": "" + } + ] + } + } + + +.. note:: The only accepted URL for the ROCe driver is from the Dell Driver website. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index bcaaa055a..d4f85bb8b 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -217,6 +217,7 @@ For a list of repositories (and their types) configured for kubernetes, view the .. toctree:: cuda ofed + bcm_roce CustomLocalRepo From 1a9306908f4ece2077b4f3f0f594bdfa8aad9253 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 14:20:29 +0530 Subject: [PATCH 135/309] Updating local repo Signed-off-by: Goveas --- docs/source/InstallationGuides/LocalRepo/bcm_roce.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst index 1dae9024e..1178191a3 100644 --- a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst +++ b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst @@ -17,7 +17,7 @@ To install ROCe, include the following line under ``softwares```: :: {"name": "bcm_roce", "version": "229.2.9.0"} -For a list of repositories (and their types) configured for ROCe, view the ``input/config/ubuntu//cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: :: +For a list of repositories (and their types) configured for ROCe, view the ``input/config/ubuntu//cuda.json`` file. To customize your ROCe installation, update the file. URLs for different versions can be found `here `_: :: { "bcm_roce": { From d493793dd34d8fa398f9e75478e1e1a8c3d8bf42 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 14:51:33 +0530 Subject: [PATCH 136/309] Updating local repo Signed-off-by: Goveas --- docs/source/InstallationGuides/LocalRepo/bcm_roce.rst | 2 +- docs/source/InstallationGuides/LocalRepo/index.rst | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst index 1178191a3..8e7761807 100644 --- a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst +++ b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst @@ -17,7 +17,7 @@ To install ROCe, include the following line under ``softwares```: :: {"name": "bcm_roce", "version": "229.2.9.0"} -For a list of repositories (and their types) configured for ROCe, view the ``input/config/ubuntu//cuda.json`` file. To customize your ROCe installation, update the file. URLs for different versions can be found `here `_: :: +For a list of repositories (and their types) configured for ROCe, view the ``input/config/ubuntu//bcm_roce.json`` file. To customize your ROCe installation, update the file. URLs for different versions can be found `here `_: :: { "bcm_roce": { diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index d4f85bb8b..fd796bb1d 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -35,7 +35,8 @@ Below is a sample version of the file: :: {"name": "utils"}, {"name": "vllm"}, {"name": "pytorch"}, - {"name": "tensorflow"} + {"name": "tensorflow"}, + {"name": "bcm_roce", "version": "229.2.9.0"} ], "amdgpu": [ From 43f319ad05ec69d120c32c538b408c69b4ad0f6c Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 27 Feb 2024 17:55:26 +0530 Subject: [PATCH 137/309] Updating local repo Signed-off-by: Goveas --- .../InstallingProvisionTool/index.rst | 12 ++++---- .../installprovisiontool.rst | 29 ------------------- .../InstallationGuides/LocalRepo/cuda.rst | 21 ++++++++++++-- .../InstallationGuides/RunningInit/index.rst | 7 +---- docs/source/Tables/software_config.csv | 3 +- 5 files changed, 27 insertions(+), 45 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index bae3ce391..656048c5f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -3,17 +3,15 @@ Installing the provision tool This playbook achieves the following tasks: - * Discovers potential cluster nodes + * Discovers potential cluster nodes. - * Installs Rocky or RHEL on the nodes + * Installs Rocky or RHEL on the nodes. - * Assigns admin/infiniband IPs with optional DHCP routing + * Assigns admin/infiniband IPs with optional DHCP routing. - * Creates access to offline repositories + * Creates access to offline repositories. - * Configures a docker registry to pull images from the internet and store them locally - - * Optionally installs OFED and CUDA + * Configures a docker registry to pull images from the internet and store them locally. .. toctree:: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index f864dce9b..4581fdf89 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -10,35 +10,6 @@ Edit the ``input/provision_config.yml`` file to update the required variables. A Optional configurations managed by the provision tool +++++++++++++++++++++++++++++++++++++++++++++++++++++ -**Installing CUDA** - - **Using the provision tool** - - * If ``cuda_toolkit_path`` is provided in ``input/provision_config.yml`` and NVIDIA GPUs are available on the target nodes, CUDA packages will be deployed post provisioning without user intervention. - - **Using the Accelerator playbook** - - * CUDA can also be installed using `accelerator.yml <../../Roles/Accelerator/index.html>`_ after provisioning the servers (Assuming the provision tool did not install CUDA packages). - - .. note:: - * The CUDA package can be downloaded from `here `_ - * CUDA requires an additional reboot while being installed. While this is taken care of by Omnia, users are required to wait an additional few minutes when running the provision tool with CUDA installation for the target nodes to come up. - - -**Installing OFED** - - **Using the provision tool** - - * If ``mlnx_ofed_path`` is provided in ``input/provision_config.yml`` and Mellanox NICs are available on the target nodes, OFED packages will be deployed post provisioning without user intervention. - - .. note:: When leveraging the provision tool to install OFED, Omnia prevents the following packages from being upgraded: dapl* ibacm infiniband* libmlx* librdma* opensm* ibutils* perftest* openmpi by appending ``exclude=dapl* ibacm infiniband* libmlx* librdma* opensm* ibutils* perftest* openmpi`` to ``/etc/yum.conf``. For more information on this, `click here `_. - - **Using the Network playbook** - - * OFED can also be installed using `network.yml <../../Roles/Network/index.html>`_ after provisioning the servers (Assuming the provision tool did not install OFED packages). - - .. note:: The OFED package can be downloaded from `here `_ . - **Assigning infiniband IPs** diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst index 256bf8d2a..f4c76d1e3 100644 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -15,7 +15,9 @@ To install CUDA, include the following line under ``softwares```: :: {"name": "cuda", "version": "12.3.2"}, -For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: :: +For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: + +For RHEL or Rocky: :: { "cuda": { @@ -33,8 +35,23 @@ For a list of repositories (and their types) configured for CUDA, view the ``inp } } +For Ubuntu: :: + + { + "cuda": { + "cluster": [ + { "package": "cuda", + "type": "iso", + "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-ubuntu2204-12-3-local_12.3.2-545.23.08-1_amd64.deb", + "path": "" + } + ] + } + } -.. note:: If the target cluster runs on RHEL, ensure the "dkms" package is included in ``input/config/rhel/8.x/cuda.json`` as illustrated above. +.. note:: +* If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. +* If the target cluster runs on RHEL or Rocky, ensure the "dkms" package is included in ``input/config//8.x/cuda.json`` as illustrated above. 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index 51496807c..1a88adcad 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -6,12 +6,7 @@ Running prereq.sh cd omnia ./prereq.sh -To install local repositories on the control plane, `click here. <../../Roles/LocalRepo/index.html>`_ - -.. note:: - * If SELinux is not disabled, it will be disabled by the script and the user will be prompted to reboot the control plane. - * If the control plane is running on the minimal edition of the OS, ensure that ``chrony`` and ``podman`` are installed before running ``provision.yml``. - +.. note:: If SELinux is not disabled, it will be disabled by the script and the user will be prompted to reboot the control plane. diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index 784821078..a0fea4658 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -30,6 +30,7 @@ Required","* The type of offline configuration user needs. ``JSON list`` -Required","A JSON list of required software and (optionally) the software revision. +Required","* A JSON list of required software and (optionally) the software revision. +* This value of version is required for OFED and CUDA. .. note:: The accepted names for software is taken from " From 83eb44a0b0800e9bb5202e204da415aa6151ab9d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 28 Feb 2024 13:46:22 +0530 Subject: [PATCH 138/309] Updating local repo Signed-off-by: Goveas --- .../LocalRepo/Prerequisite.rst | 8 +++ .../InstallationGuides/LocalRepo/cuda.rst | 27 +++++----- .../InstallationGuides/LocalRepo/index.rst | 1 + .../InstallationGuides/LocalRepo/ofed.rst | 51 +++++++++++++++++++ .../PostProvisionScript.rst | 20 ++++---- 5 files changed, 84 insertions(+), 23 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/Prerequisite.rst diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst new file mode 100644 index 000000000..7d4aed90e --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -0,0 +1,8 @@ +Before you create local repositories +------------------------------------- + +**On Ubuntu clusters** + +For persistent offline local repositories, (If the parameter ``repo_config`` in ``input/software_config`` is set to ``always``), click `here `_ to set up the required repositories. + +.. note:: This link explains how to build a mirror on an Ubuntu 20.04 server. Adapt the steps and scripts as required for any other version of Ubuntu. \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst index f4c76d1e3..c601aac1e 100644 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -17,6 +17,20 @@ To install CUDA, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: +For Ubuntu: :: + + { + "cuda": { + "cluster": [ + { "package": "cuda", + "type": "iso", + "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-ubuntu2204-12-3-local_12.3.2-545.23.08-1_amd64.deb", + "path": "" + } + ] + } + } + For RHEL or Rocky: :: { @@ -35,19 +49,6 @@ For RHEL or Rocky: :: } } -For Ubuntu: :: - - { - "cuda": { - "cluster": [ - { "package": "cuda", - "type": "iso", - "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-ubuntu2204-12-3-local_12.3.2-545.23.08-1_amd64.deb", - "path": "" - } - ] - } - } .. note:: * If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index fd796bb1d..f753b400d 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -216,6 +216,7 @@ For a list of repositories (and their types) configured for kubernetes, view the ansible-playbook local_repo.yml .. toctree:: + Prerequisite cuda ofed bcm_roce diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst index ca91b9ce0..48b9bc02e 100644 --- a/docs/source/InstallationGuides/LocalRepo/ofed.rst +++ b/docs/source/InstallationGuides/LocalRepo/ofed.rst @@ -1,3 +1,54 @@ Create local OFED repository ------------------------------ +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install OFED, include the following line under ``softwares```: :: + + {"name": "ofed", "version": "24.01-0.3.3.1"}, + + +For a list of repositories (and their types) configured for OFED, view the ``input/config///ofed.json`` file. To customize your OFED installation, update the file.: + +For Ubuntu: :: + +{ + "ofed": { + "cluster": [ + { "package": "ofed", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } +} +For RHEL or Rocky: :: + + { + "ofed": { + "cluster": [ + { "package": "ofed", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-rhel8.7-x86_64.iso", + "path": "" + } + ] + } + } + +.. note:: +* If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index 7cc3b5e97..a97f47f31 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -1,18 +1,18 @@ Creating node inventory ------------------------ -Once the **servers are provisioned**, a list of reachable nodes can be fetched using the below command: :: +When ``provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in `/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: + * ``compute_cpu_amd`` + * ``compute_cpu_intel`` + * ``compute_gpu_amd`` + * ``compute_gpu_nvidia`` + * ``compute_servicetag_ip`` - ansible-playbook post_provision.yml + .. note:: + * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. + * Nodes must be booted and the service tag must be in the DB for nodes to list in the Inventory file. + * To regenerate an inventory file, use the playbook ``utils/inventory_tagging.yml``. -This creates a node inventory in ``/opt/omnia``. :: - cat /opt/omnia/node_inventory - 10.5.0.100 service_tag=XXXXXXX operating_system=RedHat - 10.5.0.101 service_tag=XXXXXXX operating_system=RedHat - 10.5.0.102 service_tag=XXXXXXX operating_system=Rocky - 10.5.0.103 service_tag=XXXXXXX operating_system=Rocky - -To create an inventory when `Building Clusters `_, use the reachable nodes' IP addresses from the above output to assign manager, compute and login groups. For more information on the inventory file used, `click here <../samplefiles.html>`_. From ad71846d0211fd09f445583cf95467accdbf86a5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 28 Feb 2024 14:41:03 +0530 Subject: [PATCH 139/309] Updating inventory tagging Signed-off-by: Goveas --- .../InstallingProvisionTool/ViewingDB.rst | 11 +++----- .../PostProvisionScript.rst | 27 ++++++++++++++++--- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index cdddd135f..2fab009fa 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -31,13 +31,10 @@ Via omniadb 4. To view the contents of the ``nodeinfo`` table: ``select * from cluster.nodeinfo;`` :: - id | service_tag | node | hostname | admin_mac | admin_ip | bmc_ip | status | discovery_mechanism | bmc_mode | switch_ip | switch_name | switch_port - ----+-------------+---------------+-------------------+-------------------+-----------+-----------+--------+---------------------+----------+-----------+-------------+------------- - 1 | | control_plane | control.omnia.test| 2c:ea:7f:b4:6e:ed | 10.27.0.1 | 10.29.0.1 | | | | | | - 2 | 6T2R6Z2 | node1 | node1.omnia.test | 4c:d9:8f:76:48:2e | 10.27.0.3 | 10.29.0.3 | | mapping | | | | - 3 | C2KP643 | node2 | node2.omnia.test | 2c:ea:7f:3d:6b:98 | 10.27.0.2 | 10.29.0.2 | | mapping | | | | - 4 | 6TDL6Z2 | login | login.omnia.test | 20:04:0f:fa:88:d4 | 10.27.0.4 | | | mapping | | | | - (4 rows) + Node cpu gpu cpu_count gpu_count + node1 intel nvidia 1 2 + node2 amd amd 2 1 + node3 amd 1 0 Possible values of node status are powering-off, powering-on, bmcready, installing, booting, post-booting, booted, failed. diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index a97f47f31..2b6654797 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -3,10 +3,29 @@ Creating node inventory When ``provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in `/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: * ``compute_cpu_amd`` - * ``compute_cpu_intel`` - * ``compute_gpu_amd`` - * ``compute_gpu_nvidia`` - * ``compute_servicetag_ip`` + * ``compute_cpu_intel`` :: + + [compute_cpu_intel] + ABCD1 + + * ``compute_gpu_amd`` :: + + [compute_cpu_amd] + ABCD2 + ABCD3 + + * ``compute_gpu_nvidia`` :: + + [compute_gpu_nvidia] + ABCD1 + + + * ``compute_servicetag_ip`` :: + + [compute_servicetag_ip] + ABCD1 ansible_host=10.5.0.2 + ABCD2 ansible_host=10.5.0.3 + ABCD3 ansible_host=10.5.0.4 .. note:: From 07c13b6fa891154138e5a0d2f8418ecd34fed2ba Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 28 Feb 2024 16:52:47 +0530 Subject: [PATCH 140/309] Updating security information Signed-off-by: Goveas --- docs/source/Tables/security_config.csv | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/docs/source/Tables/security_config.csv b/docs/source/Tables/security_config.csv index 83368cf1a..512eaa2c5 100644 --- a/docs/source/Tables/security_config.csv +++ b/docs/source/Tables/security_config.csv @@ -1,21 +1,9 @@ Parameter,Details -"authentication_system - ``string`` - Required ","Indicates whether FreeIPA or OpenLDAP is setup. - - Choices: - - * ``openldap`` <- Default - * ``freeipa`` " -"domain_name +"domain_name ``string`` Required ","* Sets the intended domain name. * If dc=omnia,dc=test, Provide ``omnia.test`` * If dc=dell,dc=omnia,dc=com Provide ``dell.omnia.com`` **Default values**: ``omnia.test`` " -"enable_secure_login_node - ``boolean`` [1]_ - Required ","* Boolean indicating whether security features are to be enabled on the login node or not. - - **Default value**: ``false``" +, \ No newline at end of file From bf3b65aaa9c8c2604037f2424759b2e4e95437af Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 29 Feb 2024 12:22:30 +0530 Subject: [PATCH 141/309] Updating security information Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/FreeIPA.rst | 58 +++++++++ .../InstallationGuides/LocalRepo/OpenLDAP.rst | 58 +++++++++ .../LocalRepo/SecureLoginNode.rst | 74 ++++++++++++ .../InstallationGuides/LocalRepo/index.rst | 3 + .../InstallationGuides/LocalRepo/ofed.rst | 2 + docs/source/Roles/Security/index.rst | 110 ++++++++++-------- docs/source/Tables/security_config.csv | 1 - 7 files changed, 254 insertions(+), 52 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/FreeIPA.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst diff --git a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst new file mode 100644 index 000000000..8a2924cf4 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst @@ -0,0 +1,58 @@ +FreeIPA +-------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install FreeIPA, include the following line under ``softwares```: :: + + {"name": "freeipa"}, + + +For a list of repositories (and their types) configured for FreeIPA, view the ``input/config///freeipa.json`` file. To customize your FreeIPA installation, update the file.: + +For Ubuntu: :: + +{ + "ofed": { + "cluster": [ + { "package": "freeipa", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } +} + + +For RHEL or Rocky: :: + + { + "freeipa": { + "cluster": [ + {"package": "bind", "type": "rpm", "repo_name": "appstream"}, + {"package": "ipa-server-dns", "type": "rpm", "repo_name": "appstream"}, + {"package": "ipa-server", "type": "rpm", "repo_name": "appstream"}, + {"package": "bind-utils", "type": "rpm", "repo_name": "appstream"}, + {"package": "ipa-client", "type": "rpm", "repo_name": "appstream"}, + {"package": "ipa-admintools", "type": "rpm", "repo_name": "appstream"}, + {"package": "idm:DL1", "type": "module", "repo_name": "appstream"}, + {"package": "idm:DL1/{dns,adtrust}", "type": "module", "repo_name": "appstream"}, + {"package": "idm:DL1/client", "type": "module", "repo_name": "appstream"} + ] + } + } + + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst new file mode 100644 index 000000000..bf901e612 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst @@ -0,0 +1,58 @@ +OpenLDAP +-------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install OpenLDAP, include the following line under ``softwares```: :: + + {"name": "openldap"}, + + +For a list of repositories (and their types) configured for OpenLDAP, view the ``input/config///openldap.json`` file. To customize your OpenLDAP installation, update the file.: + +For Ubuntu: :: + +{ + "ofed": { + "cluster": [ + { "package": "freeipa", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } +} + + +For RHEL or Rocky: :: + + { + "openldap": { + "cluster": [ + {"package": "openldap-ltb", "type": "rpm", "repo_name": "ldap"}, + {"package": "openldap-ltb-contrib-overlays", "type": "rpm", "repo_name": "ldap"}, + {"package": "openldap-ltb-mdb-utils", "type": "rpm", "repo_name": "ldap"}, + {"package": "libsodium", "type": "rpm", "repo_name": "epel"}, + { "package": "ansible-role-ldaptoolbox-openldap", + "type": "git", + "url": "https://github.com/ltb-project/ansible-role-ldaptoolbox-openldap.git", + "version": "main" + } + ] + } + } + + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst new file mode 100644 index 000000000..893bff420 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst @@ -0,0 +1,74 @@ +Secure login node +------------------ + + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install OFED, include the following line under ``softwares```: :: + + {"name": "secure_login_node"}, + + +For a list of repositories (and their types) configured for OFED, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: + +For Ubuntu: :: + + { + "ofed": { + "cluster": [ + { "package": "ofed", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } + } + + +For RHEL or Rocky: :: + + { + "secure_login_node": { + "cluster": [ + { + "package": "community.general", + "type": "ansible_galaxy_collection", + "version": "4.4.0" + }, + { + "package": "install-snoopy", + "type": "shell", + "url": "https://github.com/a2o/snoopy/raw/install/install/install-snoopy.sh" + }, + {"package": "mailx", "type": "rpm", "repo_name": "baseos"}, + {"package": "postfix", "type": "rpm", "repo_name": "baseos"}, + {"package": "gcc", "type": "rpm", "repo_name": "appstream"}, + {"package": "gzip", "type": "rpm", "repo_name": "appstream"}, + {"package": "make", "type": "rpm", "repo_name": "baseos"}, + {"package": "procps-ng", "type": "rpm", "repo_name": "baseos"}, + {"package": "socat", "type": "rpm", "repo_name": "appstream"}, + {"package": "tar", "type": "rpm", "repo_name": "appstream"}, + {"package": "wget", "type": "rpm", "repo_name": "appstream"}, + {"package": "psacct", "type": "rpm", "repo_name": "baseos"}, + {"package": "psacct", "type": "rpm", "repo_name": "baseos"}, + {"package": "python3.9", "type": "rpm", "repo_name": "appstream"} + + ] + } + } + + + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index f753b400d..0d7a373bd 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -220,6 +220,9 @@ For a list of repositories (and their types) configured for kubernetes, view the cuda ofed bcm_roce + FreeIPA + OpenLDAP + SecureLoginNode CustomLocalRepo diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst index 48b9bc02e..9e12f451f 100644 --- a/docs/source/InstallationGuides/LocalRepo/ofed.rst +++ b/docs/source/InstallationGuides/LocalRepo/ofed.rst @@ -30,6 +30,8 @@ For Ubuntu: :: ] } } + + For RHEL or Rocky: :: { diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index c8323439b..6b3bd0399 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -11,7 +11,11 @@ The security feature allows users to set up FreeIPA and LDAP to help authenticat Configuring FreeIPA/LDAP security ________________________________ -Enter the following parameters in ``input/security_config.yml``. +**Pre requisites** + +* Run ``local_repo.yml`` to create offline repositories of FreeIPA or OpenLDAP. If both were downloaded, ensure that the non-required system is removed from ``input/software_config.json`` before running ``security.yml``. For more information, `click here <../../InstallationGuides/LocalRepo/SecureLoginNode.html>`_. + +* Enter the following parameters in ``input/security_config.yml``. .. csv-table:: Parameters for Authentication :file: ../../Tables/security_config.csv @@ -30,39 +34,85 @@ Enter the following parameters in ``input/security_config.yml``. .. [1] Boolean parameters do not need to be passed with double or single quotes. +Create a new user on OpenLDAP +----------------------------- + +1. Create an LDIF file (eg: ``create_user.ldif``) on the auth server containing the following information: + + * DN: The distinguished name that indicates where the user will be created. + * objectClass: The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. Here, the values are ``inetOrgPerson``, ``posixAccount``, and ``shadowAccount``. + * UID: The username of the replication user. + * sn: The surname of the intended user. + * cn: The given name of the intended user. + +Below is a sample file: :: + + # User Creation + dn: uid=ldapuser,ou=People,dc=omnia,dc=test + objectClass: inetOrgPerson + objectClass: posixAccount + objectClass: shadowAccount + cn: ldapuser + sn: ldapuser + loginShell:/bin/bash + uidNumber: 2000 + gidNumber: 2000 + homeDirectory: /home/ldapuser + shadowLastChange: 0 + shadowMax: 0 + shadowWarning: 0 + + # Group Creation + dn: cn=ldapuser,ou=Group,dc=omnia,dc=test + objectClass: posixGroup + cn: ldapuser + gidNumber: 2000 + memberUid: ldapuser + +.. note:: Avoid whitespaces when using an LDIF file for user creation. Extra spaces in the input data may be encrypted by OpenLDAP and cause access failures. + +2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. +3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=omnia,dc=test``) + + + Configuring login node security ________________________________ +**Prerequisites** + +* Run ``local_repo.yml`` to create an offline repository of all utilities used to secure the login node. For more information, click here <> + Enter the following parameters in ``input/login_node_security_config.yml``. +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Variable | Details | +==========================+================================================================================================================================================================================+ -| max_failures | The number of login failures that can take place before the account is locked out. | +| **max_failures** | The number of login failures that can take place before the account is locked out. | | ``integer`` | | | Optional | **Default values**: ``3`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| failure_reset_interval | Period (in seconds) after which the number of failed login attempts is reset. Min value: 30; Max value: 60. | +|**failure_reset_interval**|Period (in seconds) after which the number of failed login attempts is reset. Min value: 30; Max value: 60. | | ``integer`` | | | Optional | **Default values**: ``60`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| lockout_duration | Period (in seconds) for which users are locked out. Min value: 5; Max value: 10. | +| **lockout_duration** | Period (in seconds) for which users are locked out. Min value: 5; Max value: 10. | | ``integer`` | | | Optional | **Default values**: ``10`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| session_timeout | User sessions that have been idle for a specific period can be ended automatically. Min value: 90; Max value: 180. | +|**session_timeout** | User sessions that have been idle for a specific period can be ended automatically. Min value: 90; Max value: 180. | | ``integer`` | | | Optional | **Default values**: ``180`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| alert_email_address | Email address used for sending alerts in case of authentication failure. When blank, authentication failure alerts are disabled. Currently, only one email ID is accepted. | +|**alert_email_address** | Email address used for sending alerts in case of authentication failure. When blank, authentication failure alerts are disabled. Currently, only one email ID is accepted. | | ``string`` | | | Optional | | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| user | Access control list of users. Accepted formats are username@ip (root@1.2.3.4) or username (root). Multiple users can be separated using whitespaces. | +|**user** | Access control list of users. Accepted formats are username@ip (root@1.2.3.4) or username (root). Multiple users can be separated using whitespaces. | | ``string`` | | | Optional | | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| allow_deny | This variable decides whether users are to be allowed or denied access. Ensure that AllowUsers or DenyUsers entries on sshd configuration file are not commented. | +|**allow_deny** | This variable decides whether users are to be allowed or denied access. Ensure that AllowUsers or DenyUsers entries on sshd configuration file are not commented. | | ``string`` | | | Optional | Choices: | | | | @@ -76,7 +126,7 @@ Enter the following parameters in ``input/login_node_security_config.yml``. | | * ``false`` <- Default | | | * ``true`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| restrict_softwares | List of services to be disabled (Comma-separated). Example: 'telnet,lpd,bluetooth' | +|**restrict_softwares** | List of services to be disabled (Comma-separated). Example: 'telnet,lpd,bluetooth' | | ``string`` | | | Optional | Choices: | | | | @@ -91,8 +141,6 @@ Enter the following parameters in ``input/login_node_security_config.yml``. Installing LDAP Client ________________________ -Manager and compute nodes will have LDAP client installed and configured if ``authentication_system`` is set to "openldap". The login node does not have LDAP client installed. - .. caution:: No users/groups will be created by Omnia. FreeIPA installation on the NFS node @@ -143,46 +191,6 @@ The inventory should contain auth_server as per the inventory file in `samplefil .. caution:: No users will be created by Omnia. -Create a new user on OpenLDAP ------------------------------ - -1. Create an LDIF file (eg: ``create_user.ldif``) on the auth server containing the following information: - - * DN: The distinguished name that indicates where the user will be created. - * objectClass: The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. Here, the values are ``inetOrgPerson``, ``posixAccount``, and ``shadowAccount``. - * UID: The username of the replication user. - * sn: The surname of the intended user. - * cn: The given name of the intended user. - -Below is a sample file: :: - - # User Creation - dn: uid=ldapuser,ou=People,dc=omnia,dc=test - objectClass: inetOrgPerson - objectClass: posixAccount - objectClass: shadowAccount - cn: ldapuser - sn: ldapuser - loginShell:/bin/bash - uidNumber: 2000 - gidNumber: 2000 - homeDirectory: /home/ldapuser - shadowLastChange: 0 - shadowMax: 0 - shadowWarning: 0 - - # Group Creation - dn: cn=ldapuser,ou=Group,dc=omnia,dc=test - objectClass: posixGroup - cn: ldapuser - gidNumber: 2000 - memberUid: ldapuser - -.. note:: Avoid whitespaces when using an LDIF file for user creation. Extra spaces in the input data may be encrypted by OpenLDAP and cause access failures. - -2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. -3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=omnia,dc=test``) - .. toctree:: ReplicatingLDAP diff --git a/docs/source/Tables/security_config.csv b/docs/source/Tables/security_config.csv index 512eaa2c5..cb5ad1f77 100644 --- a/docs/source/Tables/security_config.csv +++ b/docs/source/Tables/security_config.csv @@ -6,4 +6,3 @@ * If dc=dell,dc=omnia,dc=com Provide ``dell.omnia.com`` **Default values**: ``omnia.test`` " -, \ No newline at end of file From 0853801e440b423d700ccd059f2ad1d945474a2e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 29 Feb 2024 12:33:07 +0530 Subject: [PATCH 142/309] Updating security information Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/FreeIPA.rst | 24 +++++++++---------- .../InstallationGuides/LocalRepo/OpenLDAP.rst | 4 ++-- .../LocalRepo/SecureLoginNode.rst | 4 ++-- .../InstallationGuides/LocalRepo/ofed.rst | 20 ++++++++-------- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst index 8a2924cf4..f8ee5f7c3 100644 --- a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst +++ b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst @@ -1,5 +1,5 @@ -FreeIPA --------- +Create FreeIPA repository +------------------------- 1. Enter the required values in the ``input/software_config.json`` file: @@ -19,17 +19,17 @@ For a list of repositories (and their types) configured for FreeIPA, view the `` For Ubuntu: :: -{ - "ofed": { - "cluster": [ - { "package": "freeipa", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" + { + "ofed": { + "cluster": [ + { "package": "freeipa", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } } - ] - } -} For RHEL or Rocky: :: diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst index bf901e612..97d9d111a 100644 --- a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst +++ b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst @@ -1,5 +1,5 @@ -OpenLDAP --------- +Create OpenLDAP repository +--------------------------- 1. Enter the required values in the ``input/software_config.json`` file: diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst index 893bff420..38a6034f1 100644 --- a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst +++ b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst @@ -1,5 +1,5 @@ -Secure login node ------------------- +Create secure login node repository +----------------------------------- 1. Enter the required values in the ``input/software_config.json`` file: diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst index 9e12f451f..0199b1271 100644 --- a/docs/source/InstallationGuides/LocalRepo/ofed.rst +++ b/docs/source/InstallationGuides/LocalRepo/ofed.rst @@ -19,17 +19,17 @@ For a list of repositories (and their types) configured for OFED, view the ``inp For Ubuntu: :: -{ - "ofed": { - "cluster": [ - { "package": "ofed", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" + { + "ofed": { + "cluster": [ + { "package": "ofed", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } } - ] - } -} For RHEL or Rocky: :: From 35f60bf5110da4729db8f9ea3d6eca38ce9460af Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 29 Feb 2024 12:43:14 +0530 Subject: [PATCH 143/309] Updating security information Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/OpenLDAP.rst | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst index 97d9d111a..0f11482f8 100644 --- a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst +++ b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst @@ -19,17 +19,17 @@ For a list of repositories (and their types) configured for OpenLDAP, view the ` For Ubuntu: :: -{ - "ofed": { - "cluster": [ - { "package": "freeipa", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" + { + "ofed": { + "cluster": [ + { "package": "freeipa", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } } - ] - } -} For RHEL or Rocky: :: From 2b2003c346452f2f0f70ea1bb42c60e52bb29b62 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 29 Feb 2024 12:45:50 +0530 Subject: [PATCH 144/309] Updating security information Signed-off-by: goveac --- docs/source/Roles/Security/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index 6b3bd0399..bbfeb31c0 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -92,7 +92,7 @@ Enter the following parameters in ``input/login_node_security_config.yml``. | ``integer`` | | | Optional | **Default values**: ``3`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -|**failure_reset_interval**|Period (in seconds) after which the number of failed login attempts is reset. Min value: 30; Max value: 60. | +|**failure_reset_interval**| Period (in seconds) after which the number of failed login attempts is reset. Min value: 30; Max value: 60. | | ``integer`` | | | Optional | **Default values**: ``60`` | +--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ From 090825432c89b9ff88fbfbd98872938072989ec3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 1 Mar 2024 13:25:10 +0530 Subject: [PATCH 145/309] Updating AI local repo information Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/PyTorch.rst | 25 +++++++ .../LocalRepo/SecureLoginNode.rst | 18 +---- .../LocalRepo/TensorFlow.rst | 24 +++++++ .../InstallationGuides/LocalRepo/index.rst | 3 + .../InstallationGuides/LocalRepo/kserve.rst | 24 +++++++ .../InstallationGuides/LocalRepo/vLLM.rst | 24 +++++++ docs/source/Roles/Platform/Pytorch.rst | 62 +++++++++++++++++ docs/source/Roles/Platform/SetupvLLM.rst | 5 +- docs/source/Roles/Platform/TensorFlow.rst | 66 +++++++++++++++++++ docs/source/Roles/Platform/index.rst | 5 +- docs/source/Roles/Platform/kserve.rst | 44 +++++++++++++ docs/source/Roles/Security/index.rst | 4 +- 12 files changed, 283 insertions(+), 21 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/PyTorch.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/TensorFlow.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/kserve.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/vLLM.rst create mode 100644 docs/source/Roles/Platform/Pytorch.rst create mode 100644 docs/source/Roles/Platform/TensorFlow.rst create mode 100644 docs/source/Roles/Platform/kserve.rst diff --git a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst new file mode 100644 index 000000000..afcb7bcbb --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst @@ -0,0 +1,25 @@ +Create local PyTorch repository +------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install PyTorch, include the following line under ``softwares```: :: + + {"name": "pytorch"}, + + +For a list of repositories (and their types) configured for PyTorch, view the ``input/config///pytorch.json`` file. To customize your PyTorch installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst index 38a6034f1..86e1db255 100644 --- a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst +++ b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst @@ -11,26 +11,12 @@ Create secure login node repository :class: longtable -To install OFED, include the following line under ``softwares```: :: +To secure the login node, include the following line under ``softwares```: :: {"name": "secure_login_node"}, -For a list of repositories (and their types) configured for OFED, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: - -For Ubuntu: :: - - { - "ofed": { - "cluster": [ - { "package": "ofed", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" - } - ] - } - } +For a list of repositories (and their types) configured for securing the login node, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: For RHEL or Rocky: :: diff --git a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst new file mode 100644 index 000000000..de27c1d7a --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst @@ -0,0 +1,24 @@ +Create local TensorFlow repository +----------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install TensorFlow, include the following line under ``softwares```: :: + + {"name": "tensorflow"}, + + +For a list of repositories (and their types) configured for TensorFlow, view the ``input/config///tensorflow.json`` file. To customize your TensorFlow installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 0d7a373bd..0cca08de8 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -223,6 +223,9 @@ For a list of repositories (and their types) configured for kubernetes, view the FreeIPA OpenLDAP SecureLoginNode + PyTorch + TensorFlow + kserve CustomLocalRepo diff --git a/docs/source/InstallationGuides/LocalRepo/kserve.rst b/docs/source/InstallationGuides/LocalRepo/kserve.rst new file mode 100644 index 000000000..69c30fe8b --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/kserve.rst @@ -0,0 +1,24 @@ +Create local Kserve repository +------------------------------ + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install Kserve, include the following line under ``softwares```: :: + + {"name": "kserve"}, + + +For a list of repositories (and their types) configured for Kserve, view the ``input/config///kserve.json`` file. To customize your Kserve installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/vLLM.rst b/docs/source/InstallationGuides/LocalRepo/vLLM.rst new file mode 100644 index 000000000..c8bbd73ad --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/vLLM.rst @@ -0,0 +1,24 @@ +Create local vLLM repository +------------------------------ + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install vLLM, include the following line under ``softwares```: :: + + {"name": "vLLM"}, + + +For a list of repositories (and their types) configured for vLLM, view the ``input/config///vllm.json`` file. To customize your vLLM installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml diff --git a/docs/source/Roles/Platform/Pytorch.rst b/docs/source/Roles/Platform/Pytorch.rst new file mode 100644 index 000000000..5d8c01115 --- /dev/null +++ b/docs/source/Roles/Platform/Pytorch.rst @@ -0,0 +1,62 @@ +Set up PyTorch +--------------- + +PyTorch is a popular open-source deep learning framework, renowned for its dynamic computation graph that enhances flexibility and ease of use, making it a preferred choice for researchers and developers. With strong community support, PyTorch facilitates seamless experimentation and rapid prototyping in the field of machine learning. + +**Prerequisites** +* Ensure nerdctl is available on all cluster nodes. +* If GPUs are present on the target nodes, install NVidia (CUDA 12.1) or AMD (Rocm 5.7) drivers during provisioning. CPUs do not require any additional drivers.PyTorch +* Use ``local_repo.yml`` to create an offline PyTorch repository. For more information, `click here. <../../InstallationGuides/LocalRepo/PyTorch.html>`_ + + **[Optional]** + * Ensure the system has enough space. + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. + * Container Network Interface should be enabled with nerdctl. + +**Deploying PyTorch** + +1. Change directories to the ``tools`` folder: :: + + cd tools + +2. Run the ``pytorch.yml`` playbook: :: + + ansible-playbook pytorch.yml -i inventory + +**Accessing PyTorch (CPU)** + +1. Verify that the PyTorch image present in container engine images: :: + + nerdctl images + +2. Use the container image per your needs: :: + + nerdctl run -it --rm pytorch/pytorch:latest + +For more information, `click here `_. + + +**Accessing PyTorch (AMD)** + +1. Verify that the PyTorch image present in container engine images: :: + + nerdctl images + +2. Use the container image per your needs: :: + + nerdctl run -it --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --device=/dev/kfd --device /dev/dri/card0 --device /dev/dri/card1 --device /dev/dri/card2 --device /dev/dri/renderD128 --device /dev/dri/renderD129 --group-add video --ipc=host --shm-size 8G rocm/pytorch:latest + +For more information, `click here `_. + +**Accessing PyTorch (NVidia)** + +1. Verify that the PyTorch image present in container engine images: :: + + nerdctl images + +2. Use the container image per your needs: :: + + nerdctl run --gpus all -it --rm nvcr.io/nvidia/pytorch:23.12-py3 + +For more information, `click here `_. diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index 026b43281..b627d3d65 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -11,13 +11,14 @@ With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. * Only AMD GPUs from the MI200s (gfx90a) are supported. * For nodes using AMD, ensure nerdctl is available. * For nodes using NVidia, ensure that the GPU has a compute capacity that is higher than 7 (Eg: V100, T4, RTX20xx, A100, L4, H100, etc). -* Ensure the kube_node, kube_control_node is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7.0) GPU drivers during provisioning. +* Ensure the ``kube_node``, ``kube_control_node`` is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7.0) GPU drivers during provisioning. +* Use ``local_repo.yml`` to create an offline vLLM repository. For more information, `click here. <../../InstallationGuides/LocalRepo/vLLM.html>`_ **[Optional]** * Ensure the system has enough available space. (Approximately 100GiB is required for the vLLM image. Any additional scripting will take disk capacity outside the image.) - * Ensure the passed inventory file has a kube_control_plane and kube_node_group listing all cluster nodes. + * Ensure the passed inventory file has a ``kube_control_plane`` and ``kube_node_group`` listing all cluster nodes. * Update the ``/input/software_config.json`` file with the correct vLLM version required. The default value is ``vllm-v0.2.4`` for AMD container and ``vllm latest`` for NVidia. diff --git a/docs/source/Roles/Platform/TensorFlow.rst b/docs/source/Roles/Platform/TensorFlow.rst new file mode 100644 index 000000000..062a049c9 --- /dev/null +++ b/docs/source/Roles/Platform/TensorFlow.rst @@ -0,0 +1,66 @@ +Set up TensorFlow +----------------- + +TensorFlow is a widely-used open-source deep learning framework, recognized for its static computation graph that optimizes performance and scalability, making it a favored choice for deploying machine learning models at scale in various industries. + +With an Ansible script, deploy TensorFlow on both ``kube_nodes`` and the ``kube_control_node``. After the deployment of TensorFlow, you gain access to the TensorFlow container. + +**Prerequisites** +* Ensure nerdctl is available on all cluster nodes. +* If GPUs are present on the target nodes, install NVidia (CUDA 12.1) or AMD (Rocm 5.7) drivers during provisioning. CPUs do not require any additional drivers.PyTorch +* Use ``local_repo.yml`` to create an offline TensorFlow repository. For more information, `click here <../../>`_. + + **[Optional]** + * Ensure the system has enough space. + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. + * Container Network Interface should be enabled with nerdctl. + + +**Deploying TensorFlow** + +1. Change directories to the ``tools`` folder: :: + + cd tools + +2. Run the ``tensorflow.yml`` playbook: :: + + ansible-playbook tensorflow.yml -i inventory + +**Accessing TensorFlow (CPU)** + +1. Verify that the PyTorch image present in container engine images: :: + + nerdctl images + +2. Use the container image per your needs: :: + + nerdctl run -it --rm tensorflow/tensorflow + +For more information, `click here `_. + + +**Accessing TensorFlow (AMD)** + +1. Verify that the PyTorch image present in container engine images: :: + + nerdctl images + +2. Use the container image per your needs: :: + + nerdctl run -it --network=host --device=/dev/kfd --device /dev/dri/card0 --device /dev/dri/card1 --device /dev/dri/card2 --device /dev/dri/renderD128 --device /dev/dri/renderD129 --ipc=host --shm-size 16G --group-add video --cap-add=SYS_PTRACE --security-opt seccomp=unconfined rocm/tensorflow:latest + +For more information, `click here `_. + +**Accessing TensorFlow (NVidia)** + +1. Verify that the PyTorch image present in container engine images: :: + + nerdctl images + +2. Use the container image per your needs: :: + + nerdctl run --gpus all -it --rm nvcr.io/nvidia/tensorflow:23.12-tf2-py3 + +For more information, `click here `_. + diff --git a/docs/source/Roles/Platform/index.rst b/docs/source/Roles/Platform/index.rst index b639a5e55..0a97495a4 100644 --- a/docs/source/Roles/Platform/index.rst +++ b/docs/source/Roles/Platform/index.rst @@ -18,4 +18,7 @@ Commands to install JupyterHub and Kubeflow: :: .. toctree:: InstallJupyterhub - SetupvLLM \ No newline at end of file + SetupvLLM + Pytorch + TensorFlow + kserve \ No newline at end of file diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst new file mode 100644 index 000000000..308bb1ec2 --- /dev/null +++ b/docs/source/Roles/Platform/kserve.rst @@ -0,0 +1,44 @@ +Set up Kserve +-------------- + +Kserve is an open-source serving platform that simplifies the deployment, scaling, and management of machine learning models in production environments, ensuring efficient and reliable inference capabilities. For more information, `click here. `_ + +**Prerequisites** + * The cluster is deployed with Kubernetes. + * MetalLB pod is up and running to provide an external IP to ``istio-ingressgateway``. + * A local Kserve repository should be created using ``local_repo.yml``. For more information, `click here. <../../InstallationGuides/LocalRepo/kserve.html>`_ + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * To access NVIDIA or AMD GPU acceleration in inferencing, Kubernetes NVIDIA or AMD GPU device plugins need to be installed during Kubernetes deployment. ``kserve.yml`` does not deploy GPU device plugins. + +**Deploy KServe** + + 1. Change directories to ``tools``. :: + + cd tools + + 2. Run the ``kserve.yml`` playbook: :: + + ansible-playbook kserve.yml -i inventory + + Post deployment, the following dependencies are installed: + + * Istio (version: 1.17.0) + * Certificate manager (version: 1.13.0) + * Knative (version: 1.11.0) + + To verify the installation, run ``kubectl get pod -A`` and look for the namespaces: ``cert-manager``, ``istio-system``, ``knative-serving``, and ``kserve``. + +**Deploy inference service** + + + Verify that the inference service is up and running using the command: ``kubectl get isvc -A``. + +**Access the inference service** + + Use ``kubectl get svc -A`` to check the external IP of the service ``istio-ingressgateway``. + + + + + + diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index bbfeb31c0..b750e5af8 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -13,7 +13,7 @@ ________________________________ **Pre requisites** -* Run ``local_repo.yml`` to create offline repositories of FreeIPA or OpenLDAP. If both were downloaded, ensure that the non-required system is removed from ``input/software_config.json`` before running ``security.yml``. For more information, `click here <../../InstallationGuides/LocalRepo/SecureLoginNode.html>`_. +* Run ``local_repo.yml`` to create offline repositories of FreeIPA or OpenLDAP. If both were downloaded, ensure that the non-required system is removed from ``input/software_config.json`` before running ``security.yml``. For more information, `click here <../../InstallationGuides/LocalRepo/index.html>`_. * Enter the following parameters in ``input/security_config.yml``. @@ -81,7 +81,7 @@ ________________________________ **Prerequisites** -* Run ``local_repo.yml`` to create an offline repository of all utilities used to secure the login node. For more information, click here <> +* Run ``local_repo.yml`` to create an offline repository of all utilities used to secure the login node. For more information, `click here. <../../InstallationGuides/LocalRepo/SecureLoginNode.html>`_ Enter the following parameters in ``input/login_node_security_config.yml``. From f979a9439bc49880155e81ee2c511968afa8d7b8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 1 Mar 2024 13:46:20 +0530 Subject: [PATCH 146/309] Updating AI local repo information Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/PyTorch.rst | 3 + .../LocalRepo/TensorFlow.rst | 3 + .../InstallationGuides/LocalRepo/kserve.rst | 4 +- .../InstallationGuides/LocalRepo/vLLM.rst | 2 + .../Roles/LocalRepo/CustomLocalRepo.rst | 119 ---------- docs/source/Roles/LocalRepo/index.rst | 221 ------------------ docs/source/Roles/Platform/Pytorch.rst | 16 +- docs/source/Roles/Platform/SetupvLLM.rst | 5 + docs/source/Roles/Platform/TensorFlow.rst | 10 + docs/source/Roles/Platform/kserve.rst | 6 + docs/source/Roles/index.rst | 1 - 11 files changed, 45 insertions(+), 345 deletions(-) delete mode 100644 docs/source/Roles/LocalRepo/CustomLocalRepo.rst delete mode 100644 docs/source/Roles/LocalRepo/index.rst diff --git a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst index afcb7bcbb..44d4909a2 100644 --- a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst +++ b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst @@ -23,3 +23,6 @@ For a list of repositories (and their types) configured for PyTorch, view the `` cd local_repo ansible-playbook local_repo.yml + +For information on deploying PyTorch after setting up the cluster, `click here. <../../Roles/Platform/Pytorch.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst index de27c1d7a..8c5f885d3 100644 --- a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst +++ b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst @@ -22,3 +22,6 @@ For a list of repositories (and their types) configured for TensorFlow, view the cd local_repo ansible-playbook local_repo.yml + +For information on deploying TensorFlow after setting up the cluster, `click here. <../../Roles/Platform/TensorFlow.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/kserve.rst b/docs/source/InstallationGuides/LocalRepo/kserve.rst index 69c30fe8b..932b0051d 100644 --- a/docs/source/InstallationGuides/LocalRepo/kserve.rst +++ b/docs/source/InstallationGuides/LocalRepo/kserve.rst @@ -21,4 +21,6 @@ For a list of repositories (and their types) configured for Kserve, view the ``i 3. Run the following commands: :: cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file + ansible-playbook local_repo.yml + +For information on deploying Kserve after setting up the cluster, `click here. <../../Roles/Platform/kserve.html>`_ diff --git a/docs/source/InstallationGuides/LocalRepo/vLLM.rst b/docs/source/InstallationGuides/LocalRepo/vLLM.rst index c8bbd73ad..0c7de5215 100644 --- a/docs/source/InstallationGuides/LocalRepo/vLLM.rst +++ b/docs/source/InstallationGuides/LocalRepo/vLLM.rst @@ -22,3 +22,5 @@ For a list of repositories (and their types) configured for vLLM, view the ``inp cd local_repo ansible-playbook local_repo.yml + +For information on deploying PyTorch after setting up the cluster, `click here. <../../Roles/Platform/SetupvLLM.html>`_ diff --git a/docs/source/Roles/LocalRepo/CustomLocalRepo.rst b/docs/source/Roles/LocalRepo/CustomLocalRepo.rst deleted file mode 100644 index ab6869147..000000000 --- a/docs/source/Roles/LocalRepo/CustomLocalRepo.rst +++ /dev/null @@ -1,119 +0,0 @@ -Configuring custom repositories -------------------------------- - -Use the local repository feature to create a customized set of local repositories on the control plane for the cluster nodes to access. - -1. Ensure the ``custom`` entry is included in the ``software_config.json`` file. :: - - { - "cluster_os_type": "ubuntu", - "cluster_os_version": "22.04", - "repo_config": "partial", - "softwares": [ - {"name": "k8s", "version":"1.26.12"}, - {"name": "jupyter", "version": "3.2.0"}, - {"name": "kubeflow", "version": "1.8"}, - {"name": "openldap"}, - {"name": "beegfs", "version": "7.2.6"}, - {"name": "nfs"}, - {"name": "kserve"}, - {"name": "custom"}, - {"name": "amdgpu", "version": "6.0"}, - {"name": "cuda", "version": "12.3.2"}, - {"name": "ofed", "version": "24.01-0.3.3.1"}, - {"name": "telemetry"}, - {"name": "utils"}, - {"name": "vllm"}, - {"name": "pytorch"}, - {"name": "tensorflow"} - ], - - "amdgpu": [ - {"name": "rocm", "version": "6.0" } - ], - "vllm": [ - {"name": "vllm_amd", "version":"vllm-v0.2.4"}, - {"name": "vllm_nvidia", "version": "latest"} - ], - "pytorch": [ - {"name": "pytorch_cpu", "version":"latest"}, - {"name": "pytorch_amd", "version":"latest"}, - {"name": "pytorch_nvidia", "version": "23.12-py3"} - ], - "tensorflow": [ - {"name": "tensorflow_cpu", "version":"latest"}, - {"name": "tensorflow_amd", "version":"latest"}, - {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} - ] - - } - -2. Create a ``custom.json`` file in the following directory: ``input/config//`` to define the repositories. For example, For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and create the file there. The file is a JSON list consisting of the package name, repository type, URL (optional), and version (optional). Below is a sample version of the file: :: - - { - "custom": { - "cluster": [ - { - "package": "ansible==5.3.2", - "type": "pip_module" - }, - { - "package": "docker-ce-24.0.4", - "type": "rpm", - "repo_name": "docker-ce-repo" - }, - - { - "package": "gcc", - "type": "rpm", - "repo_name": "appstream" - }, - { - "package": "community.general", - "type": "ansible_galaxy_collection", - "version": "4.4.0" - }, - - { - "package": "perl-Switch", - "type": "rpm", - "repo_name": "codeready-builder" - }, - { - "package": "prometheus-slurm-exporter", - "type": "git", - "url": "https://github.com/vpenso/prometheus-slurm-exporter.git", - "version": "master" - }, - { - "package": "ansible.utils", - "type": "ansible_galaxy_collection", - "version": "2.5.2" - }, - { - "package": "prometheus-2.23.0.linux-amd64", - "type": "tarball", - "url": "https://github.com/prometheus/prometheus/releases/download/v2.23.0/prometheus-2.23.0.linux-amd64.tar.gz" - }, - { - "package": "metallb-native", - "type": "manifest", - "url": "https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yaml" - }, - { - "package": "registry.k8s.io/pause", - "version": "3.9", - "type": "image" - } - - ] - } - } - -2. Enter the parameters required in ``input/local_repo_config.yml`` as explained `here `_. - -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - diff --git a/docs/source/Roles/LocalRepo/index.rst b/docs/source/Roles/LocalRepo/index.rst deleted file mode 100644 index 6cdaf5381..000000000 --- a/docs/source/Roles/LocalRepo/index.rst +++ /dev/null @@ -1,221 +0,0 @@ -Local repositories for the cluster -===================================== - -The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - - -Below is a sample version of the file: :: - - { - "cluster_os_type": "ubuntu", - "cluster_os_version": "22.04", - "repo_config": "partial", - "softwares": [ - {"name": "k8s", "version":"1.26.12"}, - {"name": "jupyter", "version": "3.2.0"}, - {"name": "kubeflow", "version": "1.8"}, - {"name": "openldap"}, - {"name": "beegfs", "version": "7.2.6"}, - {"name": "nfs"}, - {"name": "kserve"}, - {"name": "custom"}, - {"name": "amdgpu", "version": "6.0"}, - {"name": "cuda", "version": "12.3.2"}, - {"name": "ofed", "version": "24.01-0.3.3.1"}, - {"name": "telemetry"}, - {"name": "utils"}, - {"name": "vllm"}, - {"name": "pytorch"}, - {"name": "tensorflow"} - ], - - "amdgpu": [ - {"name": "rocm", "version": "6.0" } - ], - "vllm": [ - {"name": "vllm_amd", "version":"vllm-v0.2.4"}, - {"name": "vllm_nvidia", "version": "latest"} - ], - "pytorch": [ - {"name": "pytorch_cpu", "version":"latest"}, - {"name": "pytorch_amd", "version":"latest"}, - {"name": "pytorch_nvidia", "version": "23.12-py3"} - ], - "tensorflow": [ - {"name": "tensorflow_cpu", "version":"latest"}, - {"name": "tensorflow_amd", "version":"latest"}, - {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} - ] - - } - - -For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: - -:: - - amdgpu.json - k8s.json - openldap.json - rocm.json - -For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: - - { - - "k8s": { - - "cluster": [ - { - "package": "containerd.io-1.6.16-3.1.el8", - "type": "rpm", - "repo_name": "docker-ce-repo" - }, - { - "package": "kubelet", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" - }, - { - "package": "kubeadm", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" - }, - { - "package": "helm", - "type": "tarball", - "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" - }, - { - "package": "registry.k8s.io/kube-apiserver", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "registry.k8s.io/kube-controller-manager", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "quay.io/coreos/etcd", - "version": "v3.5.9", - "type": "image" - }, - { - "package": "quay.io/calico/node", - "version": "v3.25.2", - "type": "image" - }, - { - "package": "registry.k8s.io/pause", - "version": "3.9", - "type": "image" - }, - { - "package": "docker.io/kubernetesui/dashboard", - "version": "v2.7.0", - "type": "image" - } - ] - - } - - } - -.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. - -2. Enter the required values in the ``input/local_repo_config.yml`` file: - - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+===================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | - | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | - | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | - | Optional | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | * | - | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | - | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | - | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | - | Optional | * 'host' defines the URL and path to the registry. | - | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | - | | | - | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | * **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | * **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -3. Alternatively, run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - -.. toctree:: - CustomLocalRepo - - - diff --git a/docs/source/Roles/Platform/Pytorch.rst b/docs/source/Roles/Platform/Pytorch.rst index 5d8c01115..bba2b5b5e 100644 --- a/docs/source/Roles/Platform/Pytorch.rst +++ b/docs/source/Roles/Platform/Pytorch.rst @@ -3,15 +3,25 @@ Set up PyTorch PyTorch is a popular open-source deep learning framework, renowned for its dynamic computation graph that enhances flexibility and ease of use, making it a preferred choice for researchers and developers. With strong community support, PyTorch facilitates seamless experimentation and rapid prototyping in the field of machine learning. + **Prerequisites** + * Ensure nerdctl is available on all cluster nodes. + * If GPUs are present on the target nodes, install NVidia (CUDA 12.1) or AMD (Rocm 5.7) drivers during provisioning. CPUs do not require any additional drivers.PyTorch + * Use ``local_repo.yml`` to create an offline PyTorch repository. For more information, `click here. <../../InstallationGuides/LocalRepo/PyTorch.html>`_ + + **[Optional]** + * Ensure the system has enough space. + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. + * Container Network Interface should be enabled with nerdctl. **Deploying PyTorch** @@ -34,7 +44,7 @@ PyTorch is a popular open-source deep learning framework, renowned for its dynam nerdctl run -it --rm pytorch/pytorch:latest -For more information, `click here `_. +For more information, `click here `_. **Accessing PyTorch (AMD)** @@ -47,7 +57,7 @@ For more information, `click here `_. nerdctl run -it --cap-add=SYS_PTRACE --security-opt seccomp=unconfined --device=/dev/kfd --device /dev/dri/card0 --device /dev/dri/card1 --device /dev/dri/card2 --device /dev/dri/renderD128 --device /dev/dri/renderD129 --group-add video --ipc=host --shm-size 8G rocm/pytorch:latest -For more information, `click here `_. +For more information, `click here `_. **Accessing PyTorch (NVidia)** @@ -59,4 +69,4 @@ For more information, `click here `_. +For more information, `click here `_. diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index b627d3d65..dd8f66fc5 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -8,10 +8,15 @@ With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. **Pre requisites** + * Only AMD GPUs from the MI200s (gfx90a) are supported. + * For nodes using AMD, ensure nerdctl is available. + * For nodes using NVidia, ensure that the GPU has a compute capacity that is higher than 7 (Eg: V100, T4, RTX20xx, A100, L4, H100, etc). + * Ensure the ``kube_node``, ``kube_control_node`` is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7.0) GPU drivers during provisioning. + * Use ``local_repo.yml`` to create an offline vLLM repository. For more information, `click here. <../../InstallationGuides/LocalRepo/vLLM.html>`_ **[Optional]** diff --git a/docs/source/Roles/Platform/TensorFlow.rst b/docs/source/Roles/Platform/TensorFlow.rst index 062a049c9..e96bda59a 100644 --- a/docs/source/Roles/Platform/TensorFlow.rst +++ b/docs/source/Roles/Platform/TensorFlow.rst @@ -5,15 +5,25 @@ TensorFlow is a widely-used open-source deep learning framework, recognized for With an Ansible script, deploy TensorFlow on both ``kube_nodes`` and the ``kube_control_node``. After the deployment of TensorFlow, you gain access to the TensorFlow container. + **Prerequisites** + * Ensure nerdctl is available on all cluster nodes. + * If GPUs are present on the target nodes, install NVidia (CUDA 12.1) or AMD (Rocm 5.7) drivers during provisioning. CPUs do not require any additional drivers.PyTorch + * Use ``local_repo.yml`` to create an offline TensorFlow repository. For more information, `click here <../../>`_. + + **[Optional]** + * Ensure the system has enough space. + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. + * Container Network Interface should be enabled with nerdctl. diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index 308bb1ec2..c30855a00 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -3,11 +3,17 @@ Set up Kserve Kserve is an open-source serving platform that simplifies the deployment, scaling, and management of machine learning models in production environments, ensuring efficient and reliable inference capabilities. For more information, `click here. `_ + **Prerequisites** + * The cluster is deployed with Kubernetes. + * MetalLB pod is up and running to provide an external IP to ``istio-ingressgateway``. + * A local Kserve repository should be created using ``local_repo.yml``. For more information, `click here. <../../InstallationGuides/LocalRepo/kserve.html>`_ + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * To access NVIDIA or AMD GPU acceleration in inferencing, Kubernetes NVIDIA or AMD GPU device plugins need to be installed during Kubernetes deployment. ``kserve.yml`` does not deploy GPU device plugins. **Deploy KServe** diff --git a/docs/source/Roles/index.rst b/docs/source/Roles/index.rst index 8934de085..bca47099c 100644 --- a/docs/source/Roles/index.rst +++ b/docs/source/Roles/index.rst @@ -13,7 +13,6 @@ Below is a list of all Omnia's features: Storage/index Accelerator/index Platform/index - LocalRepo/index Platform/index Utils/index Telemetry/index From 72d8a40cf6b8716fe5713a369657846403d7955f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 1 Mar 2024 16:19:29 +0530 Subject: [PATCH 147/309] Updating AI local repo information Signed-off-by: goveac --- docs/source/Roles/index.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/Roles/index.rst b/docs/source/Roles/index.rst index bca47099c..189cf12a8 100644 --- a/docs/source/Roles/index.rst +++ b/docs/source/Roles/index.rst @@ -13,7 +13,6 @@ Below is a list of all Omnia's features: Storage/index Accelerator/index Platform/index - Platform/index Utils/index Telemetry/index From 60d7be544b6c66b207c41a5c61b52b68809ae455 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 1 Mar 2024 16:45:27 +0530 Subject: [PATCH 148/309] Updating Security local repo information Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/FreeIPA.rst | 34 ------------------ .../InstallationGuides/LocalRepo/OpenLDAP.rst | 35 ------------------- .../LocalRepo/SecureLoginNode.rst | 34 ------------------ docs/source/Roles/Security/index.rst | 1 - 4 files changed, 104 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst index f8ee5f7c3..b4cb99110 100644 --- a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst +++ b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst @@ -17,40 +17,6 @@ To install FreeIPA, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for FreeIPA, view the ``input/config///freeipa.json`` file. To customize your FreeIPA installation, update the file.: -For Ubuntu: :: - - { - "ofed": { - "cluster": [ - { "package": "freeipa", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" - } - ] - } - } - - -For RHEL or Rocky: :: - - { - "freeipa": { - "cluster": [ - {"package": "bind", "type": "rpm", "repo_name": "appstream"}, - {"package": "ipa-server-dns", "type": "rpm", "repo_name": "appstream"}, - {"package": "ipa-server", "type": "rpm", "repo_name": "appstream"}, - {"package": "bind-utils", "type": "rpm", "repo_name": "appstream"}, - {"package": "ipa-client", "type": "rpm", "repo_name": "appstream"}, - {"package": "ipa-admintools", "type": "rpm", "repo_name": "appstream"}, - {"package": "idm:DL1", "type": "module", "repo_name": "appstream"}, - {"package": "idm:DL1/{dns,adtrust}", "type": "module", "repo_name": "appstream"}, - {"package": "idm:DL1/client", "type": "module", "repo_name": "appstream"} - ] - } - } - - 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst index 0f11482f8..4359debdf 100644 --- a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst +++ b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst @@ -15,41 +15,6 @@ To install OpenLDAP, include the following line under ``softwares```: :: {"name": "openldap"}, -For a list of repositories (and their types) configured for OpenLDAP, view the ``input/config///openldap.json`` file. To customize your OpenLDAP installation, update the file.: - -For Ubuntu: :: - - { - "ofed": { - "cluster": [ - { "package": "freeipa", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" - } - ] - } - } - - -For RHEL or Rocky: :: - - { - "openldap": { - "cluster": [ - {"package": "openldap-ltb", "type": "rpm", "repo_name": "ldap"}, - {"package": "openldap-ltb-contrib-overlays", "type": "rpm", "repo_name": "ldap"}, - {"package": "openldap-ltb-mdb-utils", "type": "rpm", "repo_name": "ldap"}, - {"package": "libsodium", "type": "rpm", "repo_name": "epel"}, - { "package": "ansible-role-ldaptoolbox-openldap", - "type": "git", - "url": "https://github.com/ltb-project/ansible-role-ldaptoolbox-openldap.git", - "version": "main" - } - ] - } - } - 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst index 86e1db255..7144a3533 100644 --- a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst +++ b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst @@ -19,40 +19,6 @@ To secure the login node, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for securing the login node, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: -For RHEL or Rocky: :: - - { - "secure_login_node": { - "cluster": [ - { - "package": "community.general", - "type": "ansible_galaxy_collection", - "version": "4.4.0" - }, - { - "package": "install-snoopy", - "type": "shell", - "url": "https://github.com/a2o/snoopy/raw/install/install/install-snoopy.sh" - }, - {"package": "mailx", "type": "rpm", "repo_name": "baseos"}, - {"package": "postfix", "type": "rpm", "repo_name": "baseos"}, - {"package": "gcc", "type": "rpm", "repo_name": "appstream"}, - {"package": "gzip", "type": "rpm", "repo_name": "appstream"}, - {"package": "make", "type": "rpm", "repo_name": "baseos"}, - {"package": "procps-ng", "type": "rpm", "repo_name": "baseos"}, - {"package": "socat", "type": "rpm", "repo_name": "appstream"}, - {"package": "tar", "type": "rpm", "repo_name": "appstream"}, - {"package": "wget", "type": "rpm", "repo_name": "appstream"}, - {"package": "psacct", "type": "rpm", "repo_name": "baseos"}, - {"package": "psacct", "type": "rpm", "repo_name": "baseos"}, - {"package": "python3.9", "type": "rpm", "repo_name": "appstream"} - - ] - } - } - - - 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index b750e5af8..a021429bb 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -184,7 +184,6 @@ Run: :: The inventory should contain auth_server as per the inventory file in `samplefiles <../../samplefiles.html#inventory-file>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. * Do not include the IP of the control plane or local host in the auth_server group in the passed inventory. - * To enable security features on the login node, ensure that ``enable_secure_login_node`` in ``input/security_config.yml`` is set to true. * To customize the security features on the login node, fill out the parameters in ``input/login_node_security_config.yml``. * If a subsequent run of ``security.yml`` fails, the ``security_config.yml`` file will be unencrypted. From a22cce089893e760bfc5e1bcd5228796dc079fbf Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 6 Mar 2024 11:46:08 +0530 Subject: [PATCH 149/309] Updating NFS local repo information Signed-off-by: goveac --- .../BuildingClusters/NFS.rst | 24 +++++++++++++++++++ .../InstallationGuides/LocalRepo/index.rst | 4 ++-- docs/source/Roles/Platform/kserve.rst | 2 +- docs/source/Roles/Storage/index.rst | 4 +++- docs/source/Tables/scheduler_slurm.csv | 18 ++++++++++++++ 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 2059df825..0e26cd6ea 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -3,6 +3,8 @@ NFS bolt on * Ensure that an external NFS server is set up using the `linked steps <../../Appendices/NFSServer.html>`_ alternatively, `nfs_sas.yml <../ConfiguringStorage/index.html>`_ can be leveraged. NFS clients are mounted using the external NFS server's IP. +* Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ + * Fill out the ``nfs_client_params`` variable in the ``input/storage_config.yml`` file in JSON format using the samples provided below. * This role runs on all nodes. @@ -62,6 +64,28 @@ NFS bolt on systemctl restart nfs-server +NFS server set up +------------------ + +Set up an NFS server export on the control plane with cluster nodes clients.up + +**Pre requisites** + +* Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ +* Enter all required information in ``omnia_config.yml``. + + .. csv-table:: Parameters for Kubernetes cluster setup with NFS + :file: ../../Tables/scheduler_k8s.csv + :header-rows: 1 + :keepspace: + + .. csv-table:: Parameters for Slurm cluster setup with NFS + :file: ../../Tables/scheduler_slurm.csv + :header-rows: 1 + :keepspace: + + + If ``omnia.yml`` is not leveraged to set up NFS, run the ``storage.yml`` playbook : :: diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 0cca08de8..9bc28ae12 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -172,8 +172,8 @@ For a list of repositories (and their types) configured for kubernetes, view the +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``rhel_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``rhel_os_url`` is configured via proxy on the cluster nodes. | | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index c30855a00..06fa80699 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -12,7 +12,7 @@ Kserve is an open-source serving platform that simplifies the deployment, scalin * A local Kserve repository should be created using ``local_repo.yml``. For more information, `click here. <../../InstallationGuides/LocalRepo/kserve.html>`_ - * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node_group`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. + * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. * To access NVIDIA or AMD GPU acceleration in inferencing, Kubernetes NVIDIA or AMD GPU device plugins need to be installed during Kubernetes deployment. ``kserve.yml`` does not deploy GPU device plugins. diff --git a/docs/source/Roles/Storage/index.rst b/docs/source/Roles/Storage/index.rst index 527dc071c..09cc4c163 100644 --- a/docs/source/Roles/Storage/index.rst +++ b/docs/source/Roles/Storage/index.rst @@ -3,7 +3,7 @@ Shared and distributed storage deployment The storage role allows users to configure PowerVault Storage devices, BeeGFS and NFS services on the cluster. -First, enter all required parameters in ``input/storage_config.yml`` +1. Enter all required parameters in ``input/storage_config.yml`` +---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Name | Details | @@ -81,6 +81,8 @@ First, enter all required parameters in ``input/storage_config.yml`` .. note:: If ``storage.yml`` is run with the ``input/storage_config.yml`` filled out, BeeGFS and NFS client will be set up. +2. Ensure that the entry ``{"name": "beegfs", "version": "7.2.6"},`` is included in ``input/software_config.json`` and a local repository is created. For more information, `click here. <../../InstallationGuides/LocalRepo/index.html>`_ + **Installing BeeGFS Client** * If the user intends to use BeeGFS, ensure that a BeeGFS cluster has been set up with beegfs-mgmtd, beegfs-meta, beegfs-storage services running. diff --git a/docs/source/Tables/scheduler_slurm.csv b/docs/source/Tables/scheduler_slurm.csv index dcbb96ff0..ebaa8e38a 100644 --- a/docs/source/Tables/scheduler_slurm.csv +++ b/docs/source/Tables/scheduler_slurm.csv @@ -44,3 +44,21 @@ * ``nfs_share`` <- default * ``configless`` " +"**share_path** + + ``string`` + + Optional ","* Path to directory which will be shared across all nodes in the cluster. +* If omitted, ``/mnt/share`` is provided. +**Default value**: ""/home/omnia-share""" +"**restart_slurm_services** + + ``boolean`` + + Optional ","* Indicates whether slurm services should be restarted. + +* **Choices** + + * ``true`` <- **Default** + + * ``false``" From 9bbb419d77b66539019f37fac67c62a88ac54948 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 6 Mar 2024 18:29:03 +0530 Subject: [PATCH 150/309] Updating NFS local repo information Signed-off-by: goveac --- .../BuildingClusters/NFS.rst | 103 ++++++++---------- docs/source/Tables/storage_config.csv | 79 ++++++++++++++ docs/source/images/nfs_flowchart.png | Bin 37106 -> 21855 bytes 3 files changed, 122 insertions(+), 60 deletions(-) create mode 100644 docs/source/Tables/storage_config.csv diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 0e26cd6ea..cd3c8d98f 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -1,58 +1,72 @@ -NFS bolt on -------------- +NFS +____ -* Ensure that an external NFS server is set up using the `linked steps <../../Appendices/NFSServer.html>`_ alternatively, `nfs_sas.yml <../ConfiguringStorage/index.html>`_ can be leveraged. NFS clients are mounted using the external NFS server's IP. +Network File System (NFS) is a networking protocol for distributed file sharing. A file system defines the way data in the form of files is stored and retrieved from storage devices, such as hard disk drives, solid-state drives and tape drives. NFS is a network file sharing protocol that defines the way files are stored and retrieved from storage devices across networks. NFS is a mandatory feature for all clusters set up by Omnia. -* Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ -* Fill out the ``nfs_client_params`` variable in the ``input/storage_config.yml`` file in JSON format using the samples provided below. +**Pre requisites** -* This role runs on all nodes. +* NFS is set up on Omnia clusters based on the inputs provided in ``input/storage_config.yml``. -* Make sure that ``/etc/exports`` on the NFS server is populated with the same paths listed as ``server_share_path`` in the ``nfs_client_params`` in ``input/storage_config.yml``. + .. csv-table:: Parameters for Storage configuration + :file: ../../Tables/storage_config.csv + :header-rows: 1 + :keepspace: + :class: longtable -* Post configuration, enable the following services (using this command: ``firewall-cmd --permanent --add-service=``) and then reload the firewall (using this command: ``firewall-cmd --reload``). - - nfs + .. image:: ../../images/NFS_FlowChart.png - - rpc-bind + * The fields listed in ``nfs_client_params`` are: - - mountd + - server_ip: IP of the intended NFS server. To set up an NFS server on the control plane, use the value ``localhost``. -* Omnia supports all NFS mount options. Without user input, the default mount options are nosuid,rw,sync,hard,intr. + - server_share_path: Folder on which the NFS server mounted. + + - client_share_path: Target directory for the NFS mount on the client. If left empty, the respective ``server_share_path value`` will be taken for ``client_share_path``. + + - client_mount_options: The mount options when mounting the NFS export on the client. Default value: nosuid,rw,sync,hard,intr. For a list of mount options, `click here `_. + + - nfs_server: Indicates whether an external NFS server is available (true) or an NFS export will need to be created (false). -* The fields listed in ``nfs_client_params`` are: + To configure all cluster nodes to access a single external NFS server export, use the below sample: :: - - server_ip: IP of NFS server + - { server_ip: 10.5.0.101, server_share_path: "/mnt/share", client_share_path: "/home", client_mount_options: "nosuid,rw,sync,hard", nfs_server: true } - - server_share_path: Folder on which NFS server mounted + To configure the cluster nodes to access a new NFS server on the control plane as well as an external NFS server, use the below example: :: - - client_share_path: Target directory for the NFS mount on the client. If left empty, respective ``server_share_path value`` will be taken for ``client_share_path``. + - { server_ip: localhost, server_share_path: "/mnt/share1", client_share_path: "/home", client_mount_options: "nosuid,rw,sync,hard", nfs_server: true } + - { server_ip: 198.168.0.1, server_share_path: "/mnt/share2", client_share_path: "/mnt/mount2", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false } - - client_mount_options: The mount options when mounting the NFS export on the client. Default value: nosuid,rw,sync,hard,intr. For a list of mount options, `click here `_. + To configure the cluster nodes to access new NFS server exports on the cluster nodes, use the below sample: :: -* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to set up NFS on RHEL target nodes. + - { server_ip: 198.168.0.1, server_share_path: "/mnt/share1", client_share_path: "/mnt/mount1", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false } + - { server_ip: 198.168.0.2, server_share_path: "/mnt/share2", client_share_path: "/mnt/mount2", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false } -* For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. -* There are 3 ways to configure the feature: +* Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ +* Enter the value of ``share_path`` in ``input/omnia_config.yml``. +.. note:: Ensure that the value of ``share_path`` provided matches at least one value of ``client_share_path`` provided in ``nfs_client_params`` in ``input/storage_config.yml``. - 1. **Single NFS node** : A single NFS filesystem is mounted from a single NFS server. The value of ``nfs_client_params`` would be:: +* If an external NFS share is used, make sure that ``/etc/exports`` on the NFS server is populated with the same paths listed as ``server_share_path`` in the ``nfs_client_params`` in ``input/storage_config.yml``. +* Omnia supports all NFS mount options. Without user input, the default mount options are nosuid,rw,sync,hard,intr. - - { server_ip: 10.5.0.101, server_share_path: "/mnt/share", client_share_path: "/mnt/client", client_mount_options: "nosuid,rw,sync,hard,intr" } - 2. **Multiple Mount NFS Filesystem**: Multiple filesystems are mounted from a single NFS server. The value of ``nfs_client_params`` would be:: +**Running the playbook** - - { server_ip: 10.5.0.101, server_share_path: "/mnt/share1", client_share_path: "/mnt/client1", client_mount_options: "nosuid,rw,sync,hard,intr" } - - { server_ip: 10.5.0.101, server_share_path: "/mnt/share2", client_share_path: "/mnt/client2", client_mount_options: "nosuid,rw,sync,hard,intr" } +If ``omnia.yml`` is not leveraged to set up NFS, run the ``storage.yml`` playbook : :: - 3. **Multiple NFS Filesystems**: Multiple filesystems are mounted from multiple NFS servers. The value of ``nfs_client_params`` would be:: + cd storage + ansible-playbook storage.yml -i inventory - - { server_ip: 10.5.0.101, server_share_path: "/mnt/server1", client_share_path: "/mnt/client1", client_mount_options: "nosuid,rw,sync,hard,intr" } - - { server_ip: 10.5.0.102, server_share_path: "/mnt/server2", client_share_path: "/mnt/client2", client_mount_options: "nosuid,rw,sync,hard,intr" } - - { server_ip: 10.5.0.103, server_share_path: "/mnt/server3", client_share_path: "/mnt/client3", client_mount_options: "nosuid,rw,sync,hard,intr" } +Post configuration, enable the following services (using this command: ``firewall-cmd --permanent --add-service=``) and then reload the firewall (using this command: ``firewall-cmd --reload``). + - nfs + + - rpc-bind + + - mountd .. caution:: After an NFS client is configured, if the NFS server is rebooted, the client may not be able to reach the server. In those cases, restart the NFS services on the server using the below command: @@ -64,34 +78,3 @@ NFS bolt on systemctl restart nfs-server -NFS server set up ------------------- - -Set up an NFS server export on the control plane with cluster nodes clients.up - -**Pre requisites** - -* Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ -* Enter all required information in ``omnia_config.yml``. - - .. csv-table:: Parameters for Kubernetes cluster setup with NFS - :file: ../../Tables/scheduler_k8s.csv - :header-rows: 1 - :keepspace: - - .. csv-table:: Parameters for Slurm cluster setup with NFS - :file: ../../Tables/scheduler_slurm.csv - :header-rows: 1 - :keepspace: - - - - -If ``omnia.yml`` is not leveraged to set up NFS, run the ``storage.yml`` playbook : :: - - cd storage - ansible-playbook storage.yml -i inventory - - - - diff --git a/docs/source/Tables/storage_config.csv b/docs/source/Tables/storage_config.csv new file mode 100644 index 000000000..9d2838ca8 --- /dev/null +++ b/docs/source/Tables/storage_config.csv @@ -0,0 +1,79 @@ +Variables,Details +"**nfs_client_params** + + ``JSON List`` + + Required ","* This JSON list contains all parameters required to set up NFS. +* For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. +* When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. +* Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. +* For more information on the different kinds of configuration available, `click here. `_" +"beegfs_rdma_support + ``boolean`` + Optional","This variable is used if user has RDMA-capable network hardware (e.g., InfiniBand) + +Choices: + + * ``false`` <- Default + + * ``true``" +"beegfs_ofed_kernel_modules_path + ``string`` + Optional +","* The path where separate OFED kernel modules are installed. +* Ensure that the path provided here exists on all target nodes. + **Default value**: ``""/usr/src/ofa_kernel/default/include""`` +" +"beegfs_mgmt_server + ``string`` + Required +","BeeGFS management server IP. + +.. note:: The provided IP should have an explicit BeeGFS management server running . +" +"beegfs_mounts + ``string`` + Optional + ","Beegfs-client file system mount location. If ``storage_yml`` is being used to change the BeeGFS mounts location, set ``beegfs_unmount_client`` to ``true``. + **Default value**: ""/mnt/beegfs"" +" +"beegfs_unmount_client + ``boolean`` + Optional +","Changing this value to true will unmount running instance of BeeGFS client and should only be used when decommisioning BeeGFS, changing the mount location or changing the BeeGFS version. + +Choices: + + * ``false`` <- Default + + * ``true`` +" +"beegfs_version_change + ``boolean`` + Optional +","Use this variable to change the BeeGFS version on the target nodes. + +Choices: + + * ``false`` <- Default + + * ``true`` +" +"**ansible_config_file_path** + + ``string`` + + Required ","* Path to directory hosting ansible config file (ansible.cfg file) +* This directory is on the host running ansible, if ansible is installed using dnf +* If ansible is installed using pip, this path should be set + + **Default values**: ``/etc/ansible`` " +"beegfs_secret_storage_filepath + ``string`` + Required +","* The filepath (including the filename) where the ``connauthfile`` is placed. +* Required for Beegfs version >= 7.2.7 + + + **Default values**: ``/home/connauthfile`` +" diff --git a/docs/source/images/nfs_flowchart.png b/docs/source/images/nfs_flowchart.png index b5d5dc8a3716a41faa450b3266100b38d81c31d6..52d149731fc34ff1e2aa421ff0e8188d8dbb8ae1 100644 GIT binary patch literal 21855 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 gG`Ve2d9KCh_ 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 From b97cf948b3f4bd42676e5428d7d90040abc80915 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 6 Mar 2024 18:57:37 +0530 Subject: [PATCH 151/309] Updating NFS local repo information Signed-off-by: goveac --- docs/source/InstallationGuides/BuildingClusters/NFS.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index cd3c8d98f..5db949ef1 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -46,6 +46,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. * Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ * Enter the value of ``share_path`` in ``input/omnia_config.yml``. + .. note:: Ensure that the value of ``share_path`` provided matches at least one value of ``client_share_path`` provided in ``nfs_client_params`` in ``input/storage_config.yml``. * If an external NFS share is used, make sure that ``/etc/exports`` on the NFS server is populated with the same paths listed as ``server_share_path`` in the ``nfs_client_params`` in ``input/storage_config.yml``. From b122607f95b5ad1b250dbcf01b0d4fc149b24aa2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 10:00:18 +0530 Subject: [PATCH 152/309] Updating NFS local repo information Signed-off-by: goveac --- .../InstallationGuides/BuildingClusters/NFS.rst | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 5db949ef1..78cbbaf14 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -8,11 +8,19 @@ Network File System (NFS) is a networking protocol for distributed file sharing. * NFS is set up on Omnia clusters based on the inputs provided in ``input/storage_config.yml``. - .. csv-table:: Parameters for Storage configuration - :file: ../../Tables/storage_config.csv + .. csv-table:: Parameter for NFS configuration :header-rows: 1 - :keepspace: - :class: longtable + + Variables,Details + "**nfs_client_params** + + ``JSON List`` + + Required ","* This JSON list contains all parameters required to set up NFS. + * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. + * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. + * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. + * For more information on the different kinds of configuration available, `click here. `_" .. image:: ../../images/NFS_FlowChart.png From dc1aecb505cf7a3e905cfe618210ec5819b8ae4b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 10:04:53 +0530 Subject: [PATCH 153/309] Updating NFS local repo information Signed-off-by: goveac --- .../InstallationGuides/BuildingClusters/NFS.rst | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 78cbbaf14..062be4162 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -10,17 +10,16 @@ Network File System (NFS) is a networking protocol for distributed file sharing. .. csv-table:: Parameter for NFS configuration :header-rows: 1 + Variables,Details + "**nfs_client_params** - Variables,Details - "**nfs_client_params** + ``JSON List`` - ``JSON List`` - - Required ","* This JSON list contains all parameters required to set up NFS. - * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. - * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. - * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. - * For more information on the different kinds of configuration available, `click here. `_" + Required ","* This JSON list contains all parameters required to set up NFS. + * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. + * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. + * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. + * For more information on the different kinds of configuration available, `click here. `_" .. image:: ../../images/NFS_FlowChart.png From b7e2443972a3a72827b818f26ec16a9f7bf35527 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 10:14:33 +0530 Subject: [PATCH 154/309] Updating NFS local repo information Signed-off-by: goveac --- .../BuildingClusters/NFS.rst | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 062be4162..54d7dd0f7 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -8,18 +8,15 @@ Network File System (NFS) is a networking protocol for distributed file sharing. * NFS is set up on Omnia clusters based on the inputs provided in ``input/storage_config.yml``. - .. csv-table:: Parameter for NFS configuration - :header-rows: 1 - Variables,Details - "**nfs_client_params** - - ``JSON List`` - - Required ","* This JSON list contains all parameters required to set up NFS. - * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. - * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. - * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. - * For more information on the different kinds of configuration available, `click here. `_" + +-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=======================+=============================================================================================================================================================+ + | **nfs_client_params** | * This JSON list contains all parameters required to set up NFS. | + | | * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. | + | ``JSON List`` | * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. | + | | * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. | + | Required | * For more information on the different kinds of configuration available, `click here. `_ | + +-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ .. image:: ../../images/NFS_FlowChart.png From 807960fb54de7070e5db98fc4ae7c4e887fad6a6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 10:25:45 +0530 Subject: [PATCH 155/309] Updating NFS local repo information Signed-off-by: goveac --- .../BuildingClusters/Authentication.rst | 425 ++++++++---------- .../BuildingClusters/BeeGFS.rst | 63 +-- .../BuildingClusters/index.rst | 10 +- .../BuildingClusters/schedulerinputparams.rst | 90 +--- 4 files changed, 207 insertions(+), 381 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index 7b96a4777..f2678a6b5 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -1,248 +1,191 @@ -Centralized authentication systems -=================================== - -To enable centralized authentication in the cluster, Omnia installs either: - - - FreeIPA - - LDAP Client - -.. note:: - * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``security.yml`` on RHEL cluster nodes. - * For RHEL cluster nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all cluster nodes. Every cluster node will require a RedHat subscription. - - - -Using FreeIPA --------------- - -Enter the following parameters in ``input/security_config.yml``. - -.. caution:: Do not remove or comment any lines in the ``input/security_config.yml`` file. - -+----------------------------+----------------------------------------------------------------------------------------------+ -| Parameter | Details | -+============================+==============================================================================================+ -| freeipa_required | Boolean indicating whether FreeIPA is required or not. | -| ``boolean`` | | -| Required | Choices: | -| | | -| | * ``true`` <- Default | -| | | -| | * ``false`` | -+----------------------------+----------------------------------------------------------------------------------------------+ -| realm_name | Sets the intended realm name. | -| ``string`` | | -| Required | **Default value**: ``OMNIA.TEST`` | -+----------------------------+----------------------------------------------------------------------------------------------+ -| directory_manager_password | * Password authenticating admin level access to the Directory for system management tasks. | -| ``string`` | * It will be added to the instance of directory server created for IPA. | -| Required | * Required Length: 8 characters. | -| | * The password must not contain -,, ‘,” | -+----------------------------+----------------------------------------------------------------------------------------------+ -| kerberos_admin_password | “admin” user password for the IPA server on RockyOS. | -| ``string`` | | -| Required | | -+----------------------------+----------------------------------------------------------------------------------------------+ -| domain_name | Sets the intended domain name | -| ``string`` | | -| Required | **Default value**: ``omnia.test`` | -+----------------------------+----------------------------------------------------------------------------------------------+ +Centralized authentication on the cluster +========================================== -.. note:: - - The ``input/security_config.yml`` file is encrypted on the first run of ``security.yml`` and ``omnia.yml``: - - To view the encrypted parameters: :: - - ansible-vault view security_config.yml --vault-password-file .security_vault.key - - To edit the encrypted parameters: :: - - ansible-vault edit security_config.yml --vault-password-file .security_vault.key - - If a subsequent run of ``security.yml`` or ``omnia.yml``, all configuration files that have been encrypted by the playbook will be unencrypted. - -Omnia installs a FreeIPA server on the kube_control_plane and FreeIPA clients on the cluster and login node using one of the below commands: :: - - ansible-playbook security.yml -i inventory - - ansible-playbook omnia.yml -i inventory - -Where inventory follows the format defined under inventory file in the provided `Sample Files. <../../samplefiles.html>`_ The inventory file is case-sensitive. Follow the casing provided in the sample file link. - -The ``omnia.yml`` playbook installs Slurm, BeeFGS Client, NFS Client in addition to freeIPA. - -.. note:: - - * Omnia does not create any accounts (HPC users) on FreeIPA. To create a user, check out *FreeIPA documentation*. - - * Alternatively, use the below commands with admin credentials on the login/head node: :: - - kinit admin (When prompted, provide kerberos_admin_password as entered in security_config.yml) - ipa user-add FirstName_LastName --first=FirstName --last=LastName --password --homedir=/home/omnia-share/FirstName_LastName --shell /bin/bash - - For example: ``ipa user-add FirstName_LastName --first=FirstName --last=LastName --password --homedir=/home/omnia-share/FirstName_LastName --shell /bin/bash`` - - After the new user account logs in for the first time, you will be prompted to change the password to the account. - -**Setting up Passwordless SSH for FreeIPA** - -Once user accounts are created, admins can enable passwordless SSH for users to run HPC jobs on the cluster nodes. - -.. note:: Once user accounts are created on FreeIPA, use the accounts to login to the cluster nodes to reset the password and create a corresponding home directory. - -To customize your setup of passwordless ssh, input parameters in ``input/passwordless_ssh_config.yml``. - -+-----------------------+--------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+=======================+====================================================================================================================+ -| user_name | The list of users that requires passwordless SSH. Separate the list of users using a comma. | -| ``string`` | Eg: ``user1,user2,user3`` | -| Required | | -+-----------------------+--------------------------------------------------------------------------------------------------------------------+ -| authentication_type | Indicates whether LDAP or FreeIPA is in use on the cluster. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``freeipa`` <- Default | -| | | -| | * ``ldap`` | -+-----------------------+--------------------------------------------------------------------------------------------------------------------+ -| freeipa_user_home_dir | * This variable accepts the user home directory path for freeipa configuration. | -| ``string`` | * If nfs mount is created for user home, make sure you provide the freeipa users mount home directory path. | -| Required | | -| | **Default value**: ``"/home/omnia-share"`` | -+-----------------------+--------------------------------------------------------------------------------------------------------------------+ - - -Use the below command to enable passwordless SSH: :: - - ansible-playbook user_passwordless_ssh.yml -i inventory - -Where inventory follows the format defined under inventory file in the provided `Sample Files. <../../samplefiles.html>`_ The inventory file is case-sensitive. Follow the casing provided in the sample file link. - -.. caution:: Do not run ssh-keygen commands after passwordless SSH is set up on the nodes. - - -Using LDAP client ------------------- - -To add the cluster to an external LDAP server, Omnia enables the installation of LDAP client on all cluster nodes. - -To customize your LDAP client installation, input parameters in ``input/security_config.yml`` - -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+======================+======================================================================================================================+ -| ldap_required | Boolean indicating whether LDAP is required or not. | -| ``boolean`` | | -| Required | Choices: | -| | | -| | * ``true`` <- Default | -| | | -| | * ``false`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| domain_name | Sets the intended domain name | -| ``string`` | | -| Required | **Default value**: ``omnia.test`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| ldap_server_ip | LDAP server IP. Required if ``ldap_required`` is true. There should be an explicit LDAP server running on this IP. | -| ``string`` | | -| Optional | | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| ldap_connection_type | * For a TLS connection, provide a valid certification path. | -| ``string`` | * For an SSL connection, ensure port 636 is open. | -| Required | | -| | Choices: | -| | | -| | * ``TLS`` <- Default | -| | | -| | * ``SSL`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| ldap_ca_cert_path | * This variable accepts Server Certificate Path. | -| ``string`` | * Make sure certificate is present in the path provided. | -| Required | * The certificate should have .pem or .crt extension. | -| | * This variable is mandatory if connection type is TLS. | -| | | -| | **Default value**: ``/etc/openldap/certs/omnialdap.pem`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| user_home_dir | * This variable accepts the user home directory path for LDAP configuration. | -| ``string`` | * If nfs mount is created for user home, make sure you provide the freeipa users mount home directory path. | -| Required | | -| | **Default value**: ``"/home/omnia-share"`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| ldap_bind_username | * If LDAP server is configured with bind dn then bind dn user to be provided. | -| ``string`` | * If this value is not provided (when bind is configured in server) then ldap authentication fails. | -| Required | * Omnia does not validate this input. | -| | * Ensure that it is valid and proper. | -| | | -| | **Default value**: ``admin`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ -| ldap_bind_password | * If LDAP server is configured with bind dn then bind dn password to be provided. | -| ``string`` | * If this value is not provided (when bind is configured in server) then ldap authentication fails. | -| Required | * Omnia does not validate this input. | -| | * Ensure that it is valid and proper. | -| | | -| | **Default value**: ``admin`` | -+----------------------+----------------------------------------------------------------------------------------------------------------------+ - -.. note:: Omnia does not create any accounts (HPC users) on LDAP. To create a user, check out `LDAP documentation. `_ - - -**Setting up Passwordless SSH for LDAP** - -Once user accounts are created, admins can enable passwordless SSH for users to run HPC jobs on the cluster nodes. +The security feature allows users to set up FreeIPA and LDAP to help authenticate into HPC clusters. .. note:: - * Ensure that the control plane can reach the designated LDAP server. - * If ``enable_omnia_nfs`` is true in ``input/omnia_config.yml``, follow the below steps to configure an NFS share on your LDAP server: - - From the kube_control_plane: - 1. Add the LDAP server IP address to ``/etc/exports``. - 2. Run ``exportfs -ra`` to enable the NFS configuration. - - From the LDAP server: - 1. Add the required fstab entries in ``/etc/fstab``. (The corresponding entry will be available on the cluster nodes in ``/etc/fstab``) - 2. Mount the NFS share using ``mount manager_ip: /home/omnia-share /home/omnia-share``. - * If ``enable_omnia_nfs`` is false in ``input/omnia_config.yml``, ensure the user-configured NFS share is mounted on the LDAP server. - - -To customize your setup of passwordless ssh, input parameters in ``input/passwordless_ssh_config.yml`` - -+--------------------------+-------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+==========================+=======================================================================================================+ -| user_name | The list of users that requires passwordless SSH. Separate the list of users using a comma. | -| ``string`` | Eg: ``user1,user2,user3`` | -| Required | | -+--------------------------+-------------------------------------------------------------------------------------------------------+ -| authentication_type | Indicates whether LDAP or FreeIPA is in use on the cluster. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``freeipa`` <- Default | -| | | -| | * ``ldap`` | -+--------------------------+-------------------------------------------------------------------------------------------------------+ -| ldap_organizational_unit | * Distinguished name i.e dn in ldap is used to identify an entity in a LDAP. | -| ``string`` | * This variable includes the organizational unit (ou) which is used to identifies user in the LDAP. | -| Required | * Only provide ou details i.e ou=people, as domain name and userid is accepted already. | -| | **Default value**: ``people`` | -+--------------------------+-------------------------------------------------------------------------------------------------------+ - - -Use the below command to enable passwordless SSH: :: - - ansible-playbook user_passwordless_ssh.yml -i inventory - -.. caution:: Do not run ssh-keygen commands after passwordless SSH is set up on the nodes. - - - - - - - - + * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``security.yml`` on RHEL target nodes. + * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. + + +Configuring FreeIPA/LDAP security +________________________________ + +**Pre requisites** + +* Run ``local_repo.yml`` to create offline repositories of FreeIPA or OpenLDAP. If both were downloaded, ensure that the non-required system is removed from ``input/software_config.json`` before running ``security.yml``. For more information, `click here <../../InstallationGuides/LocalRepo/index.html>`_. + +* Enter the following parameters in ``input/security_config.yml``. + +.. csv-table:: Parameters for Authentication + :file: ../../Tables/security_config.csv + :header-rows: 1 + :keepspace: + +.. csv-table:: Parameters for OpenLDAP configuration + :file: ../../Tables/security_config_ldap.csv + :header-rows: 1 + :keepspace: + +.. csv-table:: Parameters for FreeIPA configuration + :file: ../../Tables/security_config_freeipa.csv + :header-rows: 1 + :keepspace: + +.. [1] Boolean parameters do not need to be passed with double or single quotes. + +Create a new user on OpenLDAP +----------------------------- + +1. Create an LDIF file (eg: ``create_user.ldif``) on the auth server containing the following information: + + * DN: The distinguished name that indicates where the user will be created. + * objectClass: The object class specifies the mandatory and optional attributes that can be associated with an entry of that class. Here, the values are ``inetOrgPerson``, ``posixAccount``, and ``shadowAccount``. + * UID: The username of the replication user. + * sn: The surname of the intended user. + * cn: The given name of the intended user. + +Below is a sample file: :: + + # User Creation + dn: uid=ldapuser,ou=People,dc=omnia,dc=test + objectClass: inetOrgPerson + objectClass: posixAccount + objectClass: shadowAccount + cn: ldapuser + sn: ldapuser + loginShell:/bin/bash + uidNumber: 2000 + gidNumber: 2000 + homeDirectory: /home/ldapuser + shadowLastChange: 0 + shadowMax: 0 + shadowWarning: 0 + + # Group Creation + dn: cn=ldapuser,ou=Group,dc=omnia,dc=test + objectClass: posixGroup + cn: ldapuser + gidNumber: 2000 + memberUid: ldapuser + +.. note:: Avoid whitespaces when using an LDIF file for user creation. Extra spaces in the input data may be encrypted by OpenLDAP and cause access failures. + +2. Run the command ``ldapadd -D -w < bind_password > -f create_user.ldif`` to execute the LDIF file and create the account. +3. To set up a password for this account, use the command ``ldappasswd -D -w < bind_password > -S ``. The value of ``user_dn`` is the distinguished name that indicates where the user was created. (In this example, ``ldapuser,ou=People,dc=omnia,dc=test``) + + + +Configuring login node security +________________________________ + +**Prerequisites** + +* Run ``local_repo.yml`` to create an offline repository of all utilities used to secure the login node. For more information, `click here. <../../InstallationGuides/LocalRepo/SecureLoginNode.html>`_ + +Enter the following parameters in ``input/login_node_security_config.yml``. + ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Variable | Details | ++==========================+================================================================================================================================================================================+ +| **max_failures** | The number of login failures that can take place before the account is locked out. | +| ``integer`` | | +| Optional | **Default values**: ``3`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|**failure_reset_interval**| Period (in seconds) after which the number of failed login attempts is reset. Min value: 30; Max value: 60. | +| ``integer`` | | +| Optional | **Default values**: ``60`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| **lockout_duration** | Period (in seconds) for which users are locked out. Min value: 5; Max value: 10. | +| ``integer`` | | +| Optional | **Default values**: ``10`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|**session_timeout** | User sessions that have been idle for a specific period can be ended automatically. Min value: 90; Max value: 180. | +| ``integer`` | | +| Optional | **Default values**: ``180`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|**alert_email_address** | Email address used for sending alerts in case of authentication failure. When blank, authentication failure alerts are disabled. Currently, only one email ID is accepted. | +| ``string`` | | +| Optional | | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|**user** | Access control list of users. Accepted formats are username@ip (root@1.2.3.4) or username (root). Multiple users can be separated using whitespaces. | +| ``string`` | | +| Optional | | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|**allow_deny** | This variable decides whether users are to be allowed or denied access. Ensure that AllowUsers or DenyUsers entries on sshd configuration file are not commented. | +| ``string`` | | +| Optional | Choices: | +| | | +| | * ``allow`` <- Default | +| | * ``deny`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| restrict_program_support | This variable is used to disable services. Root access is mandatory. | +| ``boolean`` | | +| Optional | Choices: | +| | | +| | * ``false`` <- Default | +| | * ``true`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +|**restrict_softwares** | List of services to be disabled (Comma-separated). Example: 'telnet,lpd,bluetooth' | +| ``string`` | | +| Optional | Choices: | +| | | +| | * ``telnet`` | +| | * ``lpd`` | +| | * ``bluetooth`` | +| | * ``rlogin`` | +| | * ``rexec`` | ++--------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Installing LDAP Client +________________________ + +.. caution:: No users/groups will be created by Omnia. + +FreeIPA installation on the NFS node +------------------------------------- + +IPA services are used to provide account management and centralized authentication. + +To customize your installation of FreeIPA, enter the following parameters in ``input/security_config.yml``. + ++-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Input Parameter | Definition | Variable value | ++=========================+=================================================================+=======================================================================================================================================================+ +| kerberos_admin_password | "admin" user password for the IPA server on RockyOS and RedHat. | The password can be found in the file ``input/security_config.yml`` . | ++-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ipa_server_hostname | The hostname of the IPA server | The hostname can be found on the manager node. | ++-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| domain_name | Domain name | The domain name can be found in the file ``input/security_config.yml``. | ++-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ +| ipa_server_ipadress | The IP address of the IPA server | The IP address can be found on the IPA server on the manager node using the ``ip a`` command. This IP address should be accessible from the NFS node. | ++-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +To set up IPA services for the NFS node in the target cluster, run the following command from the ``utils/cluster`` folder on the control plane: :: + + cd utils/cluster + ansible-playbook install_ipa_client.yml -i inventory -e kerberos_admin_password="" -e ipa_server_hostname="" -e domain_name="" -e ipa_server_ipadress="" + + +.. include:: ../../Appendices/hostnamereqs.rst + +.. note:: Use the format specified under `NFS inventory in the Sample Files <../../samplefiles.html#nfs-server-inventory-file>`_ for inventory. + +Running the security role +-------------------------- + +Run: :: + + cd security + ansible-playbook security.yml -i inventory +The inventory should contain auth_server as per the inventory file in `samplefiles <../../samplefiles.html#inventory-file>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. + * Do not include the IP of the control plane or local host in the auth_server group in the passed inventory. + * To customize the security features on the login node, fill out the parameters in ``input/login_node_security_config.yml``. + * If a subsequent run of ``security.yml`` fails, the ``security_config.yml`` file will be unencrypted. +.. caution:: No users will be created by Omnia. diff --git a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst index 832475b6b..a1a63c6c9 100644 --- a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst @@ -60,68 +60,15 @@ After the required parameters are filled in ``input/storage_config.yml``, Omnia .. caution:: Do not remove or comment any lines in the ``input/storage_config.yml`` file. -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Name | Details | -+=================================+======================================================================================================================================================================================================================================================+ -| beegfs_support | This variable is used to install beegfs-client on compute and manager nodes | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_rdma_support | This variable is used if user has RDMA-capable network hardware (e.g., InfiniBand) | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_ofed_kernel_modules_path | The path where separate OFED kernel modules are installed. | -| ``string`` | | -| Optional | **Default value**: ``"/usr/src/ofa_kernel/default/include"`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mgmt_server | BeeGFS management server IP. Note: The provided IP should have an explicit BeeGFS management server running . | -| ``string`` | | -| Required | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mounts | Beegfs-client file system mount location. If ``storage_yml`` is being used to change the BeeGFS mounts location, set beegfs_unmount_client to true | -| ``string`` | **Default value**: "/mnt/beegfs" | -| Optional | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_unmount_client | Changing this value to true will unmount running instance of BeeGFS client and should only be used when decommisioning BeeGFS, changing the mount location or changing the BeeGFS version. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_client_version | Beegfs client version needed on compute and manager nodes. | -| ``string`` | | -| Optional | **Default value**: 7.2.6 | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_version_change | Use this variable to change the BeeGFS version on the target nodes. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_secret_storage_filepath | * The filepath (including the filename) where the ``connauthfile`` is placed. | -| ``string`` | * Recommended for Beegfs version >= 7.2.7. | -| Optional | | -| | | -| | **Default value**: ``/home/connauthfile`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Parameters for Authentication + :file: ../../Tables/security_config.csv + :header-rows: 1 + :keepspace: .. note:: * BeeGFS client-server communication can take place over TCP or RDMA. If RDMA support is required, set ``beegfs_rdma_support`` should be set to true. Also, OFED should be installed on all cluster nodes. * For BeeGFS communication happening over RDMA, the ``beegfs_mgmt_server`` should be provided with the Infiniband IP of the management server. - * The parameter inventory refers to the `inventory file <../../samplefiles.html>`_ listing manager, login and compute nodes.) + * The parameter inventory refers to the `inventory file <../../samplefiles.html>`_ listing all relevant nodes.) If ``input/storage_config.yml`` is populated before running ``omnia.yml``, BeeGFS client will be set up during the run of ``omnia.yml``. diff --git a/docs/source/InstallationGuides/BuildingClusters/index.rst b/docs/source/InstallationGuides/BuildingClusters/index.rst index 3f60a8102..4dfe7ef50 100644 --- a/docs/source/InstallationGuides/BuildingClusters/index.rst +++ b/docs/source/InstallationGuides/BuildingClusters/index.rst @@ -11,11 +11,9 @@ Configuring the cluster * Kubernetes: Once all the required parameters in `omnia_config.yml `_ are filled in, ``omnia.yml`` can be used to set up kubernetes. - * BeeGFS bolt on installation: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up NFS. + * BeeGFS bolt on installation: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up BeeGFS. - * NFS bolt on support: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up BeeGFS. - - * Telemetry: Once all the required parameters in `telemetry_config.yml `_ are filled in, ``omnia.yml`` sets up `Omnia telemetry and/or iDRAC telemetry <../../Roles/Telemetry/index.html>`_. It also installs `Grafana `_ and `Loki `_ as Kubernetes pods. + * NFS support: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up NFS. .. toctree:: schedulerinputparams @@ -25,9 +23,7 @@ Configuring the cluster KubernetesAccess BeeGFS NFS - OneAPI - OpenMPI_AOCC - KernelUpdateRHEL + diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst index cbf64ef5f..327ddaf61 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst @@ -24,83 +24,23 @@ These parameters are located in ``input/omnia_config.yml``, ``input/security_con :header-rows: 1 :keepspace: +.. csv-table:: Parameters for OpenLDAP configuration + :file: ../../Tables/security_config_ldap.csv + :header-rows: 1 + :keepspace: -**storage_config.yml** +.. csv-table:: Parameters for FreeIPA configuration + :file: ../../Tables/security_config_freeipa.csv + :header-rows: 1 + :keepspace: -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Name | Details | -+=================================+======================================================================================================================================================================================================================================================+ -| nfs_client_params | If NFS client services are to be deployed, enter the configuration required here in JSON format. The server_ip provided should have an explicit NFS server running. If left blank, no NFS configuration takes place. Possible values include: | -| ``JSON list`` | 1. Single NFS file system: A single filesystem from a single NFS server is mounted. | -| Optional | | -| | Sample value: ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/share”, client_share_path: “/mnt/client”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | 2. Multiple Mount NFS file system: Multiple filesystems from a single NFS server are mounted. | -| | Sample values: | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/server1”, client_share_path: “/mnt/client1”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/server2”, client_share_path: “/mnt/client2”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | 3. Multiple NFS file systems: Multiple filesystems are mounted from multiple servers. | -| | Sample Values: ``- { server_ip: zz.zz.zz.zz, server_share_path: “/mnt/share1”, client_share_path: “/mnt/client1”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/share2”, client_share_path: “/mnt/client2”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | ``- { server_ip: yy.yy.yy.yy, server_share_path: “/mnt/share3”, client_share_path: “/mnt/client3”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | | -| | | -| | **Default value**: ``{ server_ip: , server_share_path: , client_share_path: , client_mount_options: }`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_support | This variable is used to install beegfs-client on compute and manager nodes | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_rdma_support | This variable is used if user has RDMA-capable network hardware (e.g., InfiniBand) | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_ofed_kernel_modules_path | The path where separate OFED kernel modules are installed. | -| ``string`` | | -| Optional | **Default value**: ``"/usr/src/ofa_kernel/default/include"`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mgmt_server | BeeGFS management server IP. Note: The provided IP should have an explicit BeeGFS management server running . | -| ``string`` | | -| Required | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mounts | Beegfs-client file system mount location. If ``storage_yml`` is being used to change the BeeGFS mounts location, set beegfs_unmount_client to true | -| ``string`` | **Default value**: "/mnt/beegfs" | -| Optional | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_unmount_client | Changing this value to true will unmount running instance of BeeGFS client and should only be used when decommisioning BeeGFS, changing the mount location or changing the BeeGFS version. | -| ``boolean`` [1]_ | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_client_version | Beegfs client version needed on compute and manager nodes. | -| ``string`` | | -| Optional | **Default value**: 7.2.6 | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_version_change | Use this variable to change the BeeGFS version on the target nodes. | -| ``boolean`` [1]_ | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_secret_storage_filepath | * The filepath (including the filename) where the ``connauthfile`` is placed. | -| ``string`` | * Required for Beegfs version >= 7.2.7 | -| Required | | -| | | -| | **Default values**: ``/home/connauthfile`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +**storage_config.yml** + +.. csv-table:: Parameters for Storage + :file: ../../Tables/storage_config.csv + :header-rows: 1 + :keepspace: **telemetry_config.yml** @@ -112,5 +52,5 @@ These parameters are located in ``input/omnia_config.yml``, ``input/security_con .. [1] Boolean parameters do not need to be passed with double or single quotes. -Click here for more information on `FreeIPA, LDAP `_, `Telemetry <../../Roles/Telemetry/index.html>`_, `BeeGFS `_ or, `NFS `_. +Click here for more information on `OpenLDAP, FreeIPA `_, `Telemetry <../../Roles/Telemetry/index.html>`_, `BeeGFS `_ or, `NFS `_. From 1446c317f6ba7769a6f8cc28545e911a3eff136c Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 10:34:44 +0530 Subject: [PATCH 156/309] Updating NFS local repo information Signed-off-by: goveac --- docs/source/InstallationGuides/BuildingClusters/NFS.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 54d7dd0f7..006b3e21a 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -19,7 +19,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. +-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ - .. image:: ../../images/NFS_FlowChart.png + .. image:: ../../images/nfs_flowchart.png * The fields listed in ``nfs_client_params`` are: From f7ec7f5edab1f27da41fe8a1791c7cb5c7fc14ee Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 11:03:39 +0530 Subject: [PATCH 157/309] Updating NFS local repo information Signed-off-by: goveac --- .../BuildingClusters/NFS.rst | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 006b3e21a..16aba398c 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -1,8 +1,9 @@ NFS ____ -Network File System (NFS) is a networking protocol for distributed file sharing. A file system defines the way data in the form of files is stored and retrieved from storage devices, such as hard disk drives, solid-state drives and tape drives. NFS is a network file sharing protocol that defines the way files are stored and retrieved from storage devices across networks. NFS is a mandatory feature for all clusters set up by Omnia. +Network File System (NFS) is a networking protocol for distributed file sharing. A file system defines the way data in the form of files is stored and retrieved from storage devices, such as hard disk drives, solid-state drives and tape drives. NFS is a network file sharing protocol that defines the way files are stored and retrieved from storage devices across networks. +.. note:: NFS is a mandatory feature for all clusters set up by Omnia. **Pre requisites** @@ -12,8 +13,8 @@ Network File System (NFS) is a networking protocol for distributed file sharing. | Parameter | Details | +=======================+=============================================================================================================================================================+ | **nfs_client_params** | * This JSON list contains all parameters required to set up NFS. | - | | * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. | - | ``JSON List`` | * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. | + | | * For a bolt-on set up where there is a pre-existing NFS server, set ``nfs_server`` to ``false``. | + | ``JSON List`` | * When ``nfs_server`` is set to ``true``, an NFS share is created on the a server IP in the cluster for access by all other cluster nodes. | | | * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. | | Required | * For more information on the different kinds of configuration available, `click here. `_ | +-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -23,15 +24,14 @@ Network File System (NFS) is a networking protocol for distributed file sharing. * The fields listed in ``nfs_client_params`` are: - - server_ip: IP of the intended NFS server. To set up an NFS server on the control plane, use the value ``localhost``. + - **server_ip**: IP of the intended NFS server. To set up an NFS server on the control plane, use the value ``localhost``. Use an IP address to configure access anywhere else. - - server_share_path: Folder on which the NFS server mounted. + - **server_share_path**: Folder on which the NFS server mounted. - - client_share_path: Target directory for the NFS mount on the client. If left empty, the respective ``server_share_path value`` will be taken for ``client_share_path``. + - **client_share_path**: Target directory for the NFS mount on the client. If left empty, the respective ``server_share_path value`` will be taken for ``client_share_path``. - - client_mount_options: The mount options when mounting the NFS export on the client. Default value: nosuid,rw,sync,hard,intr. For a list of mount options, `click here `_. - - nfs_server: Indicates whether an external NFS server is available (true) or an NFS export will need to be created (false). + - **nfs_server**: Indicates whether an external NFS server is available (false) or an NFS server will need to be created (true). To configure all cluster nodes to access a single external NFS server export, use the below sample: :: @@ -74,7 +74,7 @@ Post configuration, enable the following services (using this command: ``firewal - mountd .. caution:: - After an NFS client is configured, if the NFS server is rebooted, the client may not be able to reach the server. In those cases, restart the NFS services on the server using the below command: + * After an NFS client is configured, if the NFS server is rebooted, the client may not be able to reach the server. In those cases, restart the NFS services on the server using the below command: :: @@ -82,4 +82,11 @@ Post configuration, enable the following services (using this command: ``firewal systemctl enable nfs-server systemctl restart nfs-server + * When ``nfs_server`` is false, enable the following services after configuration using this command: ``firewall-cmd --permanent --add-service=``) and then reload the firewall (using this command: ``firewall-cmd --reload``). + + - nfs + + - rpc-bind + + - mountd From 2f7df4ee189389891fd6a59c42f8c23c77b21a94 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 11:13:50 +0530 Subject: [PATCH 158/309] Updating NFS local repo information Signed-off-by: goveac --- docs/source/images/nfs_flowchart.png | Bin 21855 -> 102127 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/docs/source/images/nfs_flowchart.png b/docs/source/images/nfs_flowchart.png index 52d149731fc34ff1e2aa421ff0e8188d8dbb8ae1..848b98cc9472088061f9865c7ae8176963499d58 100644 GIT binary patch literal 102127 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 gG Date: Thu, 7 Mar 2024 11:25:40 +0530 Subject: [PATCH 159/309] Updating NFS local repo information Signed-off-by: goveac --- docs/source/InstallationGuides/BuildingClusters/NFS.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 16aba398c..40ec17fba 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -30,8 +30,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. - **client_share_path**: Target directory for the NFS mount on the client. If left empty, the respective ``server_share_path value`` will be taken for ``client_share_path``. - - - **nfs_server**: Indicates whether an external NFS server is available (false) or an NFS server will need to be created (true). + - **nfs_server**: Indicates whether an external NFS server is available (``false``) or an NFS server will need to be created (``true``). To configure all cluster nodes to access a single external NFS server export, use the below sample: :: From 7ad2885aa73cf3444d2638f8ef62c6982ade6142 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 15:42:32 +0530 Subject: [PATCH 160/309] Updating Kubernetes local repo information Signed-off-by: goveac --- .../BuildingClusters/BeeGFS.rst | 4 +- .../BuildingClusters/NFS.rst | 4 +- .../BuildingClusters/installscheduler.rst | 9 +- .../LocalRepo/CustomLocalRepo.rst | 2 +- .../InstallationGuides/LocalRepo/FreeIPA.rst | 2 +- .../LocalRepo/InputParameters.rst | 89 ++++++++ .../LocalRepo/Kubernetes.rst | 25 ++ .../InstallationGuides/LocalRepo/OpenLDAP.rst | 2 +- .../LocalRepo/Prerequisite.rst | 14 +- .../InstallationGuides/LocalRepo/PyTorch.rst | 2 +- .../LocalRepo/RunningLocalRepo.rst | 142 ++++++++++++ .../LocalRepo/SecureLoginNode.rst | 2 +- .../LocalRepo/TensorFlow.rst | 2 +- .../InstallationGuides/LocalRepo/bcm_roce.rst | 2 +- .../InstallationGuides/LocalRepo/cuda.rst | 2 +- .../InstallationGuides/LocalRepo/index.rst | 214 +----------------- .../InstallationGuides/LocalRepo/kserve.rst | 2 +- .../InstallationGuides/LocalRepo/ofed.rst | 2 +- .../InstallationGuides/LocalRepo/vLLM.rst | 2 +- 19 files changed, 289 insertions(+), 234 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/InputParameters.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/Kubernetes.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst diff --git a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst index a1a63c6c9..0f76599fe 100644 --- a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst @@ -60,8 +60,8 @@ After the required parameters are filled in ``input/storage_config.yml``, Omnia .. caution:: Do not remove or comment any lines in the ``input/storage_config.yml`` file. -.. csv-table:: Parameters for Authentication - :file: ../../Tables/security_config.csv +.. csv-table:: Parameters for storage + :file: ../../Tables/storage_config.csv :header-rows: 1 :keepspace: diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 40ec17fba..4de8034ae 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -14,7 +14,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. +=======================+=============================================================================================================================================================+ | **nfs_client_params** | * This JSON list contains all parameters required to set up NFS. | | | * For a bolt-on set up where there is a pre-existing NFS server, set ``nfs_server`` to ``false``. | - | ``JSON List`` | * When ``nfs_server`` is set to ``true``, an NFS share is created on the a server IP in the cluster for access by all other cluster nodes. | + | ``JSON List`` | * When ``nfs_server`` is set to ``true``, an NFS share is created on a server IP in the cluster for access by all other cluster nodes. | | | * Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. | | Required | * For more information on the different kinds of configuration available, `click here. `_ | +-----------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -22,6 +22,8 @@ Network File System (NFS) is a networking protocol for distributed file sharing. .. image:: ../../images/nfs_flowchart.png + + * The fields listed in ``nfs_client_params`` are: - **server_ip**: IP of the intended NFS server. To set up an NFS server on the control plane, use the value ``localhost``. Use an IP address to configure access anywhere else. diff --git a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst index 4a644bdc8..520046c94 100644 --- a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst +++ b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst @@ -3,13 +3,8 @@ Building clusters 1. In the ``input/omnia_config.yml``, ``input/security_config.yml``, ``input/telemetry_config.yml`` and [optional] ``input/storage_config.yml`` files, provide the `required details `_. -.. note:: - * Use the parameter ``scheduler_type`` in ``input/omnia_config.yml`` to customize what schedulers are installed in the cluster. - * Without the login node, Slurm jobs can be scheduled only through the kube_control_plane. - -2. Create an inventory file in the *omnia* folder. Check out the `sample inventory for more information <../../samplefiles.html>`_. -.. [1] In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, do not include the kube_control_plane IP address in the compute group. In a single node setup, the compute node and the kube_control_plane must be the same. +2. Create an inventory file in the *omnia* folder. Check out the `sample inventory for more information <../../samplefiles.html>`_. If a hostname is used to refer to the target nodes, ensure that the domain name is included in the entry. IP addresses are also accepted in the inventory file. .. include:: ../../Appendices/hostnamereqs.rst @@ -33,7 +28,7 @@ To run ``omnia.yml``: :: .. note:: * To visualize the cluster (Slurm/Kubernetes) metrics on Grafana (On the control plane) during the run of ``omnia.yml``, add the parameters ``grafana_username`` and ``grafana_password`` (That is ``ansible-playbook omnia.yml -i inventory -e grafana_username="" -e grafana_password=""``). - * Having the same node in the manager and login groups in the inventory is not recommended by Omnia. + * For a Kubernetes cluster installation, ensure that the inventory includes an ``[etcd]`` entry. etcd is a consistent and highly-available key value store used as Kubernetes' backing store for all cluster data. For more information, `click here. `_ * If you want to view or edit the ``omnia_config.yml`` file, run the following command: - ``ansible-vault view omnia_config.yml --vault-password-file .omnia_vault_key`` -- To view the file. diff --git a/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst index ab6869147..1e00c1fe7 100644 --- a/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/CustomLocalRepo.rst @@ -110,7 +110,7 @@ Use the local repository feature to create a customized set of local repositorie } } -2. Enter the parameters required in ``input/local_repo_config.yml`` as explained `here `_. +2. Enter the parameters required in ``input/local_repo_config.yml`` as explained `here `_. 3. Run the following commands: :: diff --git a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst index b4cb99110..3d7ef9e7d 100644 --- a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst +++ b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst @@ -17,7 +17,7 @@ To install FreeIPA, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for FreeIPA, view the ``input/config///freeipa.json`` file. To customize your FreeIPA installation, update the file.: -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst new file mode 100644 index 000000000..8d76d1c44 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst @@ -0,0 +1,89 @@ +Input parameters for Local Repositories +---------------------------------------- + +* Input all required values in ``input/software_config.json``. + + .. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + + +* Input the required values in ``input/local_repo_config.yml``. + + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +=========================+===================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | + | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | + | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | + | Optional | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | | | + | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | + | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | + | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | + | Optional | * 'host' defines the URL and path to the registry. | + | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | + | | | + | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``rhel_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``rhel_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | * **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | * **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + diff --git a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst new file mode 100644 index 000000000..244094d07 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst @@ -0,0 +1,25 @@ +Create local Kubernetes repository +---------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install Kubernetes, include the following line under ``softwares```: :: + + {"name": "k8s", "version":"1.26.12"}, + +.. note:: The version of the software provided above is the only version of the software Omnia supports. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + +To complete the installation of Kubernetes on the cluster, `click here. <../BuildingClusters/index.rst>`_ \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst index 4359debdf..5330e39df 100644 --- a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst +++ b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst @@ -16,7 +16,7 @@ To install OpenLDAP, include the following line under ``softwares```: :: -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index 7d4aed90e..0b27f32af 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -5,4 +5,16 @@ Before you create local repositories For persistent offline local repositories, (If the parameter ``repo_config`` in ``input/software_config`` is set to ``always``), click `here `_ to set up the required repositories. -.. note:: This link explains how to build a mirror on an Ubuntu 20.04 server. Adapt the steps and scripts as required for any other version of Ubuntu. \ No newline at end of file +.. note:: This link explains how to build a mirror on an Ubuntu 20.04 server. Adapt the steps and scripts as required for any other version of Ubuntu. + +**When creating user registries** + +If ``repo_config`` in ``input/software_config.json`` is set to ``partial`` or ``never``, images listed in ``user_registry`` in ``input/local_repo_config.yml`` are accessed from user defined registries. To ensure that the control plane can correctly access the registry, ensure that the following naming convention is used to save the image: :: + + /:v + +Therefore, for the image of calico/cni version 1.2 available on quay.io that has been pulled to a local host server1.omnia.test, the accepted user registry name is: :: + + server1.omnia.test:5001/calico/cni:v1.2 + +Omnia will not be able to configure access to any registries that do not follow this naming convention. Do not include any other extraneous information in the registry name. \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst index 44d4909a2..972bb16c4 100644 --- a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst +++ b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst @@ -17,7 +17,7 @@ To install PyTorch, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for PyTorch, view the ``input/config///pytorch.json`` file. To customize your PyTorch installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst new file mode 100644 index 000000000..d1f9f0645 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -0,0 +1,142 @@ +Running local repo +------------------ + +The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + + +Below is a sample version of the file: :: + + { + "cluster_os_type": "ubuntu", + "cluster_os_version": "22.04", + "repo_config": "partial", + "softwares": [ + {"name": "k8s", "version":"1.26.12"}, + {"name": "jupyter", "version": "3.2.0"}, + {"name": "kubeflow", "version": "1.8"}, + {"name": "openldap"}, + {"name": "beegfs", "version": "7.2.6"}, + {"name": "nfs"}, + {"name": "kserve"}, + {"name": "custom"}, + {"name": "amdgpu", "version": "6.0"}, + {"name": "cuda", "version": "12.3.2"}, + {"name": "ofed", "version": "24.01-0.3.3.1"}, + {"name": "telemetry"}, + {"name": "utils"}, + {"name": "vllm"}, + {"name": "pytorch"}, + {"name": "tensorflow"}, + {"name": "bcm_roce", "version": "229.2.9.0"} + ], + + "amdgpu": [ + {"name": "rocm", "version": "6.0" } + ], + "vllm": [ + {"name": "vllm_amd", "version":"vllm-v0.2.4"}, + {"name": "vllm_nvidia", "version": "latest"} + ], + "pytorch": [ + {"name": "pytorch_cpu", "version":"latest"}, + {"name": "pytorch_amd", "version":"latest"}, + {"name": "pytorch_nvidia", "version": "23.12-py3"} + ], + "tensorflow": [ + {"name": "tensorflow_cpu", "version":"latest"}, + {"name": "tensorflow_amd", "version":"latest"}, + {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} + ] + + } + + +For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: + +:: + + amdgpu.json + k8s.json + openldap.json + rocm.json + +For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: + + { + + "k8s": { + + "cluster": [ + { + "package": "containerd.io-1.6.16-3.1.el8", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + { + "package": "kubelet", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" + }, + { + "package": "kubeadm", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" + }, + { + "package": "helm", + "type": "tarball", + "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" + }, + { + "package": "registry.k8s.io/kube-apiserver", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "registry.k8s.io/kube-controller-manager", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "quay.io/coreos/etcd", + "version": "v3.5.9", + "type": "image" + }, + { + "package": "quay.io/calico/node", + "version": "v3.25.2", + "type": "image" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + }, + { + "package": "docker.io/kubernetesui/dashboard", + "version": "v2.7.0", + "type": "image" + } + ] + + } + + } + +.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. + +2. Enter the required values in the ``input/local_repo_config.yml`` file: + +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst index 7144a3533..4199442db 100644 --- a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst +++ b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst @@ -19,7 +19,7 @@ To secure the login node, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for securing the login node, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst index 8c5f885d3..60c270d17 100644 --- a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst +++ b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst @@ -17,7 +17,7 @@ To install TensorFlow, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for TensorFlow, view the ``input/config///tensorflow.json`` file. To customize your TensorFlow installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst index 8e7761807..9285518cc 100644 --- a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst +++ b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst @@ -35,7 +35,7 @@ For a list of repositories (and their types) configured for ROCe, view the ``inp .. note:: The only accepted URL for the ROCe driver is from the Dell Driver website. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst index c601aac1e..9521cb563 100644 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -54,7 +54,7 @@ For RHEL or Rocky: :: * If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. * If the target cluster runs on RHEL or Rocky, ensure the "dkms" package is included in ``input/config//8.x/cuda.json`` as illustrated above. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 9bc28ae12..616dc002e 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -3,220 +3,9 @@ Local repositories for the cluster The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - - -Below is a sample version of the file: :: - - { - "cluster_os_type": "ubuntu", - "cluster_os_version": "22.04", - "repo_config": "partial", - "softwares": [ - {"name": "k8s", "version":"1.26.12"}, - {"name": "jupyter", "version": "3.2.0"}, - {"name": "kubeflow", "version": "1.8"}, - {"name": "openldap"}, - {"name": "beegfs", "version": "7.2.6"}, - {"name": "nfs"}, - {"name": "kserve"}, - {"name": "custom"}, - {"name": "amdgpu", "version": "6.0"}, - {"name": "cuda", "version": "12.3.2"}, - {"name": "ofed", "version": "24.01-0.3.3.1"}, - {"name": "telemetry"}, - {"name": "utils"}, - {"name": "vllm"}, - {"name": "pytorch"}, - {"name": "tensorflow"}, - {"name": "bcm_roce", "version": "229.2.9.0"} - ], - - "amdgpu": [ - {"name": "rocm", "version": "6.0" } - ], - "vllm": [ - {"name": "vllm_amd", "version":"vllm-v0.2.4"}, - {"name": "vllm_nvidia", "version": "latest"} - ], - "pytorch": [ - {"name": "pytorch_cpu", "version":"latest"}, - {"name": "pytorch_amd", "version":"latest"}, - {"name": "pytorch_nvidia", "version": "23.12-py3"} - ], - "tensorflow": [ - {"name": "tensorflow_cpu", "version":"latest"}, - {"name": "tensorflow_amd", "version":"latest"}, - {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} - ] - - } - - -For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: - -:: - - amdgpu.json - k8s.json - openldap.json - rocm.json - -For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: - - { - - "k8s": { - - "cluster": [ - { - "package": "containerd.io-1.6.16-3.1.el8", - "type": "rpm", - "repo_name": "docker-ce-repo" - }, - { - "package": "kubelet", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" - }, - { - "package": "kubeadm", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" - }, - { - "package": "helm", - "type": "tarball", - "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" - }, - { - "package": "registry.k8s.io/kube-apiserver", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "registry.k8s.io/kube-controller-manager", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "quay.io/coreos/etcd", - "version": "v3.5.9", - "type": "image" - }, - { - "package": "quay.io/calico/node", - "version": "v3.25.2", - "type": "image" - }, - { - "package": "registry.k8s.io/pause", - "version": "3.9", - "type": "image" - }, - { - "package": "docker.io/kubernetesui/dashboard", - "version": "v2.7.0", - "type": "image" - } - ] - - } - - } - -.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. - -2. Enter the required values in the ``input/local_repo_config.yml`` file: - - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+===================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | - | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | - | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | - | Optional | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | | - | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | - | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | - | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | - | Optional | * 'host' defines the URL and path to the registry. | - | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | - | | | - | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``rhel_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``rhel_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | * **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | * **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - .. toctree:: Prerequisite + Kubernetes cuda ofed bcm_roce @@ -226,6 +15,7 @@ For a list of repositories (and their types) configured for kubernetes, view the PyTorch TensorFlow kserve + RunningLocalRepo CustomLocalRepo diff --git a/docs/source/InstallationGuides/LocalRepo/kserve.rst b/docs/source/InstallationGuides/LocalRepo/kserve.rst index 932b0051d..834d48f3e 100644 --- a/docs/source/InstallationGuides/LocalRepo/kserve.rst +++ b/docs/source/InstallationGuides/LocalRepo/kserve.rst @@ -17,7 +17,7 @@ To install Kserve, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for Kserve, view the ``input/config///kserve.json`` file. To customize your Kserve installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst index 0199b1271..9b605d51d 100644 --- a/docs/source/InstallationGuides/LocalRepo/ofed.rst +++ b/docs/source/InstallationGuides/LocalRepo/ofed.rst @@ -49,7 +49,7 @@ For RHEL or Rocky: :: .. note:: * If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/vLLM.rst b/docs/source/InstallationGuides/LocalRepo/vLLM.rst index 0c7de5215..4d6f9c365 100644 --- a/docs/source/InstallationGuides/LocalRepo/vLLM.rst +++ b/docs/source/InstallationGuides/LocalRepo/vLLM.rst @@ -17,7 +17,7 @@ To install vLLM, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for vLLM, view the ``input/config///vllm.json`` file. To customize your vLLM installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo From 73b9f45db62d760551da2d3e2940a27a75c87de5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 7 Mar 2024 15:50:35 +0530 Subject: [PATCH 161/309] Updating Kubernetes local repo information Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/Prerequisite.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index 0b27f32af..dd7011a19 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -13,7 +13,7 @@ If ``repo_config`` in ``input/software_config.json`` is set to ``partial`` or `` /:v -Therefore, for the image of calico/cni version 1.2 available on quay.io that has been pulled to a local host server1.omnia.test, the accepted user registry name is: :: +Therefore, for the image of ``calico/cni`` version ``1.2`` available on ``quay.io`` that has been pulled to a local host: ``server1.omnia.test``, the accepted user registry name is: :: server1.omnia.test:5001/calico/cni:v1.2 From 84591a8eeddd8ec0423fbe61dfb29452a5566c80 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 8 Mar 2024 12:43:57 +0530 Subject: [PATCH 162/309] Updating delete node information Signed-off-by: goveac --- .../LocalRepo/Prerequisite.rst | 2 +- docs/source/Roles/Utils/deletenode.rst | 68 +++++++++++++++++++ docs/source/Roles/Utils/index.rst | 1 + docs/source/Tables/bmc.csv | 45 ------------ docs/source/Tables/mapping.csv | 46 ------------- 5 files changed, 70 insertions(+), 92 deletions(-) create mode 100644 docs/source/Roles/Utils/deletenode.rst diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index dd7011a19..7ef37792a 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -9,7 +9,7 @@ For persistent offline local repositories, (If the parameter ``repo_config`` in **When creating user registries** -If ``repo_config`` in ``input/software_config.json`` is set to ``partial`` or ``never``, images listed in ``user_registry`` in ``input/local_repo_config.yml`` are accessed from user defined registries. To ensure that the control plane can correctly access the registry, ensure that the following naming convention is used to save the image: :: +Images listed in ``user_registry`` in ``input/local_repo_config.yml`` are accessed from user defined registries. To ensure that the control plane can correctly access the registry, ensure that the following naming convention is used to save the image: :: /:v diff --git a/docs/source/Roles/Utils/deletenode.rst b/docs/source/Roles/Utils/deletenode.rst new file mode 100644 index 000000000..33994b05b --- /dev/null +++ b/docs/source/Roles/Utils/deletenode.rst @@ -0,0 +1,68 @@ +Remove node from the cluster +---------------------------- +Use this playbook to remove nodes from the cluster and stop all clustering software on the target nodes. + +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. + +**Configurations performed by the playbook** + + * Remove node from Slurm and Kubernetes cluster. + * Update Slurm and Kubernetes config. + * Slurm and Kubernetes services are stopped (not uninstalled). OS startup service list will be updated to disable Slurm and Kubernetes. + +**To run the playbook** + +Run the playbook using the following commands: :: + + cd utils + ansible-playbook remove_node_config.yml -i inventory + + +Soft reset the cluster +----------------------- +Use this playbook to stop all Slurm and Kubernetes services. This action will destroy the cluster. + +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. + +**Configurations performed by the playbook** + + * The Slurm or Kubernetes cluster will be reset. + * The configuration on the kube_control_plane or the slurm_control_plane will be reset. + * Slurm and Kubernetes services are stopped (not uninstalled). + +**To run the playbook** + +Run the playbook using the following commands: :: + + cd utils + ansible-playbook reset_cluster_config.yml -i inventory + +Delete node from the cluster +----------------------------- +Use this playbook to remove nodes from all inventory files and tables. No changes are made to the Slurm or Kubernetes cluster. + +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. + +**Configurations performed by the playbook** + + * Nodes will be deleted from the Omnia DB and xCAT node object will be deleted. + * Telemetry services will be stopped. + +**To run the playbook** + +Run the playbook using the following commands: :: + + cd utils + ansible-playbook delete_node.yml -i inventory + + +.. note:: When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. Slurm partition is also needs to be updated with these changes. + + + + + + + + + diff --git a/docs/source/Roles/Utils/index.rst b/docs/source/Roles/Utils/index.rst index 6fa895fdf..3d4cae495 100644 --- a/docs/source/Roles/Utils/index.rst +++ b/docs/source/Roles/Utils/index.rst @@ -10,6 +10,7 @@ The Utilities role allows users to set up certain tasks such as configuringPXE freeipa_installation cleanupscript + deletenode OSPackageUpdate portcleanup timescaledb_utility diff --git a/docs/source/Tables/bmc.csv b/docs/source/Tables/bmc.csv index b322bdb86..36c6c069b 100644 --- a/docs/source/Tables/bmc.csv +++ b/docs/source/Tables/bmc.csv @@ -1,26 +1,4 @@ Parameter,Details -"**network_interface_type** - -``string`` - -Required","The network type used on the Omnia cluster. - -Choices: - -* ``dedicated`` <- default -* ``lom``" -"**discovery_mechanism** - -``string`` - -Required","The mechanism through which Omnia will discover nodes for provisioning. For more information on how the mechanisms work, go to `DiscoveryMechanisms `_. - -Choices: - -* ``switch_based`` -* ``mapping`` <-default -* ``bmc`` -* ``snmpwalk``" "**provision_os** ``string`` @@ -128,29 +106,6 @@ Required","* Domain name the user intends to configure on the cluster. Required","The nic/ethernet card that is connected to the public internet. **Default values**: ``eno2``" -"**admin_nic** - -``string`` - -Required","Admin NIC of Control Plane. This is the shared LOM NIC. - -**Default values**: ``eno1``" -"**admin_nic_subnet** - -``string`` - -Required","* The subnet within which all Admin IPs are assigned. -* The value of this variable cannot be changed after successfully running ``provision.yml``. - -**Default values**: ``10.5.0.0``" -"**ib_nic_subnet** - -``string`` - -Optional","* If provided, Omnia will handle and assign static IPs to cluster node's IB network. -* Only the last 16 bits/2 octets of IPv4 are dynamic -* If provided, the DB entry will be in parallel with the pxe_subnet. -* Example: If ``admin_ip``: 10.5.0.50 and ``ib_nic_subnet``: 10.10.0.0, then ``ib_ip``: 10.10.0.50" "**bmc_nic_subnet** ``string`` diff --git a/docs/source/Tables/mapping.csv b/docs/source/Tables/mapping.csv index 3ca315d5d..55d981504 100644 --- a/docs/source/Tables/mapping.csv +++ b/docs/source/Tables/mapping.csv @@ -1,16 +1,4 @@ Parameter,Details -"**discovery_mechanism** - -``string`` - -Required","The mechanism through which Omnia will discover nodes for provisioning. For more information on how the mechanisms work, go to `DiscoveryMechanisms `_. - -Choices: - -* ``switch_based`` -* ``mapping`` <-default -* ``bmc`` -* ``snmpwalk``" "**provision_os** ``string`` @@ -102,21 +90,6 @@ Required","* Domain name the user intends to configure on the cluster. Required","The nic/ethernet card that is connected to the public internet. **Default values**: ``eno2``" -"**admin_nic** - -``string`` - -Required","Admin NIC of Control Plane. This is the shared LOM NIC. - -**Default values**: ``eno1``" -"**admin_nic_subnet** - -``string`` - -Required","* The subnet within which all Admin IPs are assigned. -* The value of this variable cannot be changed after successfully running ``provision.yml``. - -**Default values**: ``10.5.0.0``" "**admin_static_start_range** ``string`` @@ -141,25 +114,6 @@ Required","* The mapping file consists of the MAC address and its respective IP * If static IPs are required, create a csv file in the format MAC,Hostname,IP. * A sample file is provided here: examples/pxe_mapping_file.csv. * If not provided, ensure that pxe_switch_ip is provided." -"**ib_nic_subnet** - -``string`` - -Optional","* If provided, Omnia will handle and assign static IPs to cluster node's IB network. -* Only the last 16 bits/2 octets of IPv4 are dynamic -* If provided, the DB entry will be in parallel with the pxe_subnet. -* Example: If ``admin_ip``: 10.5.0.50 and ``ib_nic_subnet``: 10.10.0.0, then ``ib_ip``: 10.10.0.50" -"**bmc_nic_subnet** - -``string`` - -Required","* If provided, Omnia will assign static IPs to IB NICs on the cluster nodes within the provided subnet. -* If ``network_interface_type``: ``lom``, mandatory for discovery_mechanism: mapping, switch_based and bmc. -* If ``network_interface_type``: ``dedicated``, optional for discovery_mechanism: mapping, switch_based. -* Note that since the last 16 bits/2 octets of IPv4 are dynamic, please ensure that the parameter value is set to x.x.0.0. -* When the PXE range and BMC subnet are provided, corresponding NICs will be assigned IPs with the same 3rd and 4th octets. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -" "**bmc_nic_start_range** ``string`` From b5ce33a3b537c5985afded24b48a450b4832eab5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 8 Mar 2024 12:45:01 +0530 Subject: [PATCH 163/309] Updating delete node information Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/Kubernetes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst index 244094d07..0bbfe54cc 100644 --- a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst +++ b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst @@ -22,4 +22,4 @@ To install Kubernetes, include the following line under ``softwares```: :: cd local_repo ansible-playbook local_repo.yml -To complete the installation of Kubernetes on the cluster, `click here. <../BuildingClusters/index.rst>`_ \ No newline at end of file +To complete the installation of Kubernetes on the cluster, `click here. <../BuildingClusters/index.html>`_ \ No newline at end of file From 674f4ee851b907d3f1e7006b491f53ddcc8813f1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 11:06:56 +0530 Subject: [PATCH 164/309] Updating local repository information Signed-off-by: goveac --- .../LocalRepo/RunningLocalRepo.rst | 6 +++ docs/source/Tables/local_repo_config.csv | 42 ++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index d1f9f0645..c9dac9fb3 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -136,6 +136,12 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: +.. csv-table:: Parameters for Local Repository Configuration + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + 3. Run the following commands: :: cd local_repo diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 559a347a0..7dc081d7e 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -56,7 +56,47 @@ Mandatory","* A list of registries from where images will be downloaded for Omni ``JSON List`` -Required","* A list of all the repo urls from where rpms will be downloaded for Omnia features. +Required","* A list of all the repo urls from where rpms will be downloaded for Omnia features on RHEL clusters. +* 'url' defines the baseurl for the repository. +* 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository +* This value is not validated by Omnia. Any errors can cause Omnia to fail. + +**Default value**: :: + + - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } + - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} + - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } + - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} +" +"**omnia_repo_url_rocky** + +``JSON List`` + +Required","* A list of all the repo urls from where rpms will be downloaded for Omnia features on Rocky clusters. +* 'url' defines the baseurl for the repository. +* 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository +* This value is not validated by Omnia. Any errors can cause Omnia to fail. + +**Default value**: :: + + - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } + - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} + - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } + - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} +" +"**omnia_repo_url_ubuntu** + +``JSON List`` + +Required","* A list of all the repo urls from where rpms will be downloaded for Omnia features on Ubuntu clusters. * 'url' defines the baseurl for the repository. * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository * This value is not validated by Omnia. Any errors can cause Omnia to fail. From 4be1226d399827ada74ea0e9e86c3a9e67e05eee Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 11:30:24 +0530 Subject: [PATCH 165/309] Updating local repository information Signed-off-by: goveac --- .../LocalRepo/RunningLocalRepo.rst | 117 +++++++++++++++++- 1 file changed, 112 insertions(+), 5 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index c9dac9fb3..bbc2d6bf8 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -136,11 +136,118 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: -.. csv-table:: Parameters for Local Repository Configuration - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :keepspace: - :class: longtable + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | Parameter | Details | + +===========================+========================================================================================================================================================================================================+ + | **repo_store_path** | * The intended file path for offline repository data. | + | | * Ensure the disk partition has enough space. | + | ``string`` | | + | | **Default value**: ``"/omnia_repo"`` | + | Required | | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | + | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | + | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | + | Optional | * 'url' defines the baseurl for the repository. | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | + | | * | + | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | + | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | + | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | + | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | + | Optional | * 'host' defines the URL and path to the registry. | + | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | + | | | + | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | + | Optional | | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | + | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | + | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | + | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | + | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | + | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | + | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | Mandatory | * **Default value**: :: | + | | | + | | - "registry.k8s.io" | + | | - "quay.io" | + | | - "docker.io" | + | | | + | | | + | | | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features on a RHEL cluster. | + | | * 'url' defines the baseurl for the repository. | + | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | Required | | + | | * **Default value**: :: | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | | + | | | + | | | + | | | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_rocky** | * A list of all the repo urls from where rpms will be downloaded for Omnia features on a Rocky cluster. | + | ``JSON List`` | | + | Required | * 'url' defines the baseurl for the repository. | + | | | + | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | | + | | | + | | | + | | * **Default value**: :: | + | | | + | | | + | | | + | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | + | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | + | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | + | | - { url: "http://dl.rockylinux.org/$contentdir/$releasever/PowerTools/$basearch/os/", gpgkey: ""} | + | | | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + | **omnia_repo_url_ubuntu** | * A list of all the repo urls from where rpms will be downloaded for Omnia features on an Ubuntu cluster. | + | ``JSON List`` | * 'url' defines the baseurl for the repository. | + | Required | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | + | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | + | | * **Default value**: :: | + | | - { url: "https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable", gpgkey: "https://download.docker.com/linux/ubuntu/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/apt/{{ rocm_version }} {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfsversion}}{{ansible_distribution_release}}non-free",gpgkey:"https://www.beegfs.io/release/beegfs_{{beegfsversion}}/gpg/GPG-KEY-beegfs"}| + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/ubuntu {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://ltb-project.org/debian/openldap25/bookworm bookworm main", gpgkey: "https://ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project" } | + | | - { url: "http://security.ubuntu.com/ubuntu focal-security main", gpgkey: ""} | + | | | + | | | + | | | + +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 3. Run the following commands: :: From 84e48db1f46669e50cd67ba5a31cdad52e72ef60 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 11:51:40 +0530 Subject: [PATCH 166/309] Updating local repository information Signed-off-by: goveac --- .../LocalRepo/RunningLocalRepo.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index bbc2d6bf8..3fbf99e22 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -238,12 +238,12 @@ For a list of repositories (and their types) configured for kubernetes, view the | Required | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | | | * **Default value**: :: | - | | - { url: "https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable", gpgkey: "https://download.docker.com/linux/ubuntu/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/apt/{{ rocm_version }} {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfsversion}}{{ansible_distribution_release}}non-free",gpgkey:"https://www.beegfs.io/release/beegfs_{{beegfsversion}}/gpg/GPG-KEY-beegfs"}| - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/ubuntu {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://ltb-project.org/debian/openldap25/bookworm bookworm main", gpgkey: "https://ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project" } | - | | - { url: "http://security.ubuntu.com/ubuntu focal-security main", gpgkey: ""} | + | | - { url: "https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable", gpgkey: "https://download.docker.com/linux/ubuntu/gpg" } | + | | - { url: "https://repo.radeon.com/rocm/apt/{{ rocm_version }} {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfsversion}}{{ansible_distribution_release}}non-free",gpgkey:"https://www.beegfs.io/release/beegfs_{{beegfsversion}}/gpg/GPG-KEY-beegfs"} | + | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/ubuntu {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | + | | - { url: "https://ltb-project.org/debian/openldap25/bookworm bookworm main", gpgkey: "https://ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project" } | + | | - { url: "http://security.ubuntu.com/ubuntu focal-security main", gpgkey: ""} | | | | | | | | | | From a9dbe482f34dc8e14f76e94181805a6edc90d5a0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 12:00:43 +0530 Subject: [PATCH 167/309] Updating local repository information Signed-off-by: goveac --- .../LocalRepo/RunningLocalRepo.rst | 117 +----------------- docs/source/Tables/local_repo_config.csv | 40 +++--- 2 files changed, 28 insertions(+), 129 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index 3fbf99e22..c9dac9fb3 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -136,118 +136,11 @@ For a list of repositories (and their types) configured for kubernetes, view the 2. Enter the required values in the ``input/local_repo_config.yml`` file: - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +===========================+========================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | - | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | - | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | - | Optional | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | * | - | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | - | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | - | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | - | Optional | * 'host' defines the URL and path to the registry. | - | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | - | | | - | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | * **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features on a RHEL cluster. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | * **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rocky** | * A list of all the repo urls from where rpms will be downloaded for Omnia features on a Rocky cluster. | - | ``JSON List`` | | - | Required | * 'url' defines the baseurl for the repository. | - | | | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | | | - | | | - | | * **Default value**: :: | - | | | - | | | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | - { url: "http://dl.rockylinux.org/$contentdir/$releasever/PowerTools/$basearch/os/", gpgkey: ""} | - | | | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_ubuntu** | * A list of all the repo urls from where rpms will be downloaded for Omnia features on an Ubuntu cluster. | - | ``JSON List`` | * 'url' defines the baseurl for the repository. | - | Required | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | * **Default value**: :: | - | | - { url: "https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable", gpgkey: "https://download.docker.com/linux/ubuntu/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/apt/{{ rocm_version }} {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfsversion}}{{ansible_distribution_release}}non-free",gpgkey:"https://www.beegfs.io/release/beegfs_{{beegfsversion}}/gpg/GPG-KEY-beegfs"} | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/ubuntu {{ ansible_distribution_release }} main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://ltb-project.org/debian/openldap25/bookworm bookworm main", gpgkey: "https://ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project" } | - | | - { url: "http://security.ubuntu.com/ubuntu focal-security main", gpgkey: ""} | - | | | - | | | - | | | - +---------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Parameters for Local Repository Configuration + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :keepspace: + :class: longtable 3. Run the following commands: :: diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 7dc081d7e..b52ffa636 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -83,14 +83,21 @@ Required","* A list of all the repo urls from where rpms will be downloaded for **Default value**: :: - - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } - - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } - - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } - - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} - - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} + - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } + - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } + - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} + - { url: ""http://dl.rockylinux.org/$contentdir/$releasever/PowerTools/$basearch/os/"", gpgkey: """"} + + + + + + + " "**omnia_repo_url_ubuntu** @@ -103,12 +110,11 @@ Required","* A list of all the repo urls from where rpms will be downloaded for **Default value**: :: - - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } - - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } - - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } - - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} - - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} -" + - { url: ""https://download.docker.com/linux/ubuntu {{ ansible_distribution_release }} stable"", gpgkey: ""https://download.docker.com/linux/ubuntu/gpg"" } + - { url: ""https://repo.radeon.com/rocm/apt/{{ rocm_version }} {{ ansible_distribution_release }} main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}} {{ ansible_distribution_release }} non-free"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/ubuntu {{ ansible_distribution_release }} main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://ltb-project.org/debian/openldap25/bookworm bookworm main"", gpgkey: ""https://ltb-project.org/documentation/_static/RPM-GPG-KEY-LTB-project"" } + - { url: ""http://security.ubuntu.com/ubuntu focal-security main"", gpgkey: """"} + + " From 4766c1a9a81afc4c253a8d303a4292137118ae5e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 12:09:54 +0530 Subject: [PATCH 168/309] Updating local repository information Signed-off-by: goveac --- docs/source/Tables/local_repo_config.csv | 66 ++++++++++++++++++++---- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index b52ffa636..c3ed99576 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -11,23 +11,49 @@ Required","* The intended file path for offline repository data. ``JSON List`` -Optional","* The code ready builder URL required for downloading packages to a RHEL control plane. -* This value is required on RHEL clusters. +Optional","* This variable accepts the repository urls of the user which contains the packages required for the cluster. + +* When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. + +* When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. + +* When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. + * 'url' defines the baseurl for the repository. -* 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. -* **Sample value**: - {url: ""http://crb.com/CRB/x86_64/os/"",gpgkey: ""http://crb.com/CRB/x86_64/os/RPM-GPG-KEY""}" + +* 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. + +* **Sample value**: ``- {url: ""http://crb.com/CRB/x86_64/os/"",gpgkey: ""http://crb.com/CRB/x86_64/os/RPM-GPG-KEY""}`` + + +" "**user_registry** ``JSON List`` -Optional","* Lists external user configured mirror registries. -* For partial configurations of offline repositories, values listed here will not be configured locally. Instead, subscriptions will be set up for the cluster to access the images/RPMs online. -* 'host' defines the host for registry along with port where registry will be accessible. -* 'cert_path' defines the absolution path location for certificates for respective registry. If 'cert_path' value is omitted, an insecure registry will be configured. +Optional","* This variable accepts the registry url along with port of the user which contains the images required for cluster. + +* When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. + +* When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. + +* When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. + +* 'host' defines the URL and path to the registry. + +* 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. + * **Sample value**: :: - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } - { host: registryhostname.registry.test, cert_path: """" } + + + + + + + " "**os_repo_url** @@ -37,7 +63,7 @@ Optional","* URL to a list of repositories to be configured for Ubuntu clusters. * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``always``, the given ``os_repo_url`` will be mirrored on the control plane. * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. -* **Sample value**: http://in.archive.ubuntu.com/ubuntu" +* **Sample value**: ``http://in.archive.ubuntu.com/ubuntu``" "**omnia_registry** ``string`` @@ -49,8 +75,20 @@ Mandatory","* A list of registries from where images will be downloaded for Omni **Default value**: :: - ""registry.k8s.io"" - - ""quay.io"" - - ""docker.io"" + - ""quay.io"" + - ""docker.io"" + - ""public.ecr.aws"" + - ""gcr.io"" + - ""nvcr.io"" + + + + + + + + + " "**omnia_repo_url_rhel** @@ -71,6 +109,12 @@ Required","* A list of all the repo urls from where rpms will be downloaded for - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} + + + + + + " "**omnia_repo_url_rocky** From fea2f3b1df336c4524055e847b438664ce97bf3b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 12:19:27 +0530 Subject: [PATCH 169/309] Updating local repository information Signed-off-by: goveac --- docs/source/Tables/local_repo_config.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index c3ed99576..0ecf2579e 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -45,8 +45,8 @@ Optional","* This variable accepts the registry url along with port of the user * **Sample value**: :: - - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } - - { host: registryhostname.registry.test, cert_path: """" } + - { host: 10.11.0.100:5001, cert_path: ""/home/ca.crt"" } + - { host: registryhostname.registry.test, cert_path: """" } From b1cc4c0fffedafa3aa1681f58afc51778407cea1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 12:32:06 +0530 Subject: [PATCH 170/309] Updating local repository information Signed-off-by: goveac --- docs/source/Tables/local_repo_config.csv | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 0ecf2579e..af566ce9a 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -102,19 +102,12 @@ Required","* A list of all the repo urls from where rpms will be downloaded for **Default value**: :: - { url: ""https://download.docker.com/linux/centos/$releasever/$basearch/stable"", gpgkey: ""https://download.docker.com/linux/centos/gpg"" } - - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } - - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } - - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } - - { url: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64"", gpgkey: ""https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub""} - - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } - - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} - - - - - - + - { url: ""https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://download.fedoraproject.org/pub/epel/8/Everything/$basearch"", gpgkey: ""https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8"" } + - { url: ""https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64"", gpgkey: ""https://repo.radeon.com/rocm/rocm.gpg.key"" } + - { url: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8"", gpgkey: ""https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs"" } + - { url: ""https://yum.repos.intel.com/oneapi"", gpgkey: ""https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB"" } + - { url: ""https://ltb-project.org/rpm/openldap25/$releasever/$basearch"", gpgkey: """"} " "**omnia_repo_url_rocky** From e8b1beb830a5860639f632a199229e1d76564177 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 13:24:16 +0530 Subject: [PATCH 171/309] Updating BMC information Signed-off-by: goveac --- .../DiscoveryMechanisms/bmc.rst | 46 +++++++++++++++++-- .../DiscoveryMechanisms/switch-based.rst | 2 +- 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 205d4cad5..9ae93a1a4 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -1,4 +1,4 @@ -bmc +BMC --- For automatic provisioning of servers and discovery, the BMC method can be used. @@ -14,6 +14,8 @@ For automatic provisioning of servers and discovery, the BMC method can be used. * Target servers should be configured to boot in PXE mode with the appropriate NIC as the first boot device. +* If the ``discovery_ranges`` provided are outside the ``bmc_subnet``, ensure the target nodes can reach the control plane. + * IPMI over LAN needs to be enabled for the BMC. :: racadm set iDRAC.IPMILan.Enable 1 @@ -37,7 +39,7 @@ For automatic provisioning of servers and discovery, the BMC method can be used. * For example: If the provided ``bmc_subnet`` is ``10.3.0.0`` and there are two iDRACs in DHCP mode, the IPs assigned will be ``10.3.251.1`` and ``10.3.251.2``. -The following parameters need to be populated in ``input/provision_config.yml`` to discover target nodes using BMC. +The following parameters need to be populated in ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` to discover target nodes using BMC. .. caution:: * Do not remove or comment any lines in the ``input/provision_config.yml`` file. @@ -50,9 +52,13 @@ The following parameters need to be populated in ``input/provision_config.yml`` .. [1] Boolean parameters do not need to be passed with double or single quotes. +.. csv-table:: Credentials for BMC configuration + :file: ../../../Tables/Provision_creds.csv + :header-rows: 1 + .. note:: - The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: + The ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` files are encrypted on the first run of the provision tool: To view the encrypted parameters: :: @@ -68,6 +74,40 @@ The following parameters need to be populated in ``input/provision_config.yml`` .. caution:: The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. +The following parameters need to be populated in ``input/software_config.json`` to discover target nodes using BMC. + +.. csv-table:: Parameters + :file: ../../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + +The ``input/network_spec.yml`` file needs to be populated. A sample is provided below: :: + + --- + Networks: + - admin_network: + nic_name: "eno1" + netmask_bits: "16" + static_range: "10.5.0.1-10.5.0.200" + dynamic_range: "10.5.1.1-10.5.1.200" + network_gateway: "" + DNS: "" + MTU: "1500" + + - bmc_network: + nic_name: "" + netmask_bits: "" + static_range: "" + dynamic_range: "" + discover_ranges: "" + network_gateway: "" + MTU: "1500" + +* Ensure that the netmask bits for the BMC network and the admin network are the same. +* The static and dynamic ranges for the BMC network accepts multiple comma-separated ranges. +* The network gateways on both admin and BMC networks are optional. + + To continue to the next steps: * `Provisioning the cluster <../installprovisiontool.html>`_ \ No newline at end of file diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index 489ac7ded..b234916e3 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -26,7 +26,7 @@ switch_based -* IPMI over LAN needs to be enabled for the BMC. :: +* IPMI over LAN needs to be enabled for the control plane. :: racadm set iDRAC.IPMILan.Enable 1 racadm get iDRAC.IPMILan From 84082e89f156959b20db6c5f5ba34eaba7277d7d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 13:31:29 +0530 Subject: [PATCH 172/309] Updating BMC information Signed-off-by: goveac --- docs/source/Tables/Provision_creds.csv | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/docs/source/Tables/Provision_creds.csv b/docs/source/Tables/Provision_creds.csv index 5fcc2d566..5d84741b0 100644 --- a/docs/source/Tables/Provision_creds.csv +++ b/docs/source/Tables/Provision_creds.csv @@ -39,14 +39,3 @@ Optional","* Non-admin SNMPv3 credentials of the PXE switch. Optional","* Non-admin SNMPv3 credentials of the PXE switch. * If multiple switches are provided, ensure the credentials are same across switches. * Password must not contain -,\, ',""" -, -, -, -, -, -, -, -, -, -, -, From 95412b7de9fb38f2222d0b973af839cc1f6232ba Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 12 Mar 2024 17:16:13 +0530 Subject: [PATCH 173/309] Updating local repo information Signed-off-by: goveac --- docs/source/Tables/software_config.csv | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index a0fea4658..1e0293ebc 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -32,5 +32,6 @@ Required","* The type of offline configuration user needs. Required","* A JSON list of required software and (optionally) the software revision. * This value of version is required for OFED and CUDA. - -.. note:: The accepted names for software is taken from " +* A minimum of one software should be provided in the list for ``local_repo.yml`` to execute correctly. +.. note:: The accepted names for software is taken from ``input/config///``. input/config/// + " From 0396abf4f4eb793887f082b7e26be4f82ef88401 Mon Sep 17 00:00:00 2001 From: sbasu96 Date: Thu, 14 Mar 2024 10:13:52 +0530 Subject: [PATCH 174/309] Disabling SELinux removed from best practices Signed-off-by: Basu --- docs/source/bestpractices.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/bestpractices.rst b/docs/source/bestpractices.rst index 3c91cfb60..8ee3dd05c 100644 --- a/docs/source/bestpractices.rst +++ b/docs/source/bestpractices.rst @@ -3,7 +3,6 @@ Best Practices * Ensure that PowerCap policy is disabled and the BIOS system profile is set to 'Performance' on the Control Plane. * Ensure that there is at least 50% (~50GB) free space on the Control Plane root partition before running Omnia. To maintain the free space required, place any ISO files used in the ``/home`` directory. -* Disable SElinux on the Control Plane. * Use a `PXE mapping file `_ even when using DHCP configuration to ensure that IP assignments remain persistent across Control Plane reboots. * Avoid rebooting the Control Plane as much as possible to ensure that all network configuration does not get disturbed. * Review the prerequisites before running Omnia Scripts. From ac73552d10f482019b65ac2d8e799a16148f8d4b Mon Sep 17 00:00:00 2001 From: sbasu96 Date: Thu, 14 Mar 2024 10:58:15 +0530 Subject: [PATCH 175/309] Updating copyright Signed-off-by: Basu --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c67032aa0..7e573b44b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -8,7 +8,7 @@ project = 'Omnia' -copyright = '2023, Dell Technologies' +copyright = '2024, Dell Technologies' author = 'dell/omnia' release = '1.5' rst_epilog = "If you have any feedback about Omnia documentation, please reach out at `omnia.readme@dell.com `_." From ed8345acde03ad8e1f5b85a890fea3aa2b0463cb Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 14 Mar 2024 14:14:10 +0530 Subject: [PATCH 176/309] Updating vLLM Signed-off-by: goveac --- docs/source/Roles/Platform/SetupvLLM.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index dd8f66fc5..d64bc257f 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -1,6 +1,7 @@ Setup vLLM ----------- -vLLM 0.2.4 onwards supports model inferencing and serving on AMD GPUs with ROCm. At the moment AWQ quantization is not supported in ROCm, but SqueezeLLM quantization has been ported. Data types currently supported in ROCm are FP16 and BF16. + +vLLM is a fast and easy-to-use library for LLM inference and serving. It is seamlessly integrated with with popular HuggingFace models. It is also compatible with OpenAI API servers and GPUs (Both NVIDIA and AMD) vLLM 0.2.4 and above supports model inferencing and serving on AMD GPUs with ROCm. At the moment AWQ quantization is not supported in ROCm, but SqueezeLLM quantization has been ported. Data types currently supported in ROCm are FP16 and BF16. For NVidia, vLLM is a Python library that also contains pre-compiled C++ and CUDA (12.1) binaries. From 10d670c4bb1a9ce6f3937527691fdb70223486d5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 14 Mar 2024 14:18:24 +0530 Subject: [PATCH 177/309] Updating vLLM Signed-off-by: goveac --- docs/source/Roles/Platform/SetupvLLM.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index d64bc257f..409ed4486 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -1,7 +1,7 @@ Setup vLLM ----------- -vLLM is a fast and easy-to-use library for LLM inference and serving. It is seamlessly integrated with with popular HuggingFace models. It is also compatible with OpenAI API servers and GPUs (Both NVIDIA and AMD) vLLM 0.2.4 and above supports model inferencing and serving on AMD GPUs with ROCm. At the moment AWQ quantization is not supported in ROCm, but SqueezeLLM quantization has been ported. Data types currently supported in ROCm are FP16 and BF16. +vLLM is a fast and easy-to-use library for LLM inference and serving. It is seamlessly integrated with with popular HuggingFace models. It is also compatible with OpenAI API servers and GPUs (Both NVIDIA and AMD). vLLM 0.2.4 and above supports model inferencing and serving on AMD GPUs with ROCm. At the moment AWQ quantization is not supported in ROCm, but SqueezeLLM quantization has been ported. Data types currently supported in ROCm are FP16 and BF16. For NVidia, vLLM is a Python library that also contains pre-compiled C++ and CUDA (12.1) binaries. From 8404372ce35d89508a4e3893c270e056b97cdefd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 09:28:51 +0530 Subject: [PATCH 178/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/index.rst | 14 -- .../InstallingProvisionTool/index.rst | 1 + .../installprovisiontool.rst | 2 +- .../provisionparams.rst | 200 ++---------------- .../provisionprereqs.rst | 2 +- .../PostProvisionScript.rst | 2 + .../InstallationGuides/addinganewnode.rst | 10 - docs/source/InstallationGuides/deletenode.rst | 68 ++++++ docs/source/InstallationGuides/index.rst | 1 + .../reprovisioningthecluster.rst | 2 +- .../Overview/NetworkTopologies/Hybrid.rst | 2 +- .../source/Overview/NetworkTopologies/lom.rst | 1 - docs/source/Tables/Provision_config.csv | 99 +++++++++ docs/source/Tables/bmc.csv | 154 +------------- 14 files changed, 197 insertions(+), 361 deletions(-) create mode 100644 docs/source/InstallationGuides/deletenode.rst create mode 100644 docs/source/Tables/Provision_config.csv diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index 6df8e2d9b..ad4d74754 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -75,18 +75,4 @@ Omnia can also discover nodes via their iDRAC using IPMI. For more information regarding BMC, `click here `_ -**snmpwalk** - -Omnia can query known switches (by IP and community string) for information on target node MAC IDs. - -**Pros** - - The method can be applied to large clusters. - - User intervention is minimal. -**Cons** - - Switches should be SNMP enabled. - - Servers require a manual PXE boot if iDRAC IPs are not configured. - - PXE NIC ranges should contain IPs that are double the iDRACs present (as NIC and iDRAC MACs may need to be mapped). - - LOM architecture is not supported (including cloud enclosures: C6420, C6520, C6620). - -For more information regarding snmpwalk, `click here `_ diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index 656048c5f..7d362fb6a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -17,6 +17,7 @@ This playbook achieves the following tasks: provisionprereqs DiscoveryMechanisms/index + provisionparams installprovisiontool ViewingDB provisionservers diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 4581fdf89..e19c8c618 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -115,7 +115,7 @@ After successfully running ``provision.yml``, go to `Building Clusters <../Build * While the ``admin_nic`` on cluster nodes is configured by Omnia to be static, the public NIC IP address should be configured by user. - * If the target nodes were discovered using switch-based, mapping or snmpwalk mechanisms, manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_. + * If the target nodes were discovered using switch-based or mapping mechanisms, manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_. * If the cluster does not have access to the internet, AppStream will not function. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index e2c550435..f4909ffdf 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -1,191 +1,25 @@ Input parameters for the provision tool ------------------------------------- +----------------------------------------- -Fill in all provision-specific parameters in ``input/provision_config.yml`` +Fill in all required parameters in ``input/provision_config.yml``, ``provision_config_credentials.yml``, ``input/software_config.json``.` .. caution:: Do not remove or comment any lines in the ``input/provision_config.yml`` file. -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Parameter | Details | -+==================================+===========================================================================================================================================================================================================================================================================================================================+ -| network_interface_type | The network type used on the Omnia cluster. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``lom`` <- default | -| | * ``dedicated`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| discovery_mechanism | The mechanism through which Omnia will discover nodes for provisioning. For more information on how the mechanisms work, go to `DiscoveryMechanisms `_. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``switch_based`` <-default | -| | * ``mapping`` | -| | * ``bmc`` | -| | * ``snmpwalk`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| provision_os | The operating system to be provisioned on target nodes in the cluster. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``rhel`` <-default | -| | * ``rocky`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| provision_os_version | OS version of provision_os to be installed. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``8.0`` | -| | * ``8.1`` | -| | * ``8.2`` | -| | * ``8.3`` | -| | * ``8.4`` | -| | * ``8.5`` | -| | * ``8.6`` <- default | -| | * ``8.7`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| iso_file_path | Path where user has placed the iso image that needs to be provisioned on target nodes. Accepted files are Rocky8-DVD or RHEL-8.x-DVD (full OS). iso_file_path should contain the provision_os and provision_os_version values in the filename. | -| ``string`` | | -| Required | **Default values**: ``"/home/RHEL-8.6.0-20220420.3-x86_64-dvd1.iso"`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| timezone | Timezone to be used during OS provisioning. Available timezones are provided `here <../../Appendix.html>`_. | -| ``string`` | | -| Required | Choices: | -| | | -| | * ``GMT`` <- default | -| | * ``EST`` | -| | * ``CET`` | -| | * ``MST`` | -| | * ``CST6CDT`` | -| | * ``PST8PDT`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| language | Language to be used during OS provisioning. | -| ``string`` | | -| Required | **Default values**: ``en-US`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| default_lease_time | Default lease time for IPs assigned by DHCP. Range: 21600-86400 | -| ``integer`` | | -| Required | **Default values**: ``86400`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| provision_password | * Password set for the root account of target nodes during provisioning. | -| ``string`` | * Length >= 8 characters | -| Required | * Password must not contain -,\, '," | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| postgresdb_password | * Password set for the postgresDB on target nodes during provisioning. | -| ``string`` | * Length >= 8 characters | -| Required | * Password must not contain -,\, '," | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| node_name | * Prefix for target node names, if dynamically allocated. | -| ``string`` | * Hostname = node_name + '0000x' + domain_name | -| Required | * Hostname <= 65 characters | -| | * Example: servernode00001.Omnia.test , where node_name =servernode, domain_name =Omnia.test , 00001 used by Omnia. | -| | | -| | **Default values**: ``node`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| domain_name | * Domain name the user intends to configure on the cluster. | -| ``string`` | * Hostname = node_name + '0000x' + domain_name | -| Required | * Hostname <= 65 characters | -| | * Please provide a valid domain name according to the domain name standards. | -| | * Example: servernode00001.Omnia.test , where node_name=servernode, domain_name=Omnia.test , 00001 used by Omnia. | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| public_nic | The NIC/ethernet card that is connected to the public internet. | -| ``string`` | | -| Required | **Default values**: ``eno2`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| admin_nic | Admin NIC of Control Plane. This is the shared LOM NIC. | -| ``string`` | | -| Required | **Default values**: ``eno1`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| admin_nic_subnet | The subnet within which all Admin IPs are assigned. | -| ``string`` | | -| Required | **Default values**: ``10.5.0.0`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| pxe_mapping_file_path | * The mapping file consists of the MAC address and its respective IP address and hostname. | -| ``string`` | * If static IPs are required, create a csv file in the format MAC,Hostname,IP. | -| Optional | * A sample file is provided here: examples/pxe_mapping_file.csv. | -| | * If not provided, ensure that pxe_switch_ip is provided. | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| switch_based_details | * JSON list of switches to query for target nodes. | -| ``JSON List`` | | -| Required: switch_based | * Example: :: | -| | | -| | - { ip: 172.96.28.12, ports: '1-48,49:3,50' } | -| | | -| | * Example with 2 switches: :: | -| | | -| | - { ip: 172.96.28.12, ports: '1-48,49:3,50' } | -| | | -| | - { ip: 172.96.28.14, ports: '1,2,3,5' } | -| | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| switch_snmp3_username | The non-admin SNMPv3 username for the switch. | -| ``string`` | | -| Required: switch_based | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| switch_snmp3_password | The non-admin SNMPv3 password for the switch. | -| ``string`` | | -| Required: switch_based | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ip_start_range | * The IP start range for all the NICs within the subnets mentioned above.(Admin, BMC, IB). | -| ``string`` | * Example: For the range x.y.0.1 to x.y.0.100 with admin_nic_subnet = 10.5.0.0, target nodes will be assigned admin IPs between 10.5.0.1 and 10.5.0.100. | -| Required | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ip_end_range | * The IP end range for all the NICs within the subnets mentioned above.(Admin, BMC, IB). | -| ``string`` | * Example: For the range x.y.0.1 to x.y.0.100 with admin_nic_subnet = 10.5.0.0, target nodes will be assigned admin IPs between 10.5.0.1 and 10.5.0.100. | -| Required | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ib_nic_subnet | * If provided, Omnia will handle and assign static IPs to compute node's IB network. | -| ``string`` | * Only the last 16 bits/2 octets of IPv4 are dynamic | -| Optional | * If provided, the DB entry will be in parallel with the pxe_subnet. | -| | * Example: If ``admin_ip``: 10.5.0.50 and ``ib_nic_subnet``: 10.10.0.0, then ``ib_ip``: 10.10.0.50 | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| bmc_nic_subnet | * If provided, Omnia will assign static IPs to IB NICs on the compute nodes within the provided subnet. | -| ``string`` | * Note that since the last 16 bits/2 octets of IPv4 are dynamic, please ensure that the parameter value is set to x.x.0.0. | -| Optional | * When the PXE range and BMC subnet are provided, corresponding NICs will be assigned IPs with the same 3rd and 4th octets. | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| bmc_username | * The username for iDRAC. | -| ``string`` | * The username must not contain -,\, '," | -| Required | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| bmc_password | * The password for iDRAC. | -| ``string`` | * The password must not contain -,\, '," | -| Required | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| bmc_static_start_range | * The dhcp range for discovering the static IP assigned iDRACs within the given range. | -| ``string`` | * For the range 10.3.0.50 to 10.3.4.100 then, bmc_static_start_range: 10.3.0.50, bmc_static_end_range: 10.3.4.100 | -| Required | * To create a meaningful range of discovery, ensure that the last two octets of ``bmc_static_end_range`` are equal to or greater than the last two octets of the ``bmc_static_start_range``. That is, for the range a.b.c.d - a.b.e.f, e and f should be greater than or equal to c and d. | -| | * Ex: 172.20.0.50 - 172.20.1.101 is a valid range however, 172.20.0.101 - 172.20.1.50 is not. | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| bmc_static_end_range | * The dhcp range for discovering the static IP assigned iDRACs within the given range. | -| ``string`` | * For the range 10.3.0.50 to 10.3.4.100 then, bmc_static_start_range: 10.3.0.50, bmc_static_end_range: 10.3.4.100 | -| Required | * To create a meaningful range of discovery, ensure that the last two octets of ``bmc_static_end_range`` are equal to or greater than the last two octets of the ``bmc_static_start_range``. That is, for the range a.b.c.d - a.b.e.f, e and f should be greater than or equal to c and d. | -| | * Ex: 172.20.0.50 - 172.20.1.101 is a valid range however, 172.20.0.101 - 172.20.1.50 is not. | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| pxe_switch_ip | * PXE switch that will be connected to all iDRACs for provisioning | -| ``string`` | * Ensure that SNMP is enabled on the mentioned switch. | -| Required | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| pxe_switch_snmp_community_string | The SNMP community string used to access statistics, MAC addresses and IPs stored within a router or other device. | -| ``string`` | | -| Required | **Default values**: ``public`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| disk_partition | * User defined disk partition applied to remote servers. | -| ``JSON list`` | * The disk partition desired_capacity has to be provided in MB. | -| Optional | * Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. | -| | * Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. | -| | * Values are accepted in the form of JSON list such as: , - { mount_point: "/home", desired_capacity: "102400" } | -| | | -| | | -| | **Default values**: ``- { mount_point: "", desired_capacity: "" }`` | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| mlnx_ofed_path | Absolute path to a local copy of the .iso file containing Mellanox OFED packages. The image can be downloaded from https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/. Sample value: /root/MLNX_OFED_LINUX-5.8-1.1.2.1-rhel8.6-x86_64.iso | -| ``string`` | | -| Optional | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| cuda_toolkit_path | Absolute path to local copy of .rpm file containing CUDA packages. The cuda rpm can be downloaded from https://developer.nvidia.com/cuda-downloads. CUDA will be installed post provisioning without any user intervention. Eg: cuda_toolkit_path: "/root/cuda-repo-rhel8-12-0-local-12.0.0_525.60.13-1.x86_64.rpm" | -| ``string`` | | -| Optional | | -+----------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: provision_config.yml + :file: ../../Tables/Provision_config.csv + :header-rows: 1 + :keepspace: + +.. csv-table:: provision_config_credentials.yml + :file: ../../Tables/Provision_config.csv + :header-rows: 1 + :keepspace: + +.. csv-table:: software_config.json + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + .. note:: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 633b2e13a..8d842207f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -86,7 +86,7 @@ Note the compatibility between cluster OS and control plane OS below: In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcfg-`` using vi editor. -* When discovering nodes via snmpwalk or a mapping file, all target nodes should be set up in PXE mode before running the playbook. +* When discovering nodes via a mapping file, all target nodes should be set up in PXE mode before running the playbook. * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``provision.yml`` on RHEL target nodes. diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index 2b6654797..3a04f2987 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -3,6 +3,8 @@ Creating node inventory When ``provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in `/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: * ``compute_cpu_amd`` + + * ``compute_cpu_intel`` :: [compute_cpu_intel] diff --git a/docs/source/InstallationGuides/addinganewnode.rst b/docs/source/InstallationGuides/addinganewnode.rst index df4efe41b..ebd3a1ff7 100644 --- a/docs/source/InstallationGuides/addinganewnode.rst +++ b/docs/source/InstallationGuides/addinganewnode.rst @@ -48,16 +48,6 @@ A new node can be added using the following ways: * Manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_ -* When the discovery mechanism is ``snmpwalk``: - - * Run ``provision.yml`` after the switch as discovered the new node. :: - - cd provision - ansible-playbook provision.yml - - * Manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the Omnia nodeinfo table. `_ - - Alternatively, if a new node is to be added with no change in configuration, run the following commands: :: cd provision diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst new file mode 100644 index 000000000..33994b05b --- /dev/null +++ b/docs/source/InstallationGuides/deletenode.rst @@ -0,0 +1,68 @@ +Remove node from the cluster +---------------------------- +Use this playbook to remove nodes from the cluster and stop all clustering software on the target nodes. + +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. + +**Configurations performed by the playbook** + + * Remove node from Slurm and Kubernetes cluster. + * Update Slurm and Kubernetes config. + * Slurm and Kubernetes services are stopped (not uninstalled). OS startup service list will be updated to disable Slurm and Kubernetes. + +**To run the playbook** + +Run the playbook using the following commands: :: + + cd utils + ansible-playbook remove_node_config.yml -i inventory + + +Soft reset the cluster +----------------------- +Use this playbook to stop all Slurm and Kubernetes services. This action will destroy the cluster. + +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. + +**Configurations performed by the playbook** + + * The Slurm or Kubernetes cluster will be reset. + * The configuration on the kube_control_plane or the slurm_control_plane will be reset. + * Slurm and Kubernetes services are stopped (not uninstalled). + +**To run the playbook** + +Run the playbook using the following commands: :: + + cd utils + ansible-playbook reset_cluster_config.yml -i inventory + +Delete node from the cluster +----------------------------- +Use this playbook to remove nodes from all inventory files and tables. No changes are made to the Slurm or Kubernetes cluster. + +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. + +**Configurations performed by the playbook** + + * Nodes will be deleted from the Omnia DB and xCAT node object will be deleted. + * Telemetry services will be stopped. + +**To run the playbook** + +Run the playbook using the following commands: :: + + cd utils + ansible-playbook delete_node.yml -i inventory + + +.. note:: When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. Slurm partition is also needs to be updated with these changes. + + + + + + + + + diff --git a/docs/source/InstallationGuides/index.rst b/docs/source/InstallationGuides/index.rst index 1f86246f9..ad7c77814 100644 --- a/docs/source/InstallationGuides/index.rst +++ b/docs/source/InstallationGuides/index.rst @@ -49,6 +49,7 @@ Run the script ``prereq.sh`` to verify the system is ready for Omnia deployment. ConfiguringSwitches/index ConfiguringStorage/index Benchmarks/index + deletenode CleanUpScript diff --git a/docs/source/InstallationGuides/reprovisioningthecluster.rst b/docs/source/InstallationGuides/reprovisioningthecluster.rst index e3af26b75..22c2e4586 100644 --- a/docs/source/InstallationGuides/reprovisioningthecluster.rst +++ b/docs/source/InstallationGuides/reprovisioningthecluster.rst @@ -28,7 +28,7 @@ Where the inventory contains a list of host IPs (Sourced from the `nodeinfo tabl .. note:: * The host IPs passed in the inventory should be assigned by Omnia. They will not be changed during the re-provisioning. - * If the nodes were discovered via snmpwalk or mapping, users will be required to manually reboot target nodes. + * If the nodes were discovered via mapping, manually reboot target nodes. * Do not include groups like *manager*, *compute* and *login* in the passed inventory. **Setting up the cluster** diff --git a/docs/source/Overview/NetworkTopologies/Hybrid.rst b/docs/source/Overview/NetworkTopologies/Hybrid.rst index 814556a59..bb7569c4b 100644 --- a/docs/source/Overview/NetworkTopologies/Hybrid.rst +++ b/docs/source/Overview/NetworkTopologies/Hybrid.rst @@ -13,7 +13,7 @@ The first time the provision tool is run (to discover the dedicated BMC ports), .. caution:: * Leave the variables ``bmc_nic_subnet``, ``bmc_static_start_range`` and ``bmc_static_end_range`` blank in ``input/provision_config.yml``. Entering these variables will cause IP reassignment and can interfere with the availability of ports on your target servers. -* Do not use the following methods to discover nodes in a Hybrid setup: snmpwalk, switch-based. +* Do not use the switch_based methods to discover nodes in a Hybrid setup. Once all the dedicated NICs are discovered, re-run the provisioning tool (to discover the shared LOM ports) with the following variables in ``input/provision_config.yml``: diff --git a/docs/source/Overview/NetworkTopologies/lom.rst b/docs/source/Overview/NetworkTopologies/lom.rst index e7e078ae4..971df3777 100644 --- a/docs/source/Overview/NetworkTopologies/lom.rst +++ b/docs/source/Overview/NetworkTopologies/lom.rst @@ -6,7 +6,6 @@ A LOM port could be shared with the host operating system production traffic. Al .. image:: ../../images/omnia_network_LOM.png -.. caution:: Target nodes using LOM ports cannot be discovered via snmpwalk. **Recommended discovery mechanism** diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv new file mode 100644 index 000000000..d04453d10 --- /dev/null +++ b/docs/source/Tables/Provision_config.csv @@ -0,0 +1,99 @@ +Parameter,Details +"**public_nic** + +``string`` + +Required","The nic/ethernet card that is connected to the public internet. + +**Default values**: ``eno2``" +"**iso_file_path** + +``string`` + +Required","Path where user has placed the iso image that needs to be provisioned on target nodes. Accepted files are Rocky8-DVD or RHEL-8.x-DVD (full OS). iso_file_path should contain the provision_os and provision_os_version values in the filename. + +**Default values**: ``""/home/RHEL-8.6.0-20220420.3-x86_64-dvd1.iso""``" +"**node_name** + +``string`` + +Required","* Prefix for target node names, if dynamically allocated. +* Hostname = node_name + '0000x' + domain_name +* Hostname <= 65 characters +* Example: servernode00001.Omnia.test , where node_name =servernode, domain_name =Omnia.test , 00001 used by Omnia. + +**Default values**: ``node``" +"**domain_name** + +``string`` + +Required","* Domain name the user intends to configure on the cluster. +* Hostname = node_name + '0000x' + domain_name +* Hostname <= 65 characters +* Please provide a valid domain name according to the domain name standards. +* Example: servernode00001.Omnia.test , where node_name=servernode, domain_name=Omnia.test , 00001 used by Omnia." +"**pxe_mapping_file_path** + +``string`` + +Required","* The mapping file consists of the MAC address and its respective IP address and hostname. +* If static IPs are required, create a csv file in the format MAC,Hostname,IP. +* A sample file is provided here: examples/pxe_mapping_file.csv. +* If not provided, ensure that pxe_switch_ip is provided." +"**switch_based_details** + +``JSON List`` + +Required","* JSON list of switches to query for target nodes. +* Split port ranges are not accepted here. (Ex: 10:5-10:10 will not be valid). +* Example: :: + +  - { ip: 172.96.28.12, ports: '1-48,49:3,50' } + +* Example with 2 switches: :: + +  - { ip: 172.96.28.12, ports: '1-48,49:3,50' } + +  - { ip: 172.96.28.14, ports: '1,2,3,5' } + +" +"**disk_partition** + +``JSON list`` + +Optional","* User defined disk partition applied to remote servers. +* The disk partition desired_capacity has to be provided in MB. +* Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. +* Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. +* Values are accepted in the form of JSON list such as: , - { mount_point: ""/home"", desired_capacity: ""102400"" } + + +**Default values**: ``- { mount_point: """", desired_capacity: """" }``" +"**timezone** + +``string`` + +Required","Timezone to be used during OS provisioning. Available timezones are provided `here <../../Appendix.html>`_. + +Choices: + +* ``GMT`` <- default +* ``EST`` +* ``CET`` +* ``MST`` +* ``CST6CDT`` +* ``PST8PDT``" +"**language** + +``string`` + +Required","Language to be used during OS provisioning. + +**Default values**: ``en-US``" +"**default_lease_time** + +``integer`` + +Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 + +**Default values**: ``86400``" diff --git a/docs/source/Tables/bmc.csv b/docs/source/Tables/bmc.csv index 36c6c069b..d787928e7 100644 --- a/docs/source/Tables/bmc.csv +++ b/docs/source/Tables/bmc.csv @@ -1,34 +1,4 @@ Parameter,Details -"**provision_os** - -``string`` - -Required","The operating system to be provisioned on target nodes in the cluster. - -Choices: - -* ``rhel`` <-default -* ``rocky`` -* ``ubuntu`` - -.. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** -" -"**provision_os_version** - -``string`` - -Required","OS version of provision_os to be installed. - -Choices: - -* ``8.0`` -* ``8.1`` -* ``8.2`` -* ``8.3`` -* ``8.4`` -* ``8.5`` -* ``8.6`` <- default -* ``8.7``" "**iso_file_path** ``string`` @@ -64,22 +34,6 @@ Required","Language to be used during OS provisioning. Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 **Default values**: ``86400``" -"**provision_password** - -``string`` - -Required","* Password set for the root account of target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',"" -* The first character of the string should be an alphabet." -"**postgresdb_password** - -``string`` - -Required","* Password set for the postgresDB on target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',"" -* The first character of the string should be an alphabet." "**node_name** ``string`` @@ -106,104 +60,23 @@ Required","* Domain name the user intends to configure on the cluster. Required","The nic/ethernet card that is connected to the public internet. **Default values**: ``eno2``" -"**bmc_nic_subnet** - -``string`` - -Required","* If provided, Omnia will assign static IPs to BMC NICs on the cluster nodes within the provided subnet. -* If ``network_interface_type``: ``lom``, mandatory for discovery_mechanism: mapping, switch_based and bmc. -* If ``network_interface_type``: ``dedicated``, optional for discovery_mechanism: mapping, snmpwalk. -* Note that since the last 16 bits/2 octets of IPv4 are dynamic, please ensure that the parameter value is set to x.x.0.0. -* When the PXE range and BMC subnet are provided, corresponding NICs will be assigned IPs with the same 3rd and 4th octets. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -" -"**bmc_username** - -``string`` - -Required","* The username for iDRAC. -* The username must not contain -,\, ',""" -"**bmc_password** - -``string`` - -Required","* The password for iDRAC. -* The password must not contain -,\, ',"" -* The first character of the string should be an alphabet." -"**bmc_static_start_range** - -``string`` - -Required","* The dhcp range for discovering the static IP assigned iDRACs within the given range. -* For the range 10.3.0.50 to 10.3.4.100 then, bmc_static_start_range: 10.3.0.50, bmc_static_end_range: 10.3.4.100 -* To create a meaningful range of discovery, ensure that the last two octets of ``bmc_static_end_range`` are equal to or greater than the last two octets of the ``bmc_static_start_range``. That is, for the range a.b.c.d - a.b.e.f, e and f should be greater than or equal to c and d. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -* Ex: 172.20.0.50 - 172.20.1.101 is a valid range however, 172.20.0.101 - 172.20.1.50 is not." -"**bmc_static_end_range** - -``string`` - -Required","* The dhcp range for discovering the static IP assigned iDRACs within the given range. -* For the range 10.3.0.50 to 10.3.4.100 then, bmc_static_start_range: 10.3.0.50, bmc_static_end_range: 10.3.4.100 -* To create a meaningful range of discovery, ensure that the last two octets of ``bmc_static_end_range`` are equal to or greater than the last two octets of the ``bmc_static_start_range``. That is, for the range a.b.c.d - a.b.e.f, e and f should be greater than or equal to c and d. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -* Ex: 172.20.0.50 - 172.20.1.101 is a valid range however, 172.20.0.101 - 172.20.1.50 is not." "**update_repos** ``boolean`` [1]_ -Required","* Indicates whether ``provision.yml`` will update offline RHEL repos. - +Required","* Indicates whether ``provision.yml`` will update offline RHEL repos. + * If ``update_repos``: false, the update repos for BaseOS and AppStream will not be updated to the latest versions available. * If ``update_repos``: true, the update repos for BaseOS and AppStream will be updated to the latest versions available. .. note:: By default, AppSteam and BaseOS repos will be configured from the given ISO file. - -Choices: - -``false`` <- Default - -``true`` " -" **rhel_repo_alphabetical_folders** - ``boolean`` [1]_ - - Required ","* Indicates whether the packages in local or subscription repos should be ordered in alphabetical directories. - - -* This variable should be filled if control plane OS is RHEL and local RHEL repository is available. - - - -Choices: - -``false`` <- Default - -``true`` " -"**rhel_repo_local_path** - -``JSON list`` - -Optional ","* The repo path and names of the software repository to be configured on the cluster nodes. - -* Provide the repo data file path, which ends with .repo extension in repo_url parameter. - -* Provide a **valid** url for BaseOS and AppStream repositories. Omnia does not validate the ``repo_url`` provided. Invalid entries will cause ``provision.yml`` to fail. - -* This variable should be filled if control plane OS is RHEL and subscription is not activated. - -* This variable should be filled if the control plane OS is Rocky and the ``provision_os`` is rhel. - - -Sample value: :: +Choices: - - { repo: ""AppStream"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-appstream.repo"", repo_name: ""RHEL-8-appstream-partners"" } - - - { repo: ""BaseOS"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-baseos.repo"", repo_name: ""RHEL-8-baseos-partners"" } - +``false`` <- Default - " +``true`` " "**disk_partition** ``JSON list`` @@ -216,20 +89,3 @@ Optional","* User defined disk partition applied to remote servers. **Default values**: ``- { mount_point: """", desired_capacity: """" }``" -"**mlnx_ofed_path** - -``string`` - -Optional",Absolute path to a local copy of the .iso file containing Mellanox OFED packages. The image can be downloaded from https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/. Sample value: /root/MLNX_OFED_LINUX-5.8-1.1.2.1-rhel8.6-x86_64.iso -"**cuda_toolkit_path** - -``string`` - -Optional","Absolute path to local copy of .rpm file containing CUDA packages. The cuda rpm can be downloaded from https://developer.nvidia.com/cuda-downloads. CUDA will be installed post provisioning without any user intervention. Eg: cuda_toolkit_path: ""/root/cuda-repo-rhel8-12-0-local-12.0.0_525.60.13-1.x86_64.rpm""" -"**apptainer_support** - -``boolean`` [1]_ - -Required","* Indicates whether apptainer will be installed on the cluster to enable execution of HPC benchmarks in a containeraized environment. -* If ``apptainer_support``: false, apptainer will not be installed on the cluster. -* If ``apptainer_support``: true, apptainer will be installed on the cluster." From 03068c5ed359f961561389212f3cbefa3611c82a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 09:37:25 +0530 Subject: [PATCH 179/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/provisionparams.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index f4909ffdf..38d922212 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -11,7 +11,7 @@ Fill in all required parameters in ``input/provision_config.yml``, ``provision_c :keepspace: .. csv-table:: provision_config_credentials.yml - :file: ../../Tables/Provision_config.csv + :file: ../../Tables/Provision_creds.csv :header-rows: 1 :keepspace: From 3fe69adf3d3107f106357685b3bfa5edd1b05fa6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 09:39:29 +0530 Subject: [PATCH 180/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/provisionparams.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 38d922212..6efe52348 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -1,7 +1,7 @@ Input parameters for the provision tool ----------------------------------------- -Fill in all required parameters in ``input/provision_config.yml``, ``provision_config_credentials.yml``, ``input/software_config.json``.` +Fill in all required parameters in ``input/provision_config.yml``, ``provision_config_credentials.yml``, ``input/software_config.json``. .. caution:: Do not remove or comment any lines in the ``input/provision_config.yml`` file. @@ -24,6 +24,7 @@ Fill in all required parameters in ``input/provision_config.yml``, ``provision_c .. note:: The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: + To view the encrypted parameters: :: ansible-vault view provision_config.yml --vault-password-file .provision_vault_key From 8b0aab6f59f3ed462e65ad111ac2635906cbdff3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 09:52:49 +0530 Subject: [PATCH 181/309] Updating documentation Signed-off-by: goveac --- .../provisionparams.rst | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 6efe52348..651929410 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -20,6 +20,30 @@ Fill in all required parameters in ``input/provision_config.yml``, ``provision_c :header-rows: 1 :keepspace: +.. [1] Boolean parameters do not need to be passed with double or single quotes. + + +Update the ``input/network_spec.yml`` file for all networks available for use by the control plane. A sample is provided below: :: + + --- + Networks: + - admin_network: + nic_name: "eno1" + netmask_bits: "16" + static_range: "10.5.0.1-10.5.0.200" + dynamic_range: "10.5.1.1-10.5.1.200" + network_gateway: "" + DNS: "" + MTU: "1500" + + - bmc_network: + nic_name: "" + netmask_bits: "" + static_range: "" + dynamic_range: "" + discover_ranges: "" + network_gateway: "" + MTU: "1500" .. note:: From a220d2b791245b228f7f4a4f78230cda443bf955 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 12:19:12 +0530 Subject: [PATCH 182/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/bmc.rst | 77 +------------------ .../DiscoveryMechanisms/index.rst | 2 +- .../DiscoveryMechanisms/mappingfile.rst | 35 +-------- .../DiscoveryMechanisms/switch-based.rst | 33 +------- .../InstallingProvisionTool/index.rst | 1 - .../provisionparams.rst | 4 +- .../InstallationGuides/addinganewnode.rst | 75 +++++++++++++----- docs/source/InstallationGuides/deletenode.rst | 10 ++- .../reprovisioningthecluster.rst | 22 ++---- .../Roles/Platform/InstallJupyterhub.rst | 2 +- docs/source/Roles/Platform/Pytorch.rst | 2 +- docs/source/Roles/Platform/TensorFlow.rst | 2 +- docs/source/Roles/Platform/kserve.rst | 2 +- docs/source/Tables/Provision_config.csv | 4 +- docs/source/Tables/Provision_creds.csv | 4 +- 15 files changed, 87 insertions(+), 188 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 9ae93a1a4..32ddf362f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -24,85 +24,12 @@ For automatic provisioning of servers and discovery, the BMC method can be used. - IP ranges (``bmc_static_start_range``, ``bmc_static_start_range``) provided to Omnia for BMC discovery should be within the same subnet. .. caution:: - * To create a meaningful range of discovery, ensure that the last two octets of ``bmc_static_end_range`` are equal to or greater than the last two octets of the ``bmc_static_start_range``. That is, for the range a.b.c.d - a.b.e.f, e and f should be greater than or equal to c and d. *Ex: 172.20.0.50 - 172.20.1.101 is a valid range however, 172.20.0.101 - 172.20.1.50 is not.* * If you are re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (``BIOS Settings`` > ``Boot Settings`` > ``UEFI Boot Settings``) on all target nodes. - * ``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet`` should have the same subnet mask (Omnia only supports /16 subnet masks currently). -- All iDRACs should be reachable from the ``admin_nic``. +- All target servers should be reachable from the ``admin_network`` specified in ``input/network_spec.yml``. -.. note:: - *When iDRACs are in DHCP mode** - * The IP range *x.y.246.1* - *x.y.255.253* (where x and y are provided by the first two octets of ``bmc_nic_subnet``) are reserved by Omnia. - * *x.y.246.1* - *x.y.250.253* will be the range of IPs reserved for dynamic assignment by Omnia. - * During provisioning, Omnia updates servers to static mode and assigns IPs from *x.y.251.1* - *x.y.255.253*. - * Users can see the IPs (that have been assigned from *x.y.251.1* - *x.y.255.253*) in the DB after provisioning the servers. - * For example: - If the provided ``bmc_subnet`` is ``10.3.0.0`` and there are two iDRACs in DHCP mode, the IPs assigned will be ``10.3.251.1`` and ``10.3.251.2``. - -The following parameters need to be populated in ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` to discover target nodes using BMC. - -.. caution:: - * Do not remove or comment any lines in the ``input/provision_config.yml`` file. - * **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** - -.. csv-table:: Parameters - :file: ../../../Tables/bmc.csv - :header-rows: 1 - :keepspace: - -.. [1] Boolean parameters do not need to be passed with double or single quotes. - -.. csv-table:: Credentials for BMC configuration - :file: ../../../Tables/Provision_creds.csv - :header-rows: 1 - -.. note:: - - The ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` files are encrypted on the first run of the provision tool: - - To view the encrypted parameters: :: - - ansible-vault view provision_config.yml --vault-password-file .provision_vault_key - - To edit the encrypted parameters: :: - - ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key - - - - -.. caution:: The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. - - -The following parameters need to be populated in ``input/software_config.json`` to discover target nodes using BMC. - -.. csv-table:: Parameters - :file: ../../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - -The ``input/network_spec.yml`` file needs to be populated. A sample is provided below: :: - - --- - Networks: - - admin_network: - nic_name: "eno1" - netmask_bits: "16" - static_range: "10.5.0.1-10.5.0.200" - dynamic_range: "10.5.1.1-10.5.1.200" - network_gateway: "" - DNS: "" - MTU: "1500" - - - bmc_network: - nic_name: "" - netmask_bits: "" - static_range: "" - dynamic_range: "" - discover_ranges: "" - network_gateway: "" - MTU: "1500" +*When entering details in ``input/network_spec.yml``* * Ensure that the netmask bits for the BMC network and the admin network are the same. * The static and dynamic ranges for the BMC network accepts multiple comma-separated ranges. * The network gateways on both admin and BMC networks are optional. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index ad4d74754..d1939fdb8 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -27,7 +27,7 @@ Omnia can query known switches (by SNMPv3 username/password) for information on **Cons** - Users need to enable IPMI on target servers. -- Servers require a manual PXE boot after the first run of the provision tool +- Servers require a manual PXE boot after the first run of the provision tool. For more information regarding switch-based discovery, `click here `_ diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index d1b351a44..01cc1b88b 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -1,6 +1,6 @@ mapping -------------- -Manually collect PXE NIC information for target servers and define them to Omnia using a mapping file using the below format: +Manually collect PXE NIC information for target servers and define them to Omnia (using the ``pxe_mapping_file`` variable in ``input/provision_config.yml```) using a mapping file using the below format: **pxe_mapping_file.csv** @@ -21,39 +21,6 @@ Manually collect PXE NIC information for target servers and define them to Omnia * Target servers should be configured to boot in PXE mode with the appropriate NIC as the first boot device. -.. caution:: - * Do not remove or comment any lines in the ``input/provision_config.yml`` file. - * **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** - * ``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet`` should have the same subnet mask (Omnia only supports /16 subnet masks currently). - -The following parameters need to be populated in ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` to discover target nodes using a mapping file. - -.. csv-table:: Parameters for Mapping file configuration - :file: ../../../Tables/mapping.csv - :header-rows: 1 - -.. [1] Boolean parameters do not need to be passed with double or single quotes. - -.. csv-table:: Credentials for Mapping file configuration - :file: ../../../Tables/Provision_creds.csv - :header-rows: 1 - -.. caution:: The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. - -.. note:: - - The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: - - To view the encrypted parameters: :: - - ansible-vault view provision_config.yml --vault-password-file .provision_vault_key - - To edit the encrypted parameters: :: - - ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key - - - To continue to the next steps: * `Provisioning the cluster <../installprovisiontool.html>`_ \ No newline at end of file diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index b234916e3..c168f85f4 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -38,46 +38,21 @@ switch_based * Set the IP address of the control plane with a /16 subnet mask. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. image:: ../../../images/ControlPlaneNic.png +* Ensure that the variable ``switch_based_details`` in ``input/provision_config.yml`` is provided. .. caution:: * Do not use daisy chain ports or the port used to connect to the control plane in ``switch_based_details`` in ``input/provision_config.yml``. This can cause IP conflicts on servers attached to potential target ports. * Omnia does not validate SNMP switch credentials, if the provision tool is run with incorrect credentials, use the clean-up script and re-run the provision tool with the correct credentials. - * If you are re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (``BIOS Settings`` > ``Boot Settings`` > ``UEFI Boot Settings``) on all target nodes. - * ``admin_nic_subnet``, ``ib_nic_subnet`` and ``bmc_nic_subnet`` should have the same subnet mask (Omnia only supports /16 subnet masks currently). + * If you are re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (**BIOS Settings > Boot Settings > UEFI Boot Settings**) on all target nodes. .. note:: - * The IP range *x.y.246.1* - *x.y.255.253* (where x and y are provided by the first two octets of ``bmc_nic_subnet``) are reserved by Omnia. - * If any of the target nodes have a pre-provisioned IP, do not use a ``bmc_subnet`` and/or ``ip_start_range``/``ip_end_range`` that encapsulates the pre-provisioned IP. - - For example, if there are target nodes hosted at 10.3.0.11 and 10.3.0.12, ``bmc_subnet`` = 10.3.0.0 with ``ip_start_range`` = 10.3.0.1/ ``ip_end_range`` = 10.3.0.255 will cause a conflict with newly assigned servers however, ``bmc_subnet`` = 10.3.0.0 with ``ip_start_range`` = 10.3.0.100/ ``ip_end_range`` = 10.3.0.150 would be accepted. Alternatively, a different subnet would be acceptable,ie ``bmc_subnet`` = 10.13.0.0. -The following parameters need to be populated in ``input/provision_config.yml`` to discover target nodes using a mapping file. + * If any of the target nodes have a pre-provisioned IP, ensure that these IPs are not part of the ``bmc_subnet`` specified in ``input/network_spec.yml``. + * -.. caution:: - * Do not remove or comment any lines in the ``input/provision_config.yml`` file. - * **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** - -.. csv-table:: Parameters - :file: ../../../Tables/switch-based.csv - :header-rows: 1 - -.. [1] Boolean parameters do not need to be passed with double or single quotes. - -.. note:: - - The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: - - To view the encrypted parameters: :: - - ansible-vault view provision_config.yml --vault-password-file .provision_vault_key - - To edit the encrypted parameters: :: - - ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. - - To continue to the next steps: * `Provisioning the cluster <../installprovisiontool.html>`_ \ No newline at end of file diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index 7d362fb6a..0799a243d 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -20,5 +20,4 @@ This playbook achieves the following tasks: provisionparams installprovisiontool ViewingDB - provisionservers diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 651929410..f3f089f05 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -47,7 +47,7 @@ Update the ``input/network_spec.yml`` file for all networks available for use by .. note:: - The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: + * The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: To view the encrypted parameters: :: @@ -57,6 +57,8 @@ Update the ``input/network_spec.yml`` file for all networks available for use by ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key + * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. + .. caution:: * The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. diff --git a/docs/source/InstallationGuides/addinganewnode.rst b/docs/source/InstallationGuides/addinganewnode.rst index ebd3a1ff7..4bbc497d4 100644 --- a/docs/source/InstallationGuides/addinganewnode.rst +++ b/docs/source/InstallationGuides/addinganewnode.rst @@ -1,21 +1,15 @@ Adding new nodes -+++++++++++++++++ +++++++++++++++++++ **Provisioning the new node** -While adding a new node to the cluster, users can modify the following: - - - The operating system - - CUDA - - OFED - A new node can be added using the following ways: -* When the discovery mechanism is ``mapping``: +* If ``pxe_mapping_file_path`` is provided in ``input/provision_config.yml```: * Update the existing mapping file by appending the new entry (without the disrupting the older entries) or provide a new mapping file by pointing ``pxe_mapping_file_path`` in ``provision_config.yml`` to the new location. - .. note:: When re-running ``provision.yml`` with a new mapping file, ensure that existing IPs from the current mapping file are not provided in the new mapping file. Any IP overlap between mapping files will result in PXE failure. This can only be resolved by running `the Clean Up script `_ followed by ``provision.yml``. + .. note:: When re-running ``discovery_provision.yml`` with a new mapping file, ensure that existing IPs from the current mapping file are not provided in the new mapping file. Any IP overlap between mapping files will result in PXE failure. This can only be resolved by running `the Clean Up script `_ followed by ``provision.yml``. * Run ``provision.yml``.:: @@ -43,7 +37,7 @@ A new node can be added using the following ways: * Run ``provision.yml``. :: - cd provision + ansible-playbook provision.yml * Manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_ @@ -51,37 +45,72 @@ A new node can be added using the following ways: Alternatively, if a new node is to be added with no change in configuration, run the following commands: :: cd provision - ansible-playbook discovery_provision.yml + ansible-playbook discovery_provision.yml -i inventory Verify that the node has been provisioned successfully by `checking the Omnia nodeinfo table. `_ -**Adding the new node to the cluster** +**Adding new compute nodes to the cluster** 1. Insert the new IPs in the existing inventory file following the below example. -*Existing inventory* +*Existing kubernetes inventory* :: - [manager] + [kube_control_plane] 10.5.0.101 - [compute] + [kube_node] + 10.5.0.102 + 10.5.0.103 + + [auth_server] + 10.5.0.101 + + + +*Updated kubernetes inventory with the new node information* + +:: + + [kube_control_plane] + 10.5.0.101 + + [kube_node] + 10.5.0.102 + 10.5.0.103 + 10.5.0.105 + 10.5.0.106 + + [auth_server] + 10.5.0.101 + +*Existing Slurm inventory* + +:: + + [slurm_control_node] + 10.5.0.101 + + [slurm_node] 10.5.0.102 10.5.0.103 [login] 10.5.0.104 + [auth_server] + 10.5.0.101 + -*Updated inventory with the new node information* +*Updated Slurm inventory with the new node information* :: - [manager] + [slurm_control_node] 10.5.0.101 - [compute] + [slurm_node] 10.5.0.102 10.5.0.103 10.5.0.105 @@ -90,11 +119,15 @@ Verify that the node has been provisioned successfully by `checking the Omnia no [login] 10.5.0.104 -In the above example, nodes 10.5.0.105 and 10.5.0.106 have been added to the cluster as a compute nodes. + [auth_server] + 10.5.0.101 + + +In the above examples, nodes 10.5.0.105 and 10.5.0.106 have been added to the cluster as compute nodes. .. note:: - * Do not change the kube_control_plane in the existing inventory. Simply add the new node information in the compute group. - * Only the ``scheduler_type`` in ``input/omnia_config.yml`` and the variables in ``input/storage_config.yml`` can be updated while re-running ``omnia.yml`` to add the new node. All other variables in the files ``input/omnia_config.yml`` and ``input/security_config.yml`` must be unedited. + * Do not change the kube_control_plane/slurm_control_node/auth_server in the existing inventory. Simply add the new node information in the kube_node/slurm_node group. + * When re-running ``omnia.yml`` to add a new node, ensure that the ``input/security_config.yml`` and ``input/omnia_config.yml`` are not edited between runs. 3. To install `security `_, `job scheduler `_ and storage tools (`NFS `_, `BeeGFS `_) on the node, run ``omnia.yml``: :: diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst index 33994b05b..d01d178ed 100644 --- a/docs/source/InstallationGuides/deletenode.rst +++ b/docs/source/InstallationGuides/deletenode.rst @@ -1,5 +1,6 @@ -Remove node from the cluster ----------------------------- +Remove Slurm/K8s configuration from a node +------------------------------------------- + Use this playbook to remove nodes from the cluster and stop all clustering software on the target nodes. .. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. @@ -37,8 +38,9 @@ Run the playbook using the following commands: :: cd utils ansible-playbook reset_cluster_config.yml -i inventory -Delete node from the cluster ------------------------------ +Delete provisioned node +------------------------ + Use this playbook to remove nodes from all inventory files and tables. No changes are made to the Slurm or Kubernetes cluster. .. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. diff --git a/docs/source/InstallationGuides/reprovisioningthecluster.rst b/docs/source/InstallationGuides/reprovisioningthecluster.rst index 22c2e4586..cea0797e2 100644 --- a/docs/source/InstallationGuides/reprovisioningthecluster.rst +++ b/docs/source/InstallationGuides/reprovisioningthecluster.rst @@ -1,20 +1,14 @@ Re-provisioning the cluster ++++++++++++++++++++++++++++ -In the event that an existing Omnia cluster needs a different OS version or a fresh installation, the cluster can be re-provisioned. While re-provisioning the cluster, users can modify the following: +**Pre-requisites** - - The operating system - - CUDA - - OFED + * Run the `delete node playbook. `_ for every target node. -Omnia can re-provision the cluster by running the following command: :: +In the event that an existing Omnia cluster needs a different OS version or a fresh installation, the cluster can be re-provisioned. - cd provision - ansible-playbook provision.yml -i inventory +If a re-deployment with no modifications are required :: -Alternatively, if a re-deployment with no modifcations are required :: - - cd provision ansible-playbook discovery_provision.yml -i inventory @@ -39,10 +33,10 @@ Where the inventory contains a list of host IPs (Sourced from the `nodeinfo tabl :: - [manager] + [kube_control_plane] 10.5.0.101 - [compute] + [kube_node] 10.5.0.102 10.5.0.103 @@ -53,10 +47,10 @@ Where the inventory contains a list of host IPs (Sourced from the `nodeinfo tabl :: - [manager] + [kube_control_plane] 10.5.0.102 - [compute] + [kube_node] 10.5.0.101 10.5.0.103 10.5.0.104 diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 0b438b65e..7f68b2019 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -1,4 +1,4 @@ -Using Jupyterhub +Setup Jupyterhub ----------------- Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jupyterhub is deployed, log into the UI to create your own notebook servers. For more information, `click here `_. diff --git a/docs/source/Roles/Platform/Pytorch.rst b/docs/source/Roles/Platform/Pytorch.rst index bba2b5b5e..5b1371b8b 100644 --- a/docs/source/Roles/Platform/Pytorch.rst +++ b/docs/source/Roles/Platform/Pytorch.rst @@ -1,4 +1,4 @@ -Set up PyTorch +Setup PyTorch --------------- PyTorch is a popular open-source deep learning framework, renowned for its dynamic computation graph that enhances flexibility and ease of use, making it a preferred choice for researchers and developers. With strong community support, PyTorch facilitates seamless experimentation and rapid prototyping in the field of machine learning. diff --git a/docs/source/Roles/Platform/TensorFlow.rst b/docs/source/Roles/Platform/TensorFlow.rst index e96bda59a..51fb71c56 100644 --- a/docs/source/Roles/Platform/TensorFlow.rst +++ b/docs/source/Roles/Platform/TensorFlow.rst @@ -1,4 +1,4 @@ -Set up TensorFlow +Setup TensorFlow ----------------- TensorFlow is a widely-used open-source deep learning framework, recognized for its static computation graph that optimizes performance and scalability, making it a favored choice for deploying machine learning models at scale in various industries. diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index 06fa80699..dfedd297d 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -1,4 +1,4 @@ -Set up Kserve +Setup Kserve -------------- Kserve is an open-source serving platform that simplifies the deployment, scaling, and management of machine learning models in production environments, ensuring efficient and reliable inference capabilities. For more information, `click here. `_ diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index d04453d10..b71c83022 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -36,7 +36,7 @@ Required","* Domain name the user intends to configure on the cluster. ``string`` -Required","* The mapping file consists of the MAC address and its respective IP address and hostname. +Required (Mapping discovery mechanism)","* The mapping file consists of the MAC address and its respective IP address and hostname. * If static IPs are required, create a csv file in the format MAC,Hostname,IP. * A sample file is provided here: examples/pxe_mapping_file.csv. * If not provided, ensure that pxe_switch_ip is provided." @@ -44,7 +44,7 @@ Required","* The mapping file consists of the MAC address and its respective IP ``JSON List`` -Required","* JSON list of switches to query for target nodes. +Required (Switch based discovery mechanism)","* JSON list of switches to query for target nodes. * Split port ranges are not accepted here. (Ex: 10:5-10:10 will not be valid). * Example: :: diff --git a/docs/source/Tables/Provision_creds.csv b/docs/source/Tables/Provision_creds.csv index 5d84741b0..4e31ccdb4 100644 --- a/docs/source/Tables/Provision_creds.csv +++ b/docs/source/Tables/Provision_creds.csv @@ -29,13 +29,13 @@ Required","* The password set on target iDRACs. ``string`` -Optional","* Non-admin SNMPv3 credentials of the PXE switch. +Optional (Required for Switch based discovery mechanism)","* Non-admin SNMPv3 credentials of the PXE switch. * If multiple switches are provided, ensure the credentials are same across switches. * Username must not contain -,\, ',""" "**switch_snmp3_password** ``string`` -Optional","* Non-admin SNMPv3 credentials of the PXE switch. +Optional (Required for Switch based discovery mechanism)","* Non-admin SNMPv3 credentials of the PXE switch. * If multiple switches are provided, ensure the credentials are same across switches. * Password must not contain -,\, ',""" From 15d8ac13c0c1b527f694f6896e68349f00a2faf8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 12:49:24 +0530 Subject: [PATCH 183/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/index.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index d1939fdb8..dc7ea7da5 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -37,13 +37,12 @@ Manually collect PXE NIC information for target servers and manually define them **pxe_mapping_file.csv** -:: - - MAC,Hostname,IP - xx:yy:zz:aa:bb:cc,server,10.5.0.101 +:: - aa:bb:cc:dd:ee:ff,server2, 10.5.0.102 + SERVICE_TAG,HOSTNAME,ADMIN_MAC,ADMIN_IP,BMC_IP + 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 + V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 **Pros** From 7d4cdf9c76cacc29f0fde941f9bbc5a9b2538b6d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 14:32:47 +0530 Subject: [PATCH 184/309] Updating documentation Signed-off-by: goveac --- .../provisionparams.rst | 32 ++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index f3f089f05..00b8f08de 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -45,6 +45,32 @@ Update the ``input/network_spec.yml`` file for all networks available for use by network_gateway: "" MTU: "1500" + # - thor_network1: + + # netmask_bits: "20" + + # CIDR: "10.10.16.0" + + # network_gateway: "" + + # MTU: "1500" + + # VLAN: "" + + + + # - thor_network2: + + # netmask_bits: "20" + + # static_range: "10.10.1.1-10.10.15.254" + + # network_gateway: "" + + # MTU: "1500" + + # VLAN: "1" + .. note:: * The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: @@ -57,7 +83,11 @@ Update the ``input/network_spec.yml`` file for all networks available for use by ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key - * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. + * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. Also, the properties ``nic_name``, ``static_range``, and ``dynamic_range`` cannot be edited on subsequent runs of the provision tool. + * Netmask bits is mandatory and should be same for both the ``admin_network`` and ``bmc_network`` (ie between 1 and 32; 1 and 32 are acceptable values). + * Ensure that the CIDR is aligned with the ``netmask_bits`` provided. + * The ``discover_ranges`` property of the ``bmc_network`` can accept multiple comma-separated ranges. + * The ``VLAN`` property is optional but should be between 0 and 4095 (0 and 4095 are not acceptable values). .. caution:: From 4f23d6b124063b50c8c5a0664d4dcbff12c4b787 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 15:39:30 +0530 Subject: [PATCH 185/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/index.rst | 2 +- .../DiscoveryMechanisms/switch-based.rst | 1 - .../installprovisiontool.rst | 2 + .../provisionparams.rst | 12 --- .../provisionprereqs.rst | 7 +- .../InstallationGuides/addinganewnode.rst | 33 ++++---- docs/source/InstallationGuides/deletenode.rst | 75 +++++++++++++++---- .../reprovisioningthecluster.rst | 66 +++++++++++----- 8 files changed, 126 insertions(+), 72 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index dc7ea7da5..30bc1d16f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -1,7 +1,7 @@ Discovery Mechanisms ----------------------- -Typically, the choice of discovery mechanism depends on the `Network Topology <../../../Overview/NetworkTopologies/index.html>`_ in your setup. Depending on the value of ``discovery_mechanism`` in ``input/provision_config.yml``, potential target servers can be discovered one of four ways: +Typically, the choice of discovery mechanism depends on the `Network Topology <../../../Overview/NetworkTopologies/index.html>`_ in your setup. Depending on the value of ``discovery_mechanism`` in ``input/provision_config.yml``, potential target servers can be discovered one of three ways: .. toctree:: mappingfile diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index c168f85f4..1f3ea99ff 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -48,7 +48,6 @@ switch_based .. note:: * If any of the target nodes have a pre-provisioned IP, ensure that these IPs are not part of the ``bmc_subnet`` specified in ``input/network_spec.yml``. - * To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index e19c8c618..00c07254e 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -86,6 +86,8 @@ To deploy the Omnia provision tool, run the following command :: * Discovers all target servers based on specifications in ``input/provision_config.yml``. + .. note:: Even if ``switch_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the bmc_network before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. + * PostgreSQL database is set up with all relevant cluster information such as MAC IDs, hostname, admin IP, infiniband IPs, BMC IPs etc. * Configures the control plane with NTP services for cluster node synchronization. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 00b8f08de..e26f7f988 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -46,29 +46,17 @@ Update the ``input/network_spec.yml`` file for all networks available for use by MTU: "1500" # - thor_network1: - # netmask_bits: "20" - # CIDR: "10.10.16.0" - # network_gateway: "" - # MTU: "1500" - # VLAN: "" - - # - thor_network2: - # netmask_bits: "20" - # static_range: "10.10.1.1-10.10.15.254" - # network_gateway: "" - # MTU: "1500" - # VLAN: "1" .. note:: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 8d842207f..c4067fbfe 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -3,8 +3,6 @@ Before you run the provision tool * (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14.13 `_ and `Python 3.9 `_ are installed on the system. SELinux should also be disabled. -* If the control plane is running on the minimal edition of the OS, ensure that ``chrony`` and ``podman`` are installed before running ``provision.yml``. - * Set the IP address of the control plane with a /16 subnet mask. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. figure:: ../../images/ControlPlaneNic.png @@ -82,7 +80,7 @@ Note the compatibility between cluster OS and control plane OS below: To verify the device name: :: - ip link show + ip link show In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcfg-`` using vi editor. @@ -144,9 +142,6 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf RHEL-8-baseos-partners Red Hat Enterprise Linux 8.6.0 Partners (BaseOS) RHEL-8-crb-partners Red Hat Enterprise Linux 8.6.0 Partners (CRB) -* Uninstall epel-release if installed on the control plane as Omnia configures epel-release on the control plane. To uninstall epel-release, use the following commands: :: - - dnf remove epel-release -y * Ensure that the ``pxe_nic`` and ``public_nic`` are in the firewalld zone: public. diff --git a/docs/source/InstallationGuides/addinganewnode.rst b/docs/source/InstallationGuides/addinganewnode.rst index 4bbc497d4..7fee2d7b0 100644 --- a/docs/source/InstallationGuides/addinganewnode.rst +++ b/docs/source/InstallationGuides/addinganewnode.rst @@ -9,43 +9,38 @@ A new node can be added using the following ways: * Update the existing mapping file by appending the new entry (without the disrupting the older entries) or provide a new mapping file by pointing ``pxe_mapping_file_path`` in ``provision_config.yml`` to the new location. - .. note:: When re-running ``discovery_provision.yml`` with a new mapping file, ensure that existing IPs from the current mapping file are not provided in the new mapping file. Any IP overlap between mapping files will result in PXE failure. This can only be resolved by running `the Clean Up script `_ followed by ``provision.yml``. + .. note:: When re-running ``discovery_provision.yml`` with a new mapping file, ensure that existing IPs from the current mapping file are not provided in the new mapping file. Any IP overlap between mapping files will result in PXE failure. This can only be resolved by running `the Clean Up script `_ followed by ``discovery_provision.yml``. - * Run ``provision.yml``.:: + * Run ``discovery_provision.yml``.:: - cd provision - ansible-playbook provision.yml + ansible-playbook discovery_provision.yml - * Manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_ + * Manually PXE boot the target servers after the ``discovery_provision.yml`` playbook (if ``bmc_ip`` is not provided in the mapping file) is executed and the target node lists as **booted** `in the nodeinfo table `_ -* When the discovery mechanism is ``bmc``: +* When target nodes were discovered using BMC: - * Run ``provision.yml`` once the node has joined the cluster using an IP that exists within the provided range. :: + * Run ``discovery_provision.yml`` once the node has joined the cluster using an IP that exists within the provided range. :: - cd provision - ansible-playbook provision.yml -* When the discovery mechanism is ``switch-based``: + ansible-playbook discovery_provision.yml - * Edit or append JSON list stored in ``switch-based-details`` in ``input/provision_config.yml``. +* When target nodes were discovered using ``switch_based_details`` in ``input/provision_config.yml``: + + * Edit or append JSON list stored in ``switch_based_details`` in ``input/provision_config.yml``. .. note:: * All ports residing on the same switch should be listed in the same JSON list element. - * Ports configured via Omnia should be not be removed from ``switch-based-details`` in ``input/provision_config.yml``. - + * Ports configured via Omnia should be not be removed from ``switch_based_details`` in ``input/provision_config.yml``. - * Run ``provision.yml``. :: + * Run ``discovery_provision.yml``. :: - ansible-playbook provision.yml - * Manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_ + ansible-playbook discovery_provision.yml -Alternatively, if a new node is to be added with no change in configuration, run the following commands: :: + * Manually PXE boot the target servers after the ``discovery_provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_ - cd provision - ansible-playbook discovery_provision.yml -i inventory Verify that the node has been provisioned successfully by `checking the Omnia nodeinfo table. `_ diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst index d01d178ed..de071bbce 100644 --- a/docs/source/InstallationGuides/deletenode.rst +++ b/docs/source/InstallationGuides/deletenode.rst @@ -1,35 +1,41 @@ Remove Slurm/K8s configuration from a node ------------------------------------------- -Use this playbook to remove nodes from the cluster and stop all clustering software on the target nodes. +Use this playbook to remove slurm and kubernetes configuration from slurm or kubernetes worker nodes of the cluster and stop all clustering software on the worker nodes. -.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook may timeout waiting for the node state to change. **Configurations performed by the playbook** - * Remove node from Slurm and Kubernetes cluster. - * Update Slurm and Kubernetes config. - * Slurm and Kubernetes services are stopped (not uninstalled). OS startup service list will be updated to disable Slurm and Kubernetes. + * The node is removed from the Slurm and Kubernetes cluster. + * Slurm and Kubernetes services are stopped and uninstalled. OS startup service list will be updated to disable Slurm and Kubernetes. **To run the playbook** Run the playbook using the following commands: :: cd utils - ansible-playbook remove_node_config.yml -i inventory + ansible-playbook remove_node_configuration.yml -i inventory + +To specify only Slurm or Kubernetes nodes while running the playbook, use the tags ``slurm_node`` or ``kube_node``. That is: + +To remove only slurm nodes, use ``ansible-playbook remove_node_configuration.yml -i inventory --tags slurm_node``. +To remove only kubernetes nodes, use ``ansible-playbook remove_node_configuration.yml -i inventory --tags kube_node``. + +To skip confirmation while running the playbook, use ``ansible-playbook remove_node_configuration.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. + Soft reset the cluster ----------------------- Use this playbook to stop all Slurm and Kubernetes services. This action will destroy the cluster. -.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. +.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook may timeout waiting for the node state to change. **Configurations performed by the playbook** - * The Slurm or Kubernetes cluster will be reset. * The configuration on the kube_control_plane or the slurm_control_plane will be reset. - * Slurm and Kubernetes services are stopped (not uninstalled). + * Slurm and Kubernetes services are stopped and removed. **To run the playbook** @@ -38,17 +44,50 @@ Run the playbook using the following commands: :: cd utils ansible-playbook reset_cluster_config.yml -i inventory +To specify only Slurm or Kubernetes nodes while running the playbook, use the tags ``slurm_node`` or ``kube_node``. That is: + +To reset only slurm nodes, use ``ansible-playbook reset_cluster_config.yml -i inventory --tags slurm_node``. +To reset only kubernetes nodes, use ``ansible-playbook reset_cluster_config.yml -i inventory --tags kube_node``. + +To skip confirmation while running the playbook, use ``ansible-playbook reset_cluster_config.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. + +The inventory file passed for ``reset_cluster_config`` should follow the below format: + +*For a slurm cluster* :: + + [slurm_control_node] + {ip or servicetag} + + [slurmdbd] + {ip or servicetag} + + [slurm_node] + {ip or servicetag} + {ip or servicetag} + +*For a kubernetes cluster* :: + + [kube_control_plane] + {ip or servicetag} + + [etcd] + {ip or servicetag} + + [kube_node] + {ip or servicetag} + {ip or servicetag} + Delete provisioned node ------------------------ -Use this playbook to remove nodes from all inventory files and tables. No changes are made to the Slurm or Kubernetes cluster. +Use this playbook to remove discovered or provisioned nodes from all inventory files and Omnia database tables. No changes are made to the Slurm or Kubernetes cluster. -.. note:: All target nodes should be drained before executing the playbook. If a job is running on any target nodes, the playbook will exit. +.. note:: To undo changes made by this playbook, re-run the provision tool on the target node. **Configurations performed by the playbook** - * Nodes will be deleted from the Omnia DB and xCAT node object will be deleted. - * Telemetry services will be stopped. + * Nodes will be deleted from the Omnia DB and the xCAT node object will be deleted. + * Telemetry services will be stopped and removed. **To run the playbook** @@ -57,8 +96,16 @@ Run the playbook using the following commands: :: cd utils ansible-playbook delete_node.yml -i inventory +To skip confirmation while running the playbook, use ``ansible-playbook delete_node.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. + +The inventory file passed for ``delete_node.yml`` should follow the below format: :: + + [nodes] + {ip or servicetag} + {ip or servicetag} + -.. note:: When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. Slurm partition is also needs to be updated with these changes. +.. note:: When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. diff --git a/docs/source/InstallationGuides/reprovisioningthecluster.rst b/docs/source/InstallationGuides/reprovisioningthecluster.rst index cea0797e2..36d196fd2 100644 --- a/docs/source/InstallationGuides/reprovisioningthecluster.rst +++ b/docs/source/InstallationGuides/reprovisioningthecluster.rst @@ -9,27 +9,29 @@ In the event that an existing Omnia cluster needs a different OS version or a fr If a re-deployment with no modifications are required :: - ansible-playbook discovery_provision.yml -i inventory + ansible-playbook discovery_provision.yml +**Setting up the cluster** + +1. Insert the new IPs in the existing inventory file following the below example. -Where the inventory contains a list of host IPs (Sourced from the `nodeinfo table `_) as shown below: +*Existing kubernetes inventory* :: + [kube_control_plane] 10.5.0.101 - 10.5.0.102 + [kube_node] + 10.5.0.102 + 10.5.0.103 -.. note:: - * The host IPs passed in the inventory should be assigned by Omnia. They will not be changed during the re-provisioning. - * If the nodes were discovered via mapping, manually reboot target nodes. - * Do not include groups like *manager*, *compute* and *login* in the passed inventory. + [auth_server] + 10.5.0.101 -**Setting up the cluster** -1. Insert the new IPs (only if a new node is to be added) and/or move nodes between groups in the existing inventory file following the below example. -*Existing inventory* +*Updated kubernetes inventory with the new node information* :: @@ -39,29 +41,55 @@ Where the inventory contains a list of host IPs (Sourced from the `nodeinfo tabl [kube_node] 10.5.0.102 10.5.0.103 + 10.5.0.105 + 10.5.0.106 - [login] - 10.5.0.104 + [auth_server] + 10.5.0.101 -*Updated inventory with the new node information* +*Existing Slurm inventory* :: - [kube_control_plane] + [slurm_control_node] + 10.5.0.101 + + [slurm_node] 10.5.0.102 + 10.5.0.103 - [kube_node] + [login] + 10.5.0.104 + + [auth_server] + 10.5.0.101 + + +*Updated Slurm inventory with the new node information* + +:: + + [slurm_control_node] 10.5.0.101 + + [slurm_node] + 10.5.0.102 10.5.0.103 - 10.5.0.104 + 10.5.0.105 10.5.0.106 [login] - 10.5.0.105 + 10.5.0.104 + + [auth_server] + 10.5.0.101 -In the above example, the compute node: 10.5.0.102 has been moved to manager, a new login node: 10.5.0.105 has been set up, and the node: 10.5.0.106 has been added to the cluster as a compute node. -.. note:: To change the configuration of the cluster, the files ``input/omnia_config.yml``, ``input/security_config.yml`` and ``input/storage_config.yml`` can be updated before running ``omnia.yml``. +In the above examples, nodes 10.5.0.105 and 10.5.0.106 have been added to the cluster as compute nodes. + +.. note:: + * Do not change the kube_control_plane/slurm_control_node/auth_server in the existing inventory. Simply add the new node information in the kube_node/slurm_node group. + * When re-running ``omnia.yml`` to add a new node, ensure that the ``input/security_config.yml`` and ``input/omnia_config.yml`` are not edited between runs. 3. To install `security `_, `job scheduler `_ and storage tools (`NFS `_, `BeeGFS `_) on the node, run ``omnia.yml``: :: From 2edb290905fc18131a1dc6a55a7154262ac0f2d8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 15:50:14 +0530 Subject: [PATCH 186/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/DiscoveryMechanisms/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index 30bc1d16f..fdfe550cb 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -1,7 +1,7 @@ Discovery Mechanisms ----------------------- -Typically, the choice of discovery mechanism depends on the `Network Topology <../../../Overview/NetworkTopologies/index.html>`_ in your setup. Depending on the value of ``discovery_mechanism`` in ``input/provision_config.yml``, potential target servers can be discovered one of three ways: +Depending on the values provided in ``input/provision_config.yml``, target nodes can be discovered in one of three ways: .. toctree:: mappingfile From 766a2af7ccbd6159b32265d320190ab7296d2265 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:09:21 +0530 Subject: [PATCH 187/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/index.rst | 1 - .../DiscoveryMechanisms/switch-based.rst | 7 +-- .../installprovisiontool.rst | 54 ++++++------------- .../provisionparams.rst | 10 ++-- docs/source/limitations.rst | 1 - 5 files changed, 22 insertions(+), 51 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index fdfe550cb..32bd7328c 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -7,7 +7,6 @@ Depending on the values provided in ``input/provision_config.yml``, target nodes mappingfile switch-based bmc - snmp **switch_based** diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index 1f3ea99ff..9630270af 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -7,7 +7,7 @@ switch_based * Switch port range where all BMC NICs are connected should be provided. -* SNMP v3 should be enabled on the switch. +* SNMP v3 should be enabled on the switch and the credentials should be provided in ``input/provision_config_credentials.yml``. * Non-admin user credentials for the switch need to be provided. @@ -43,12 +43,13 @@ switch_based .. caution:: * Do not use daisy chain ports or the port used to connect to the control plane in ``switch_based_details`` in ``input/provision_config.yml``. This can cause IP conflicts on servers attached to potential target ports. * Omnia does not validate SNMP switch credentials, if the provision tool is run with incorrect credentials, use the clean-up script and re-run the provision tool with the correct credentials. - * If you are re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (**BIOS Settings > Boot Settings > UEFI Boot Settings**) on all target nodes. + * If you are re-provisioning your cluster (that is, re-running the ``discovery_provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``static_range`` against ``bmc_network`` in ``input/network_spec.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (**BIOS Settings > Boot Settings > UEFI Boot Settings**) on all target nodes. + .. note:: * If any of the target nodes have a pre-provisioned IP, ensure that these IPs are not part of the ``bmc_subnet`` specified in ``input/network_spec.yml``. - + * Even if ``switch_based_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the ``bmc_network`` before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 00c07254e..374069dea 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -10,28 +10,11 @@ Edit the ``input/provision_config.yml`` file to update the required variables. A Optional configurations managed by the provision tool +++++++++++++++++++++++++++++++++++++++++++++++++++++ -**Assigning infiniband IPs** - - - When ``ib_nic_subnet`` is provided in ``input/provision_config.yml``, the infiniband NIC on target nodes are assigned IPv4 addresses within the subnet without user intervention. When PXE range and Infiniband subnet are provided, the infiniband NICs will be assigned IPs with the same 3rd and 4th octets as the PXE NIC. - - * For example on a target node, when the PXE NIC is assigned 10.5.0.101, and the Infiniband NIC is assigned 10.10.0.101 (where ``ib_nic_subnet`` is 10.10.0.0). - - .. note:: The IP is assigned to the interface **ib0** on target nodes only if the interface is present in **active** mode. If no such NIC interface is found, xCAT will list the status of the node object as failed. - -**Assigning BMC IPs** - - When target nodes are discovered via SNMP or mapping files (ie ``discovery_mechanism`` is set to snmp or mapping in ``input/provision_config.yml``), the ``bmc_nic_subnet`` in ``input/provision_config.yml`` can be used to assign BMC IPs to iDRAC without user intervention. When PXE range and BMC subnet are provided, the iDRAC NICs will be assigned IPs with the same 3rd and 4th octets as the PXE NIC. - - * For example on a target node, when the PXE NIC is assigned 10.5.0.101, and the iDRAC NIC is assigned 10.3.0.101 (where ``bmc_nic_subnet`` is 10.3.0.0). - **Using multiple versions of a given OS** -Omnia now supports deploying different versions of the same OS. With each run of ``provision.yml``, a new deployable OS image is created with a distinct type (rocky or RHEL) and version (8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7) depending on the values provided in ``input/provision_config.yml``. +Omnia now supports deploying different versions of the same OS. With each run of ``discovery_provision.yml``, a new deployable OS image is created with a distinct type (rocky, Ubuntu, or RHEL) and version (8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 20.04, 22.04) depending on the values provided in ``input/provision_config.yml``. -.. note:: - * While Omnia deploys the minimal version of the OS, the multiple version feature requires that the Rocky full (DVD) version of the OS be provided. - * The multiple OS feature is only available with Rocky 8.7 when xCAT 2.16.5 is in use. [Currently, Omnia uses 2.16.4] +.. note:: While Omnia deploys the minimal version of the OS, the multiple version feature requires that the Rocky full (DVD) version of the OS be provided. **Disk partitioning** @@ -48,20 +31,19 @@ Omnia now supports deploying different versions of the same OS. With each run of Running the provision tool ++++++++++++++++++++++++++++ -To deploy the Omnia provision tool, run the following command :: +To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, ``input/network_spec.yml``, and ``input/provision_config_credentials.yml`` are updated and then run:: - cd provision ansible-playbook discovery_provision.yml -``provision.yml`` runs in three stages that can be called individually: +``discovery_provision.yml`` runs in three stages that can be called individually: **Preparing the control plane** * Installs required tool packages. * Verifies and updates firewall settings. * Installs xCAT. - * Configures Omnia databases basis ``input/provision_config.yml``. + * Configures Omnia databases basis ``input/network_spec.yml``. * Creates an inventory of all nodes in the cluster at ``/opt/omnia/omnia_inventory/``. This inventory will list nodes based on the type of CPUs and GPUs they have. The inventory files are: * ``compute_cpu_amd`` @@ -77,25 +59,23 @@ To deploy the Omnia provision tool, run the following command :: * To regenerate an inventory file, use the playbook ``omnia/utils/inventory_tagging.yml``. - To call this playbook individually, ensure that ``input/provision_config.yml`` and ``input/provision_config_credentials.yml`` are updated and then run:: - - cd Prepare_cp + cd prepare_cp ansible-playbook prepare_cp.yml **Discovering the nodes** - * Discovers all target servers based on specifications in ``input/provision_config.yml``. + * Discovers all target servers. - .. note:: Even if ``switch_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the bmc_network before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. + .. note:: Even if ``switch_based_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the ``bmc_network`` before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. - * PostgreSQL database is set up with all relevant cluster information such as MAC IDs, hostname, admin IP, infiniband IPs, BMC IPs etc. + * PostgreSQL database is set up with all relevant cluster information such as MAC IDs, hostname, admin IP, BMC IPs etc. * Configures the control plane with NTP services for cluster node synchronization. To call this playbook individually, run:: - cd Discovery + cd discovery ansible-playbook discovery.yml **Provisioning the nodes** @@ -104,11 +84,11 @@ To deploy the Omnia provision tool, run the following command :: To call this playbook individually, run:: - cd Provision + cd provision ansible-playbook provision.yml ---- -After successfully running ``provision.yml``, go to `Building Clusters <../BuildingClusters/index.html>`_ to setup Slurm, Kubernetes, NFS, BeeGFS and Authentication. +After successfully running ``discovery_provision.yml``, go to `Building Clusters <../BuildingClusters/index.html>`_ to setup Slurm, Kubernetes, NFS, BeeGFS and Authentication. ---- .. note:: @@ -117,17 +97,13 @@ After successfully running ``provision.yml``, go to `Building Clusters <../Build * While the ``admin_nic`` on cluster nodes is configured by Omnia to be static, the public NIC IP address should be configured by user. - * If the target nodes were discovered using switch-based or mapping mechanisms, manually PXE boot the target servers after the ``provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_. - - * If the cluster does not have access to the internet, AppStream will not function. + * If the target nodes were discovered using switch-based or mapping mechanisms, manually PXE boot the target servers after the ``discovery_provision.yml`` playbook is executed and the target node lists as **booted** `in the nodeinfo table `_. * All ports required for xCAT to run will be opened (For a complete list, check out the `Security Configuration Document <../../SecurityConfigGuide/ProductSubsystemSecurity.html#firewall-settings>`_). - * After running ``provision.yml``, the file ``input/provision_config.yml`` will be encrypted. To edit the file, use the command: ``ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key`` - - * Post execution of ``provision.yml``, IPs/hostnames cannot be re-assigned by changing the mapping file. However, the addition of new nodes is supported as explained `here <../addinganewnode.html>`_. + * After running ``discovery_provision.yml``, the file ``input/provision_config_credentials.yml`` will be encrypted. To edit the file, use the command: ``ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key`` - * Ensure the `clean up script <../CleanUpScript.html>`_ is run before any subsequent executions of ``provision.yml``. + * Post execution of ``discovery_provision.yml``, IPs/hostnames cannot be re-assigned by changing the mapping file. However, the addition of new nodes is supported as explained `here <../addinganewnode.html>`_. * Default Python is installed during provisioning on Ubuntu cluster nodes. For Ubuntu 22.04, Python 3.10 is installed. For Ubuntu 20.04, Python 3.8 is installed. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index e26f7f988..3b4c4cd65 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -61,15 +61,15 @@ Update the ``input/network_spec.yml`` file for all networks available for use by .. note:: - * The ``input/provision_config.yml`` file is encrypted on the first run of the provision tool: + * The ``input/provision_config_credentials.yml`` file is encrypted on the first run of the provision tool: To view the encrypted parameters: :: - ansible-vault view provision_config.yml --vault-password-file .provision_vault_key + ansible-vault view provision_config_credentials.yml --vault-password-file .provision_vault_key To edit the encrypted parameters: :: - ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key + ansible-vault edit provision_config_credentials.yml --vault-password-file .provision_vault_key * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. Also, the properties ``nic_name``, ``static_range``, and ``dynamic_range`` cannot be edited on subsequent runs of the provision tool. * Netmask bits is mandatory and should be same for both the ``admin_network`` and ``bmc_network`` (ie between 1 and 32; 1 and 32 are acceptable values). @@ -77,7 +77,3 @@ Update the ``input/network_spec.yml`` file for all networks available for use by * The ``discover_ranges`` property of the ``bmc_network`` can accept multiple comma-separated ranges. * The ``VLAN`` property is optional but should be between 0 and 4095 (0 and 4095 are not acceptable values). -.. caution:: - - * The IP address *192.168.25.x* is used for PowerVault Storage communications. Therefore, do not use this IP address for other configurations. - * The IP range *x.y.246.1* - *x.y.255.253* (where x and y are provided by the first two octets of ``bmc_nic_subnet``) are reserved by Omnia. \ No newline at end of file diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst index 5a6908100..cd9e6418e 100644 --- a/docs/source/limitations.rst +++ b/docs/source/limitations.rst @@ -36,5 +36,4 @@ Limitations - OpenSUSE Leap 15.3 is not supported on the Control Plane. - Omnia might contain some unused MACs since LOM switch have both iDRAC MACs as well as ethernet MACs, PXE NIC ranges should contain IPs that are double the iDRACs present. - FreeIPA authentication is not supported on the control plane. -- The multiple OS feature is only available with Rocky 8.7 when xCAT 2.16.5 is in use. Currently, Omnia uses 2.16.4. - Currently, Omnia only supports the splitting of switch ports. Switch ports cannot be un-split using this script. From d3323aa03b2d9a6f4837baa60eb6caf5f26b547b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:23:27 +0530 Subject: [PATCH 188/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/InstallingProvisionTool/index.rst | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index 0799a243d..a1b5a4af4 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -5,13 +5,10 @@ This playbook achieves the following tasks: * Discovers potential cluster nodes. - * Installs Rocky or RHEL on the nodes. + * Installs Rocky, Ubuntu, or RHEL on the nodes. * Assigns admin/infiniband IPs with optional DHCP routing. - - * Creates access to offline repositories. - - * Configures a docker registry to pull images from the internet and store them locally. +- .. toctree:: From ff1700dd45fda0b1d3e7c5892c24a8f6e162ff50 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:28:45 +0530 Subject: [PATCH 189/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/ViewingDB.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index 2fab009fa..8a522e2ee 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -32,9 +32,9 @@ Via omniadb 4. To view the contents of the ``nodeinfo`` table: ``select * from cluster.nodeinfo;`` :: Node cpu gpu cpu_count gpu_count - node1 intel nvidia 1 2 - node2 amd amd 2 1 - node3 amd 1 0 + node1 intel nvidia 1 2 + node2 amd   amd 2 1 + node3 amd 1 0 Possible values of node status are powering-off, powering-on, bmcready, installing, booting, post-booting, booted, failed. From 676cf3049a9fcc6a8060c69910b8129af29cd681 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:38:41 +0530 Subject: [PATCH 190/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/InstallingProvisionTool/index.rst | 1 - docs/source/Troubleshooting/troubleshootingguide.rst | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index a1b5a4af4..3aead3445 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -8,7 +8,6 @@ This playbook achieves the following tasks: * Installs Rocky, Ubuntu, or RHEL on the nodes. * Assigns admin/infiniband IPs with optional DHCP routing. -- .. toctree:: diff --git a/docs/source/Troubleshooting/troubleshootingguide.rst b/docs/source/Troubleshooting/troubleshootingguide.rst index fea9b799f..c8255a3a1 100644 --- a/docs/source/Troubleshooting/troubleshootingguide.rst +++ b/docs/source/Troubleshooting/troubleshootingguide.rst @@ -15,17 +15,17 @@ Connecting to internal databases Checking and updating encrypted parameters ----------------------------------------------- -1. Move to the filepath where the parameters are saved (as an example, we will be using ``provision_config.yml``): :: +1. Move to the filepath where the parameters are saved (as an example, we will be using ``provision_config_credentials.yml``): :: cd input/ 2. To view the encrypted parameters: :: - ansible-vault view provision_config.yml --vault-password-file .provision_vault_key + ansible-vault view provision_config_credentials.yml --vault-password-file .provision_vault_key 3. To edit the encrypted parameters: :: - ansible-vault edit provision_config.yml --vault-password-file .provision_vault_key + ansible-vault edit provision_config_credentials.yml --vault-password-file .provision_vault_key Checking pod status on the control plane -------------------------------------------- From f75ed7abb4a1fdced8ef96c0deb3044acdac6ae9 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:40:20 +0530 Subject: [PATCH 191/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/ViewingDB.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index 8a522e2ee..92aa3f981 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -31,10 +31,12 @@ Via omniadb 4. To view the contents of the ``nodeinfo`` table: ``select * from cluster.nodeinfo;`` :: - Node cpu gpu cpu_count gpu_count - node1 intel nvidia 1 2 - node2 amd   amd 2 1 - node3 amd 1 0 + id | service_tag | node | hostname | admin_mac | admin_ip | bmc_ip | status | discovery_mechanism | bmc_mode | switch_ip | switch_name | switch_port | cpu | gpu | cpu_count | gpu_count$ + ----+-------------+---------------+---------------+-------------------+--------------+------------+--------+---------------------+----------+-----------+-------------+-------------+-----+-----+-----------+---------- + 1 | | control_plane | newcp.new.dev | 00:0a:f7:dc:11:42 | 10.5.255.254 | 0.0.0.0 | | | | | | | | | | + 2 | 2189N04 | node2 | node2.new.dev | c4:cb:e1:b5:70:44 | 10.5.0.12 | 10.30.0.12 | booted | mapping | | | | | amd | | 1 | 0 + 3 | 3HSTB33 | node3 | node3.new.dev | f4:02:70:b8:bc:2a | 10.5.0.10 | 10.30.0.10 | booted | mapping | | | | | amd | amd | 2 | 1 + (3 rows) Possible values of node status are powering-off, powering-on, bmcready, installing, booting, post-booting, booted, failed. From 2f736a857e237e59674c904b9ad33ebae8e53f8a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:44:40 +0530 Subject: [PATCH 192/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/InstallingProvisionTool/ViewingDB.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst index 92aa3f981..2773a4ec8 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/ViewingDB.rst @@ -34,8 +34,8 @@ Via omniadb id | service_tag | node | hostname | admin_mac | admin_ip | bmc_ip | status | discovery_mechanism | bmc_mode | switch_ip | switch_name | switch_port | cpu | gpu | cpu_count | gpu_count$ ----+-------------+---------------+---------------+-------------------+--------------+------------+--------+---------------------+----------+-----------+-------------+-------------+-----+-----+-----------+---------- 1 | | control_plane | newcp.new.dev | 00:0a:f7:dc:11:42 | 10.5.255.254 | 0.0.0.0 | | | | | | | | | | - 2 | 2189N04 | node2 | node2.new.dev | c4:cb:e1:b5:70:44 | 10.5.0.12 | 10.30.0.12 | booted | mapping | | | | | amd | | 1 | 0 - 3 | 3HSTB33 | node3 | node3.new.dev | f4:02:70:b8:bc:2a | 10.5.0.10 | 10.30.0.10 | booted | mapping | | | | | amd | amd | 2 | 1 + 2 | xxxxxxx | node2 | node2.new.dev | c4:cb:e1:b5:70:44 | 10.5.0.12 | 10.30.0.12 | booted | mapping | | | | | amd | | 1 | 0 + 3 | xxxxxxx | node3 | node3.new.dev | f4:02:70:b8:bc:2a | 10.5.0.10 | 10.30.0.10 | booted | mapping | | | | | amd | amd | 2 | 1 (3 rows) From 4a89d44a1587c0376220d10d530360ed787aa715 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:51:09 +0530 Subject: [PATCH 193/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/DiscoveryMechanisms/bmc.rst | 4 ++-- .../DiscoveryMechanisms/switch-based.rst | 5 ++--- .../InstallingProvisionTool/provisionprereqs.rst | 2 +- docs/source/limitations.rst | 1 - 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 32ddf362f..6f96f01d7 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -5,7 +5,7 @@ For automatic provisioning of servers and discovery, the BMC method can be used. **Pre requisites** -* Set the IP address of the control plane with a /16 subnet mask. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. +* Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. image:: ../../../images/ControlPlaneNic.png * BMC NICs should have a static IP assigned or be configured in DHCP mode. @@ -24,7 +24,7 @@ For automatic provisioning of servers and discovery, the BMC method can be used. - IP ranges (``bmc_static_start_range``, ``bmc_static_start_range``) provided to Omnia for BMC discovery should be within the same subnet. .. caution:: - * If you are re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (``BIOS Settings`` > ``Boot Settings`` > ``UEFI Boot Settings``) on all target nodes. + * If you are re-provisioning your cluster (that is, re-running the ``discovery_provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``static_range`` against ``bmc_network`` in ``input/network_spec.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (**BIOS Settings > Boot Settings > UEFI Boot Settings**) on all target nodes. - All target servers should be reachable from the ``admin_network`` specified in ``input/network_spec.yml``. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index 9630270af..d411e56b2 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -35,7 +35,7 @@ switch_based * Target servers should be configured to boot in PXE mode with appropriate NIC as the first boot device. -* Set the IP address of the control plane with a /16 subnet mask. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. +* Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. image:: ../../../images/ControlPlaneNic.png * Ensure that the variable ``switch_based_details`` in ``input/provision_config.yml`` is provided. @@ -47,8 +47,7 @@ switch_based .. note:: - - * If any of the target nodes have a pre-provisioned IP, ensure that these IPs are not part of the ``bmc_subnet`` specified in ``input/network_spec.yml``. + * If any of the target nodes have a pre-provisioned BMC IP, ensure that these IPs are not part of the ``static_range`` specified in ``input/network_spec.yml`` under the ``bmc_network`` to avoid any node IP conflicts. * Even if ``switch_based_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the ``bmc_network`` before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index c4067fbfe..b49769f76 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -3,7 +3,7 @@ Before you run the provision tool * (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14.13 `_ and `Python 3.9 `_ are installed on the system. SELinux should also be disabled. -* Set the IP address of the control plane with a /16 subnet mask. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. +* Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. figure:: ../../images/ControlPlaneNic.png diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst index cd9e6418e..35033069a 100644 --- a/docs/source/limitations.rst +++ b/docs/source/limitations.rst @@ -3,7 +3,6 @@ Limitations - Once ``provision.yml`` is used to configure devices, it is recommended to avoid rebooting the control plane. -- Omnia provision tools only support /16 subnet masks for provisioning. - Omnia supports adding only 1000 nodes when discovered via BMC. - Removal of Slurm and Kubernetes component roles are not supported. However, the scheduler type can be customized by setting ``scheduler_type`` in ``input/omnia_config.yml`` prior to running ``omnia.yml``. From 51bee599b65d290dc26d5123e2e909077825200a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 16:58:26 +0530 Subject: [PATCH 194/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/DiscoveryMechanisms/bmc.rst | 5 ++--- .../InstallationGuides/InstallingProvisionTool/index.rst | 4 +--- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 6f96f01d7..23a890b28 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -21,10 +21,9 @@ For automatic provisioning of servers and discovery, the BMC method can be used. racadm set iDRAC.IPMILan.Enable 1 racadm get iDRAC.IPMILan -- IP ranges (``bmc_static_start_range``, ``bmc_static_start_range``) provided to Omnia for BMC discovery should be within the same subnet. -.. caution:: - * If you are re-provisioning your cluster (that is, re-running the ``discovery_provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``static_range`` against ``bmc_network`` in ``input/network_spec.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (**BIOS Settings > Boot Settings > UEFI Boot Settings**) on all target nodes. + +.. caution:: If you are re-provisioning your cluster (that is, re-running the ``discovery_provision.yml`` playbook) after a `clean-up <../../CleanUpScript.html>`_, ensure to use a different ``static_range`` against ``bmc_network`` in ``input/network_spec.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (**BIOS Settings > Boot Settings > UEFI Boot Settings**) on all target nodes. - All target servers should be reachable from the ``admin_network`` specified in ``input/network_spec.yml``. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index 3aead3445..e3512a183 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -5,9 +5,7 @@ This playbook achieves the following tasks: * Discovers potential cluster nodes. - * Installs Rocky, Ubuntu, or RHEL on the nodes. - - * Assigns admin/infiniband IPs with optional DHCP routing. + * Installs Rocky, Ubuntu, or RHEL on the discovered nodes. .. toctree:: From 1dc7df327cf650e1edbf4d1f5b85ff30dde69cde Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 15 Mar 2024 17:34:36 +0530 Subject: [PATCH 195/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/switch-based.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index d411e56b2..4a57016e5 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -47,7 +47,7 @@ switch_based .. note:: - * If any of the target nodes have a pre-provisioned BMC IP, ensure that these IPs are not part of the ``static_range`` specified in ``input/network_spec.yml`` under the ``bmc_network`` to avoid any node IP conflicts. + * If any of the target nodes have a pre-provisioned BMC IP, ensure that these IPs are not part of the ``static_range`` specified in ``input/network_spec.yml`` under the ``bmc_network`` to avoid any bmc IP conflicts. * Even if ``switch_based_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the ``bmc_network`` before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. From 10b3fce12fddc9ef76d7b979c47fdb0b41108095 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:00:24 +0530 Subject: [PATCH 196/309] Updating documentation Signed-off-by: goveac --- .../BuildingClusters/NFS.rst | 3 ++- .../BuildingClusters/schedulerprereqs.rst | 6 +---- .../LocalRepo/RunningLocalRepo.rst | 13 +++++++++- docs/source/Roles/Platform/kserve.rst | 18 ++++++++++--- docs/source/Roles/Utils/updatelocalrepo.rst | 9 +++++++ docs/source/Tables/local_repo_config.csv | 26 ------------------- docs/source/Troubleshooting/knownissues.rst | 10 +++++++ 7 files changed, 49 insertions(+), 36 deletions(-) create mode 100644 docs/source/Roles/Utils/updatelocalrepo.rst diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 4de8034ae..05f96e84f 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -51,6 +51,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. * Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ * Enter the value of ``share_path`` in ``input/omnia_config.yml``. +* If the intended cluster will run Slurm, set the value of ``Slurm_installation_type`` in ``input/omnia_config.yml`` to ``nfs_share``. .. note:: Ensure that the value of ``share_path`` provided matches at least one value of ``client_share_path`` provided in ``nfs_client_params`` in ``input/storage_config.yml``. @@ -60,7 +61,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. **Running the playbook** -If ``omnia.yml`` is not leveraged to set up NFS, run the ``storage.yml`` playbook : :: +Run the ``storage.yml`` playbook : :: cd storage ansible-playbook storage.yml -i inventory diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst index 98d34f32a..576180e60 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst @@ -9,11 +9,7 @@ Before you build clusters * Verify that all nodes are assigned a group. Use the `inventory <../../samplefiles.html>`_ as a reference. The inventory file is case-sensitive. Follow the casing provided in the sample file link. - * The manager group should have exactly 1 manager node. - - * The compute group should have at least 1 node. - - * The login group is optional. If present, it should have exactly 1 node. +* If NFS is required on the cluster, run `storage.yml. `_ .. note:: * The inventory file accepts both IPs and FQDNs as long as they can be resolved by DNS. diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index c9dac9fb3..9b5b0dedd 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -145,4 +145,15 @@ For a list of repositories (and their types) configured for kubernetes, view the 3. Run the following commands: :: cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file + ansible-playbook local_repo.yml + + + +**Update local repositories (RHEL)** + +This playbook updates all local repositories configured on a RHEL cluster after local repositories have been configured. + +To run the playbook: :: + + cd utils + ansible-playbook update_user_repo.yml -i inventory \ No newline at end of file diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index dfedd297d..c7d0fe142 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -1,7 +1,7 @@ Setup Kserve -------------- -Kserve is an open-source serving platform that simplifies the deployment, scaling, and management of machine learning models in production environments, ensuring efficient and reliable inference capabilities. For more information, `click here. `_ +Kserve is an open-source serving platform that simplifies the deployment, scaling, and management of machine learning models in production environments, ensuring efficient and reliable inference capabilities. For more information, `click here. `_ Omnia deploys KServe (v0.11.0) on the kubernetes cluster. Once KServe is deployed, any inference service can be installed on the kubernetes cluster. **Prerequisites** @@ -10,6 +10,8 @@ Kserve is an open-source serving platform that simplifies the deployment, scalin * MetalLB pod is up and running to provide an external IP to ``istio-ingressgateway``. + * The domain name on the kubernetes cluster should be **cluster.local**. The KServe inference service will not work with a custom ``cluster_name`` property on the kubernetes cluster. + * A local Kserve repository should be created using ``local_repo.yml``. For more information, `click here. <../../InstallationGuides/LocalRepo/kserve.html>`_ * Ensure the passed inventory file includes a ``kube_control_plane`` and a ``kube_node`` listing all cluster nodes. `Click here <../../samplefiles.html>`_ for a sample file. @@ -36,12 +38,22 @@ Kserve is an open-source serving platform that simplifies the deployment, scalin **Deploy inference service** +**Prerequisites** - Verify that the inference service is up and running using the command: ``kubectl get isvc -A``. + * Verify that the inference service is up and running using the command: ``kubectl get isvc -A``. + * Pull the intended inference model and the corresponding runtime-specific images into the nodes. + * As part of the deployment, Omnia deploys `standard model runtimes. `_ If a custom model is deployed, deploy a custom runtime first. **Access the inference service** - Use ``kubectl get svc -A`` to check the external IP of the service ``istio-ingressgateway``. +1. Use ``kubectl get svc -A`` to check the external IP of the service ``istio-ingressgateway``. +2. To access inferencing from the ingressgateway with HOST header, run the below command: :: + + curl -v -H "Host: " -H "Content-Type: application/json" "http://:/v1/models/:predict" -d @./iris-input.json + +For example: :: + + curl -v -H "Host: sklearn-pvc.default.example.com" -H "Content-Type: application/json" "http://10.20.0.101:80/v1/models/sklearn-pvc:predict" -d @./iris-input.json diff --git a/docs/source/Roles/Utils/updatelocalrepo.rst b/docs/source/Roles/Utils/updatelocalrepo.rst new file mode 100644 index 000000000..3873739fa --- /dev/null +++ b/docs/source/Roles/Utils/updatelocalrepo.rst @@ -0,0 +1,9 @@ +Update local repositories (RHEL) +--------------------------------- + +This playbook updates all local repositories configured on a RHEL cluster after `local repositories have been configured. <../../InstallationGuides/LocalRepo/index.html>_ + +To run the playbook: :: + + cd utils + ansible-playbook update_user_repo.yml -i inventory \ No newline at end of file diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index af566ce9a..2e421862f 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -64,32 +64,6 @@ Optional","* URL to a list of repositories to be configured for Ubuntu clusters. * When the value of ``repo_config`` in ``input/local_repo_config.yml`` is set to ``partial`` or ``never``, the given ``os_repo_url`` is configured via proxy on the compute nodes. * **Sample value**: ``http://in.archive.ubuntu.com/ubuntu``" -"**omnia_registry** - -``string`` - -Mandatory","* A list of registries from where images will be downloaded for Omnia features. -* All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. -* This value is not validated by Omnia. Any errors can cause Omnia to fail. - -**Default value**: :: - - - ""registry.k8s.io"" - - ""quay.io"" - - ""docker.io"" - - ""public.ecr.aws"" - - ""gcr.io"" - - ""nvcr.io"" - - - - - - - - - - " "**omnia_repo_url_rhel** ``JSON List`` diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index 98aaa3472..5d2425b22 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -207,6 +207,16 @@ Wait for 15 minutes after the Kubernetes cluster reboots. Next, verify the statu 3. Run the Kubernetes and Kubeflow playbooks. +⦾ **What to do if pulling the Kserve inference model fail with "Unable to fetch image "kserve/sklearnserver:v0.11.2": failed to resolve image to digest: Get "https://index.docker.io/v2/": dial tcp 3.219.239.5:443: i/o timeout."?** + +1. Edit the kubernetes configuration map: :: + + kubectl edit configmap -n knative-serving config-deployment + +2. Add docker.io and index.docker.io as part of the registries-skipping-tag-resolving. + +For more information, `click here. `_ + ⦾ **Why does the 'Initialize Kubeadm' task fail with 'nnode.Registration.name: Invalid value: \"\"'?** From d8f74bd98a1fcc7c436ba342dd268f740bb0b81d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:11:25 +0530 Subject: [PATCH 197/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/CleanUpScript.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/source/InstallationGuides/CleanUpScript.rst b/docs/source/InstallationGuides/CleanUpScript.rst index b029dab32..aa6410c4e 100644 --- a/docs/source/InstallationGuides/CleanUpScript.rst +++ b/docs/source/InstallationGuides/CleanUpScript.rst @@ -8,6 +8,19 @@ To run the script: :: cd utils ansible-playbook control_plane_cleanup.yml +To skip the deletion of the configured local repositories (stored in ``repo_store_path`` and xCAT repositories), run: :: + + ansible-playbook control_plane_cleanup.yml –skip-tags downloads + +To delete the changes made by ``local_repo.yml`` while retaining the ``repo_store_path`` folder, run: :: + + ansible-playbook control_plane_cleanup.yml –tags local_repo --skip-tags downloads + +To delete the changes made by ``local_repo.yml`` including the ``repo_store_path`` folder, run: :: + + ansible-playbook control_plane_cleanup.yml –tags local_repo + + .. caution:: * When re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a clean-up, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (``BIOS Settings`` > ``Boot Settings`` > ``UEFI Boot Settings``) on all target nodes. * On subsequent runs of ``provision.yml``, if users are unable to log into the server, refresh the ssh key manually and retry. :: From 2cd88498531b705c5229bd8f6c9ca6a4c70c7714 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:21:49 +0530 Subject: [PATCH 198/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/SetupvLLM.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index 409ed4486..b2d5e2c64 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -32,6 +32,8 @@ With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. +.. note:: This playbook was validated using Ubuntu 22.04 and RHEL 8.8. + **Deploying vLLM** 1. Change directories to the ``tools`` folder: :: From 6ad591a9f003cd551ae176c77d608eff02e556f5 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:30:45 +0530 Subject: [PATCH 199/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/Prerequisite.rst | 2 ++ docs/source/Tables/Provision_creds.csv | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index 7ef37792a..ce73e76bd 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -9,6 +9,8 @@ For persistent offline local repositories, (If the parameter ``repo_config`` in **When creating user registries** +To avoid docker pull limits, provide docker credentials (``docker_username``, ``docker_password``) in ``input/provision_config_credentials.yml``. + Images listed in ``user_registry`` in ``input/local_repo_config.yml`` are accessed from user defined registries. To ensure that the control plane can correctly access the registry, ensure that the following naming convention is used to save the image: :: /:v diff --git a/docs/source/Tables/Provision_creds.csv b/docs/source/Tables/Provision_creds.csv index 4e31ccdb4..ca9b374c8 100644 --- a/docs/source/Tables/Provision_creds.csv +++ b/docs/source/Tables/Provision_creds.csv @@ -39,3 +39,16 @@ Optional (Required for Switch based discovery mechanism)","* Non-admin SNMPv3 cr Optional (Required for Switch based discovery mechanism)","* Non-admin SNMPv3 credentials of the PXE switch. * If multiple switches are provided, ensure the credentials are same across switches. * Password must not contain -,\, ',""" +"**docker_username** + +``string`` + +Optional","* Username for Dockerhub account used for Docker logins. +* A kubernetes secret will be created and patched to the service account in default namespace. +* This kubernetes secret can be used to pull images from private repositories." +"**docker_password** + +``string`` + +Optional","* Password for Dockerhub account used for Docker logins. +* This value is mandatory if ``docker_username`` is provided." \ No newline at end of file From 3393a4c34704269d0e0032970da191606e6cd15b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:33:01 +0530 Subject: [PATCH 200/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/RunningInit/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index 1a88adcad..26883c481 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -1,7 +1,7 @@ Running prereq.sh ================= -``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.14.13). :: +``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.14.14). :: cd omnia ./prereq.sh From 74748238ec53686ad4d93ec1d9112fdd1b245de9 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:41:33 +0530 Subject: [PATCH 201/309] Updating documentation Signed-off-by: goveac --- .../Overview/SupportMatrix/OperatingSystems/RedHat.rst | 5 ----- .../source/Overview/SupportMatrix/OperatingSystems/Rocky.rst | 4 ---- 2 files changed, 9 deletions(-) diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst index 631ef04cb..54bf6577f 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst @@ -4,11 +4,6 @@ Red Hat Enterprise Linux ========== ============= ============= OS Version Control Plane Cluster Nodes ========== ============= ============= -8.1 No Yes -8.2 No Yes -8.3 No Yes -8.4 Yes Yes -8.5 Yes Yes 8.6 Yes Yes 8.7 Yes Yes 8.8 Yes Yes diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst index 23f51161d..744e6baca 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst @@ -6,10 +6,6 @@ Rocky +------------+---------------+---------------+ | OS Version | Control Plane | Cluster Nodes | +============+===============+===============+ -| 8.4 | Yes | No | -+------------+---------------+---------------+ -| 8.5 | Yes | No | -+------------+---------------+---------------+ | 8.6 | Yes | No | +------------+---------------+---------------+ | 8.7 | Yes | No | From 4440000254c63143f49b8e3c846778c3e6563eb3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 10:45:19 +0530 Subject: [PATCH 202/309] Updating documentation Signed-off-by: goveac --- docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst index 744e6baca..035bd6900 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst @@ -14,7 +14,7 @@ Rocky +------------+---------------+---------------+ .. note:: - * Always deploy the DVD (Full) Edition of the OS on cluster Nodes. + * Always deploy the DVD (Full) Edition of the OS on cluster nodes. * AMD ROCm driver installation is not supported by Omnia on Rocky cluster nodes. From 9f42ba8b6f8077857b0ef0d479b7e617892d5e24 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 11:10:14 +0530 Subject: [PATCH 203/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/kserve.rst | 60 +++++++++++++++++++++++++-- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index c7d0fe142..7a0a0e002 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -34,26 +34,78 @@ Kserve is an open-source serving platform that simplifies the deployment, scalin * Certificate manager (version: 1.13.0) * Knative (version: 1.11.0) - To verify the installation, run ``kubectl get pod -A`` and look for the namespaces: ``cert-manager``, ``istio-system``, ``knative-serving``, and ``kserve``. + To verify the installation, run ``kubectl get pod -A`` and look for the namespaces: ``cert-manager``, ``istio-system``, ``knative-serving``, and ``kserve``. :: + + root@sparknode1:/tmp# kubectl get pod -A + NAMESPACE NAME READY STATUS RESTARTS AGE + cert-manager cert-manager-5d999567d7-mfgdk 1/1 Running 0 44h + cert-manager cert-manager-cainjector-5d755dcf56-877dm 1/1 Running 0 44h + cert-manager cert-manager-webhook-7f7b47c4d4-qzjst 1/1 Running 0 44h + default model-store-pod 1/1 Running 0 43h + default sklearn-pvc-predictor-00001-deployment-667d9f764c-clkbn 2/2 Running 0 43h + istio-system istio-ingressgateway-79cc8bf885-lqgm7 1/1 Running 0 44h + istio-system istiod-777dc7ffbc-b4plt 1/1 Running 0 44h + knative-serving activator-59dff6d45c-28t2x 1/1 Running 0 44h + knative-serving autoscaler-dbf4d8d66-4wj8f 1/1 Running 0 44h + knative-serving controller-6bfd96676f-rdlxl 1/1 Running 0 44h + knative-serving net-istio-controller-6ff9b86f6b-9trb8 1/1 Running 0 44h + knative-serving net-istio-webhook-845d4d74b4-r9d8z 1/1 Running 0 44h + knative-serving webhook-678bd64859-q4ghb 1/1 Running 0 44h + kserve kserve-controller-manager-f9c5984c5-xz7lp 2/2 Running 0 44h **Deploy inference service** **Prerequisites** - * Verify that the inference service is up and running using the command: ``kubectl get isvc -A``. + * To deploy a model joblib file with PVC as model storage, `click here `_ + * Verify that the inference service is up and running using the command: ``kubectl get isvc -A``.:: + + root@sparknode1:/tmp# kubectl get isvc -A + NAMESPACE NAME URL READY PREV LATEST PREVROLLEDOUTREVISION LATESTREADYREVISION AGE + default sklearn-pvc http://sklearn-pvc.default.example.com True 100 sklearn-pvc-predictor-00001 9m18s + + * Pull the intended inference model and the corresponding runtime-specific images into the nodes. * As part of the deployment, Omnia deploys `standard model runtimes. `_ If a custom model is deployed, deploy a custom runtime first. + * To avoid problems with image to digest mapping when pulling inference runtime images, `click here. <../../Troubleshooting/KnownIssues.html>`_ + **Access the inference service** -1. Use ``kubectl get svc -A`` to check the external IP of the service ``istio-ingressgateway``. +1. Use ``kubectl get svc -A`` to check the external IP of the service ``istio-ingressgateway``. :: + + root@sparknode1:/tmp# kubectl get svc -n istio-system + NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE + istio-ingressgateway LoadBalancer 10.233.30.227 10.20.0.101 15021:32743/TCP,80:30134/TCP,443:32241/TCP 44h + istiod ClusterIP 10.233.18.185 15010/TCP,15012/TCP,443/TCP,15014/TCP 44h + knative-local-gateway ClusterIP 10.233.37.248 80/TCP 44h + 2. To access inferencing from the ingressgateway with HOST header, run the below command: :: curl -v -H "Host: " -H "Content-Type: application/json" "http://:/v1/models/:predict" -d @./iris-input.json For example: :: - curl -v -H "Host: sklearn-pvc.default.example.com" -H "Content-Type: application/json" "http://10.20.0.101:80/v1/models/sklearn-pvc:predict" -d @./iris-input.json + root@sparknode2:/tmp# curl -v -H "Host: sklearn-pvc.default.example.com" -H "Content-Type: application/json" "http://10.20.0.101:80/v1/models/sklearn-pvc:predict" -d @./iris-input.json + * Trying 10.20.0.101:80... + * Connected to 10.20.0.101 (10.20.0.101) port 80 (#0) + > POST /v1/models/sklearn-pvc:predict HTTP/1.1 + > Host: sklearn-pvc.default.example.com + > User-Agent: curl/7.81.0 + > Accept: */* + > Content-Type: application/json + > Content-Length: 76 + > + * Mark bundle as not supporting multiuse + < HTTP/1.1 200 OK + < content-length: 21 + < content-type: application/json + < date: Sat, 16 Mar 2024 09:36:31 GMT + < server: istio-envoy + < x-envoy-upstream-service-time: 7 + < + * Connection #0 to host 10.20.0.101 left intact + {"predictions":[1,1]}r From 47b53bf400c2cb9d6eb05114dc65d5caac9374e2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 11:13:27 +0530 Subject: [PATCH 204/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/kserve.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index 7a0a0e002..e0c13ef61 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -80,7 +80,7 @@ Kserve is an open-source serving platform that simplifies the deployment, scalin istiod ClusterIP 10.233.18.185 15010/TCP,15012/TCP,443/TCP,15014/TCP 44h knative-local-gateway ClusterIP 10.233.37.248 80/TCP 44h -2. To access inferencing from the ingressgateway with HOST header, run the below command: :: +2. To access inferencing from the ingressgateway with HOST header, run the below command from the kube_control_plane or kube_node: :: curl -v -H "Host: " -H "Content-Type: application/json" "http://:/v1/models/:predict" -d @./iris-input.json From 39cb5565a6111e6977582f57f69dfb7abd6cafbd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 11:27:10 +0530 Subject: [PATCH 205/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/kserve.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/kserve.rst b/docs/source/Roles/Platform/kserve.rst index e0c13ef61..a40b36f6f 100644 --- a/docs/source/Roles/Platform/kserve.rst +++ b/docs/source/Roles/Platform/kserve.rst @@ -105,7 +105,7 @@ For example: :: < x-envoy-upstream-service-time: 7 < * Connection #0 to host 10.20.0.101 left intact - {"predictions":[1,1]}r + {"predictions":[1,1]} From f901f9185c38dd668c3eb5a14517f6f842023e69 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 13:36:03 +0530 Subject: [PATCH 206/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Platform/index.rst b/docs/source/Roles/Platform/index.rst index 0a97495a4..04a942a02 100644 --- a/docs/source/Roles/Platform/index.rst +++ b/docs/source/Roles/Platform/index.rst @@ -5,8 +5,8 @@ If you want to install JupyterHub and Kubeflow playbooks, you have to first inst Commands to install JupyterHub and Kubeflow: :: - ansible-playbook platforms/jupyterhub.yml -i inventory - ansible-playbook platforms/kubeflow.yml -i inventory + ansible-playbook tools/jupyterhub.yml -i inventory + ansible-playbook tools/kubeflow.yml -i inventory .. note:: When the Internet connectivity is unstable or slow, it may take more time to pull the images to create the Kubeflow containers. If the time limit is exceeded, the **Apply Kubeflow configurations** task may fail. To resolve this issue, you must redeploy Kubernetes cluster and reinstall Kubeflow by completing the following steps: From c5f943f4f92fd82d5859e4aad5d347ac6d62fcd4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 13:50:14 +0530 Subject: [PATCH 207/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 374069dea..d4e6d950a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -56,6 +56,7 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. * Nodes must be booted and the service tag must be in the DB for nodes to list in the Inventory file. + * Nodes are not removed from the inventory files even if they are physically disconnected. Ensure to run the `delete node playbook <../deletenode.html#delete-provisioned-node>`_ to remove the node. * To regenerate an inventory file, use the playbook ``omnia/utils/inventory_tagging.yml``. From 66ab04b348b5486b6ec1fdaa6bfc74ce6009bb55 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 13:52:46 +0530 Subject: [PATCH 208/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index d4e6d950a..23a1bfefb 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -60,6 +60,8 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, * To regenerate an inventory file, use the playbook ``omnia/utils/inventory_tagging.yml``. + :: + cd prepare_cp ansible-playbook prepare_cp.yml From 18e18da63343390ee81d11a920c3afe51fc7019f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:05:45 +0530 Subject: [PATCH 209/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index 9b5b0dedd..39a63f83c 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -139,8 +139,8 @@ For a list of repositories (and their types) configured for kubernetes, view the .. csv-table:: Parameters for Local Repository Configuration :file: ../../Tables/local_repo_config.csv :header-rows: 1 + :widths: auto :keepspace: - :class: longtable 3. Run the following commands: :: From 45e5e548be3702333fd9a3a823f20a090bba3159 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:10:26 +0530 Subject: [PATCH 210/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index 39a63f83c..ef8352ddc 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -140,7 +140,6 @@ For a list of repositories (and their types) configured for kubernetes, view the :file: ../../Tables/local_repo_config.csv :header-rows: 1 :widths: auto - :keepspace: 3. Run the following commands: :: From 44ac4433eb8a2f5acd5e847ed0ac3e185e9317bd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:17:38 +0530 Subject: [PATCH 211/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index bdda09736..d97e39667 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -10,6 +10,7 @@ .wy-table-responsive { display: block; width: fit-content; + table-layout: fixed; block-size: fit-content; overflow: visible !important; max-width: 750px; From be57e0b1035c9f70ba1cfd78df9f029172f7c2b0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:27:08 +0530 Subject: [PATCH 212/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 1 + docs/source/_static/theme.css | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index d97e39667..0b65eeb4f 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -16,3 +16,4 @@ max-width: 750px; } + diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index 9f79ab122..ec7e78cea 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -3,6 +3,7 @@ } .wy-nav-content { background-color: #ffffff; + width: 800px; } .wy-side-nav-search img { display: block; From 1f81415c36678a7156a4f490d25bd477b50e4a86 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:38:33 +0530 Subject: [PATCH 213/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 0b65eeb4f..eb72276f8 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -12,8 +12,7 @@ width: fit-content; table-layout: fixed; block-size: fit-content; - overflow: visible !important; + overflow: auto !important; max-width: 750px; } - From 2a68578acabfc63ea8c966d3f8261330bcc80739 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:50:08 +0530 Subject: [PATCH 214/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index eb72276f8..79d177dd5 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -1,18 +1,26 @@ .wy-table-responsive table td { white-space: inherit !important; word-break: break-all; !important; + overflow-wrap: break-word; !important; } .wy-table-responsive table th { background-color: #2980b9; color: white; } + +.wy-table-responsive table#id2 { + max-width: 750px; + overflow-wrap: break-word; + +} + .wy-table-responsive { display: block; width: fit-content; table-layout: fixed; block-size: fit-content; - overflow: auto !important; + overflow: visible !important; max-width: 750px; } From f01b0ba3e766cd721a99226bc4e3bd81a43044cd Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 14:55:32 +0530 Subject: [PATCH 215/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 79d177dd5..19097a4be 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -12,6 +12,8 @@ .wy-table-responsive table#id2 { max-width: 750px; overflow-wrap: break-word; + background-color: #b92989 + } From bb759b06d65e721889f655131445d4952518d526 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:03:01 +0530 Subject: [PATCH 216/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 19097a4be..f946390ff 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -10,10 +10,9 @@ } .wy-table-responsive table#id2 { - max-width: 750px; + max-width: 750px; !important; overflow-wrap: break-word; - background-color: #b92989 - + } From 0fada1606ce79c1629c2ffe5aa580435bf2b5e30 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:10:13 +0530 Subject: [PATCH 217/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index f946390ff..7de0f3bcb 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -11,7 +11,9 @@ .wy-table-responsive table#id2 { max-width: 750px; !important; - overflow-wrap: break-word; + overflow-wrap: anywhere; + word-break: break-all; !important; + overflow: scroll; } From c2cab5429d660af76a7204a43eac4fa12aef0aaa Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:31:00 +0530 Subject: [PATCH 218/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 2 -- docs/source/_static/theme.css | 5 +++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 7de0f3bcb..e40b9617b 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -14,8 +14,6 @@ overflow-wrap: anywhere; word-break: break-all; !important; overflow: scroll; - - } .wy-table-responsive { diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index ec7e78cea..be2779df0 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -74,6 +74,7 @@ /* Main content ==================================================== */ + .wy-nav-content .highlight, .wy-nav-content .rst-content .warning { background: rgba(238, 238, 238, 0.78); @@ -96,6 +97,10 @@ color: rgb(7, 7, 7); } +.wy-nav-content .highlight .rst-content pre.literal-block{ + word-break: break-all; +} + .wy-nav-content a.reference { color: rgb(41, 128, 185); } From f81538d2f6ab0236f82aafb9712c1752bb6226ae Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:37:46 +0530 Subject: [PATCH 219/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index be2779df0..3a3e527f7 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -97,7 +97,7 @@ color: rgb(7, 7, 7); } -.wy-nav-content .highlight .rst-content pre.literal-block{ + .wy-nav-content .rst-content .linenodiv pre, .rst-content div[class^=highlight] pre, .rst-content pre.literal-block{ word-break: break-all; } From 15ae36f3c005e1b2760c1d18db7a2c16026a27cc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:44:03 +0530 Subject: [PATCH 220/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 1 + docs/source/_static/theme.css | 3 --- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index e40b9617b..c652c18bf 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -14,6 +14,7 @@ overflow-wrap: anywhere; word-break: break-all; !important; overflow: scroll; + text-wrap: wrap; } .wy-table-responsive { diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index 3a3e527f7..d46e03af7 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -97,9 +97,6 @@ color: rgb(7, 7, 7); } - .wy-nav-content .rst-content .linenodiv pre, .rst-content div[class^=highlight] pre, .rst-content pre.literal-block{ - word-break: break-all; -} .wy-nav-content a.reference { color: rgb(41, 128, 185); From ef08e63314f1c8b25cf6074a4d73bc4f69953279 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:46:58 +0530 Subject: [PATCH 221/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index c652c18bf..7c19afe2f 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -13,8 +13,7 @@ max-width: 750px; !important; overflow-wrap: anywhere; word-break: break-all; !important; - overflow: scroll; - text-wrap: wrap; + overflow: scroll; !important; } .wy-table-responsive { From 9f1619fb0d3c3d4c0e461bf91170118e50ca57cb Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 15:52:03 +0530 Subject: [PATCH 222/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 7c19afe2f..1fb86334d 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -14,6 +14,7 @@ overflow-wrap: anywhere; word-break: break-all; !important; overflow: scroll; !important; + width: 750px; } .wy-table-responsive { From 8d03cbf4e21dcf3c8ebb6beb3a5d3e6d69a71e33 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 16:03:48 +0530 Subject: [PATCH 223/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/theme.css | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index d46e03af7..64b63839f 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -23,8 +23,10 @@ cursor: pointer; *zoom: 1; } -.rst-content code.literal { +.rst-content div[class^=highlight], .rst-content pre.literal-block { word-break: break-all; !important; + overflow-x: scroll ; + width: 400px; } .wy-side-nav-search .wy-dropdown>a img.logo, .wy-side-nav-search>a img.logo { @@ -98,6 +100,7 @@ } + .wy-nav-content a.reference { color: rgb(41, 128, 185); } From d60c1238ebbf68da306701713ab846ddfb3713c6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 16:23:48 +0530 Subject: [PATCH 224/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/theme.css | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index 64b63839f..6017b10ef 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -23,10 +23,12 @@ cursor: pointer; *zoom: 1; } -.rst-content div[class^=highlight], .rst-content pre.literal-block { - word-break: break-all; !important; - overflow-x: scroll ; - width: 400px; + +.wy-nav-content .rst.highlight-default.notranslate { + + width: 550px; + + } .wy-side-nav-search .wy-dropdown>a img.logo, .wy-side-nav-search>a img.logo { From eb0082c13f1ff12feb4c119be4126080b2c2e5a3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 16:43:48 +0530 Subject: [PATCH 225/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/theme.css | 6 ------ docs/source/samplefiles.rst | 5 ----- 2 files changed, 11 deletions(-) diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index 6017b10ef..5d813ce9a 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -24,12 +24,6 @@ *zoom: 1; } -.wy-nav-content .rst.highlight-default.notranslate { - - width: 550px; - - -} .wy-side-nav-search .wy-dropdown>a img.logo, .wy-side-nav-search>a img.logo { display: block; diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index fa50e694c..144639b44 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -74,11 +74,6 @@ inventory file - [calico_rr] - - #node7 - - pxe_mapping_file.csv ------------------------------------ From 1edef6521c13182935581fd9937837da7427ccb3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 16:55:24 +0530 Subject: [PATCH 226/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 1fb86334d..6634a833e 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -13,7 +13,7 @@ max-width: 750px; !important; overflow-wrap: anywhere; word-break: break-all; !important; - overflow: scroll; !important; + overflow: auto; !important; width: 750px; } From 3e1fa30438fe1775e26031c025df9482768e4780 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 17:03:52 +0530 Subject: [PATCH 227/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 6634a833e..d19bcd727 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -9,13 +9,9 @@ } -.wy-table-responsive table#id2 { - max-width: 750px; !important; - overflow-wrap: anywhere; - word-break: break-all; !important; - overflow: auto; !important; - width: 750px; -} + .rst-content div[class^=highlight], .rst-content pre.literal-block { + width: 650px; + } .wy-table-responsive { display: block; From 4201bc1b2b532defd63102fa54edf8a22adb6411 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 17:14:31 +0530 Subject: [PATCH 228/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index d19bcd727..f406b0145 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -6,11 +6,12 @@ .wy-table-responsive table th { background-color: #2980b9; color: white; - } .rst-content div[class^=highlight], .rst-content pre.literal-block { - width: 650px; + width: 600px; + overflow-x: unset; + } .wy-table-responsive { From 6faae62580f3ab449fdb86e4b5d433a91bb8cad1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 17:20:17 +0530 Subject: [PATCH 229/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/theme.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index 5d813ce9a..8c5defa5c 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -3,7 +3,7 @@ } .wy-nav-content { background-color: #ffffff; - width: 800px; + width: 1000px; } .wy-side-nav-search img { display: block; From d8b843c193abfe34cc9c03a0707eb98d6caf16a8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 17:29:15 +0530 Subject: [PATCH 230/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index f406b0145..1f22e9e2a 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -2,6 +2,7 @@ white-space: inherit !important; word-break: break-all; !important; overflow-wrap: break-word; !important; + background-color: white; } .wy-table-responsive table th { background-color: #2980b9; @@ -11,7 +12,6 @@ .rst-content div[class^=highlight], .rst-content pre.literal-block { width: 600px; overflow-x: unset; - } .wy-table-responsive { From 0944e86712119ffb04392d9268e88ce0e8e023b1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 18 Mar 2024 17:34:03 +0530 Subject: [PATCH 231/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 1f22e9e2a..0785733df 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -4,6 +4,8 @@ overflow-wrap: break-word; !important; background-color: white; } + + .wy-table-responsive table th { background-color: #2980b9; color: white; @@ -14,6 +16,10 @@ overflow-x: unset; } + .rst-content table.docutils td, .rst-content table.field-list td, .wy-table td { + background-color: white; + } + .wy-table-responsive { display: block; width: fit-content; From 3820c5ea5bd4ea580adb6eed260ac16638380f82 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 08:12:31 +0530 Subject: [PATCH 232/309] Updating documentation Signed-off-by: goveac --- docs/source/Tables/software_config.csv | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index 1e0293ebc..fb8b5f2da 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -24,7 +24,11 @@ Required","* The type of offline configuration user needs. * When the value is set to ``partial``, Omnia creates a local repository/registry on the Control plane hosting all the packages/images except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. * When the value is set to ``never``, Omnia does not create a local repository/registry. All the packages/images are directly downloaded on the cluster. .. note:: All local repositories that are not available as images or RPMs will be configured locally. -* **Accepted values**: always, **partial**, and never. +* **Accepted values**: + + * ``always`` + * ``partial`` <- Default + * ``never`` " "**softwares** From ed07a63a765edbb06f6973aa38b303f48e857d4d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 11:44:17 +0530 Subject: [PATCH 233/309] Updating documentation Signed-off-by: goveac --- .../BuildingClusters/schedulerinputparams.rst | 2 +- .../DiscoveryMechanisms/bmc.rst | 1 + .../provisionparams.rst | 80 ++++++++++--------- .../provisionprereqs.rst | 14 +--- docs/source/InstallationGuides/deletenode.rst | 10 +-- .../SupportMatrix/OperatingSystems/RedHat.rst | 4 +- .../SupportMatrix/OperatingSystems/Rocky.rst | 4 +- .../SupportMatrix/OperatingSystems/Ubuntu.rst | 6 +- docs/source/Overview/releasenotes.rst | 5 ++ .../Roles/Platform/InstallJupyterhub.rst | 4 +- docs/source/Roles/Platform/Pytorch.rst | 3 +- docs/source/Roles/Platform/SetupvLLM.rst | 5 +- docs/source/Roles/Platform/TensorFlow.rst | 10 +-- docs/source/Roles/Platform/index.rst | 19 +---- docs/source/Roles/Platform/kserve.rst | 2 + docs/source/Roles/Platform/kubeflow.rst | 11 +++ docs/source/Tables/software_config.csv | 3 +- docs/source/samplefiles.rst | 6 -- 18 files changed, 99 insertions(+), 90 deletions(-) create mode 100644 docs/source/Roles/Platform/kubeflow.rst diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst index 327ddaf61..d67a6e1bc 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerinputparams.rst @@ -7,7 +7,7 @@ These parameters are located in ``input/omnia_config.yml``, ``input/security_con **omnia_config.yml** -.. csv-table:: Parameters for kubernetes +.. csv-table:: Parameters for kubernetes setup :file: ../../Tables/scheduler_k8s.csv :header-rows: 1 :keepspace: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 23a890b28..fb0ce7082 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -27,6 +27,7 @@ For automatic provisioning of servers and discovery, the BMC method can be used. - All target servers should be reachable from the ``admin_network`` specified in ``input/network_spec.yml``. +* BMC network details should be provided in the ``input/network_spec.yml`` file. *When entering details in ``input/network_spec.yml``* * Ensure that the netmask bits for the BMC network and the admin network are the same. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 3b4c4cd65..f6214f6bc 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -23,41 +23,49 @@ Fill in all required parameters in ``input/provision_config.yml``, ``provision_c .. [1] Boolean parameters do not need to be passed with double or single quotes. -Update the ``input/network_spec.yml`` file for all networks available for use by the control plane. A sample is provided below: :: - - --- - Networks: - - admin_network: - nic_name: "eno1" - netmask_bits: "16" - static_range: "10.5.0.1-10.5.0.200" - dynamic_range: "10.5.1.1-10.5.1.200" - network_gateway: "" - DNS: "" - MTU: "1500" - - - bmc_network: - nic_name: "" - netmask_bits: "" - static_range: "" - dynamic_range: "" - discover_ranges: "" - network_gateway: "" - MTU: "1500" - - # - thor_network1: - # netmask_bits: "20" - # CIDR: "10.10.16.0" - # network_gateway: "" - # MTU: "1500" - # VLAN: "" - - # - thor_network2: - # netmask_bits: "20" - # static_range: "10.10.1.1-10.10.15.254" - # network_gateway: "" - # MTU: "1500" - # VLAN: "1" +Update the ``input/network_spec.yml`` file for all networks available for use by the control plane. + + * The following ``admin_nic`` details are mandatory. + * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. + * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. + * ``static_range``: The static range of IPs to be provisioned on target nodes. + * ``dynamic_range``: The + * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. + * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. + + * If the ``nic_name`` is the same on both the admin_network and the bmc_network, a LOM setup is assumed. + * BMC network details are not required when target nodes are discovered using a mapping file. + * If ``bmc_network`` properties are provided, target nodes will be discovered using the BMC method. + + +A sample is provided below: :: + + --- + Networks: + - admin_network: + nic_name: "eno1" + netmask_bits: "16" + static_range: "10.5.0.1-10.5.0.200" + dynamic_range: "10.5.1.1-10.5.1.200" + correlation_to_admin: true + admin_uncorrelated_node_start_ip: "10.5.0.50" + network_gateway: "" + DNS: "" + MTU: "1500" + + - bmc_network: + nic_name: "" + netmask_bits: "" + static_range: "" + dynamic_range: "" + reassignment_to_static: true + discover_ranges: "" + network_gateway: "" + MTU: "1500" + + + + .. note:: @@ -72,7 +80,7 @@ Update the ``input/network_spec.yml`` file for all networks available for use by ansible-vault edit provision_config_credentials.yml --vault-password-file .provision_vault_key * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. Also, the properties ``nic_name``, ``static_range``, and ``dynamic_range`` cannot be edited on subsequent runs of the provision tool. - * Netmask bits is mandatory and should be same for both the ``admin_network`` and ``bmc_network`` (ie between 1 and 32; 1 and 32 are acceptable values). + * Netmask bits are mandatory and should be same for both the ``admin_network`` and ``bmc_network`` (ie between 1 and 32; 1 and 32 are acceptable values). * Ensure that the CIDR is aligned with the ``netmask_bits`` provided. * The ``discover_ranges`` property of the ``bmc_network`` can accept multiple comma-separated ranges. * The ``VLAN`` property is optional but should be between 0 and 4095 (0 and 4095 are not acceptable values). diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index b49769f76..6ed47f084 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -1,7 +1,9 @@ Before you run the provision tool --------------------------------- -* (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14.13 `_ and `Python 3.9 `_ are installed on the system. SELinux should also be disabled. +* (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14.14 `_ and `Python 3.9 `_ are installed on the system. + +* All target bare-metal servers should be reachable to the chosen control plane. * Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. @@ -67,12 +69,6 @@ Note the compatibility between cluster OS and control plane OS below: .. [1] Ensure that control planes running RHEL have an active subscription or are configured to access local repositories. The following repositories should be enabled on the control plane: **AppStream**, **Code Ready Builder (CRB)**, **BaseOS**. For RHEL control planes running 8.5 and below, ensure that sshpass is additionally available to install or download to the control plane (from any local repository). -* To **optionally** set up CUDA and OFED using the provisioning tool, download the required repositories to the control plane from here to deploy on the target nodes: - - 1. `For NVIDIA GPUs: `_: CUDA is a parallel computing platform and application programming interface that allows software to use certain types of graphics processing units for general purpose processing, an approach called general-purpose computing on GPUs. - - 2. `For Mellanox `_: OFED (OpenFabrics Enterprise Distribution) is open-source software for RDMA and kernel bypass applications. OFED can be used in business, research and scientific environments that require highly efficient networks, storage connectivity and parallel computing. - * Ensure that all connection names under the network manager match their corresponding device names. To verify network connection names: :: @@ -90,8 +86,6 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. -* Users should also ensure that all repos (AppStream, BaseOS and CRB) are available on the RHEL control plane. - .. note:: * Enable a repository from your RHEL subscription, run the following commands: :: @@ -143,8 +137,6 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf RHEL-8-crb-partners Red Hat Enterprise Linux 8.6.0 Partners (CRB) -* Ensure that the ``pxe_nic`` and ``public_nic`` are in the firewalld zone: public. - .. note:: * After configuration and installation of the cluster, changing the control plane is not supported. If you need to change the control plane, you must redeploy the entire cluster. diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst index de071bbce..8b0d6b737 100644 --- a/docs/source/InstallationGuides/deletenode.rst +++ b/docs/source/InstallationGuides/deletenode.rst @@ -42,16 +42,16 @@ Use this playbook to stop all Slurm and Kubernetes services. This action will de Run the playbook using the following commands: :: cd utils - ansible-playbook reset_cluster_config.yml -i inventory + ansible-playbook reset_cluster_configuration.yml -i inventory To specify only Slurm or Kubernetes nodes while running the playbook, use the tags ``slurm_node`` or ``kube_node``. That is: -To reset only slurm nodes, use ``ansible-playbook reset_cluster_config.yml -i inventory --tags slurm_node``. -To reset only kubernetes nodes, use ``ansible-playbook reset_cluster_config.yml -i inventory --tags kube_node``. +To reset only slurm nodes, use ``ansible-playbook reset_cluster_configuration.yml -i inventory --tags slurm_node``. +To reset only kubernetes nodes, use ``ansible-playbook reset_cluster_configuration.yml -i inventory --tags kube_node``. -To skip confirmation while running the playbook, use ``ansible-playbook reset_cluster_config.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. +To skip confirmation while running the playbook, use ``ansible-playbook reset_cluster_configuration.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. -The inventory file passed for ``reset_cluster_config`` should follow the below format: +The inventory file passed for ``reset_cluster_configuration`` should follow the below format: *For a slurm cluster* :: diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst index 54bf6577f..09c016c8e 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst @@ -4,11 +4,13 @@ Red Hat Enterprise Linux ========== ============= ============= OS Version Control Plane Cluster Nodes ========== ============= ============= -8.6 Yes Yes +8.6 [1]_ Yes Yes 8.7 Yes Yes 8.8 Yes Yes ========== ============= ============= +.. [1]:: This version of RHEL does not support vLLM installation via Omnia. + .. note:: * Always deploy the DVD Edition of the OS on cluster nodes to access offline repos. * For RHEL 8.5 and below, ensure that RHEL subscription is enabled OR sshpass is available to install or download to the control plane (from any local repository). diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst index 035bd6900..64c19cd28 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst @@ -8,11 +8,13 @@ Rocky +============+===============+===============+ | 8.6 | Yes | No | +------------+---------------+---------------+ -| 8.7 | Yes | No | +| 8.7 [1]_ | Yes | No | +------------+---------------+---------------+ | 8.8 | Yes | Yes | +------------+---------------+---------------+ +.. [1]:: This version of Rocky does not support vLLM installation via Omnia. + .. note:: * Always deploy the DVD (Full) Edition of the OS on cluster nodes. * AMD ROCm driver installation is not supported by Omnia on Rocky cluster nodes. diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst index 53c8890b5..df6c3a64d 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst @@ -4,6 +4,8 @@ Ubuntu ========== ============= ============= OS Version Control Plane Cluster Nodes ========== ============= ============= -20.04 Yes Yes +20.04 [1]_ Yes Yes 22.04 Yes Yes -========== ============= ============= \ No newline at end of file +========== ============= ============= + +.. [1]:: This version of Ubuntu does not support vLLM installation via Omnia. \ No newline at end of file diff --git a/docs/source/Overview/releasenotes.rst b/docs/source/Overview/releasenotes.rst index 33c89d3de..1a7f6c6fc 100644 --- a/docs/source/Overview/releasenotes.rst +++ b/docs/source/Overview/releasenotes.rst @@ -1,6 +1,11 @@ Releases ============ +1.6 +---- + +TBD + 1.5 ---- diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 7f68b2019..7061c665e 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -7,8 +7,8 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Ensure the kubernetes cluster is setup and working. If NVidia or AMD GPU acceleration is required for the notebook, install the Kubernetes NVidia or AMD GPU device plugin during Kubernetes deployment. * Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. -* Review the ``omnia/tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. -* Update the ``omnia/input/software_config.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. +* Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. +* Update the ``input/config/`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. diff --git a/docs/source/Roles/Platform/Pytorch.rst b/docs/source/Roles/Platform/Pytorch.rst index 5b1371b8b..172a1c518 100644 --- a/docs/source/Roles/Platform/Pytorch.rst +++ b/docs/source/Roles/Platform/Pytorch.rst @@ -8,7 +8,7 @@ PyTorch is a popular open-source deep learning framework, renowned for its dynam * Ensure nerdctl is available on all cluster nodes. -* If GPUs are present on the target nodes, install NVidia (CUDA 12.1) or AMD (Rocm 5.7) drivers during provisioning. CPUs do not require any additional drivers.PyTorch +* If GPUs are present on the target nodes, install NVidia CUDA (with containerd) or AMD Rocm 5.7 drivers during provisioning. CPUs do not require any additional drivers. * Use ``local_repo.yml`` to create an offline PyTorch repository. For more information, `click here. <../../InstallationGuides/LocalRepo/PyTorch.html>`_ @@ -22,7 +22,6 @@ PyTorch is a popular open-source deep learning framework, renowned for its dynam * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. - * Container Network Interface should be enabled with nerdctl. **Deploying PyTorch** diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index b2d5e2c64..b4f09028c 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -7,8 +7,11 @@ For NVidia, vLLM is a Python library that also contains pre-compiled C++ and CUD With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. After the deployment of vLLM, access the vllm container (AMD GPU) and import the vLLM Python package (NVIDIA GPU). For more information, `click here `_ +.. note:: This playbook was validated using Ubuntu 22.04 and RHEL 8.8. + **Pre requisites** +* Ensure nerdctl and containerd is available on all cluster nodes. * Only AMD GPUs from the MI200s (gfx90a) are supported. @@ -32,7 +35,7 @@ With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. * Nerdctl does not support mounting directories as devices because it is not a feature of containerd (The runtime that nerdctl uses). Individual files need to be attached while running nerdctl. -.. note:: This playbook was validated using Ubuntu 22.04 and RHEL 8.8. + **Deploying vLLM** diff --git a/docs/source/Roles/Platform/TensorFlow.rst b/docs/source/Roles/Platform/TensorFlow.rst index 51fb71c56..30204fd5b 100644 --- a/docs/source/Roles/Platform/TensorFlow.rst +++ b/docs/source/Roles/Platform/TensorFlow.rst @@ -8,9 +8,9 @@ With an Ansible script, deploy TensorFlow on both ``kube_nodes`` and the ``kube_ **Prerequisites** -* Ensure nerdctl is available on all cluster nodes. +* Ensure nerdctl= is available on all cluster nodes. -* If GPUs are present on the target nodes, install NVidia (CUDA 12.1) or AMD (Rocm 5.7) drivers during provisioning. CPUs do not require any additional drivers.PyTorch +* If GPUs are present on the target nodes, install NVidia CUDA (with containerd) or AMD ROCm drivers during provisioning. CPUs do not require any additional drivers.PyTorch * Use ``local_repo.yml`` to create an offline TensorFlow repository. For more information, `click here <../../>`_. @@ -39,7 +39,7 @@ With an Ansible script, deploy TensorFlow on both ``kube_nodes`` and the ``kube_ **Accessing TensorFlow (CPU)** -1. Verify that the PyTorch image present in container engine images: :: +1. Verify that the tensorflow image present in container engine images: :: nerdctl images @@ -52,7 +52,7 @@ For more information, `click here `_. **Accessing TensorFlow (AMD)** -1. Verify that the PyTorch image present in container engine images: :: +1. Verify that the tensorflow image present in container engine images: :: nerdctl images @@ -64,7 +64,7 @@ For more information, `click here //``. input/config/// - " +.. note:: The accepted names for software is taken from ``input/config///``." diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index 144639b44..8bf2be3d9 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -54,12 +54,6 @@ inventory file # node1 - # node2in - - # node3 - - - [kube_node] # node2 From 9fb54eda8964e4ca51762aa99fdb43c3444f5537 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 11:50:47 +0530 Subject: [PATCH 234/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 2 +- docs/source/Roles/Platform/Pytorch.rst | 2 +- docs/source/Roles/Platform/SetupvLLM.rst | 6 ++---- docs/source/Roles/Platform/TensorFlow.rst | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 7061c665e..2abde2244 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -8,7 +8,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Ensure the kubernetes cluster is setup and working. If NVidia or AMD GPU acceleration is required for the notebook, install the Kubernetes NVidia or AMD GPU device plugin during Kubernetes deployment. * Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. * Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. -* Update the ``input/config/`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. +* Update the ``input/config///jupyter.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. diff --git a/docs/source/Roles/Platform/Pytorch.rst b/docs/source/Roles/Platform/Pytorch.rst index 172a1c518..cc1343c36 100644 --- a/docs/source/Roles/Platform/Pytorch.rst +++ b/docs/source/Roles/Platform/Pytorch.rst @@ -8,7 +8,7 @@ PyTorch is a popular open-source deep learning framework, renowned for its dynam * Ensure nerdctl is available on all cluster nodes. -* If GPUs are present on the target nodes, install NVidia CUDA (with containerd) or AMD Rocm 5.7 drivers during provisioning. CPUs do not require any additional drivers. +* If GPUs are present on the target nodes, install NVidia CUDA (with containerd) or AMD Rocm drivers during provisioning. CPUs do not require any additional drivers. * Use ``local_repo.yml`` to create an offline PyTorch repository. For more information, `click here. <../../InstallationGuides/LocalRepo/PyTorch.html>`_ diff --git a/docs/source/Roles/Platform/SetupvLLM.rst b/docs/source/Roles/Platform/SetupvLLM.rst index b4f09028c..59efe0d18 100644 --- a/docs/source/Roles/Platform/SetupvLLM.rst +++ b/docs/source/Roles/Platform/SetupvLLM.rst @@ -11,15 +11,13 @@ With an Ansible script, deploy vLLM on both the kube_node and kube_control_node. **Pre requisites** -* Ensure nerdctl and containerd is available on all cluster nodes. +* Ensure nerdctl is available on all cluster nodes. * Only AMD GPUs from the MI200s (gfx90a) are supported. -* For nodes using AMD, ensure nerdctl is available. - * For nodes using NVidia, ensure that the GPU has a compute capacity that is higher than 7 (Eg: V100, T4, RTX20xx, A100, L4, H100, etc). -* Ensure the ``kube_node``, ``kube_control_node`` is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (CUDA 12.1) or AMD (RocM 5.7.0) GPU drivers during provisioning. +* Ensure the ``kube_node``, ``kube_control_node`` is setup and working. If NVidia or AMD GPU acceleration is required for the task, install the NVidia (with containerd) or AMD ROCm GPU drivers during provisioning. * Use ``local_repo.yml`` to create an offline vLLM repository. For more information, `click here. <../../InstallationGuides/LocalRepo/vLLM.html>`_ diff --git a/docs/source/Roles/Platform/TensorFlow.rst b/docs/source/Roles/Platform/TensorFlow.rst index 30204fd5b..39e7a5933 100644 --- a/docs/source/Roles/Platform/TensorFlow.rst +++ b/docs/source/Roles/Platform/TensorFlow.rst @@ -8,7 +8,7 @@ With an Ansible script, deploy TensorFlow on both ``kube_nodes`` and the ``kube_ **Prerequisites** -* Ensure nerdctl= is available on all cluster nodes. +* Ensure nerdctl is available on all cluster nodes. * If GPUs are present on the target nodes, install NVidia CUDA (with containerd) or AMD ROCm drivers during provisioning. CPUs do not require any additional drivers.PyTorch From 380c0a09b683c78ffa10feb0d1538b142336a929 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 11:58:27 +0530 Subject: [PATCH 235/309] Updating documentation Signed-off-by: goveac --- .../Overview/SupportMatrix/OperatingSystems/RedHat.rst | 6 +++--- .../Overview/SupportMatrix/OperatingSystems/Rocky.rst | 2 +- .../Overview/SupportMatrix/OperatingSystems/Ubuntu.rst | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst index 09c016c8e..e845cd9fa 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst @@ -4,12 +4,12 @@ Red Hat Enterprise Linux ========== ============= ============= OS Version Control Plane Cluster Nodes ========== ============= ============= -8.6 [1]_ Yes Yes -8.7 Yes Yes +8.6 Yes Yes +8.7 [1]_ Yes Yes 8.8 Yes Yes ========== ============= ============= -.. [1]:: This version of RHEL does not support vLLM installation via Omnia. +.. [1] This version of RHEL does not support vLLM installation via Omnia. .. note:: * Always deploy the DVD Edition of the OS on cluster nodes to access offline repos. diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst index 64c19cd28..b49947726 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Rocky.rst @@ -13,7 +13,7 @@ Rocky | 8.8 | Yes | Yes | +------------+---------------+---------------+ -.. [1]:: This version of Rocky does not support vLLM installation via Omnia. +.. [1] This version of Rocky does not support vLLM installation via Omnia. .. note:: * Always deploy the DVD (Full) Edition of the OS on cluster nodes. diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst index df6c3a64d..ff7067389 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst @@ -8,4 +8,4 @@ OS Version Control Plane Cluster Nodes 22.04 Yes Yes ========== ============= ============= -.. [1]:: This version of Ubuntu does not support vLLM installation via Omnia. \ No newline at end of file +.. [1] This version of Ubuntu does not support vLLM installation via Omnia. \ No newline at end of file From f49bd510ee1a8bd99423c13f2730abaedb04ed27 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 12:02:03 +0530 Subject: [PATCH 236/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 2abde2244..b33a59251 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -5,7 +5,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup **Prerequisites** -* Ensure the kubernetes cluster is setup and working. If NVidia or AMD GPU acceleration is required for the notebook, install the Kubernetes NVidia or AMD GPU device plugin during Kubernetes deployment. +* Ensure the kubernetes cluster is setup and working. * Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. * Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. * Update the ``input/config///jupyter.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. From 3cdff4b6248d8370ef82742995c06273b95ad7bb Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 12:05:16 +0530 Subject: [PATCH 237/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index b33a59251..7d5afdf5a 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -6,7 +6,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup **Prerequisites** * Ensure the kubernetes cluster is setup and working. -* Ensure the inventory file includes a ``kube_control_plane`` group listing all cluster nodes. +* Ensure the inventory file includes a ``kube_node`` group listing all cluster nodes. * Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. * Update the ``input/config///jupyter.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. From 26663e1a94dec6e9837432a854c10dec78b45800 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 15:43:31 +0530 Subject: [PATCH 238/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 63 +++++++++++++++++++ .../InstallingProvisionTool/index.rst | 1 + 2 files changed, 64 insertions(+) create mode 100644 docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst new file mode 100644 index 000000000..7d521fdd3 --- /dev/null +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -0,0 +1,63 @@ +Configuring additional NICs on the nodes +------------------------------------------- +After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boot up, additional NICs can be configured on target nodes using the ``nic_update.yml `` playbook. + +**Prerequisites** + + * All target nodes are provisioned and booted. `Click here to verify the status of all nodes. `_ + + * The ``input/network_spec.yml`` file has been updated with all network information including admin network and bmc network information. + + * The ``input/server_spec.yml`` file has been updated with all NIC information of the target nodes. + * All NICs listed in the ``server_spec.yml`` file are grouped into categories (groups for servers). The string "Categories:" should not be edited out of the ``input/server_spec.yml`` file. + * The property ``nicname`` is the unique identifier of NICs in the file. + * The property ``nictype`` indicates what kind of NIC is in use (ethernet, infiniband, or vlan). If the ``nictype`` is set to ``vlan``, ensure to specify a primary NIC for the VLAN using the property ``nicdevices``. + * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of ``nic_update.yml``, existing groups cannot be edited or deleted. + .. note:: The ``nicnetwork`` property should match any of the networks specified in ``input/network_spec.yml``. + + Below is a sample ``input/server_spec.yml`` file: :: + + --- + Categories: + - group-1: + - network: + - ensp0: + nicnetwork: "thor_network1" + nictypes: "ethernet" + - ensp0.5: + nicnetwork: "thor_network2" + nictypes: "vlan" + nicdevices: "ensp0" + + - group-2: + - network: + - eno1: + nicnetwork: "thor_network1" + nictypes: "ethernet" + + +Use the below commands to add the NICs: :: + + cd nic_update + ansible-playbook nic_update/nic_update -i inventory + +Where the inventory file passed includes user-defined groups,servers associated with them, and a mapping from the groups specified and the categories in ``input/server_spec.yml``. Below is a sample: :: + + [waco1] + 10.5.0.3 + + [waco1:vars] + Categories=group-1 + + [waco2] + 10.5.0.4 + 10.5.0.5 + + [waco2:vars] + Categories=group-2 + +Based on the provided sample files, server 10.5.0.3 has been mapped to waco1 which corresponds to group-1. Therefore, the NICs ensp0 and ensp0.5 will be configured in an ethernet VLAN group with ens0.5 as the primary device. + + + + diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst index e3512a183..aed089b25 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/index.rst @@ -14,4 +14,5 @@ This playbook achieves the following tasks: provisionparams installprovisiontool ViewingDB + AdditionalNIC From 27e583de5a1f170523dd8e5c65339a25b7a81ca1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 15:47:02 +0530 Subject: [PATCH 239/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index 7d521fdd3..f6cc5ea9c 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -9,11 +9,13 @@ After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boo * The ``input/network_spec.yml`` file has been updated with all network information including admin network and bmc network information. * The ``input/server_spec.yml`` file has been updated with all NIC information of the target nodes. + * All NICs listed in the ``server_spec.yml`` file are grouped into categories (groups for servers). The string "Categories:" should not be edited out of the ``input/server_spec.yml`` file. * The property ``nicname`` is the unique identifier of NICs in the file. * The property ``nictype`` indicates what kind of NIC is in use (ethernet, infiniband, or vlan). If the ``nictype`` is set to ``vlan``, ensure to specify a primary NIC for the VLAN using the property ``nicdevices``. * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of ``nic_update.yml``, existing groups cannot be edited or deleted. - .. note:: The ``nicnetwork`` property should match any of the networks specified in ``input/network_spec.yml``. + + .. note:: The ``nicnetwork`` property should match any of the networks specified in ``input/network_spec.yml``. Below is a sample ``input/server_spec.yml`` file: :: From 51105b1ae8d0b131b7ab14bf5d648082a173a2cf Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 15:50:43 +0530 Subject: [PATCH 240/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index f6cc5ea9c..ff334f248 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -13,7 +13,7 @@ After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boo * All NICs listed in the ``server_spec.yml`` file are grouped into categories (groups for servers). The string "Categories:" should not be edited out of the ``input/server_spec.yml`` file. * The property ``nicname`` is the unique identifier of NICs in the file. * The property ``nictype`` indicates what kind of NIC is in use (ethernet, infiniband, or vlan). If the ``nictype`` is set to ``vlan``, ensure to specify a primary NIC for the VLAN using the property ``nicdevices``. - * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of ``nic_update.yml``, existing groups cannot be edited or deleted. + * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of the playbook, existing groups cannot be edited or deleted. .. note:: The ``nicnetwork`` property should match any of the networks specified in ``input/network_spec.yml``. From b83ac379a5ed7c061a58ed81374ba96eb0836f27 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 15:53:37 +0530 Subject: [PATCH 241/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index ff334f248..634754265 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -17,7 +17,7 @@ After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boo .. note:: The ``nicnetwork`` property should match any of the networks specified in ``input/network_spec.yml``. - Below is a sample ``input/server_spec.yml`` file: :: +Below is a sample ``input/server_spec.yml`` file: :: --- Categories: From b7f24ce2cda54798e5035c9c634c183d9c0a7e10 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 15:56:33 +0530 Subject: [PATCH 242/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index 634754265..4d19977c1 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -1,6 +1,6 @@ Configuring additional NICs on the nodes ------------------------------------------- -After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boot up, additional NICs can be configured on target nodes using the ``nic_update.yml `` playbook. +After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boot up, additional NICs can be configured on target nodes using the ``nic_update.yml`` playbook. **Prerequisites** From ffc6292058f17f1daa282f60f79ae61a02df0407 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 19 Mar 2024 16:58:15 +0530 Subject: [PATCH 243/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/bcm_roce.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst index 9285518cc..d474774da 100644 --- a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst +++ b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst @@ -1,7 +1,7 @@ -Create local ROCe repository +Create local RoCE repository ----------------------------- -.. note:: The ROCe driver is only supported on Ubuntu clusters. +.. note:: The RoCE driver is only supported on Ubuntu clusters. 1. Enter the required values in the ``input/software_config.json`` file: @@ -12,12 +12,12 @@ Create local ROCe repository :class: longtable -To install ROCe, include the following line under ``softwares```: :: +To install RoCE, include the following line under ``softwares```: :: {"name": "bcm_roce", "version": "229.2.9.0"} -For a list of repositories (and their types) configured for ROCe, view the ``input/config/ubuntu//bcm_roce.json`` file. To customize your ROCe installation, update the file. URLs for different versions can be found `here `_: :: +For a list of repositories (and their types) configured for RoCE, view the ``input/config/ubuntu//bcm_roce.json`` file. To customize your RoCE installation, update the file. URLs for different versions can be found `here `_: :: { "bcm_roce": { @@ -33,7 +33,7 @@ For a list of repositories (and their types) configured for ROCe, view the ``inp } -.. note:: The only accepted URL for the ROCe driver is from the Dell Driver website. +.. note:: The only accepted URL for the RoCE driver is from the Dell Driver website. 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: From 4984850deec5287d2fbb90527399051b352e416a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 09:27:06 +0530 Subject: [PATCH 244/309] Updating documentation Signed-off-by: goveac --- .../Benchmarks/AutomatingOneAPI.rst | 2 +- .../Benchmarks/AutomatingOpenMPI.rst | 2 +- .../InstallationGuides/Benchmarks/OneAPI.rst | 2 +- .../BuildingClusters/Authentication.rst | 4 +- .../BuildingClusters/BeeGFS.rst | 4 +- .../BuildingClusters/index.rst | 4 - .../BuildingClusters/installscheduler.rst | 3 +- .../BuildingClusters/schedulerprereqs.rst | 4 +- .../ConfiguringStorage/index.rst | 2 +- .../LocalRepo/InputParameters.rst | 198 +++++++++++------- .../InstallationGuides/LocalRepo/PyTorch.rst | 6 + .../LocalRepo/RunningLocalRepo.rst | 143 +------------ .../LocalRepo/TensorFlow.rst | 6 + .../InstallationGuides/LocalRepo/amdgpu.rst | 24 +++ .../InstallationGuides/LocalRepo/beegfs | 28 +++ .../InstallationGuides/LocalRepo/index.rst | 1 + .../InstallationGuides/LocalRepo/jupyter.rst | 28 +++ .../InstallationGuides/LocalRepo/kserve.rst | 6 +- .../InstallationGuides/LocalRepo/kubeflow.rst | 28 +++ .../InstallationGuides/LocalRepo/vLLM.rst | 5 + docs/source/Roles/Telemetry/index.rst | 2 +- docs/source/Roles/Utils/epel.rst | 2 +- docs/source/Roles/Utils/kernel_upgrade.rst | 2 +- docs/source/Roles/Utils/rhsm_subscription.rst | 2 +- docs/source/Troubleshooting/knownissues.rst | 6 +- 25 files changed, 276 insertions(+), 238 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/amdgpu.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/beegfs create mode 100644 docs/source/InstallationGuides/LocalRepo/jupyter.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/kubeflow.rst diff --git a/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst b/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst index 264fba516..71e616269 100644 --- a/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst +++ b/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst @@ -6,7 +6,7 @@ This topic explains how to automatically update servers for MPI jobs. To manuall **Pre-requisites** * ``provision.yml`` has been executed. -* An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 manager and 1 compute. +* An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 slurm_control_node and 1 slurm_node. * Verify that the target nodes are in the ``booted`` state. For more information, `click here <../InstallingProvisionTool/ViewingDB.html>`_. **To run the playbook**:: diff --git a/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst b/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst index c772bfbe4..452016d00 100644 --- a/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst +++ b/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst @@ -6,7 +6,7 @@ This topic explains how to automatically update AMD servers for MPI jobs. To man **Pre-requisites** * ``provision.yml`` has been executed. -* An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 manager and 1 compute. +* An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 slurm_control_node and 1 slurm_node. * Verify that the target nodes are in the ``booted`` state. For more information, `click here <../InstallingProvisionTool/ViewingDB.html>`_. **To run the playbook**:: diff --git a/docs/source/InstallationGuides/Benchmarks/OneAPI.rst b/docs/source/InstallationGuides/Benchmarks/OneAPI.rst index e8c1c9cb4..28f5d6419 100644 --- a/docs/source/InstallationGuides/Benchmarks/OneAPI.rst +++ b/docs/source/InstallationGuides/Benchmarks/OneAPI.rst @@ -5,7 +5,7 @@ This topic explains how to manually install oneAPI for MPI jobs. To install oneA **Pre-requisites** -* An Omnia **slurm** cluster running with at least 2 nodes: 1 manager and 1 compute. +* An Omnia **slurm** cluster running with at least 2 nodes: 1 slurm_control_node and 1 slurm_node. * Verify that the target nodes are in the ``booted`` state. For more information, `click here <../InstallingProvisionTool/ViewingDB.html>`_. diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index f2678a6b5..8f747666b 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -155,11 +155,11 @@ To customize your installation of FreeIPA, enter the following parameters in ``i +=========================+=================================================================+=======================================================================================================================================================+ | kerberos_admin_password | "admin" user password for the IPA server on RockyOS and RedHat. | The password can be found in the file ``input/security_config.yml`` . | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ipa_server_hostname | The hostname of the IPA server | The hostname can be found on the manager node. | +| ipa_server_hostname | The hostname of the IPA server | The hostname can be found on the control plane. | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ | domain_name | Domain name | The domain name can be found in the file ``input/security_config.yml``. | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ -| ipa_server_ipadress | The IP address of the IPA server | The IP address can be found on the IPA server on the manager node using the ``ip a`` command. This IP address should be accessible from the NFS node. | +| ipa_server_ipadress | The IP address of the IPA server | The IP address can be found on the IPA server on the control plane using ``ip a``. This IP address should be accessible from the NFS node. | +-------------------------+-----------------------------------------------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst index 0f76599fe..d361344e3 100644 --- a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst @@ -43,8 +43,6 @@ To open the ports required, use the following steps: -* Ensure that the nodes in the inventory have been assigned **only** these roles: manager and compute. - * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to set up BeeGFS on RHEL cluster nodes. * For RHEL cluster nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all cluster nodes. Every cluster node will require a RedHat subscription. @@ -56,7 +54,7 @@ To open the ports required, use the following steps: **Installing the BeeGFS client via Omnia** -After the required parameters are filled in ``input/storage_config.yml``, Omnia installs BeeGFS on manager and compute nodes while executing the ``omnia.yml`` playbook. +After the required parameters are filled in ``input/storage_config.yml``, Omnia installs BeeGFS on all nodes while executing the ``storage.yml`` playbook. .. caution:: Do not remove or comment any lines in the ``input/storage_config.yml`` file. diff --git a/docs/source/InstallationGuides/BuildingClusters/index.rst b/docs/source/InstallationGuides/BuildingClusters/index.rst index 4dfe7ef50..350af9ef6 100644 --- a/docs/source/InstallationGuides/BuildingClusters/index.rst +++ b/docs/source/InstallationGuides/BuildingClusters/index.rst @@ -11,10 +11,6 @@ Configuring the cluster * Kubernetes: Once all the required parameters in `omnia_config.yml `_ are filled in, ``omnia.yml`` can be used to set up kubernetes. - * BeeGFS bolt on installation: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up BeeGFS. - - * NFS support: Once all the required parameters in `storage_config.yml `_ are filled in, ``omnia.yml`` can be used to set up NFS. - .. toctree:: schedulerinputparams schedulerprereqs diff --git a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst index 520046c94..149c24bbf 100644 --- a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst +++ b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst @@ -18,8 +18,7 @@ Building clusters i. ``security.yml``: This playbook sets up centralized authentication (LDAP/FreeIPA) on the cluster. For more information, `click here. `_ ii. ``scheduler.yml``: This playbook sets up job schedulers (Slurm or Kubernetes) on the cluster. - iii. ``storage.yml``: This playbook sets up storage tools like `BeeGFS `_ and `NFS `_. - iv. ``telemetry.yml``: This playbook sets up `Omnia telemetry and/or iDRAC telemetry <../../Roles/Telemetry/index.html>`_. It also installs `Grafana `_ and `Loki `_ as Kubernetes pods. + iii. ``telemetry.yml``: This playbook sets up `Omnia telemetry and/or iDRAC telemetry <../../Roles/Telemetry/index.html>`_. It also installs `Grafana `_ and `Loki `_ as Kubernetes pods. To run ``omnia.yml``: :: diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst index 576180e60..9970de71e 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst @@ -9,11 +9,11 @@ Before you build clusters * Verify that all nodes are assigned a group. Use the `inventory <../../samplefiles.html>`_ as a reference. The inventory file is case-sensitive. Follow the casing provided in the sample file link. -* If NFS is required on the cluster, run `storage.yml. `_ +* If `NFS `_ or `BeeGFS `_ are required on the cluster, run ``storage.yml``. .. note:: * The inventory file accepts both IPs and FQDNs as long as they can be resolved by DNS. - * In a multi-node setup, IP's cannot be repeated in the manager or compute groups. That is, don't include the kube_control_plane IP address in the compute group. In a single node setup, the compute node and the kube_control_plane must be the same. + * In a multi-node setup, IP's cannot be listed as a control plane and a cluster node. That is, don't include the kube_control_plane IP address in the compute group. In a single node setup, the compute node and the kube_control_plane must be the same. * Users should also ensure that all repos are available on the cluster nodes running RHEL. diff --git a/docs/source/InstallationGuides/ConfiguringStorage/index.rst b/docs/source/InstallationGuides/ConfiguringStorage/index.rst index 110f21862..01b9763e4 100644 --- a/docs/source/InstallationGuides/ConfiguringStorage/index.rst +++ b/docs/source/InstallationGuides/ConfiguringStorage/index.rst @@ -122,7 +122,7 @@ To configure an NFS server, enter the following parameters in ``storage/nfs_serv | Required | | | | * ``server_share_path``: The path at which volume is mounted on nfs node | | | * ``server_export_options``: Default value is- rw,sync,no_root_squash (unless specified otherwise). For a list of accepted options, `click here `_ | -| | * ``client_shared_path``: The path at which volume is mounted on manager, compute, login node. This value is taken as server_share_path unless specified otherwise. | +| | * ``client_shared_path``: The path at which volume is mounted on all nodes. This value is taken as ``server_share_path`` unless specified otherwise. | | | * ``client_mount_options``: Default value is- nosuid,rw,sync,hard,intr (unless specified otherwise). For a list of accepted options, `click here `_ | | | | | | Must specify atleast 1 volume | diff --git a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst index 8d76d1c44..d0071bc95 100644 --- a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst +++ b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst @@ -9,81 +9,133 @@ Input parameters for Local Repositories :keepspace: :class: longtable +Below is a sample version of the file: :: + { + "cluster_os_type": "ubuntu", + "cluster_os_version": "22.04", + "repo_config": "partial", + "softwares": [ + {"name": "k8s", "version":"1.26.12"}, + {"name": "jupyter"}, + {"name": "openldap"}, + {"name": "kubeflow"}, + {"name": "beegfs", "version": "7.4.2"}, + {"name": "nfs"}, + {"name": "kserve"}, + {"name": "amdgpu", "version": "6.0"}, + {"name": "cuda", "version": "12.3.2"}, + {"name": "ofed", "version": "24.01-0.3.3.1"}, + {"name": "vllm"}, + {"name": "pytorch"}, + {"name": "tensorflow"}, + {"name": "bcm_roce", "version": "229.2.9.0"} + ], + + "kserve": [ + {"name": "istio"}, + {"name": "cert_manager"}, + {"name": "knative"} + ], + "amdgpu": [ + {"name": "rocm", "version": "6.0" } + ], + "vllm": [ + {"name": "vllm_amd"}, + {"name": "vllm_nvidia"} + ], + "pytorch": [ + {"name": "pytorch_cpu"}, + {"name": "pytorch_amd"}, + {"name": "pytorch_nvidia"} + ], + "tensorflow": [ + {"name": "tensorflow_cpu"}, + {"name": "tensorflow_amd"}, + {"name": "tensorflow_nvidia"} + ] + + } + +For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: + +:: + + amdgpu.json + k8s.json + openldap.json + rocm.json + +For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: + + { + + "k8s": { + + "cluster": [ + { + "package": "containerd.io-1.6.16-3.1.el8", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + { + "package": "kubelet", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" + }, + { + "package": "kubeadm", + "type": "tarball", + "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" + }, + { + "package": "helm", + "type": "tarball", + "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" + }, + { + "package": "registry.k8s.io/kube-apiserver", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "registry.k8s.io/kube-controller-manager", + "version": "v{{ k8s_version }}", + "type": "image" + }, + { + "package": "quay.io/coreos/etcd", + "version": "v3.5.9", + "type": "image" + }, + { + "package": "quay.io/calico/node", + "version": "v3.25.2", + "type": "image" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + }, + { + "package": "docker.io/kubernetesui/dashboard", + "version": "v2.7.0", + "type": "image" + } + ] + + } + + } + +.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. * Input the required values in ``input/local_repo_config.yml``. - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | Parameter | Details | - +=========================+===================================================================================================================================================================================================+ - | **repo_store_path** | * The intended file path for offline repository data. | - | | * Ensure the disk partition has enough space. | - | ``string`` | | - | | **Default value**: ``"/omnia_repo"`` | - | Required | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_repo_url** | * This variable accepts the repository urls of the user which contains the packages required for the cluster. | - | | * When ``repo_config`` is always, the given list will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local repository is created on the control plane containing packages that are not part of the user's repository. | - | | * When ``repo_config`` is never, no local repository is created and packages are downloaded on all cluster nodes. | - | Optional | * 'url' defines the baseurl for the repository. | - | | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted then gpgcheck=0 is set for that repository. | - | | | - | | **Sample value**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **user_registry** | * This variable accepts the registry url along with port of the user which contains the images required for cluster. | - | | * When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. | - | ``JSON List`` | * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. | - | | * When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. | - | Optional | * 'host' defines the URL and path to the registry. | - | | * 'cert_path' defines the absolute path where the security certificates for each registry. If this path is not provided, insecure registries are configured. | - | | | - | | **Sample value**: ``- {host: 10.11.0.100:5001, cert_path: "/home/ca.crt"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **ubuntu_os_url** | * This variable defines the repositories to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on Ubuntu and ignored if the cluster runs on RHEL or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``ubuntu_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``ubuntu_os_url`` is configured via proxy on the cluster nodes. | - | | * **Sample Values**: ``http://in.archive.ubuntu.com/ubuntu`` | - | Optional | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **rhel_os_url** | * This variable defines the code ready builder URL to be configured on all the compute nodes. | - | | * This variable is required if the cluster runs on RHEL and ignored if the cluster runs on Ubuntu or Rocky. | - | ``string`` | * When ``repo_config`` is ``always``, the given ``rhel_os_url`` is mirrored on the control plane. | - | | * When ``repo_config`` is ``partial`` or ``never``, the given ``rhel_os_url`` is configured via proxy on the cluster nodes. | - | Optional | * **Sample Values**: ``- {url: "http://crb.com/CRB/x86_64/os/",gpgkey: "http://crb.com/CRB/x86_64/os/RPM-GPG-KEY"}`` | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_registry** | * A list of registries from where images will be downloaded for Omnia features. | - | | * All registries mentioned in ``user_registry`` will be set as mirror for ``omnia_registry`` items. | - | ``string`` | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | | | - | Mandatory | * **Default value**: :: | - | | | - | | - "registry.k8s.io" | - | | - "quay.io" | - | | - "docker.io" | - | | | - | | | - | | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ - | **omnia_repo_url_rhel** | * A list of all the repo urls from where rpms will be downloaded for Omnia features. | - | | * 'url' defines the baseurl for the repository. | - | ``JSON List`` | * 'gpgkey' defines gpgkey for the repository. If 'gpgkey' is omitted, then gpgcheck=0 is set for that repository | - | | * This value is not validated by Omnia. Any errors can cause Omnia to fail. | - | Required | | - | | * **Default value**: :: | - | | | - | | - { url: "https://download.docker.com/linux/centos/$releasever/$basearch/stable", gpgkey: "https://download.docker.com/linux/centos/gpg" } | - | | - { url: "https://repo.radeon.com/rocm/rhel8/{{ rocm_version }}/main", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://download.fedoraproject.org/pub/epel/8/Everything/$basearch", gpgkey: "https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-8" } | - | | - { url: "https://repo.radeon.com/amdgpu/{{ amdgpu_version }}/rhel/{{ cluster_os_version }}/main/x86_64", gpgkey: "https://repo.radeon.com/rocm/rocm.gpg.key" } | - | | - { url: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/dists/rhel8", gpgkey: "https://www.beegfs.io/release/beegfs_{{beegfs_version}}/gpg/GPG-KEY-beegfs" } | - | | - { url: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64", gpgkey: "https://developer.download.nvidia.com/compute/cuda/repos/rhel8/x86_64/D42D0685.pub"} | - | | - { url: "https://yum.repos.intel.com/oneapi", gpgkey: "https://yum.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" } | - | | - { url: "https://ltb-project.org/rpm/openldap25/$releasever/$basearch", gpgkey: ""} | - | | | - | | | - | | | - | | | - +-------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + .. csv-table:: Parameters for Local Repository Configuration + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :widths: auto +* Input ``docker_username`` and ``docker_password`` in ``input/provision_config_credentials.yml`` to avoid image pullback errors. \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst index 972bb16c4..9d2dff940 100644 --- a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst +++ b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst @@ -14,6 +14,12 @@ To install PyTorch, include the following line under ``softwares```: :: {"name": "pytorch"}, + "pytorch": [ + {"name": "pytorch_cpu"}, + {"name": "pytorch_amd"}, + {"name": "pytorch_nvidia"} + ], + For a list of repositories (and their types) configured for PyTorch, view the ``input/config///pytorch.json`` file. To customize your PyTorch installation, update the file. diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index ef8352ddc..71c5222b9 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -3,154 +3,17 @@ Running local repo The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: -1. Enter the required values in the ``input/software_config.json`` file: -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - - -Below is a sample version of the file: :: - - { - "cluster_os_type": "ubuntu", - "cluster_os_version": "22.04", - "repo_config": "partial", - "softwares": [ - {"name": "k8s", "version":"1.26.12"}, - {"name": "jupyter", "version": "3.2.0"}, - {"name": "kubeflow", "version": "1.8"}, - {"name": "openldap"}, - {"name": "beegfs", "version": "7.2.6"}, - {"name": "nfs"}, - {"name": "kserve"}, - {"name": "custom"}, - {"name": "amdgpu", "version": "6.0"}, - {"name": "cuda", "version": "12.3.2"}, - {"name": "ofed", "version": "24.01-0.3.3.1"}, - {"name": "telemetry"}, - {"name": "utils"}, - {"name": "vllm"}, - {"name": "pytorch"}, - {"name": "tensorflow"}, - {"name": "bcm_roce", "version": "229.2.9.0"} - ], - - "amdgpu": [ - {"name": "rocm", "version": "6.0" } - ], - "vllm": [ - {"name": "vllm_amd", "version":"vllm-v0.2.4"}, - {"name": "vllm_nvidia", "version": "latest"} - ], - "pytorch": [ - {"name": "pytorch_cpu", "version":"latest"}, - {"name": "pytorch_amd", "version":"latest"}, - {"name": "pytorch_nvidia", "version": "23.12-py3"} - ], - "tensorflow": [ - {"name": "tensorflow_cpu", "version":"latest"}, - {"name": "tensorflow_amd", "version":"latest"}, - {"name": "tensorflow_nvidia", "version": "23.12-tf2-py3"} - ] - - } - - -For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: - -:: - - amdgpu.json - k8s.json - openldap.json - rocm.json - -For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: - - { - - "k8s": { - - "cluster": [ - { - "package": "containerd.io-1.6.16-3.1.el8", - "type": "rpm", - "repo_name": "docker-ce-repo" - }, - { - "package": "kubelet", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" - }, - { - "package": "kubeadm", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" - }, - { - "package": "helm", - "type": "tarball", - "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" - }, - { - "package": "registry.k8s.io/kube-apiserver", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "registry.k8s.io/kube-controller-manager", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "quay.io/coreos/etcd", - "version": "v3.5.9", - "type": "image" - }, - { - "package": "quay.io/calico/node", - "version": "v3.25.2", - "type": "image" - }, - { - "package": "registry.k8s.io/pause", - "version": "3.9", - "type": "image" - }, - { - "package": "docker.io/kubernetesui/dashboard", - "version": "v2.7.0", - "type": "image" - } - ] - - } - - } - -.. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. - -2. Enter the required values in the ``input/local_repo_config.yml`` file: - -.. csv-table:: Parameters for Local Repository Configuration - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :widths: auto - -3. Run the following commands: :: +Run the following commands: :: cd local_repo ansible-playbook local_repo.yml -**Update local repositories (RHEL)** +**Update local repositories** -This playbook updates all local repositories configured on a RHEL cluster after local repositories have been configured. +This playbook updates all local repositories configured on a provisioned cluster after local repositories have been configured. To run the playbook: :: diff --git a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst index 60c270d17..324b8e5f5 100644 --- a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst +++ b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst @@ -14,6 +14,12 @@ To install TensorFlow, include the following line under ``softwares```: :: {"name": "tensorflow"}, + "tensorflow": [ + {"name": "tensorflow_cpu"}, + {"name": "tensorflow_amd"}, + {"name": "tensorflow_nvidia"} + ] + For a list of repositories (and their types) configured for TensorFlow, view the ``input/config///tensorflow.json`` file. To customize your TensorFlow installation, update the file. diff --git a/docs/source/InstallationGuides/LocalRepo/amdgpu.rst b/docs/source/InstallationGuides/LocalRepo/amdgpu.rst new file mode 100644 index 000000000..84967906a --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/amdgpu.rst @@ -0,0 +1,24 @@ +Create local ROCm repository +----------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install ROCm, include the following line under ``softwares```: :: + + "amdgpu": [ + {"name": "rocm", "version": "6.0" } + ] + + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/beegfs b/docs/source/InstallationGuides/LocalRepo/beegfs new file mode 100644 index 000000000..167c8e489 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/beegfs @@ -0,0 +1,28 @@ +Create local beegfs repository +------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install BeeGFS, include the following line under ``softwares```: :: + + {"name": "beegfs"}, + + +For a list of repositories (and their types) configured for beegfs, view the ``input/config///beegfs.json`` file. To customize your beegfs installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + + +For information on deploying BeeGFS before setting up the cluster, `click here. <../BuildingClusters/BeeGFS.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 616dc002e..01375a83e 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -5,6 +5,7 @@ The local repository feature will help create offline repositories on the contro .. toctree:: Prerequisite + InputParameters Kubernetes cuda ofed diff --git a/docs/source/InstallationGuides/LocalRepo/jupyter.rst b/docs/source/InstallationGuides/LocalRepo/jupyter.rst new file mode 100644 index 000000000..21ce1ce32 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/jupyter.rst @@ -0,0 +1,28 @@ +Create local kubeflow repository +------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install kubeflow, include the following line under ``softwares```: :: + + {"name": "kubeflow"}, + + +For a list of repositories (and their types) configured for kubeflow, view the ``input/config///kubeflow.json`` file. To customize your kubeflow installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + + +For information on deploying kubeflow after setting up the cluster, `click here. <../../Roles/Platform/kubeflow.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/kserve.rst b/docs/source/InstallationGuides/LocalRepo/kserve.rst index 834d48f3e..ca4738721 100644 --- a/docs/source/InstallationGuides/LocalRepo/kserve.rst +++ b/docs/source/InstallationGuides/LocalRepo/kserve.rst @@ -12,7 +12,11 @@ Create local Kserve repository To install Kserve, include the following line under ``softwares```: :: - {"name": "kserve"}, + "kserve": [ + {"name": "istio"}, + {"name": "cert_manager"}, + {"name": "knative"} + ] For a list of repositories (and their types) configured for Kserve, view the ``input/config///kserve.json`` file. To customize your Kserve installation, update the file. diff --git a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst new file mode 100644 index 000000000..55255d9b4 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst @@ -0,0 +1,28 @@ +Create local Jupyter repository +------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install PyTorch, include the following line under ``softwares```: :: + + {"name": "jupyter"}, + + +For a list of repositories (and their types) configured for jupyter, view the ``input/config///jupyter.json`` file. To customize your jupyter installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + + +For information on deploying jupyter after setting up the cluster, `click here. <../../Roles/Platform/InstallJupyterhub.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/vLLM.rst b/docs/source/InstallationGuides/LocalRepo/vLLM.rst index 4d6f9c365..9302c2fe5 100644 --- a/docs/source/InstallationGuides/LocalRepo/vLLM.rst +++ b/docs/source/InstallationGuides/LocalRepo/vLLM.rst @@ -14,6 +14,11 @@ To install vLLM, include the following line under ``softwares```: :: {"name": "vLLM"}, + "vllm": [ + {"name": "vllm_amd"}, + {"name": "vllm_nvidia"} + ], + For a list of repositories (and their types) configured for vLLM, view the ``input/config///vllm.json`` file. To customize your vLLM installation, update the file. diff --git a/docs/source/Roles/Telemetry/index.rst b/docs/source/Roles/Telemetry/index.rst index 8b2579d24..f651b1917 100644 --- a/docs/source/Roles/Telemetry/index.rst +++ b/docs/source/Roles/Telemetry/index.rst @@ -45,7 +45,7 @@ To modify how data is collected from the cluster, modify the variables in ``omni .. note:: * Currently, changing the ``grafana_username`` and ``grafana_password`` values is not supported via ``telemetry.yml``. * The passed inventory should have an idrac group, if ``idrac_telemetry_support`` is true. - * If ``omnia_telemetry_support`` is true, then the inventory should have manager and compute groups along with optional login group. + * If ``omnia_telemetry_support`` is true, then the inventory should have control plane and cluster node groups (as specified in the sample files) along with optional login group. * Rocky 8.7 is not compatible with the Kubernetes installed by ``telemetry.yml`` due to known issues with cri-o. For more information, `click here `_. * If a subsequent run of ``telemetry.yml`` fails, the ``telemetry_config.yml`` file will be unencrypted. diff --git a/docs/source/Roles/Utils/epel.rst b/docs/source/Roles/Utils/epel.rst index 8a9e0eebc..a0ddb831c 100644 --- a/docs/source/Roles/Utils/epel.rst +++ b/docs/source/Roles/Utils/epel.rst @@ -12,5 +12,5 @@ To run the script: :: cd omnia/utils ansible-playbook install_hpc_thirdparty_packages.yml -i inventory -Where the inventory refers to a file listing all manager and compute nodes per the format provided in `inventory file <../samplefiles.html>`_. +Where the inventory refers to a file listing all nodes per the format provided in `inventory file <../samplefiles.html>`_. diff --git a/docs/source/Roles/Utils/kernel_upgrade.rst b/docs/source/Roles/Utils/kernel_upgrade.rst index 796f091a6..8d2a42f72 100644 --- a/docs/source/Roles/Utils/kernel_upgrade.rst +++ b/docs/source/Roles/Utils/kernel_upgrade.rst @@ -18,5 +18,5 @@ Via CLI: :: cd omnia/utils ansible-playbook kernel_upgrade.yml -i inventory -e rhsm_kernel_version=x.xx.x-xxxx -Where the inventory refers to a file listing all manager and compute nodes per the format provided in `inventory file <../samplefiles.html>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. +Where the inventory refers to a file listing all nodes per the format provided in `inventory file <../samplefiles.html>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. diff --git a/docs/source/Roles/Utils/rhsm_subscription.rst b/docs/source/Roles/Utils/rhsm_subscription.rst index 3090fe5d0..b56e846d3 100644 --- a/docs/source/Roles/Utils/rhsm_subscription.rst +++ b/docs/source/Roles/Utils/rhsm_subscription.rst @@ -146,7 +146,7 @@ Before running ``omnia.yml``, it is mandatory that red hat subscription be set u cd utils ansible-playbook rhsm_subscription.yml -i inventory -e redhat_subscription_activation_key="" -e redhat_subscription_org_id="" -Where the inventory refers to a file listing all manager and compute nodes per the format provided in `inventory file <../../samplefiles.html>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. +Where the inventory refers to a file listing all nodes per the format provided in `inventory file <../../samplefiles.html>`_. The inventory file is case-sensitive. Follow the casing provided in the sample file link. diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index 5d2425b22..f6be9191f 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -25,7 +25,7 @@ Omnia does not maintain any order when assigning hostnames to target nodes. **Resolution**: Ensure a control plane IP is assigned to the admin NIC. -⦾ **Kubernetes pods on the kube_control_plane are in CreateContainerConfigError and Calico Pods are in CrashLoopBackoff error after running omnia.yml.** +⦾ **Kubernetes pods on the kube_control_plane are in CreateContainerConfigError and Calico Pods are in CrashLoopBackoff error after running omnia.yml (version 1.5 and below).** **Potential Cause:** @@ -193,7 +193,7 @@ Wait for 15 minutes after the Kubernetes cluster reboots. Next, verify the statu 3. Set ``scheduler_type: "k8s"`` in ``input/omnia_config.yml`` and run ``omnia.yml``. -⦾ **Why does pulling images to create the Kubeflow timeout causing the 'Apply Kubeflow Configuration' task to fail?** +⦾ **Why does pulling images to create the Kubeflow timeout causing the 'Apply Kubeflow Configuration' task to fail? (version 1.5 and below)** **Potential Cause**: Unstable or slow Internet connectivity. @@ -462,7 +462,7 @@ The required services are not running on the node. Verify the service status usi **Resolution**: Enable all required repositories via your red hat subscription. -⦾ **Why would FreeIPA server/client installation fail?** +⦾ **Why would FreeIPA server/client installation fail? (version 1.5 and below)** **Potential Cause**: From f079fc008c9c3a371e3bbe3f992110105b0648b4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 09:44:32 +0530 Subject: [PATCH 245/309] Updating documentation Signed-off-by: goveac --- .../LocalRepo/InputParameters.rst | 80 +++++-------------- .../InstallationGuides/LocalRepo/index.rst | 6 ++ 2 files changed, 28 insertions(+), 58 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst index d0071bc95..c9897f404 100644 --- a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst +++ b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst @@ -57,76 +57,40 @@ Below is a sample version of the file: :: } -For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and view the file list: +For a list of accepted values in ``softwares``, go to ``input/config//`` and view the list of JSON files available. The filenames present in this location (without the * .json extension) are a list of accepted software names. The repositories to be downloaded for each software are listed the corresponding JSON file. For example: For a cluster running Ubuntu 22.04, go to ``input/config/ubuntu/22.04/`` and view the file list: :: amdgpu.json + bcm_roce.json + beegfs.json + cuda.json + jupyter.json k8s.json + kserve.json + kubeflow.json + nfs.json + ofed.json openldap.json - rocm.json + pytorch.json + tensorflow.json + vllm.json -For a list of repositories (and their types) configured for kubernetes, view the ``k8s.json``` file: :: +For a list of repositories (and their types) configured for amdgpu, view the ``amdgpu.json``` file: :: { - - "k8s": { - + "amdgpu": { "cluster": [ - { - "package": "containerd.io-1.6.16-3.1.el8", - "type": "rpm", - "repo_name": "docker-ce-repo" - }, - { - "package": "kubelet", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubelet" - }, - { - "package": "kubeadm", - "type": "tarball", - "url": "https://dl.k8s.io/release/v{{ k8s_version }}/bin/linux/amd64/kubeadm" - }, - { - "package": "helm", - "type": "tarball", - "url": "https://get.helm.sh/helm-v3.12.3-linux-amd64.tar.gz" - }, - { - "package": "registry.k8s.io/kube-apiserver", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "registry.k8s.io/kube-controller-manager", - "version": "v{{ k8s_version }}", - "type": "image" - }, - { - "package": "quay.io/coreos/etcd", - "version": "v3.5.9", - "type": "image" - }, - { - "package": "quay.io/calico/node", - "version": "v3.25.2", - "type": "image" - }, - { - "package": "registry.k8s.io/pause", - "version": "3.9", - "type": "image" - }, - { - "package": "docker.io/kubernetesui/dashboard", - "version": "v2.7.0", - "type": "image" - } + {"package": "linux-headers-$(uname -r)", "type": "deb", "repo_name": "jammy"}, + {"package": "linux-modules-extra-$(uname -r)", "type": "deb", "repo_name": "jammy"}, + {"package": "amdgpu-dkms", "type": "deb", "repo_name": "amdgpu"} + ] + }, + "rocm": { + "cluster": [ + {"package": "rocm-hip-sdk{{ rocm_version }}*", "type": "deb", "repo_name": "rocm"} ] - } - } .. note:: To configure a locally available repository that does not have a pre-defined json file, `click here `_. diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 01375a83e..591e8051f 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -8,11 +8,17 @@ The local repository feature will help create offline repositories on the contro InputParameters Kubernetes cuda + amdgpu + beegfs + nfs ofed bcm_roce FreeIPA OpenLDAP SecureLoginNode + jupyter + kubeflow + vLLM PyTorch TensorFlow kserve From 7c26993599a6f72bee7cf8125f9d292ff80c2be6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 09:48:54 +0530 Subject: [PATCH 246/309] Updating documentation Signed-off-by: goveac --- .../LocalRepo/InputParameters.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst index c9897f404..c9f15f787 100644 --- a/docs/source/InstallationGuides/LocalRepo/InputParameters.rst +++ b/docs/source/InstallationGuides/LocalRepo/InputParameters.rst @@ -3,11 +3,11 @@ Input parameters for Local Repositories * Input all required values in ``input/software_config.json``. - .. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable Below is a sample version of the file: :: @@ -97,9 +97,9 @@ For a list of repositories (and their types) configured for amdgpu, view the ``a * Input the required values in ``input/local_repo_config.yml``. - .. csv-table:: Parameters for Local Repository Configuration - :file: ../../Tables/local_repo_config.csv - :header-rows: 1 - :widths: auto +.. csv-table:: Parameters for Local Repository Configuration + :file: ../../Tables/local_repo_config.csv + :header-rows: 1 + :widths: auto * Input ``docker_username`` and ``docker_password`` in ``input/provision_config_credentials.yml`` to avoid image pullback errors. \ No newline at end of file From f0827617cdf0d6f0527c035679751fac85777bcb Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 09:56:53 +0530 Subject: [PATCH 247/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 0785733df..a5e7e6bcd 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -12,7 +12,7 @@ } .rst-content div[class^=highlight], .rst-content pre.literal-block { - width: 600px; + width: 575px; overflow-x: unset; } From c730d05b49d6aad406b028f1c38829feb51dceff Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 13:25:35 +0530 Subject: [PATCH 248/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 7d5afdf5a..633d6afe9 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -55,3 +55,16 @@ The IP address is listed against ``proxy-public``. 2. Select **Stop Server**. .. note:: Stopping the notebook server only terminates the user pod. The users data persists and can be accessed by loggin in and starting the notebook server again. + +**Updating the Jupyterhub configuration** + +1. Update the ``tools/jupyter_config.yml`` file with the new configuration. +2. Clear the existing configuration by running the below commands: :: + + kubectl delete ns jupyterhub + kubectl delete pv jupyterhub-pv + +3. Re-run the ``jupyterhub.yml`` playbook. :: + + cd tools + ansible-playbook jupyterhub.yml -i inventory \ No newline at end of file From 0ac915afc136ef30787b9cfdd5feaa3dc5db1a2e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 14:35:33 +0530 Subject: [PATCH 249/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 633d6afe9..411869877 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -59,7 +59,7 @@ The IP address is listed against ``proxy-public``. **Updating the Jupyterhub configuration** 1. Update the ``tools/jupyter_config.yml`` file with the new configuration. -2. Clear the existing configuration by running the below commands: :: +2. **[Optional]** Clear the existing configuration by running the below commands: :: kubectl delete ns jupyterhub kubectl delete pv jupyterhub-pv @@ -67,4 +67,11 @@ The IP address is listed against ``proxy-public``. 3. Re-run the ``jupyterhub.yml`` playbook. :: cd tools - ansible-playbook jupyterhub.yml -i inventory \ No newline at end of file + ansible-playbook jupyterhub.yml -i inventory + +**Clearing the Jupyterhub configuration** + +Clear the existing configuration by running the below commands: :: + + kubectl delete ns jupyterhub + kubectl delete pv jupyterhub-pv From 87a77de720cc873b02dc8471cd3afffe27ac94c2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 15:55:09 +0530 Subject: [PATCH 250/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 64 +++- .../provisionparams.rst | 18 +- docs/source/Tables/Provision_config.csv | 6 +- docs/source/Tables/bmc.csv | 91 ------ docs/source/Tables/mapping.csv | 217 ------------- docs/source/Tables/switch-based.csv | 295 ------------------ 6 files changed, 73 insertions(+), 618 deletions(-) delete mode 100644 docs/source/Tables/bmc.csv delete mode 100644 docs/source/Tables/mapping.csv delete mode 100644 docs/source/Tables/switch-based.csv diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index 4d19977c1..53d98f854 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -6,12 +6,66 @@ After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boo * All target nodes are provisioned and booted. `Click here to verify the status of all nodes. `_ - * The ``input/network_spec.yml`` file has been updated with all network information including admin network and bmc network information. + * The ``input/network_spec.yml`` file has been updated with all network information in addition to admin network and bmc network information. Below are all applicable properties of an additional network: + * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. + * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. + * ``static_range``: The static range of IPs to be provisioned on target nodes. + * ``dynamic_range``: The dynamic range of IPs to be provisioned on target nodes. + * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. + * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. + * ``CIDR``: Classless or Classless Inter-Domain Routing (CIDR) addresses use variable length subnet masking (VLSM) to alter the ratio between the network and host address bits in an IP address. + * ``MTU``: Maximum transmission unit (MTU) is a measurement in bytes of the largest data packets that an Internet-connected device can accept. + * ``DNS``: A DNS server is a computer equipped with a database that stores the public IP addresses linked to the domain names of websites, enabling users to reach websites using their IP addresses. + * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. + + Below is a sample ``input/network_spec.yml`` file: :: + + --- + Networks: + - admin_network: + nic_name: "eno1" + netmask_bits: "16" + static_range: "10.5.0.1-10.5.0.200" + dynamic_range: "10.5.1.1-10.5.1.200" + correlation_to_admin: true + admin_uncorrelated_node_start_ip: "10.5.0.50" + network_gateway: "" + DNS: "" + MTU: "1500" + + - bmc_network: + nic_name: "" + netmask_bits: "" + static_range: "" + dynamic_range: "" + reassignment_to_static: true + discover_ranges: "" + network_gateway: "" + MTU: "1500" + + #********************************************************************** + # Following are the templates for providing additional network details + #********************************************************************** + + # - thor_network1: + # netmask_bits: "20" + # CIDR: "10.10.16.0" + # network_gateway: "" + # MTU: "1500" + # VLAN: "" + # + # - thor_network2: + # netmask_bits: "20" + # static_range: "10.10.1.1-10.10.15.254" + # network_gateway: "" + # MTU: "1500" + # VLAN: "1" + * The ``input/server_spec.yml`` file has been updated with all NIC information of the target nodes. * All NICs listed in the ``server_spec.yml`` file are grouped into categories (groups for servers). The string "Categories:" should not be edited out of the ``input/server_spec.yml`` file. - * The property ``nicname`` is the unique identifier of NICs in the file. + * The name of the NIC specified in the file (in this sample, ``ensp0``, ``ensp0.5``, and ``eno1``) is the unique identifier of NICs in the file. * The property ``nictype`` indicates what kind of NIC is in use (ethernet, infiniband, or vlan). If the ``nictype`` is set to ``vlan``, ensure to specify a primary NIC for the VLAN using the property ``nicdevices``. * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of the playbook, existing groups cannot be edited or deleted. @@ -38,10 +92,10 @@ Below is a sample ``input/server_spec.yml`` file: :: nictypes: "ethernet" -Use the below commands to add the NICs: :: +Use the below commands to assign IPs to the NICs: :: cd nic_update - ansible-playbook nic_update/nic_update -i inventory + ansible-playbook nic_update -i inventory Where the inventory file passed includes user-defined groups,servers associated with them, and a mapping from the groups specified and the categories in ``input/server_spec.yml``. Below is a sample: :: @@ -58,7 +112,7 @@ Where the inventory file passed includes user-defined groups,servers associated [waco2:vars] Categories=group-2 -Based on the provided sample files, server 10.5.0.3 has been mapped to waco1 which corresponds to group-1. Therefore, the NICs ensp0 and ensp0.5 will be configured in an ethernet VLAN group with ens0.5 as the primary device. +Based on the provided sample files, server 10.5.0.3 has been mapped to waco1 which corresponds to group-1. Therefore, the NICs ensp0 and ensp0.5 will be configured in an ethernet VLAN group with ens0 as the primary device. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index f6214f6bc..63b1ba96e 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -26,16 +26,20 @@ Fill in all required parameters in ``input/provision_config.yml``, ``provision_c Update the ``input/network_spec.yml`` file for all networks available for use by the control plane. * The following ``admin_nic`` details are mandatory. - * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. - * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. - * ``static_range``: The static range of IPs to be provisioned on target nodes. - * ``dynamic_range``: The - * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. - * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. + * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. + * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. + * ``static_range``: The static range of IPs to be provisioned on target nodes. + * ``dynamic_range``: The dynamic range of IPs to be provisioned on target nodes. + * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. + * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. + * ``CIDR``: Classless or Classless Inter-Domain Routing (CIDR) addresses use variable length subnet masking (VLSM) to alter the ratio between the network and host address bits in an IP address. + * ``MTU``: Maximum transmission unit (MTU) is a measurement in bytes of the largest data packets that an Internet-connected device can accept. + * ``DNS``: A DNS server is a computer equipped with a database that stores the public IP addresses linked to the domain names of websites, enabling users to reach websites using their IP addresses. + * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. * If the ``nic_name`` is the same on both the admin_network and the bmc_network, a LOM setup is assumed. * BMC network details are not required when target nodes are discovered using a mapping file. - * If ``bmc_network`` properties are provided, target nodes will be discovered using the BMC method. + * If ``bmc_network`` properties are provided, target nodes will be discovered using the BMC method in addition to the methods whose details are explicitly provided in ``provision_config.yml``. A sample is provided below: :: diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index b71c83022..9a8fc6c00 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -36,10 +36,10 @@ Required","* Domain name the user intends to configure on the cluster. ``string`` -Required (Mapping discovery mechanism)","* The mapping file consists of the MAC address and its respective IP address and hostname. -* If static IPs are required, create a csv file in the format MAC,Hostname,IP. +Required (Mapping discovery mechanism)","* The mapping file consists of the Service tag, Admin MAC,Hostname and its respective admin IP address and/or BMC IP. +* Ensure that the admin IP addresses provided are within the ``admin_static_ranges``. * A sample file is provided here: examples/pxe_mapping_file.csv. -* If not provided, ensure that pxe_switch_ip is provided." +* The headers of the CSV are SERVICE_TAG,ADMIN_MAC,HOSTNAME,ADMIN_IP,BMC_IP." "**switch_based_details** ``JSON List`` diff --git a/docs/source/Tables/bmc.csv b/docs/source/Tables/bmc.csv deleted file mode 100644 index d787928e7..000000000 --- a/docs/source/Tables/bmc.csv +++ /dev/null @@ -1,91 +0,0 @@ -Parameter,Details -"**iso_file_path** - -``string`` - -Required","Path where user has placed the iso image that needs to be provisioned on target nodes. Accepted files are Rocky8-DVD or RHEL-8.x-DVD (full OS). iso_file_path should contain the provision_os and provision_os_version values in the filename. - -**Default values**: ``""/home/RHEL-8.6.0-20220420.3-x86_64-dvd1.iso""``" -"**timezone** - -``string`` - -Required","Timezone to be used during OS provisioning. Available timezones are provided `here <../../Appendix.html>`_. - -Choices: - -* ``GMT`` <- default -* ``EST`` -* ``CET`` -* ``MST`` -* ``CST6CDT`` -* ``PST8PDT``" -"**language** - -``string`` - -Required","Language to be used during OS provisioning. - -**Default values**: ``en-US``" -"**default_lease_time** - -``integer`` - -Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 - -**Default values**: ``86400``" -"**node_name** - -``string`` - -Required","* Prefix for target node names, if dynamically allocated. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Example: servernode00001.Omnia.test , where node_name =servernode, domain_name =Omnia.test , 00001 used by Omnia. - -**Default values**: ``node``" -"**domain_name** - -``string`` - -Required","* Domain name the user intends to configure on the cluster. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Please provide a valid domain name according to the domain name standards. -* Example: servernode00001.Omnia.test , where node_name=servernode, domain_name=Omnia.test , 00001 used by Omnia." -"**public_nic** - -``string`` - -Required","The nic/ethernet card that is connected to the public internet. - -**Default values**: ``eno2``" -"**update_repos** - -``boolean`` [1]_ - -Required","* Indicates whether ``provision.yml`` will update offline RHEL repos. - -* If ``update_repos``: false, the update repos for BaseOS and AppStream will not be updated to the latest versions available. - -* If ``update_repos``: true, the update repos for BaseOS and AppStream will be updated to the latest versions available. - -.. note:: By default, AppSteam and BaseOS repos will be configured from the given ISO file. - -Choices: - -``false`` <- Default - -``true`` " -"**disk_partition** - -``JSON list`` - -Optional","* User defined disk partition applied to remote servers. -* The disk partition desired_capacity has to be provided in MB. -* Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. -* Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. -* Values are accepted in the form of JSON list such as: , - { mount_point: ""/home"", desired_capacity: ""102400"" } - - -**Default values**: ``- { mount_point: """", desired_capacity: """" }``" diff --git a/docs/source/Tables/mapping.csv b/docs/source/Tables/mapping.csv deleted file mode 100644 index 55d981504..000000000 --- a/docs/source/Tables/mapping.csv +++ /dev/null @@ -1,217 +0,0 @@ -Parameter,Details -"**provision_os** - -``string`` - -Required","The operating system to be provisioned on target nodes in the cluster. - -Choices: - -* ``rhel`` <-default -* ``rocky`` -* ``ubuntu`` - -.. caution:: **THE ROCKY LINUX OS VERSION ON THE CLUSTER WILL BE UPGRADED TO THE LATEST 8.x VERSION AVAILABLE IRRESPECTIVE OF THE PROVISION_OS_VERSION PROVIDED IN PROVISION_CONFIG.YML.** -" -"**provision_os_version** - -``string`` - -Required","OS version of provision_os to be installed. - -Choices: - -* ``8.0`` -* ``8.1`` -* ``8.2`` -* ``8.3`` -* ``8.4`` -* ``8.5`` -* ``8.6`` <- default -* ``8.7``" -"**iso_file_path** - -``string`` - -Required","Path where user has placed the iso image that needs to be provisioned on target nodes. Accepted files are Rocky8-DVD or RHEL-8.x-DVD (full OS). iso_file_path should contain the provision_os and provision_os_version values in the filename. - -**Default values**: ``""/home/RHEL-8.6.0-20220420.3-x86_64-dvd1.iso""``" -"**timezone** - -``string`` - -Required","Timezone to be used during OS provisioning. Available timezones are provided `here <../../Appendix.html>`_. - -Choices: - -* ``GMT`` <- default -* ``EST`` -* ``CET`` -* ``MST`` -* ``CST6CDT`` -* ``PST8PDT``" -"**language** - -``string`` - -Required","Language to be used during OS provisioning. - -**Default values**: ``en-US``" -"**default_lease_time** - -``integer`` - -Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 - -**Default values**: ``86400``" -"**node_name** - -``string`` - -Required","* Prefix for target node names, if dynamically allocated. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Example: servernode00001.Omnia.test , where node_name =servernode, domain_name =Omnia.test , 00001 used by Omnia. - -**Default values**: ``node``" -"**domain_name** - -``string`` - -Required","* Domain name the user intends to configure on the cluster. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Please provide a valid domain name according to the domain name standards. -* Example: servernode00001.Omnia.test , where node_name=servernode, domain_name=Omnia.test , 00001 used by Omnia." -"**public_nic** - -``string`` - -Required","The nic/ethernet card that is connected to the public internet. - -**Default values**: ``eno2``" -"**admin_static_start_range** - -``string`` - -Required","* The start IP of the admin NIC provisioning range. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -* Only the last two octects (16 bits) of IPv4 are dynamic. -**Default values**: ``10.5.0.0``" -"**admin_static_start_range** - -``string`` - -Required","* The end IP of the admin NIC provisioning range. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -* Only the last two octects (16 bits) of IPv4 are dynamic. -**Default values**: ``10.5.0.0``" -"**pxe_mapping_file_path** - -``string`` - -Required","* The mapping file consists of the MAC address and its respective IP address and hostname. -* If static IPs are required, create a csv file in the format MAC,Hostname,IP. -* A sample file is provided here: examples/pxe_mapping_file.csv. -* If not provided, ensure that pxe_switch_ip is provided." -"**bmc_nic_start_range** - -``string`` - -Required","* The start IP of the admin NIC provisioning range. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -* Only the last two octects (16 bits) of IPv4 are dynamic. -**Default values**: ``10.5.0.0``" -"**bmc_nic_start_range** - -``string`` - -Required","* The end IP of the admin NIC provisioning range. -* The value of this variable cannot be changed after successfully running ``provision.yml``. -* Only the last two octects (16 bits) of IPv4 are dynamic. -**Default values**: ``10.5.0.0``" -"**update_repos** - -``boolean`` [1]_ - -Required","* Indicates whether ``provision.yml`` will update offline RHEL repos. - -* If ``update_repos``: false, the update repos for BaseOS and AppStream will not be updated to the latest versions available. - -* If ``update_repos``: true, the update repos for BaseOS and AppStream will be updated to the latest versions available. - -.. note:: By default, AppSteam and BaseOS repos will be configured from the given ISO file. - -Choices: - -``false`` <- Default - -``true`` " -" **rhel_repo_alphabetical_folders** - ``boolean`` [1]_ - - Required ","* Indicates whether the packages in local or subscription repos should be ordered in alphabetical directories. - - -* This variable should be filled if control plane OS is RHEL and local RHEL repository is available. - - - -Choices: - -``false`` <- Default - -``true`` " -"**rhel_repo_local_path** - -``JSON list`` - -Optional ","* The repo path and names of the software repository to be configured on the cluster nodes. - -* Provide the repo data file path, which ends with .repo extension in repo_url parameter. - -* Provide a **valid** url for BaseOS and AppStream repositories. Omnia does not validate the ``repo_url`` provided. Invalid entries will cause ``provision.yml`` to fail. - -* This variable should be filled if control plane OS is RHEL and subscription is not activated. - -* This variable should be filled if the control plane OS is Rocky and the ``provision_os`` is rhel. - - -Sample value: :: - - - - { repo: ""AppStream"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-appstream.repo"", repo_name: ""RHEL-8-appstream-partners"" } - - - { repo: ""BaseOS"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-baseos.repo"", repo_name: ""RHEL-8-baseos-partners"" } - - - " -"**disk_partition** - -``JSON list`` - -Optional","* User defined disk partition applied to remote servers. -* The disk partition desired_capacity has to be provided in MB. -* Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. -* Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. -* Values are accepted in the form of JSON list such as: , - { mount_point: ""/home"", desired_capacity: ""102400"" } - - -**Default values**: ``- { mount_point: """", desired_capacity: """" }``" -"**mlnx_ofed_path** - -``string`` - -Optional",Absolute path to a local copy of the .iso file containing Mellanox OFED packages. The image can be downloaded from https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/. Sample value: /root/MLNX_OFED_LINUX-5.8-1.1.2.1-rhel8.6-x86_64.iso -"**cuda_toolkit_path** - -``string`` - -Optional","Absolute path to local copy of .rpm file containing CUDA packages. The cuda rpm can be downloaded from https://developer.nvidia.com/cuda-downloads. CUDA will be installed post provisioning without any user intervention. Eg: cuda_toolkit_path: ""/root/cuda-repo-rhel8-12-0-local-12.0.0_525.60.13-1.x86_64.rpm""" -"**apptainer_support** - -``boolean`` [1]_ - -Required","* Indicates whether apptainer will be installed on the cluster to enable execution of HPC benchmarks in a containeraized environment. -* If ``apptainer_support``: false, apptainer will not be installed on the cluster. -* If ``apptainer_support``: true, apptainer will be installed on the cluster." diff --git a/docs/source/Tables/switch-based.csv b/docs/source/Tables/switch-based.csv deleted file mode 100644 index 323e1aeb7..000000000 --- a/docs/source/Tables/switch-based.csv +++ /dev/null @@ -1,295 +0,0 @@ -Parameter,Details -"**network_interface_type** - -``string`` - -Required","The network type used on the Omnia cluster. - -Choices: - -* ``dedicated`` <- default -* ``lom``" -"**discovery_mechanism** - -``string`` - -Required","The mechanism through which Omnia will discover nodes for provisioning. For more information on how the mechanisms work, go to `DiscoveryMechanisms `_. - -Choices: - -* ``switch_based`` -* ``mapping`` <-default -* ``bmc`` -* ``snmpwalk``" -"**provision_os** - -``string`` - -Required","The operating system to be provisioned on target nodes in the cluster. - -Choices: - -* ``rhel`` <-default -* ``rocky``" -"**provision_os_version** - -``string`` - -Required","OS version of provision_os to be installed. - -Choices: - -* ``8.0`` -* ``8.1`` -* ``8.2`` -* ``8.3`` -* ``8.4`` -* ``8.5`` -* ``8.6`` <- default -* ``8.7``" -"**iso_file_path** - -``string`` - -Required","Path where user has placed the iso image that needs to be provisioned on target nodes. Accepted files are Rocky8-DVD or RHEL-8.x-DVD (full OS). iso_file_path should contain the provision_os and provision_os_version values in the filename. - -**Default values**: ``""/home/RHEL-8.6.0-20220420.3-x86_64-dvd1.iso""``" -"**timezone** - -``string`` - -Required","Timezone to be used during OS provisioning. Available timezones are provided `here <../../Appendix.html>`_. - -Choices: - -* ``GMT`` <- default -* ``EST`` -* ``CET`` -* ``MST`` -* ``CST6CDT`` -* ``PST8PDT``" -"**language** - -``string`` - -Required","Language to be used during OS provisioning. - -**Default values**: ``en-US``" -"**default_lease_time** - -``integer`` - -Required","Default lease time for IPs assigned by DHCP. Range: 21600-86400 - -**Default values**: ``86400``" -"**provision_password** - -``string`` - -Required","* Password set for the root account of target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',"" -* The first character of the string should be an alphabet." -"**postgresdb_password** - -``string`` - -Required","* Password set for the postgresDB on target nodes during provisioning. -* Length >= 8 characters -* Password must not contain -,\, ',"" -* The first character of the string should be an alphabet." -"**node_name** - -``string`` - -Required","* Prefix for target node names, if dynamically allocated. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Example: servernode00001.Omnia.test , where node_name =servernode, domain_name =Omnia.test , 00001 used by Omnia. - -**Default values**: ``node``" -"**domain_name** - -``string`` - -Required","* Domain name the user intends to configure on the cluster. -* Hostname = node_name + '0000x' + domain_name -* Hostname <= 65 characters -* Please provide a valid domain name according to the domain name standards. -* Example: servernode00001.Omnia.test , where node_name=servernode, domain_name=Omnia.test , 00001 used by Omnia." -"**public_nic** - -``string`` - -Required","The nic/ethernet card that is connected to the public internet. - -**Default values**: ``eno2``" -"**admin_nic** - -``string`` - -Required","* Admin NIC of Control Plane. This is the shared LOM NIC. -* The value of this variable cannot be changed after successfully running ``provision.yml``. - -**Default values**: ``eno1``" -"**admin_nic_subnet** - -``string`` - -Required","The subnet within which all Admin IPs are assigned. - -**Default values**: ``10.5.0.0``" -"**switch_based_details** - -``JSON List`` - -Required","* JSON list of switches to query for target nodes. -* Split port ranges are not accepted here. (Ex: 10:5-10:10 will not be valid). -* Example: :: - -  - { ip: 172.96.28.12, ports: '1-48,49:3,50' } - -* Example with 2 switches: :: - -  - { ip: 172.96.28.12, ports: '1-48,49:3,50' } - -  - { ip: 172.96.28.14, ports: '1,2,3,5' } - -" -"**switch_snmp3_username** - -``string`` - -Required",The non-admin SNMPv3 username for the switch. -"**switch_snmp3_password** - -``string`` - -Required","* The non-admin SNMPv3 password for the switch. -* The first character of the string should be an alphabet." -"**ip_start_range** - -``string`` - -Required","* The IP start range for all the NICs within the subnets mentioned above.(Admin, BMC, IB). -* Example: For the range x.y.0.1 to x.y.0.100 with admin_nic_subnet = 10.5.0.0, target nodes will be assigned admin IPs between 10.5.0.1 and 10.5.0.100." -"**ip_end_range** - -``string`` - -Required","* The IP end range for all the NICs within the subnets mentioned above.(Admin, BMC, IB). -* Example: For the range x.y.0.1 to x.y.0.100 with admin_nic_subnet = 10.5.0.0, target nodes will be assigned admin IPs between 10.5.0.1 and 10.5.0.100." -"**ib_nic_subnet** - -``string`` - -Optional","* If provided, Omnia will handle and assign static IPs to cluster node's IB network. -* Only the last 16 bits/2 octets of IPv4 are dynamic -* If provided, the DB entry will be in parallel with the pxe_subnet. -* Example: If ``admin_ip``: 10.5.0.50 and ``ib_nic_subnet``: 10.10.0.0, then ``ib_ip``: 10.10.0.50" -"**bmc_nic_subnet** - -``string`` - -Required","* If provided, Omnia will assign static IPs to BMC NICs on the cluster nodes within the provided subnet. -* If ``network_interface_type``: ``lom``, mandatory for discovery_mechanism: mapping, switch_based and bmc. -* If ``network_interface_type``: ``dedicated``, optional for discovery_mechanism: mapping, snmpwalk. -* Note that since the last 16 bits/2 octets of IPv4 are dynamic, please ensure that the parameter value is set to x.x.0.0. -* When the PXE range and BMC subnet are provided, corresponding NICs will be assigned IPs with the same 3rd and 4th octets." -"**bmc_username** - -``string`` - -Required","* The username for iDRAC. -* The username must not contain -,\, ',""" -"**bmc_password** - -``string`` - -Required","* The password for iDRAC. -* The password must not contain -,\, ',""" -"**update_repos** - -``boolean`` [1]_ - -Required","* Indicates whether ``provision.yml`` will update offline RHEL repos. - -* If ``update_repos``: false, the update repos for BaseOS and AppStream will not be updated to the latest versions available. - -* If ``update_repos``: true, the update repos for BaseOS and AppStream will be updated to the latest versions available. - -.. note:: By default, AppSteam and BaseOS repos will be configured from the given ISO file. - -Choices: - -``false`` <- Default - -``true`` " -" **rhel_repo_alphabetical_folders** - ``boolean`` [1]_ - - Required ","* Indicates whether the packages in local or subscription repos should be ordered in alphabetical directories. - - -* This variable should be filled if control plane OS is RHEL and local RHEL repository is available. - - - -Choices: - -``false`` <- Default - -``true`` " -"**rhel_repo_local_path** - -``JSON list`` - -Optional ","* The repo path and names of the software repository to be configured on the cluster nodes. - -* Provide the repo data file path, which ends with .repo extension in repo_url parameter. - -* Provide a **valid** url for BaseOS and AppStream repositories. Omnia does not validate the ``repo_url`` provided. Invalid entries will cause ``provision.yml`` to fail. - -* This variable should be filled if control plane OS is RHEL and subscription is not activated. - -* This variable should be filled if the control plane OS is Rocky and the ``provision_os`` is rhel. - - -Sample value: :: - - - - { repo: ""AppStream"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-appstream.repo"", repo_name: ""RHEL-8-appstream-partners"" } - - - { repo: ""BaseOS"", repo_url: ""http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.8/RHEL-8-baseos.repo"", repo_name: ""RHEL-8-baseos-partners"" } - - - " -"**disk_partition** - -``JSON list`` - -Optional","* User defined disk partition applied to remote servers. -* The disk partition desired_capacity has to be provided in MB. -* Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. -* Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. -* Values are accepted in the form of JSON list such as: , - { mount_point: ""/home"", desired_capacity: ""102400"" } - - -**Default values**: ``- { mount_point: """", desired_capacity: """" }``" -"**mlnx_ofed_path** - -``string`` - -Optional",Absolute path to a local copy of the .iso file containing Mellanox OFED packages. The image can be downloaded from https://network.nvidia.com/products/infiniband-drivers/linux/mlnx_ofed/. Sample value: /root/MLNX_OFED_LINUX-5.8-1.1.2.1-rhel8.6-x86_64.iso -"**cuda_toolkit_path** - -``string`` - -Optional","Absolute path to local copy of .rpm file containing CUDA packages. The cuda rpm can be downloaded from https://developer.nvidia.com/cuda-downloads. CUDA will be installed post provisioning without any user intervention. Eg: cuda_toolkit_path: ""/root/cuda-repo-rhel8-12-0-local-12.0.0_525.60.13-1.x86_64.rpm""" -"**apptainer_support** - -``boolean`` [1]_ - -Required","* Indicates whether apptainer will be installed on the cluster to enable execution of HPC benchmarks in a containeraized environment. -* If ``apptainer_support``: false, apptainer will not be installed on the cluster. -* If ``apptainer_support``: true, apptainer will be installed on the cluster." From 393ba3032fb42f7cc9282104e38f40cf40539039 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 15:58:37 +0530 Subject: [PATCH 251/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/PostProvisionScript.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index 3a04f2987..c59b92ea7 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -1,8 +1,13 @@ Creating node inventory ------------------------ -When ``provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in `/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: - * ``compute_cpu_amd`` +When ``provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in ``/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: + + * ``compute_cpu_amd`` :: + + [compute_cpu_amd] + ABCD1 + * ``compute_cpu_intel`` :: From 85cc961d952241301563f1533d1bc0758cef2fc6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 16:11:29 +0530 Subject: [PATCH 252/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 106 +++++++----------- .../provisionparams.rst | 2 +- 2 files changed, 44 insertions(+), 64 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index 53d98f854..d29bf053c 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -4,70 +4,50 @@ After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boo **Prerequisites** - * All target nodes are provisioned and booted. `Click here to verify the status of all nodes. `_ - - * The ``input/network_spec.yml`` file has been updated with all network information in addition to admin network and bmc network information. Below are all applicable properties of an additional network: - * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. - * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. - * ``static_range``: The static range of IPs to be provisioned on target nodes. - * ``dynamic_range``: The dynamic range of IPs to be provisioned on target nodes. - * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. - * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. - * ``CIDR``: Classless or Classless Inter-Domain Routing (CIDR) addresses use variable length subnet masking (VLSM) to alter the ratio between the network and host address bits in an IP address. - * ``MTU``: Maximum transmission unit (MTU) is a measurement in bytes of the largest data packets that an Internet-connected device can accept. - * ``DNS``: A DNS server is a computer equipped with a database that stores the public IP addresses linked to the domain names of websites, enabling users to reach websites using their IP addresses. - * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. - - Below is a sample ``input/network_spec.yml`` file: :: +* All target nodes are provisioned and booted. `Click here to verify the status of all nodes. `_ - --- - Networks: - - admin_network: - nic_name: "eno1" - netmask_bits: "16" - static_range: "10.5.0.1-10.5.0.200" - dynamic_range: "10.5.1.1-10.5.1.200" - correlation_to_admin: true - admin_uncorrelated_node_start_ip: "10.5.0.50" - network_gateway: "" - DNS: "" - MTU: "1500" - - - bmc_network: - nic_name: "" - netmask_bits: "" - static_range: "" - dynamic_range: "" - reassignment_to_static: true - discover_ranges: "" - network_gateway: "" - MTU: "1500" - - #********************************************************************** - # Following are the templates for providing additional network details - #********************************************************************** - - # - thor_network1: - # netmask_bits: "20" - # CIDR: "10.10.16.0" - # network_gateway: "" - # MTU: "1500" - # VLAN: "" - # - # - thor_network2: - # netmask_bits: "20" - # static_range: "10.10.1.1-10.10.15.254" - # network_gateway: "" - # MTU: "1500" - # VLAN: "1" - - - * The ``input/server_spec.yml`` file has been updated with all NIC information of the target nodes. - - * All NICs listed in the ``server_spec.yml`` file are grouped into categories (groups for servers). The string "Categories:" should not be edited out of the ``input/server_spec.yml`` file. - * The name of the NIC specified in the file (in this sample, ``ensp0``, ``ensp0.5``, and ``eno1``) is the unique identifier of NICs in the file. - * The property ``nictype`` indicates what kind of NIC is in use (ethernet, infiniband, or vlan). If the ``nictype`` is set to ``vlan``, ensure to specify a primary NIC for the VLAN using the property ``nicdevices``. - * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of the playbook, existing groups cannot be edited or deleted. +* The ``input/network_spec.yml`` file has been updated with all network information in addition to admin network and bmc network information. Below are all applicable properties of an additional network: + + * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. + * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. + * ``static_range``: The static range of IPs to be provisioned on target nodes. + * ``dynamic_range``: The dynamic range of IPs to be provisioned on target nodes. + * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. + * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. + * ``CIDR``: Classless or Classless Inter-Domain Routing (CIDR) addresses use variable length subnet masking (VLSM) to alter the ratio between the network and host address bits in an IP address. + * ``MTU``: Maximum transmission unit (MTU) is a measurement in bytes of the largest data packets that an Internet-connected device can accept. + * ``DNS``: A DNS server is a computer equipped with a database that stores the public IP addresses linked to the domain names of websites, enabling users to reach websites using their IP addresses. + * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. + +.. note:: + + * If a ``CIDR`` value is provided, the complete subnet is used for Omnia to assign IPs and where possible, the IPs will be correlated with the assignment on the admin network. + * If a VLAN is required, ensure that a VLAN ID is provided in the field ``vlan``. This field is not supported on admin or bmc networks. + + +Below is a sample of additional NIC information in a ``input/network_spec.yml`` file: :: + + - thor_network1: + netmask_bits: "20" + CIDR: "10.10.16.0" + network_gateway: "" + MTU: "1500" + VLAN: "" + + - thor_network2: + netmask_bits: "20" + static_range: "10.10.1.1-10.10.15.254" + network_gateway: "" + MTU: "1500" + VLAN: "1" + + +* The ``input/server_spec.yml`` file has been updated with all NIC information of the target nodes. + + * All NICs listed in the ``server_spec.yml`` file are grouped into categories (groups for servers). The string "Categories:" should not be edited out of the ``input/server_spec.yml`` file. + * The name of the NIC specified in the file (in this sample, ``ensp0``, ``ensp0.5``, and ``eno1``) is the unique identifier of NICs in the file. + * The property ``nictype`` indicates what kind of NIC is in use (ethernet, infiniband, or vlan). If the ``nictype`` is set to ``vlan``, ensure to specify a primary NIC for the VLAN using the property ``nicdevices``. + * While new groups can be added to the ``server_spec.yml`` file on subsequent runs of the playbook, existing groups cannot be edited or deleted. .. note:: The ``nicnetwork`` property should match any of the networks specified in ``input/network_spec.yml``. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 63b1ba96e..591fcf162 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -35,7 +35,7 @@ Update the ``input/network_spec.yml`` file for all networks available for use by * ``CIDR``: Classless or Classless Inter-Domain Routing (CIDR) addresses use variable length subnet masking (VLSM) to alter the ratio between the network and host address bits in an IP address. * ``MTU``: Maximum transmission unit (MTU) is a measurement in bytes of the largest data packets that an Internet-connected device can accept. * ``DNS``: A DNS server is a computer equipped with a database that stores the public IP addresses linked to the domain names of websites, enabling users to reach websites using their IP addresses. - * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. + * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. This value is not supported on admin and bmc networks. * If the ``nic_name`` is the same on both the admin_network and the bmc_network, a LOM setup is assumed. * BMC network details are not required when target nodes are discovered using a mapping file. From 4456d7727f32eef35b698cef0e57506f1d968ddf Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 20 Mar 2024 17:34:59 +0530 Subject: [PATCH 253/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 411869877..960e35691 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -56,20 +56,15 @@ The IP address is listed against ``proxy-public``. .. note:: Stopping the notebook server only terminates the user pod. The users data persists and can be accessed by loggin in and starting the notebook server again. -**Updating the Jupyterhub configuration** +**Redeploy Jupyterhub with new configurations** 1. Update the ``tools/jupyter_config.yml`` file with the new configuration. -2. **[Optional]** Clear the existing configuration by running the below commands: :: - - kubectl delete ns jupyterhub - kubectl delete pv jupyterhub-pv - -3. Re-run the ``jupyterhub.yml`` playbook. :: +2. Re-run the ``jupyterhub.yml`` playbook. :: cd tools ansible-playbook jupyterhub.yml -i inventory -**Clearing the Jupyterhub configuration** +**Clearing Jupyterhub configuration** Clear the existing configuration by running the below commands: :: From 91101a5c9caf3b9452b5bc8ff072687c30463519 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 09:22:20 +0530 Subject: [PATCH 254/309] Updating documentation Signed-off-by: goveac --- .../Benchmarks/AutomatingOpenMPI.rst | 1 + .../InstallationGuides/LocalRepo/FreeIPA.rst | 2 +- .../LocalRepo/Kubernetes.rst | 2 +- .../InstallationGuides/LocalRepo/OpenLDAP.rst | 2 +- .../InstallationGuides/LocalRepo/PyTorch.rst | 2 +- .../LocalRepo/SecureLoginNode.rst | 2 +- .../LocalRepo/TensorFlow.rst | 2 +- .../InstallationGuides/LocalRepo/amdgpu.rst | 2 +- .../InstallationGuides/LocalRepo/bcm_roce.rst | 2 +- .../InstallationGuides/LocalRepo/beegfs | 2 +- .../InstallationGuides/LocalRepo/cuda.rst | 2 +- .../InstallationGuides/LocalRepo/index.rst | 2 ++ .../InstallationGuides/LocalRepo/jupyter.rst | 2 +- .../InstallationGuides/LocalRepo/kserve.rst | 2 +- .../InstallationGuides/LocalRepo/kubeflow.rst | 2 +- .../InstallationGuides/LocalRepo/ofed.rst | 2 +- .../InstallationGuides/LocalRepo/openMPI.rst | 28 +++++++++++++++++++ .../InstallationGuides/LocalRepo/ucx.rst | 28 +++++++++++++++++++ .../InstallationGuides/LocalRepo/vLLM.rst | 2 +- docs/source/conf.py | 2 +- 20 files changed, 75 insertions(+), 16 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/openMPI.rst create mode 100644 docs/source/InstallationGuides/LocalRepo/ucx.rst diff --git a/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst b/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst index 452016d00..eb6c8bfe1 100644 --- a/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst +++ b/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst @@ -8,6 +8,7 @@ This topic explains how to automatically update AMD servers for MPI jobs. To man * ``provision.yml`` has been executed. * An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 slurm_control_node and 1 slurm_node. * Verify that the target nodes are in the ``booted`` state. For more information, `click here <../InstallingProvisionTool/ViewingDB.html>`_. +* A local OpenMPI repository has been created. For more information, `click here. <../LocalRepo/openMPI.html>` **To run the playbook**:: diff --git a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst index 3d7ef9e7d..c1ac700b6 100644 --- a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst +++ b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst @@ -17,7 +17,7 @@ To install FreeIPA, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for FreeIPA, view the ``input/config///freeipa.json`` file. To customize your FreeIPA installation, update the file.: -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst index 0bbfe54cc..f6de81a3c 100644 --- a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst +++ b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst @@ -16,7 +16,7 @@ To install Kubernetes, include the following line under ``softwares```: :: .. note:: The version of the software provided above is the only version of the software Omnia supports. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst index 5330e39df..1445cf663 100644 --- a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst +++ b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst @@ -16,7 +16,7 @@ To install OpenLDAP, include the following line under ``softwares```: :: -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst index 9d2dff940..16768edec 100644 --- a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst +++ b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst @@ -23,7 +23,7 @@ To install PyTorch, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for PyTorch, view the ``input/config///pytorch.json`` file. To customize your PyTorch installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst index 4199442db..4dfae0ebd 100644 --- a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst +++ b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst @@ -19,7 +19,7 @@ To secure the login node, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for securing the login node, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst index 324b8e5f5..484d9dd61 100644 --- a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst +++ b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst @@ -23,7 +23,7 @@ To install TensorFlow, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for TensorFlow, view the ``input/config///tensorflow.json`` file. To customize your TensorFlow installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/amdgpu.rst b/docs/source/InstallationGuides/LocalRepo/amdgpu.rst index 84967906a..b6ff1a73d 100644 --- a/docs/source/InstallationGuides/LocalRepo/amdgpu.rst +++ b/docs/source/InstallationGuides/LocalRepo/amdgpu.rst @@ -17,7 +17,7 @@ To install ROCm, include the following line under ``softwares```: :: ] -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst index d474774da..19f1e431a 100644 --- a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst +++ b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst @@ -35,7 +35,7 @@ For a list of repositories (and their types) configured for RoCE, view the ``inp .. note:: The only accepted URL for the RoCE driver is from the Dell Driver website. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/beegfs b/docs/source/InstallationGuides/LocalRepo/beegfs index 167c8e489..783d81a2a 100644 --- a/docs/source/InstallationGuides/LocalRepo/beegfs +++ b/docs/source/InstallationGuides/LocalRepo/beegfs @@ -17,7 +17,7 @@ To install BeeGFS, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for beegfs, view the ``input/config///beegfs.json`` file. To customize your beegfs installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst index 9521cb563..11be5e73f 100644 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ b/docs/source/InstallationGuides/LocalRepo/cuda.rst @@ -54,7 +54,7 @@ For RHEL or Rocky: :: * If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. * If the target cluster runs on RHEL or Rocky, ensure the "dkms" package is included in ``input/config//8.x/cuda.json`` as illustrated above. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 591e8051f..7f7702253 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -9,6 +9,8 @@ The local repository feature will help create offline repositories on the contro Kubernetes cuda amdgpu + ucx + openMPI beegfs nfs ofed diff --git a/docs/source/InstallationGuides/LocalRepo/jupyter.rst b/docs/source/InstallationGuides/LocalRepo/jupyter.rst index 21ce1ce32..3ce98b23f 100644 --- a/docs/source/InstallationGuides/LocalRepo/jupyter.rst +++ b/docs/source/InstallationGuides/LocalRepo/jupyter.rst @@ -17,7 +17,7 @@ To install kubeflow, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for kubeflow, view the ``input/config///kubeflow.json`` file. To customize your kubeflow installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/kserve.rst b/docs/source/InstallationGuides/LocalRepo/kserve.rst index ca4738721..baf500200 100644 --- a/docs/source/InstallationGuides/LocalRepo/kserve.rst +++ b/docs/source/InstallationGuides/LocalRepo/kserve.rst @@ -21,7 +21,7 @@ To install Kserve, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for Kserve, view the ``input/config///kserve.json`` file. To customize your Kserve installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst index 55255d9b4..419e40897 100644 --- a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst +++ b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst @@ -17,7 +17,7 @@ To install PyTorch, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for jupyter, view the ``input/config///jupyter.json`` file. To customize your jupyter installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst index 9b605d51d..703b22744 100644 --- a/docs/source/InstallationGuides/LocalRepo/ofed.rst +++ b/docs/source/InstallationGuides/LocalRepo/ofed.rst @@ -49,7 +49,7 @@ For RHEL or Rocky: :: .. note:: * If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/InstallationGuides/LocalRepo/openMPI.rst b/docs/source/InstallationGuides/LocalRepo/openMPI.rst new file mode 100644 index 000000000..94d2a75dc --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/openMPI.rst @@ -0,0 +1,28 @@ +Create local OpenMPI repository +-------------------------------- + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install UCX, include the following line under ``softwares```: :: + + {"name": "openmpi", "version":"4.1.6"}, + + +For a list of repositories (and their types) configured for OpenMPI, view the ``input/config///openmpi.json`` file. To customize your OpenMPI installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + + +OpenMPI is deployed on the cluster when the above configurations are complete and `omnia.yml is run. <../BuildingClusters/index.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/ucx.rst b/docs/source/InstallationGuides/LocalRepo/ucx.rst new file mode 100644 index 000000000..ee39eb359 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/ucx.rst @@ -0,0 +1,28 @@ +Create local Unified Communication X repository +------------------------------------------------ + +1. Enter the required values in the ``input/software_config.json`` file: + +.. csv-table:: Parameters for Software Configuration + :file: ../../Tables/software_config.csv + :header-rows: 1 + :keepspace: + :class: longtable + + +To install UCX, include the following line under ``softwares```: :: + + {"name": "ucx", "version":"1.15.0"}, + + +For a list of repositories (and their types) configured for UCX, view the ``input/config///ucx.json`` file. To customize your UCX installation, update the file. + +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +3. Run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + + +UCX is deployed on the cluster when the above configurations are complete and `omnia.yml is run. <../BuildingClusters/index.html>`_ + diff --git a/docs/source/InstallationGuides/LocalRepo/vLLM.rst b/docs/source/InstallationGuides/LocalRepo/vLLM.rst index 9302c2fe5..7eddc6244 100644 --- a/docs/source/InstallationGuides/LocalRepo/vLLM.rst +++ b/docs/source/InstallationGuides/LocalRepo/vLLM.rst @@ -22,7 +22,7 @@ To install vLLM, include the following line under ``softwares```: :: For a list of repositories (and their types) configured for vLLM, view the ``input/config///vllm.json`` file. To customize your vLLM installation, update the file. -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. +2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: cd local_repo diff --git a/docs/source/conf.py b/docs/source/conf.py index 817ca9e45..17f9f78b7 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -10,7 +10,7 @@ project = 'Omnia' copyright = '2024, Dell Technologies' author = 'dell/omnia' -release = '1.5' +release = '1.6' rst_epilog = "If you have any feedback about Omnia documentation, please reach out at `omnia.readme@dell.com `_." import sys From 746f63d19abed5edef732a18417753f8ebca349a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 10:36:55 +0530 Subject: [PATCH 255/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/RunningLocalRepo.rst | 6 ++++-- docs/source/Tables/software_config.csv | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index 71c5222b9..6f96cd3fc 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -9,7 +9,7 @@ Run the following commands: :: cd local_repo ansible-playbook local_repo.yml - +.. note:: After ``local_repo.yml`` has run, the value of ``repo_config`` in ``input/software_config.json`` cannot be updated without running the `control_plane_cleanup.yml <../CleanUpScript.html>`_ script first. **Update local repositories** @@ -18,4 +18,6 @@ This playbook updates all local repositories configured on a provisioned cluster To run the playbook: :: cd utils - ansible-playbook update_user_repo.yml -i inventory \ No newline at end of file + ansible-playbook update_user_repo.yml -i inventory + + diff --git a/docs/source/Tables/software_config.csv b/docs/source/Tables/software_config.csv index 8d902892f..49a55cfc7 100644 --- a/docs/source/Tables/software_config.csv +++ b/docs/source/Tables/software_config.csv @@ -23,7 +23,11 @@ Required","* The type of offline configuration user needs. * When the value is set to ``always``, Omnia creates a local repository/registry on the Control plane hosting all the packages/images required for the cluster. * When the value is set to ``partial``, Omnia creates a local repository/registry on the Control plane hosting all the packages/images except those listed in the ``user_registry`` in ``input/local_repo_config.yml``. * When the value is set to ``never``, Omnia does not create a local repository/registry. All the packages/images are directly downloaded on the cluster. -.. note:: All local repositories that are not available as images or RPMs will be configured locally. +.. note:: + * After ``local_repo.yml`` has run, the value of ``repo_config`` in ``input/software_config.json`` cannot be updated without running the `control_plane_cleanup.yml <../CleanUpScript.html>`_ script first. + * All local repositories that are not available as images or RPMs will be configured locally. + + * **Accepted values**: * ``always`` From 15471542dd6b9becccf983f4bbf54a0b227cdf34 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 11:16:56 +0530 Subject: [PATCH 256/309] Updating documentation Signed-off-by: goveac --- docs/source/Troubleshooting/knownissues.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index f6be9191f..2d5bc5b74 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -124,9 +124,10 @@ This issue is caused by incompatibility between Rocky 8.7 and kubernetes due to * The errors occur when the Docker pull limit is exceeded. **Resolution**: - * For ``omnia.yml`` and ``provision.yml`` : Provide the docker username and password for the Docker Hub account in the *omnia_config.yml* file and execute the playbook. + * Ensure that the ``docker_username`` and ``docker_password`` are provided in ``input/provision_config_credentials.yml``. + + * For a HPC cluster, during ``omnia.yml`` execution, a kubernetes secret 'dockerregcred' will be created in default namespace and patched to service account. User needs to patch this secret in their respective namespace while deploying custom applications and use the secret as imagePullSecrets in yaml file to avoid ErrImagePull. `Click here for more info. `_ - * For HPC cluster, during ``omnia.yml execution``, a kubernetes secret 'dockerregcred' will be created in default namespace and patched to service account. User needs to patch this secret in their respective namespace while deploying custom applications and use the secret as imagePullSecrets in yaml file to avoid ErrImagePull. [Click here for more info](https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/) .. note:: If the playbook is already executed and the pods are in **ImagePullBack** state, then run ``kubeadm reset -f`` in all the nodes before re-executing the playbook with the docker credentials. ⦾ **Why does the task 'Gather facts from all the nodes' stuck when re-running ``omnia.yml``?** From ce0c21f7d9a725b9b418d4b7e1bced511bb5107d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 11:45:41 +0530 Subject: [PATCH 257/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/provisionparams.rst | 1 + docs/source/Troubleshooting/knownissues.rst | 7 +++++++ docs/source/images/nerdctlError.png | Bin 0 -> 60504 bytes 3 files changed, 8 insertions(+) create mode 100644 docs/source/images/nerdctlError.png diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index 591fcf162..d1d2f4edd 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -85,6 +85,7 @@ A sample is provided below: :: * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. Also, the properties ``nic_name``, ``static_range``, and ``dynamic_range`` cannot be edited on subsequent runs of the provision tool. * Netmask bits are mandatory and should be same for both the ``admin_network`` and ``bmc_network`` (ie between 1 and 32; 1 and 32 are acceptable values). + * Do not assign the subnet 10.4.0.0/24 to any interfaces in the network as nerdctl uses it by default. * Ensure that the CIDR is aligned with the ``netmask_bits`` provided. * The ``discover_ranges`` property of the ``bmc_network`` can accept multiple comma-separated ranges. * The ``VLAN`` property is optional but should be between 0 and 4095 (0 and 4095 are not acceptable values). diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index 2d5bc5b74..f15738e4c 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -331,7 +331,14 @@ Recommended Actions: systemctl enable nfs-server.service +⦾ **Why does the task `configure registry: Start and enable nerdctl-registry service` fail with "Job for nerdctl-registry.service failed because the control process exited with error code"?** +.. image:: ../images/nerdctlError.png + + +**Potential Cause**: + + The subnet 10.4.0.0/24 has been assigned to the admin, bmc, or additional network. nerdctl uses this subnet by default and cannot be assigned to any other interface in the system. ⦾ **Why does the task 'Install Packages' fail on the NFS node with the message: ``Failure in talking to yum: Cannot find a valid baseurl for repo: base/7/x86_64.``** diff --git a/docs/source/images/nerdctlError.png b/docs/source/images/nerdctlError.png new file mode 100644 index 0000000000000000000000000000000000000000..4c65d9f1aa9b734b1060dfbffffc4e675d7651f9 GIT binary patch literal 60504 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 aucgB*eZ;bW-UauNA0>G;xqKN@pZ@~_q}bU2 literal 0 HcmV?d00001 From cfe4b0ffb836153b42ca4c0123c072da0613e5db Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 12:30:30 +0530 Subject: [PATCH 258/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/addinganewnode.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/source/InstallationGuides/addinganewnode.rst b/docs/source/InstallationGuides/addinganewnode.rst index 7fee2d7b0..67ce4a464 100644 --- a/docs/source/InstallationGuides/addinganewnode.rst +++ b/docs/source/InstallationGuides/addinganewnode.rst @@ -62,6 +62,10 @@ Verify that the node has been provisioned successfully by `checking the Omnia no [auth_server] 10.5.0.101 + [etcd] + + # node1 + *Updated kubernetes inventory with the new node information* @@ -80,6 +84,11 @@ Verify that the node has been provisioned successfully by `checking the Omnia no [auth_server] 10.5.0.101 + [etcd] + + # node1 + + *Existing Slurm inventory* :: @@ -121,6 +130,7 @@ Verify that the node has been provisioned successfully by `checking the Omnia no In the above examples, nodes 10.5.0.105 and 10.5.0.106 have been added to the cluster as compute nodes. .. note:: + * The ``[etcd]`` group only supports an odd number of servers in the group. * Do not change the kube_control_plane/slurm_control_node/auth_server in the existing inventory. Simply add the new node information in the kube_node/slurm_node group. * When re-running ``omnia.yml`` to add a new node, ensure that the ``input/security_config.yml`` and ``input/omnia_config.yml`` are not edited between runs. From 754126242c8181693b31e98ac7854ba14415c340 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 13:06:13 +0530 Subject: [PATCH 259/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/index.rst | 19 +- .../InstallationGuides/LocalRepo/jupyter.rst | 10 +- .../InstallationGuides/LocalRepo/kubeflow.rst | 10 +- .../LocalRepo/localrepos.rst | 301 ++++++++++++++++++ .../InstallationGuides/LocalRepo/openMPI.rst | 2 +- 5 files changed, 313 insertions(+), 29 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/localrepos.rst diff --git a/docs/source/InstallationGuides/LocalRepo/index.rst b/docs/source/InstallationGuides/LocalRepo/index.rst index 7f7702253..2dda128f6 100644 --- a/docs/source/InstallationGuides/LocalRepo/index.rst +++ b/docs/source/InstallationGuides/LocalRepo/index.rst @@ -6,24 +6,7 @@ The local repository feature will help create offline repositories on the contro .. toctree:: Prerequisite InputParameters - Kubernetes - cuda - amdgpu - ucx - openMPI - beegfs - nfs - ofed - bcm_roce - FreeIPA - OpenLDAP - SecureLoginNode - jupyter - kubeflow - vLLM - PyTorch - TensorFlow - kserve + localrepos RunningLocalRepo CustomLocalRepo diff --git a/docs/source/InstallationGuides/LocalRepo/jupyter.rst b/docs/source/InstallationGuides/LocalRepo/jupyter.rst index 3ce98b23f..de087df74 100644 --- a/docs/source/InstallationGuides/LocalRepo/jupyter.rst +++ b/docs/source/InstallationGuides/LocalRepo/jupyter.rst @@ -1,4 +1,4 @@ -Create local kubeflow repository +Create local Jupyterhub repository ------------------------------- 1. Enter the required values in the ``input/software_config.json`` file: @@ -10,12 +10,12 @@ Create local kubeflow repository :class: longtable -To install kubeflow, include the following line under ``softwares```: :: +To install Jupyterhub, include the following line under ``softwares```: :: - {"name": "kubeflow"}, + {"name": "jupyter"}, -For a list of repositories (and their types) configured for kubeflow, view the ``input/config///kubeflow.json`` file. To customize your kubeflow installation, update the file. +For a list of repositories (and their types) configured for jupyter, view the ``input/config///jupyter.json`` file. To customize your jupyter installation, update the file. 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: @@ -24,5 +24,5 @@ For a list of repositories (and their types) configured for kubeflow, view the ` ansible-playbook local_repo.yml -For information on deploying kubeflow after setting up the cluster, `click here. <../../Roles/Platform/kubeflow.html>`_ +For information on deploying kubeflow after setting up the cluster, `click here. <../../Roles/Platform/InstallJupyterhub.html>`_ diff --git a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst index 419e40897..89a78fb0b 100644 --- a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst +++ b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst @@ -1,4 +1,4 @@ -Create local Jupyter repository +Create local Kubeflow repository ------------------------------- 1. Enter the required values in the ``input/software_config.json`` file: @@ -10,12 +10,12 @@ Create local Jupyter repository :class: longtable -To install PyTorch, include the following line under ``softwares```: :: +To install kubeflow, include the following line under ``softwares```: :: - {"name": "jupyter"}, + {"name": "kubeflow"}, -For a list of repositories (and their types) configured for jupyter, view the ``input/config///jupyter.json`` file. To customize your jupyter installation, update the file. +For a list of repositories (and their types) configured for jupyter, view the ``input/config///kubeflow.json`` file. To customize your jupyter installation, update the file. 2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. 3. Run the following commands: :: @@ -24,5 +24,5 @@ For a list of repositories (and their types) configured for jupyter, view the `` ansible-playbook local_repo.yml -For information on deploying jupyter after setting up the cluster, `click here. <../../Roles/Platform/InstallJupyterhub.html>`_ +For information on deploying jupyter after setting up the cluster, `click here. <../../Roles/Platform/kubeflow.html>`_ diff --git a/docs/source/InstallationGuides/LocalRepo/localrepos.rst b/docs/source/InstallationGuides/LocalRepo/localrepos.rst new file mode 100644 index 000000000..8cfaaa2a9 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/localrepos.rst @@ -0,0 +1,301 @@ +Configuring specific local repositories +----------------------------------------- + +**AMDGPU ROCm** + + To install ROCm, include the following line under ``softwares```: :: + + "amdgpu": [ + {"name": "rocm", "version": "6.0" } + ] + + +**BCM RoCE** + + + To install RoCE, include the following line under ``softwares```: :: + + {"name": "bcm_roce", "version": "229.2.9.0"} + + + For a list of repositories (and their types) configured for RoCE, view the ``input/config/ubuntu//bcm_roce.json`` file. To customize your RoCE installation, update the file. URLs for different versions can be found `here `_: :: + + { + "bcm_roce": { + "cluster": [ + { + "package": "bcm_roce_driver_{{ bcm_roce_version }}", + "type": "tarball", + "url": "", + "path": "" + } + ] + } + } + + + .. note:: + * The RoCE driver is only supported on Ubuntu clusters. + * The only accepted URL for the RoCE driver is from the Dell Driver website. + +**BeeGFS** + + To install BeeGFS, include the following line under ``softwares```: :: + + {"name": "beegfs"}, + +**CUDA** + + To install CUDA, include the following line under ``softwares```: :: + + {"name": "cuda", "version": "12.3.2"}, + + + For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: + + For Ubuntu: :: + + { + "cuda": { + "cluster": [ + { "package": "cuda", + "type": "iso", + "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-ubuntu2204-12-3-local_12.3.2-545.23.08-1_amd64.deb", + "path": "" + } + ] + } + } + + For RHEL or Rocky: :: + + { + "cuda": { + "cluster": [ + { "package": "cuda", + "type": "iso", + "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-rhel8-12-3-local-12.3.2_545.23.08-1.x86_64.rpm", + "path": "" + }, + { "package": "dkms", + "type": "rpm", + "repo_name": "epel" + } + ] + } + } + + + .. note:: + * If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. + * If the target cluster runs on RHEL or Rocky, ensure the "dkms" package is included in ``input/config//8.x/cuda.json`` as illustrated above. + +**Custom repositories** + + Include the following line under ``softwares```: :: + + {"name": "custom"}, + + Create a ``custom.json`` file in the following directory: ``input/config//`` to define the repositories. For example, For a cluster running RHEL 8.8, go to ``input/config/rhel/8.8/`` and create the file there. The file is a JSON list consisting of the package name, repository type, URL (optional), and version (optional). Below is a sample version of the file: :: + + { + "custom": { + "cluster": [ + { + "package": "ansible==5.3.2", + "type": "pip_module" + }, + { + "package": "docker-ce-24.0.4", + "type": "rpm", + "repo_name": "docker-ce-repo" + }, + + { + "package": "gcc", + "type": "rpm", + "repo_name": "appstream" + }, + { + "package": "community.general", + "type": "ansible_galaxy_collection", + "version": "4.4.0" + }, + + { + "package": "perl-Switch", + "type": "rpm", + "repo_name": "codeready-builder" + }, + { + "package": "prometheus-slurm-exporter", + "type": "git", + "url": "https://github.com/vpenso/prometheus-slurm-exporter.git", + "version": "master" + }, + { + "package": "ansible.utils", + "type": "ansible_galaxy_collection", + "version": "2.5.2" + }, + { + "package": "prometheus-2.23.0.linux-amd64", + "type": "tarball", + "url": "https://github.com/prometheus/prometheus/releases/download/v2.23.0/prometheus-2.23.0.linux-amd64.tar.gz" + }, + { + "package": "metallb-native", + "type": "manifest", + "url": "https://raw.githubusercontent.com/metallb/metallb/v0.13.4/config/manifests/metallb-native.yaml" + }, + { + "package": "registry.k8s.io/pause", + "version": "3.9", + "type": "image" + } + + ] + } + } + +**FreeIPA** + + To install FreeIPA, include the following line under ``softwares```: :: + + {"name": "freeipa"}, + +**Jupyterhub** + + To install Jupyterhub, include the following line under ``softwares```: :: + + {"name": "jupyter"}, + +**Kserve** + + To install Kserve, include the following line under ``softwares```: :: + + "kserve": [ + {"name": "istio"}, + {"name": "cert_manager"}, + {"name": "knative"} + ] + +**Kubeflow** + + To install kubeflow, include the following line under ``softwares```: :: + + {"name": "kubeflow"}, + +**Kubernetes** + + To install Kubernetes, include the following line under ``softwares```: :: + + {"name": "k8s", "version":"1.26.12"}, + + .. note:: The version of the software provided above is the only version of the software Omnia supports. + +**OFED** + + To install OFED, include the following line under ``softwares```: :: + + {"name": "ofed", "version": "24.01-0.3.3.1"}, + + + For a list of repositories (and their types) configured for OFED, view the ``input/config///ofed.json`` file. To customize your OFED installation, update the file.: + + For Ubuntu: :: + + { + "ofed": { + "cluster": [ + { "package": "ofed", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", + "path": "" + } + ] + } + } + + + For RHEL or Rocky: :: + + { + "ofed": { + "cluster": [ + { "package": "ofed", + "type": "iso", + "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-rhel8.7-x86_64.iso", + "path": "" + } + ] + } + } + +.. note:: If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json``. + +**OpenLDAP** + + To install OpenLDAP, include the following line under ``softwares```: :: + + {"name": "openldap"}, + +**OpenMPI** + + To install OpenMPI, include the following line under ``softwares```: :: + + {"name": "openmpi", "version":"4.1.6"}, + +**Pytorch** + + To install PyTorch, include the following line under ``softwares```: :: + + {"name": "pytorch"}, + + "pytorch": [ + {"name": "pytorch_cpu"}, + {"name": "pytorch_amd"}, + {"name": "pytorch_nvidia"} + ], +**Secure Login Node** + + To secure the login node, include the following line under ``softwares```: :: + + {"name": "secure_login_node"}, + + +**TensorFlow** + + To install TensorFlow, include the following line under ``softwares```: :: + + {"name": "tensorflow"}, + + "tensorflow": [ + {"name": "tensorflow_cpu"}, + {"name": "tensorflow_amd"}, + {"name": "tensorflow_nvidia"} + ] + +**Unified Communication X** + + To install UCX, include the following line under ``softwares```: :: + + {"name": "ucx", "version":"1.15.0"}, + +**vLLM** + + To install vLLM, include the following line under ``softwares```: :: + + {"name": "vLLM"}, + + "vllm": [ + {"name": "vllm_amd"}, + {"name": "vllm_nvidia"} + ], + + + + + + + diff --git a/docs/source/InstallationGuides/LocalRepo/openMPI.rst b/docs/source/InstallationGuides/LocalRepo/openMPI.rst index 94d2a75dc..5a8ab4216 100644 --- a/docs/source/InstallationGuides/LocalRepo/openMPI.rst +++ b/docs/source/InstallationGuides/LocalRepo/openMPI.rst @@ -10,7 +10,7 @@ Create local OpenMPI repository :class: longtable -To install UCX, include the following line under ``softwares```: :: +To install OpenMPI, include the following line under ``softwares```: :: {"name": "openmpi", "version":"4.1.6"}, From e0eff88d214d6ceecbb98e17c50b59f8698a45c1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 13:36:23 +0530 Subject: [PATCH 260/309] Updating documentation Signed-off-by: goveac --- .../LocalRepo/localrepos.rst | 28 +++++++ docs/source/Roles/Storage/index.rst | 77 +------------------ docs/source/Tables/storage_config.csv | 2 +- 3 files changed, 33 insertions(+), 74 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/localrepos.rst b/docs/source/InstallationGuides/LocalRepo/localrepos.rst index 8cfaaa2a9..71f038be3 100644 --- a/docs/source/InstallationGuides/LocalRepo/localrepos.rst +++ b/docs/source/InstallationGuides/LocalRepo/localrepos.rst @@ -44,6 +44,8 @@ Configuring specific local repositories {"name": "beegfs"}, +For information on deploying BeeGFS after setting up the cluster, `click here. <../../Roles/Storage/index.html>`_ + **CUDA** To install CUDA, include the following line under ``softwares```: :: @@ -164,12 +166,16 @@ Configuring specific local repositories {"name": "freeipa"}, +For information on deploying FreeIPA after setting up the cluster, `click here. <../../Roles/Security/index.html>`_ + **Jupyterhub** To install Jupyterhub, include the following line under ``softwares```: :: {"name": "jupyter"}, +For information on deploying Jupyterhub after setting up the cluster, `click here. <../../Roles/Platform/InstallJupyterhub.html>`_ + **Kserve** To install Kserve, include the following line under ``softwares```: :: @@ -180,12 +186,17 @@ Configuring specific local repositories {"name": "knative"} ] +For information on deploying Kserve after setting up the cluster, `click here. <../../Roles/Platform/kserve.html>`_ + **Kubeflow** To install kubeflow, include the following line under ``softwares```: :: {"name": "kubeflow"}, +For information on deploying kubeflow after setting up the cluster, `click here. <../../Roles/Platform/kubeflow.html>`_ + + **Kubernetes** To install Kubernetes, include the following line under ``softwares```: :: @@ -194,6 +205,8 @@ Configuring specific local repositories .. note:: The version of the software provided above is the only version of the software Omnia supports. + + **OFED** To install OFED, include the following line under ``softwares```: :: @@ -240,12 +253,17 @@ Configuring specific local repositories {"name": "openldap"}, +Features that are part of the OpenLDAP repository are enabled by running `security.yml <../../Roles/Security/index.html>`_ + **OpenMPI** To install OpenMPI, include the following line under ``softwares```: :: {"name": "openmpi", "version":"4.1.6"}, + +OpenMPI is deployed on the cluster when the above configurations are complete and `omnia.yml is run. <../BuildingClusters/index.html>`_ + **Pytorch** To install PyTorch, include the following line under ``softwares```: :: @@ -257,12 +275,16 @@ Configuring specific local repositories {"name": "pytorch_amd"}, {"name": "pytorch_nvidia"} ], + +For information on deploying Pytorch after setting up the cluster, `click here. <../../Roles/Platform/Pytorch.html>`_ + **Secure Login Node** To secure the login node, include the following line under ``softwares```: :: {"name": "secure_login_node"}, +Features that are part of the secure_login_node repository are enabled by running `security.yml <../../Roles/Security/index.html>`_ **TensorFlow** @@ -276,12 +298,16 @@ Configuring specific local repositories {"name": "tensorflow_nvidia"} ] +For information on deploying TensorFlow after setting up the cluster, `click here. <../../Roles/Platform/TensorFlow.html>`_ + **Unified Communication X** To install UCX, include the following line under ``softwares```: :: {"name": "ucx", "version":"1.15.0"}, +UCX is deployed on the cluster when the ``local_repo.yml`` is run then `omnia.yml is run. <../BuildingClusters/index.html>`_ + **vLLM** To install vLLM, include the following line under ``softwares```: :: @@ -293,6 +319,8 @@ Configuring specific local repositories {"name": "vllm_nvidia"} ], +For information on deploying vLLM after setting up the cluster, `click here. <../../Roles/Platform/SetupvLLM.html>`_ + diff --git a/docs/source/Roles/Storage/index.rst b/docs/source/Roles/Storage/index.rst index 09cc4c163..270a59a26 100644 --- a/docs/source/Roles/Storage/index.rst +++ b/docs/source/Roles/Storage/index.rst @@ -5,79 +5,10 @@ The storage role allows users to configure PowerVault Storage devices, BeeGFS an 1. Enter all required parameters in ``input/storage_config.yml`` -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| Name | Details | -+=================================+======================================================================================================================================================================================================================================================+ -| nfs_client_params | If NFS client services are to be deployed, enter the configuration required here in JSON format. The server_ip provided should have an explicit NFS server running. If left blank, no NFS configuration takes place. Possible values include: | -| ``JSON list`` | 1. Single NFS file system: A single filesystem from a single NFS server is mounted. | -| Optional | | -| | Sample value: ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/share”, client_share_path: “/mnt/client”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | 2. Multiple Mount NFS file system: Multiple filesystems from a single NFS server are mounted. | -| | Sample values: | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/server1”, client_share_path: “/mnt/client1”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/server2”, client_share_path: “/mnt/client2”, client_mount_options: “nosuid,rw,sync,hard,intr” }`` | -| | 3. Multiple NFS file systems: Multiple filesystems are mounted from multiple servers. | -| | Sample Values: ``- { server_ip: zz.zz.zz.zz, server_share_path: “/mnt/share1”, client_share_path: “/mnt/client1”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | ``- { server_ip: xx.xx.xx.xx, server_share_path: “/mnt/share2”, client_share_path: “/mnt/client2”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | ``- { server_ip: yy.yy.yy.yy, server_share_path: “/mnt/share3”, client_share_path: “/mnt/client3”, client_mount_options: “nosuid,rw,sync,hard,intr”}`` | -| | | -| | | -| | **Default value**: ``{ server_ip: , server_share_path: , client_share_path: , client_mount_options: }`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_support | This variable is used to install beegfs-client on compute and manager nodes | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_rdma_support | This variable is used if user has RDMA-capable network hardware (e.g., InfiniBand) | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_ofed_kernel_modules_path | The path where separate OFED kernel modules are installed. | -| ``string`` | | -| Optional | **Default value**: ``"/usr/src/ofa_kernel/default/include"`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mgmt_server | BeeGFS management server IP. Note: The provided IP should have an explicit BeeGFS management server running . | -| ``string`` | | -| Required | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_mounts | Beegfs-client file system mount location. If ``storage_yml`` is being used to change the BeeGFS mounts location, set beegfs_unmount_client to true | -| ``string`` | **Default value**: "/mnt/beegfs" | -| Optional | | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_unmount_client | Changing this value to true will unmount running instance of BeeGFS client and should only be used when decommisioning BeeGFS, changing the mount location or changing the BeeGFS version. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_client_version | Beegfs client version needed on compute and manager nodes. | -| ``string`` | | -| Optional | **Default value**: 7.2.6 | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_version_change | Use this variable to change the BeeGFS version on the target nodes. | -| ``boolean`` | | -| Optional | Choices: | -| | | -| | * ``false`` <- Default | -| | | -| | * ``true`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| beegfs_secret_storage_filepath | * The filepath (including the filename) where the ``connauthfile`` is placed. | -| ``string`` | * Required for Beegfs version >= 7.2.7 | -| Required | | -| | | -| | **Default values**: ``/home/connauthfile`` | -+---------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +.. csv-table:: Parameters for Storage + :file: ../../Tables/storage_config.csv + :header-rows: 1 + :keepspace: .. note:: If ``storage.yml`` is run with the ``input/storage_config.yml`` filled out, BeeGFS and NFS client will be set up. diff --git a/docs/source/Tables/storage_config.csv b/docs/source/Tables/storage_config.csv index 9d2838ca8..2cfb4421d 100644 --- a/docs/source/Tables/storage_config.csv +++ b/docs/source/Tables/storage_config.csv @@ -68,7 +68,7 @@ Choices: * If ansible is installed using pip, this path should be set **Default values**: ``/etc/ansible`` " -"beegfs_secret_storage_filepath +"**beegfs_secret_storage_filepath** ``string`` Required ","* The filepath (including the filename) where the ``connauthfile`` is placed. From 9e31bdfb8d83ff2da159c508d0e1cfea5976cffa Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 21 Mar 2024 17:17:04 +0530 Subject: [PATCH 261/309] Updating documentation Signed-off-by: goveac --- .../LocalRepo/localrepos.rst | 36 +++++++++---------- docs/source/Troubleshooting/knownissues.rst | 7 +++- 2 files changed, 24 insertions(+), 19 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/localrepos.rst b/docs/source/InstallationGuides/LocalRepo/localrepos.rst index 71f038be3..f3bc3ce5f 100644 --- a/docs/source/InstallationGuides/LocalRepo/localrepos.rst +++ b/docs/source/InstallationGuides/LocalRepo/localrepos.rst @@ -3,7 +3,7 @@ Configuring specific local repositories **AMDGPU ROCm** - To install ROCm, include the following line under ``softwares```: :: + To install ROCm, include the following line under ``softwares``: :: "amdgpu": [ {"name": "rocm", "version": "6.0" } @@ -13,7 +13,7 @@ Configuring specific local repositories **BCM RoCE** - To install RoCE, include the following line under ``softwares```: :: + To install RoCE, include the following line under ``softwares``: :: {"name": "bcm_roce", "version": "229.2.9.0"} @@ -40,7 +40,7 @@ Configuring specific local repositories **BeeGFS** - To install BeeGFS, include the following line under ``softwares```: :: + To install BeeGFS, include the following line under ``softwares``: :: {"name": "beegfs"}, @@ -48,7 +48,7 @@ For information on deploying BeeGFS after setting up the cluster, `click here. < **CUDA** - To install CUDA, include the following line under ``softwares```: :: + To install CUDA, include the following line under ``softwares``: :: {"name": "cuda", "version": "12.3.2"}, @@ -94,7 +94,7 @@ For information on deploying BeeGFS after setting up the cluster, `click here. < **Custom repositories** - Include the following line under ``softwares```: :: + Include the following line under ``softwares``: :: {"name": "custom"}, @@ -162,7 +162,7 @@ For information on deploying BeeGFS after setting up the cluster, `click here. < **FreeIPA** - To install FreeIPA, include the following line under ``softwares```: :: + To install FreeIPA, include the following line under ``softwares``: :: {"name": "freeipa"}, @@ -170,7 +170,7 @@ For information on deploying FreeIPA after setting up the cluster, `click here. **Jupyterhub** - To install Jupyterhub, include the following line under ``softwares```: :: + To install Jupyterhub, include the following line under ``softwares``: :: {"name": "jupyter"}, @@ -178,7 +178,7 @@ For information on deploying Jupyterhub after setting up the cluster, `click her **Kserve** - To install Kserve, include the following line under ``softwares```: :: + To install Kserve, include the following line under ``softwares``: :: "kserve": [ {"name": "istio"}, @@ -190,7 +190,7 @@ For information on deploying Kserve after setting up the cluster, `click here. < **Kubeflow** - To install kubeflow, include the following line under ``softwares```: :: + To install kubeflow, include the following line under ``softwares``: :: {"name": "kubeflow"}, @@ -199,7 +199,7 @@ For information on deploying kubeflow after setting up the cluster, `click here. **Kubernetes** - To install Kubernetes, include the following line under ``softwares```: :: + To install Kubernetes, include the following line under ``softwares``: :: {"name": "k8s", "version":"1.26.12"}, @@ -209,7 +209,7 @@ For information on deploying kubeflow after setting up the cluster, `click here. **OFED** - To install OFED, include the following line under ``softwares```: :: + To install OFED, include the following line under ``softwares``: :: {"name": "ofed", "version": "24.01-0.3.3.1"}, @@ -249,7 +249,7 @@ For information on deploying kubeflow after setting up the cluster, `click here. **OpenLDAP** - To install OpenLDAP, include the following line under ``softwares```: :: + To install OpenLDAP, include the following line under ``softwares``: :: {"name": "openldap"}, @@ -257,7 +257,7 @@ Features that are part of the OpenLDAP repository are enabled by running `securi **OpenMPI** - To install OpenMPI, include the following line under ``softwares```: :: + To install OpenMPI, include the following line under ``softwares``: :: {"name": "openmpi", "version":"4.1.6"}, @@ -266,7 +266,7 @@ OpenMPI is deployed on the cluster when the above configurations are complete an **Pytorch** - To install PyTorch, include the following line under ``softwares```: :: + To install PyTorch, include the following line under ``softwares``: :: {"name": "pytorch"}, @@ -280,7 +280,7 @@ For information on deploying Pytorch after setting up the cluster, `click here. **Secure Login Node** - To secure the login node, include the following line under ``softwares```: :: + To secure the login node, include the following line under ``softwares``: :: {"name": "secure_login_node"}, @@ -288,7 +288,7 @@ Features that are part of the secure_login_node repository are enabled by runnin **TensorFlow** - To install TensorFlow, include the following line under ``softwares```: :: + To install TensorFlow, include the following line under ``softwares``: :: {"name": "tensorflow"}, @@ -302,7 +302,7 @@ For information on deploying TensorFlow after setting up the cluster, `click her **Unified Communication X** - To install UCX, include the following line under ``softwares```: :: + To install UCX, include the following line under ``softwares``: :: {"name": "ucx", "version":"1.15.0"}, @@ -310,7 +310,7 @@ UCX is deployed on the cluster when the ``local_repo.yml`` is run then `omnia.ym **vLLM** - To install vLLM, include the following line under ``softwares```: :: + To install vLLM, include the following line under ``softwares``: :: {"name": "vLLM"}, diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index f15738e4c..041f32a2c 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -338,8 +338,13 @@ Recommended Actions: **Potential Cause**: - The subnet 10.4.0.0/24 has been assigned to the admin, bmc, or additional network. nerdctl uses this subnet by default and cannot be assigned to any other interface in the system. + * The subnet 10.4.0.0/24 has been assigned to the admin, bmc, or additional network. nerdctl uses this subnet by default and cannot be assigned to any other interface in the system. + * The docker pull limit has been breached. +**Resolution**: + + * Reassign the conflicting network to a different subnet. + * Update ``input/provision_config_credentials.yml`` with the ``docker_username`` and ``docker_password``. ⦾ **Why does the task 'Install Packages' fail on the NFS node with the message: ``Failure in talking to yum: Cannot find a valid baseurl for repo: base/7/x86_64.``** From 31ac8688a042abec9e563a511d9777db6c0b6cb7 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 22 Mar 2024 08:02:40 +0530 Subject: [PATCH 262/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/deletenode.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst index 8b0d6b737..5318e5c23 100644 --- a/docs/source/InstallationGuides/deletenode.rst +++ b/docs/source/InstallationGuides/deletenode.rst @@ -98,11 +98,19 @@ Run the playbook using the following commands: :: To skip confirmation while running the playbook, use ``ansible-playbook delete_node.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. -The inventory file passed for ``delete_node.yml`` should follow the below format: :: +The inventory file passed for ``delete_node.yml`` should follow one of the below formats: :: [nodes] - {ip or servicetag} - {ip or servicetag} + {ip address} + {ip address} + + + +:: + + [nodes] + {service tag} + {service tag} .. note:: When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. From 3134225cd276f258d6315f39275c3ef91c11a66b Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 22 Mar 2024 11:53:45 +0530 Subject: [PATCH 263/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/Prerequisite.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index ce73e76bd..98ddf59d8 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -1,6 +1,14 @@ Before you create local repositories ------------------------------------- +**Space considerations** + +If all available software stacks are configured, the free space required is as below: + + * For packages: 30GB + * For images (in ``/var``): 400GB + * For storing repositories (the file path should be specified in ``repo_store_path`` in ``input/local_repo_config.yml``): 30GB. + **On Ubuntu clusters** For persistent offline local repositories, (If the parameter ``repo_config`` in ``input/software_config`` is set to ``always``), click `here `_ to set up the required repositories. From 2ed08685a09622d53992bc93d41a43006f47e33c Mon Sep 17 00:00:00 2001 From: cgoveas Date: Fri, 22 Mar 2024 12:30:51 +0530 Subject: [PATCH 264/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/DiscoveryMechanisms/bmc.rst | 3 ++- .../DiscoveryMechanisms/mappingfile.rst | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index fb0ce7082..d5a411d7a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -8,7 +8,8 @@ For automatic provisioning of servers and discovery, the BMC method can be used. * Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. image:: ../../../images/ControlPlaneNic.png -* BMC NICs should have a static IP assigned or be configured in DHCP mode. +* To assign IPs on the BMC network while discovering servers using a BMC details, target servers should be in DHCP mode or switch details should be provided. + * BMC credentials should be the same across all servers and provided as input to Omnia in the parameters explained below. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index 01cc1b88b..f769923ec 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -19,7 +19,7 @@ Manually collect PXE NIC information for target servers and define them to Omnia * The MAC address provided in ``pxe_mapping_file.csv`` should refer to the PXE NIC on the target nodes. * If the field ``bmc_ip`` is not populated, manually set the nodes to PXE mode and start provisioning. If the fields are populated and IPMI is enabled, Omnia will take care of provisioning automatically. * Target servers should be configured to boot in PXE mode with the appropriate NIC as the first boot device. - + * To assign IPs on the BMC network while discovering servers using a mapping file, target servers should be in DHCP mode or switch details should be provided. To continue to the next steps: From c3756c1c9e17ee7d44b84dfe52b04bbfe29f974a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 25 Mar 2024 08:28:43 +0530 Subject: [PATCH 265/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/LocalRepo/Prerequisite.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index 98ddf59d8..77f643dbb 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -3,7 +3,7 @@ Before you create local repositories **Space considerations** -If all available software stacks are configured, the free space required is as below: +If all available software stacks are configured, the free space required on the control plane is as below: * For packages: 30GB * For images (in ``/var``): 400GB From bf879771a8d91c1ca004156049859281427c0c5e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 25 Mar 2024 09:18:33 +0530 Subject: [PATCH 266/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/LocalRepo/FreeIPA.rst | 24 -------- .../LocalRepo/Kubernetes.rst | 25 -------- .../InstallationGuides/LocalRepo/OpenLDAP.rst | 23 ------- .../InstallationGuides/LocalRepo/PyTorch.rst | 34 ----------- .../LocalRepo/RunningLocalRepo.rst | 23 ------- .../LocalRepo/SecureLoginNode.rst | 26 -------- .../LocalRepo/TensorFlow.rst | 33 ---------- .../InstallationGuides/LocalRepo/amdgpu.rst | 24 -------- .../InstallationGuides/LocalRepo/bcm_roce.rst | 42 ------------- .../InstallationGuides/LocalRepo/beegfs | 28 --------- .../InstallationGuides/LocalRepo/cuda.rst | 61 ------------------- .../InstallationGuides/LocalRepo/jupyter.rst | 28 --------- .../InstallationGuides/LocalRepo/kserve.rst | 30 --------- .../InstallationGuides/LocalRepo/kubeflow.rst | 28 --------- .../InstallationGuides/LocalRepo/ofed.rst | 56 ----------------- .../InstallationGuides/LocalRepo/openMPI.rst | 28 --------- .../InstallationGuides/LocalRepo/ucx.rst | 28 --------- .../InstallationGuides/LocalRepo/vLLM.rst | 31 ---------- 18 files changed, 572 deletions(-) delete mode 100644 docs/source/InstallationGuides/LocalRepo/FreeIPA.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/Kubernetes.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/PyTorch.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/TensorFlow.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/amdgpu.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/bcm_roce.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/beegfs delete mode 100644 docs/source/InstallationGuides/LocalRepo/cuda.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/jupyter.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/kserve.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/kubeflow.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/ofed.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/openMPI.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/ucx.rst delete mode 100644 docs/source/InstallationGuides/LocalRepo/vLLM.rst diff --git a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst b/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst deleted file mode 100644 index c1ac700b6..000000000 --- a/docs/source/InstallationGuides/LocalRepo/FreeIPA.rst +++ /dev/null @@ -1,24 +0,0 @@ -Create FreeIPA repository -------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install FreeIPA, include the following line under ``softwares```: :: - - {"name": "freeipa"}, - - -For a list of repositories (and their types) configured for FreeIPA, view the ``input/config///freeipa.json`` file. To customize your FreeIPA installation, update the file.: - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml diff --git a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst b/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst deleted file mode 100644 index f6de81a3c..000000000 --- a/docs/source/InstallationGuides/LocalRepo/Kubernetes.rst +++ /dev/null @@ -1,25 +0,0 @@ -Create local Kubernetes repository ----------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install Kubernetes, include the following line under ``softwares```: :: - - {"name": "k8s", "version":"1.26.12"}, - -.. note:: The version of the software provided above is the only version of the software Omnia supports. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - -To complete the installation of Kubernetes on the cluster, `click here. <../BuildingClusters/index.html>`_ \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst b/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst deleted file mode 100644 index 1445cf663..000000000 --- a/docs/source/InstallationGuides/LocalRepo/OpenLDAP.rst +++ /dev/null @@ -1,23 +0,0 @@ -Create OpenLDAP repository ---------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install OpenLDAP, include the following line under ``softwares```: :: - - {"name": "openldap"}, - - - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml diff --git a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst b/docs/source/InstallationGuides/LocalRepo/PyTorch.rst deleted file mode 100644 index 16768edec..000000000 --- a/docs/source/InstallationGuides/LocalRepo/PyTorch.rst +++ /dev/null @@ -1,34 +0,0 @@ -Create local PyTorch repository -------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install PyTorch, include the following line under ``softwares```: :: - - {"name": "pytorch"}, - - "pytorch": [ - {"name": "pytorch_cpu"}, - {"name": "pytorch_amd"}, - {"name": "pytorch_nvidia"} - ], - - -For a list of repositories (and their types) configured for PyTorch, view the ``input/config///pytorch.json`` file. To customize your PyTorch installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - - -For information on deploying PyTorch after setting up the cluster, `click here. <../../Roles/Platform/Pytorch.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst deleted file mode 100644 index 6f96cd3fc..000000000 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ /dev/null @@ -1,23 +0,0 @@ -Running local repo ------------------- - -The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. ``local_repo/local_repo.yml`` runs with inputs from ``input/software_config.json`` and ``input/local_repo_config.yml``: - - -Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - -.. note:: After ``local_repo.yml`` has run, the value of ``repo_config`` in ``input/software_config.json`` cannot be updated without running the `control_plane_cleanup.yml <../CleanUpScript.html>`_ script first. - -**Update local repositories** - -This playbook updates all local repositories configured on a provisioned cluster after local repositories have been configured. - -To run the playbook: :: - - cd utils - ansible-playbook update_user_repo.yml -i inventory - - diff --git a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst b/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst deleted file mode 100644 index 4dfae0ebd..000000000 --- a/docs/source/InstallationGuides/LocalRepo/SecureLoginNode.rst +++ /dev/null @@ -1,26 +0,0 @@ -Create secure login node repository ------------------------------------ - - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To secure the login node, include the following line under ``softwares```: :: - - {"name": "secure_login_node"}, - - -For a list of repositories (and their types) configured for securing the login node, view the ``input/config///secure_login_node.json`` file. To customize your repository installation, update the file.: - - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst b/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst deleted file mode 100644 index 484d9dd61..000000000 --- a/docs/source/InstallationGuides/LocalRepo/TensorFlow.rst +++ /dev/null @@ -1,33 +0,0 @@ -Create local TensorFlow repository ------------------------------------ - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install TensorFlow, include the following line under ``softwares```: :: - - {"name": "tensorflow"}, - - "tensorflow": [ - {"name": "tensorflow_cpu"}, - {"name": "tensorflow_amd"}, - {"name": "tensorflow_nvidia"} - ] - - -For a list of repositories (and their types) configured for TensorFlow, view the ``input/config///tensorflow.json`` file. To customize your TensorFlow installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - -For information on deploying TensorFlow after setting up the cluster, `click here. <../../Roles/Platform/TensorFlow.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/amdgpu.rst b/docs/source/InstallationGuides/LocalRepo/amdgpu.rst deleted file mode 100644 index b6ff1a73d..000000000 --- a/docs/source/InstallationGuides/LocalRepo/amdgpu.rst +++ /dev/null @@ -1,24 +0,0 @@ -Create local ROCm repository ------------------------------ - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install ROCm, include the following line under ``softwares```: :: - - "amdgpu": [ - {"name": "rocm", "version": "6.0" } - ] - - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst b/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst deleted file mode 100644 index 19f1e431a..000000000 --- a/docs/source/InstallationGuides/LocalRepo/bcm_roce.rst +++ /dev/null @@ -1,42 +0,0 @@ -Create local RoCE repository ------------------------------ - -.. note:: The RoCE driver is only supported on Ubuntu clusters. - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install RoCE, include the following line under ``softwares```: :: - - {"name": "bcm_roce", "version": "229.2.9.0"} - - -For a list of repositories (and their types) configured for RoCE, view the ``input/config/ubuntu//bcm_roce.json`` file. To customize your RoCE installation, update the file. URLs for different versions can be found `here `_: :: - - { - "bcm_roce": { - "cluster": [ - { - "package": "bcm_roce_driver_{{ bcm_roce_version }}", - "type": "tarball", - "url": "", - "path": "" - } - ] - } - } - - -.. note:: The only accepted URL for the RoCE driver is from the Dell Driver website. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/beegfs b/docs/source/InstallationGuides/LocalRepo/beegfs deleted file mode 100644 index 783d81a2a..000000000 --- a/docs/source/InstallationGuides/LocalRepo/beegfs +++ /dev/null @@ -1,28 +0,0 @@ -Create local beegfs repository -------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install BeeGFS, include the following line under ``softwares```: :: - - {"name": "beegfs"}, - - -For a list of repositories (and their types) configured for beegfs, view the ``input/config///beegfs.json`` file. To customize your beegfs installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - - -For information on deploying BeeGFS before setting up the cluster, `click here. <../BuildingClusters/BeeGFS.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/cuda.rst b/docs/source/InstallationGuides/LocalRepo/cuda.rst deleted file mode 100644 index 11be5e73f..000000000 --- a/docs/source/InstallationGuides/LocalRepo/cuda.rst +++ /dev/null @@ -1,61 +0,0 @@ -Create local CUDA repository ------------------------------ - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install CUDA, include the following line under ``softwares```: :: - - {"name": "cuda", "version": "12.3.2"}, - - -For a list of repositories (and their types) configured for CUDA, view the ``input/config///cuda.json`` file. To customize your CUDA installation, update the file. URLs for different versions can be found `here `_: - -For Ubuntu: :: - - { - "cuda": { - "cluster": [ - { "package": "cuda", - "type": "iso", - "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-ubuntu2204-12-3-local_12.3.2-545.23.08-1_amd64.deb", - "path": "" - } - ] - } - } - -For RHEL or Rocky: :: - - { - "cuda": { - "cluster": [ - { "package": "cuda", - "type": "iso", - "url": "https://developer.download.nvidia.com/compute/cuda/12.3.2/local_installers/cuda-repo-rhel8-12-3-local-12.3.2_545.23.08-1.x86_64.rpm", - "path": "" - }, - { "package": "dkms", - "type": "rpm", - "repo_name": "epel" - } - ] - } - } - - -.. note:: -* If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. -* If the target cluster runs on RHEL or Rocky, ensure the "dkms" package is included in ``input/config//8.x/cuda.json`` as illustrated above. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/jupyter.rst b/docs/source/InstallationGuides/LocalRepo/jupyter.rst deleted file mode 100644 index de087df74..000000000 --- a/docs/source/InstallationGuides/LocalRepo/jupyter.rst +++ /dev/null @@ -1,28 +0,0 @@ -Create local Jupyterhub repository -------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install Jupyterhub, include the following line under ``softwares```: :: - - {"name": "jupyter"}, - - -For a list of repositories (and their types) configured for jupyter, view the ``input/config///jupyter.json`` file. To customize your jupyter installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - - -For information on deploying kubeflow after setting up the cluster, `click here. <../../Roles/Platform/InstallJupyterhub.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/kserve.rst b/docs/source/InstallationGuides/LocalRepo/kserve.rst deleted file mode 100644 index baf500200..000000000 --- a/docs/source/InstallationGuides/LocalRepo/kserve.rst +++ /dev/null @@ -1,30 +0,0 @@ -Create local Kserve repository ------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install Kserve, include the following line under ``softwares```: :: - - "kserve": [ - {"name": "istio"}, - {"name": "cert_manager"}, - {"name": "knative"} - ] - - -For a list of repositories (and their types) configured for Kserve, view the ``input/config///kserve.json`` file. To customize your Kserve installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - -For information on deploying Kserve after setting up the cluster, `click here. <../../Roles/Platform/kserve.html>`_ diff --git a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst b/docs/source/InstallationGuides/LocalRepo/kubeflow.rst deleted file mode 100644 index 89a78fb0b..000000000 --- a/docs/source/InstallationGuides/LocalRepo/kubeflow.rst +++ /dev/null @@ -1,28 +0,0 @@ -Create local Kubeflow repository -------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install kubeflow, include the following line under ``softwares```: :: - - {"name": "kubeflow"}, - - -For a list of repositories (and their types) configured for jupyter, view the ``input/config///kubeflow.json`` file. To customize your jupyter installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - - -For information on deploying jupyter after setting up the cluster, `click here. <../../Roles/Platform/kubeflow.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/ofed.rst b/docs/source/InstallationGuides/LocalRepo/ofed.rst deleted file mode 100644 index 703b22744..000000000 --- a/docs/source/InstallationGuides/LocalRepo/ofed.rst +++ /dev/null @@ -1,56 +0,0 @@ -Create local OFED repository ------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install OFED, include the following line under ``softwares```: :: - - {"name": "ofed", "version": "24.01-0.3.3.1"}, - - -For a list of repositories (and their types) configured for OFED, view the ``input/config///ofed.json`` file. To customize your OFED installation, update the file.: - -For Ubuntu: :: - - { - "ofed": { - "cluster": [ - { "package": "ofed", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-ubuntu20.04-x86_64.iso", - "path": "" - } - ] - } - } - - -For RHEL or Rocky: :: - - { - "ofed": { - "cluster": [ - { "package": "ofed", - "type": "iso", - "url": "https://content.mellanox.com/ofed/MLNX_OFED-24.01-0.3.3.1/MLNX_OFED_LINUX-24.01-0.3.3.1-rhel8.7-x86_64.iso", - "path": "" - } - ] - } - } - -.. note:: -* If the package version is customized, ensure that the ``version`` value is updated in ``software_config.json```. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml \ No newline at end of file diff --git a/docs/source/InstallationGuides/LocalRepo/openMPI.rst b/docs/source/InstallationGuides/LocalRepo/openMPI.rst deleted file mode 100644 index 5a8ab4216..000000000 --- a/docs/source/InstallationGuides/LocalRepo/openMPI.rst +++ /dev/null @@ -1,28 +0,0 @@ -Create local OpenMPI repository --------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install OpenMPI, include the following line under ``softwares```: :: - - {"name": "openmpi", "version":"4.1.6"}, - - -For a list of repositories (and their types) configured for OpenMPI, view the ``input/config///openmpi.json`` file. To customize your OpenMPI installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - - -OpenMPI is deployed on the cluster when the above configurations are complete and `omnia.yml is run. <../BuildingClusters/index.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/ucx.rst b/docs/source/InstallationGuides/LocalRepo/ucx.rst deleted file mode 100644 index ee39eb359..000000000 --- a/docs/source/InstallationGuides/LocalRepo/ucx.rst +++ /dev/null @@ -1,28 +0,0 @@ -Create local Unified Communication X repository ------------------------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install UCX, include the following line under ``softwares```: :: - - {"name": "ucx", "version":"1.15.0"}, - - -For a list of repositories (and their types) configured for UCX, view the ``input/config///ucx.json`` file. To customize your UCX installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - - -UCX is deployed on the cluster when the above configurations are complete and `omnia.yml is run. <../BuildingClusters/index.html>`_ - diff --git a/docs/source/InstallationGuides/LocalRepo/vLLM.rst b/docs/source/InstallationGuides/LocalRepo/vLLM.rst deleted file mode 100644 index 7eddc6244..000000000 --- a/docs/source/InstallationGuides/LocalRepo/vLLM.rst +++ /dev/null @@ -1,31 +0,0 @@ -Create local vLLM repository ------------------------------- - -1. Enter the required values in the ``input/software_config.json`` file: - -.. csv-table:: Parameters for Software Configuration - :file: ../../Tables/software_config.csv - :header-rows: 1 - :keepspace: - :class: longtable - - -To install vLLM, include the following line under ``softwares```: :: - - {"name": "vLLM"}, - - "vllm": [ - {"name": "vllm_amd"}, - {"name": "vllm_nvidia"} - ], - - -For a list of repositories (and their types) configured for vLLM, view the ``input/config///vllm.json`` file. To customize your vLLM installation, update the file. - -2. Enter the required values in the ``input/local_repo_config.yml`` file. For parameter information, `click here `_. -3. Run the following commands: :: - - cd local_repo - ansible-playbook local_repo.yml - -For information on deploying PyTorch after setting up the cluster, `click here. <../../Roles/Platform/SetupvLLM.html>`_ From f11e1c59de66009afbea6de69c6a2cc0252f90c9 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 25 Mar 2024 11:39:21 +0530 Subject: [PATCH 267/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 3 +++ docs/source/bestpractices.rst | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 23a1bfefb..5615f9a5d 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -38,6 +38,9 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, ``discovery_provision.yml`` runs in three stages that can be called individually: +.. caution:: Always execute ``discovery_provision.yml`` within the ``omnia`` directory. That is, always change directories (``cd omnia``) to the path where the playbook resides before running the playbook. + + **Preparing the control plane** * Installs required tool packages. diff --git a/docs/source/bestpractices.rst b/docs/source/bestpractices.rst index 8ee3dd05c..09981f851 100644 --- a/docs/source/bestpractices.rst +++ b/docs/source/bestpractices.rst @@ -2,6 +2,7 @@ Best Practices ============== * Ensure that PowerCap policy is disabled and the BIOS system profile is set to 'Performance' on the Control Plane. +* Always execute playbooks within the directory they reside in. That is, always change directories (``cd``) to the path where the playbook resides before running the playbook. * Ensure that there is at least 50% (~50GB) free space on the Control Plane root partition before running Omnia. To maintain the free space required, place any ISO files used in the ``/home`` directory. * Use a `PXE mapping file `_ even when using DHCP configuration to ensure that IP assignments remain persistent across Control Plane reboots. * Avoid rebooting the Control Plane as much as possible to ensure that all network configuration does not get disturbed. From 03f7fa0854655824c24b89385f2f76604a1b5983 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 25 Mar 2024 16:09:59 +0530 Subject: [PATCH 268/309] Updating documentation Signed-off-by: goveac --- .../BuildingClusters/KubernetesAccess.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 4c8ec133a..3cecd6cdd 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -1,7 +1,7 @@ Granting Kubernetes access --------------------------- -Omnia grants Kubernetes node access to users defined on the kube_control_plane using the ``k8_access.yml`` playbook. +Omnia grants Kubernetes node access to users defined on the kube_control_plane using the ``k8s_access.yml`` playbook. **Prerequisites** @@ -21,12 +21,13 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u | Required | | +---------------+--------------------------------------------------------------------------------------------+ -* Verify that all intended users have a home directory set up on the kube_control_plane. -* Update the ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2`` to customize the access level assigned to the intended users. +* Verify that all intended users have a home directory (in the format ``/home/``) set up on the kube_control_plane. +* Job access is granted based on the values provided in ``resources`` and ``verbs`` variables in ``scheduler/roles/k8s_access/template/role.yml.j2``. These values cannot be modified. * ``resources`` are a list of kubernetes objects or entities that are used to define, configure, and manage applications or infrastructure within a Kubernetes cluster. Possible values include ``["pods", "services", "deployments", "jobs"]``. * ``verbs`` are a list of actions that can be taken on the ``resources``. Possible values are ``["create", "get", "list", "update", "delete"]``. + * The passed inventory should contain a defined ``kube_control_plane``. :: @@ -58,4 +59,5 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u To run the playbook, use the below command: :: + cd scheduler ansible-playbook -i inventory k8s_access.yml \ No newline at end of file From 0c4df4e8c761114d41673f18e8d09fb7bdc8df7d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 25 Mar 2024 16:25:17 +0530 Subject: [PATCH 269/309] Updating documentation Signed-off-by: goveac --- docs/source/Tables/local_repo_config.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 2e421862f..904575d6b 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -37,7 +37,7 @@ Optional","* This variable accepts the registry url along with port of the user * When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. -* When ``repo_config`` is never, no local registry is created and packages are downloaded on all cluster nodes. +* When ``repo_config`` is never, no local registry is created and packages/images are downloaded on all cluster nodes. * 'host' defines the URL and path to the registry. From 81b56e726eb643784f821084b5bfcd93392fa04d Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 16:21:31 +0530 Subject: [PATCH 270/309] Updating documentation Signed-off-by: goveac --- .../Benchmarks/AutomatingOneAPI.rst | 2 +- .../Benchmarks/AutomatingOpenMPI.rst | 2 +- .../BuildingClusters/KubernetesAccess.rst | 2 +- docs/source/InstallationGuides/CleanUpScript.rst | 4 ++-- .../ConfiguringStorage/index.rst | 2 +- .../InstallingProvisionTool/AdditionalNIC.rst | 2 +- .../DiscoveryMechanisms/switch-based.rst | 6 ++++-- .../installprovisiontool.rst | 14 +++++++------- .../InstallingProvisionTool/provisionprereqs.rst | 2 +- .../InstallationGuides/PostProvisionScript.rst | 2 +- docs/source/Logging/ControlPlaneLogs.rst | 2 +- .../SupportMatrix/OperatingSystems/RedHat.rst | 4 +--- .../SupportMatrix/OperatingSystems/Ubuntu.rst | 4 +++- docs/source/Roles/Accelerator/index.rst | 2 +- docs/source/Roles/Network/index.rst | 2 +- .../Roles/Telemetry/Visualizations/index.rst | 2 +- docs/source/Roles/Telemetry/index.rst | 2 +- docs/source/Roles/Utils/OSPackageUpdate.rst | 2 +- docs/source/Roles/Utils/rhsm_subscription.rst | 2 +- docs/source/Tables/Provision_config.csv | 15 ++++++++++++++- docs/source/Troubleshooting/FAQ.rst | 10 +++++----- docs/source/Troubleshooting/knownissues.rst | 2 +- docs/source/limitations.rst | 2 +- 23 files changed, 52 insertions(+), 37 deletions(-) diff --git a/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst b/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst index 71e616269..7468d0258 100644 --- a/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst +++ b/docs/source/InstallationGuides/Benchmarks/AutomatingOneAPI.rst @@ -5,7 +5,7 @@ This topic explains how to automatically update servers for MPI jobs. To manuall **Pre-requisites** -* ``provision.yml`` has been executed. +* ``discovery_provision.yml`` has been executed. * An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 slurm_control_node and 1 slurm_node. * Verify that the target nodes are in the ``booted`` state. For more information, `click here <../InstallingProvisionTool/ViewingDB.html>`_. diff --git a/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst b/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst index eb6c8bfe1..afbadf149 100644 --- a/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst +++ b/docs/source/InstallationGuides/Benchmarks/AutomatingOpenMPI.rst @@ -5,7 +5,7 @@ This topic explains how to automatically update AMD servers for MPI jobs. To man **Pre-requisites** -* ``provision.yml`` has been executed. +* ``discovery_provision.yml`` has been executed. * An Omnia **slurm** cluster has been set up by ``omnia.yml`` running with at least 2 nodes: 1 slurm_control_node and 1 slurm_node. * Verify that the target nodes are in the ``booted`` state. For more information, `click here <../InstallingProvisionTool/ViewingDB.html>`_. * A local OpenMPI repository has been created. For more information, `click here. <../LocalRepo/openMPI.html>` diff --git a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst index 3cecd6cdd..651a0fc6a 100644 --- a/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst +++ b/docs/source/InstallationGuides/BuildingClusters/KubernetesAccess.rst @@ -9,7 +9,7 @@ Omnia grants Kubernetes node access to users defined on the kube_control_plane u **Input parameters** -* Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma separated list of users. +* Update the variable ``user_name``, in the ``input/k8s_access_config.yml`` file with a comma-separated list of users. +---------------+--------------------------------------------------------------------------------------------+ | Parameter | Details | diff --git a/docs/source/InstallationGuides/CleanUpScript.rst b/docs/source/InstallationGuides/CleanUpScript.rst index aa6410c4e..714372da3 100644 --- a/docs/source/InstallationGuides/CleanUpScript.rst +++ b/docs/source/InstallationGuides/CleanUpScript.rst @@ -22,8 +22,8 @@ To delete the changes made by ``local_repo.yml`` including the ``repo_store_path .. caution:: - * When re-provisioning your cluster (that is, re-running the ``provision.yml`` playbook) after a clean-up, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (``BIOS Settings`` > ``Boot Settings`` > ``UEFI Boot Settings``) on all target nodes. - * On subsequent runs of ``provision.yml``, if users are unable to log into the server, refresh the ssh key manually and retry. :: + * When re-provisioning your cluster (that is, re-running the ``discovery_provision.yml`` playbook) after a clean-up, ensure to use a different ``admin_nic_subnet`` in ``input/provision_config.yml`` to avoid a conflict with newly assigned servers. Alternatively, disable any OS available in the ``Boot Option Enable/Disable`` section of your BIOS settings (``BIOS Settings`` > ``Boot Settings`` > ``UEFI Boot Settings``) on all target nodes. + * On subsequent runs of ``discovery_provision.yml``, if users are unable to log into the server, refresh the ssh key manually and retry. :: ssh-keygen -R diff --git a/docs/source/InstallationGuides/ConfiguringStorage/index.rst b/docs/source/InstallationGuides/ConfiguringStorage/index.rst index 01b9763e4..1bca4c0fb 100644 --- a/docs/source/InstallationGuides/ConfiguringStorage/index.rst +++ b/docs/source/InstallationGuides/ConfiguringStorage/index.rst @@ -61,7 +61,7 @@ Fill out all required parameters in ``storage/powervault_input.yml``: | ``string`` | | | Required | **Default values**: ``omnia`` | +--------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| powervault_volumes | Specify the volume details for powervault and NFS Server node. Multiple volumes can be defined as comma separated values. example: omnia_home1, omnia_home2. | +| powervault_volumes | Specify the volume details for powervault and NFS Server node. Multiple volumes can be defined as comma-separated values. example: omnia_home1, omnia_home2. | | ``string`` | | | Required | **Default values**: ``omnia_home`` | +--------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index d29bf053c..c21fc8302 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -1,6 +1,6 @@ Configuring additional NICs on the nodes ------------------------------------------- -After running ``provision.yml`` or ``discovery_provision.yml`` and the nodes boot up, additional NICs can be configured on target nodes using the ``nic_update.yml`` playbook. +After running ``discovery_provision.yml`` or ``discovery_provision.yml`` and the nodes boot up, additional NICs can be configured on target nodes using the ``nic_update.yml`` playbook. **Prerequisites** diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index 4a57016e5..f089a9e03 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -13,10 +13,12 @@ switch_based .. note:: * To create an SNMPv3 user on S series switches (running OS10), use the following commands: + - To create SNMP view: ``snmp-server view test_view internet included`` - To create SNMP group: ``snmp-server group testgroup 3 auth read test_view`` - To create SNMP users: ``snmp-server user authuser1 testgroup 3 auth sha authpasswd1`` * To verify the changes made, use the following commands: + - To view the SNMP views: ``show snmp view`` - To view the SNMP groups: ``show snmp group`` - To view the SNMP users: ``show snmp user`` @@ -31,14 +33,14 @@ switch_based racadm set iDRAC.IPMILan.Enable 1 racadm get iDRAC.IPMILan -* BMC credentials should be the same across all servers and provided as input to Omnia. +* BMC credentials should be the same across all servers and provided as input to Omnia. All BMC network details should be provided in ``input/network_spec.yml``. * Target servers should be configured to boot in PXE mode with appropriate NIC as the first boot device. * Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. image:: ../../../images/ControlPlaneNic.png -* Ensure that the variable ``switch_based_details`` in ``input/provision_config.yml`` is provided. +* Ensure that the variable ``switch_based_details`` in ``input/provision_config.yml`` is provided. Addtionally, set the value of ``enable_switch_based`` to true in ``input/provision_config.yml``. .. caution:: * Do not use daisy chain ports or the port used to connect to the control plane in ``switch_based_details`` in ``input/provision_config.yml``. This can cause IP conflicts on servers attached to potential target ports. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 5615f9a5d..0cbf85625 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -1,7 +1,7 @@ Provisioning the cluster -------------------------- -Edit the ``input/provision_config.yml`` file to update the required variables. A list of the variables required is available by `discovery mechanism `_. +Edit the ``input/provision_config.yml``, ``input/provision_config.yml`` file to update the required variables. A list of the variables required is available by `discovery mechanism `_. .. note:: The first PXE device on target nodes should be the designated active NIC for PXE booting. @@ -86,12 +86,12 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, **Provisioning the nodes** - * The intended operating system and version is provisioned on the nodes. + * The intended operating system and version is provisioned on the primary disk partition on the nodes. If a BOSS Controller card is available on the target node, the operating system is provisioned on the boss controller disks. To call this playbook individually, run:: cd provision - ansible-playbook provision.yml + ansible-playbook discovery_provision.yml ---- After successfully running ``discovery_provision.yml``, go to `Building Clusters <../BuildingClusters/index.html>`_ to setup Slurm, Kubernetes, NFS, BeeGFS and Authentication. @@ -115,18 +115,18 @@ After successfully running ``discovery_provision.yml``, go to `Building Clusters .. caution:: - * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. - * To avoid breaking the passwordless SSH channel on the control plane, do not run ``ssh-keygen`` commands post execution of ``provision.yml`` to create a new key. + * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. If the new environment variables still do not come into effect, enable manually using ``source /etc/profile.d + * To avoid breaking the passwordless SSH channel on the control plane, do not run ``ssh-keygen`` commands post execution of ``discovery_provision.yml`` to create a new key. * Do not delete the following directories: - ``/root/xcat`` - ``/root/xcat-dbback`` - ``/docker-registry`` - ``/opt/omnia`` - ``/var/log/omnia`` - * On subsequent runs of ``provision.yml``, if users are unable to log into the server, refresh the ssh key manually and retry. :: + * On subsequent runs of ``discovery_provision.yml``, if users are unable to log into the server, refresh the ssh key manually and retry. :: ssh-keygen -R - * If a subsequent run of ``provision.yml`` fails, the ``input/provision_config.yml`` file will be unencrypted. + * If a subsequent run of ``discovery_provision.yml`` fails, the ``input/provision_config.yml`` file will be unencrypted. To create a node inventory in ``/opt/omnia``, `click here <../PostProvisionScript.html>`_. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 6ed47f084..8f96c446e 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -82,7 +82,7 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf * When discovering nodes via a mapping file, all target nodes should be set up in PXE mode before running the playbook. -* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``provision.yml`` on RHEL target nodes. +* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``discovery_provision.yml`` on RHEL target nodes. * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index c59b92ea7..9810b8756 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -1,7 +1,7 @@ Creating node inventory ------------------------ -When ``provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in ``/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: +When ``discovery_provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_tagging.yml`` is run, a set of inventory files is created in ``/opt/omnia/omnia_inventory/``. The inventories are created based on the type of CPUs and GPUs nodes have. The inventory files are: * ``compute_cpu_amd`` :: diff --git a/docs/source/Logging/ControlPlaneLogs.rst b/docs/source/Logging/ControlPlaneLogs.rst index 8e91c2ddf..7babc1f96 100644 --- a/docs/source/Logging/ControlPlaneLogs.rst +++ b/docs/source/Logging/ControlPlaneLogs.rst @@ -28,7 +28,7 @@ Logs of individual containers Provisioning logs -------------------- -Logs pertaining to actions taken during ``provision.yml`` can be viewed in ``/var/log/xcat/cluster.log`` and ``/var/log/xcat/computes.log`` on the control plane. +Logs pertaining to actions taken during ``discovery_provision.yml`` can be viewed in ``/var/log/xcat/cluster.log`` and ``/var/log/xcat/computes.log`` on the control plane. .. note:: As long as a node has been added to a cluster by Omnia, deployment events taking place on the node will be updated in ``/var/log/xcat/cluster.log``. diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst index e845cd9fa..3e77aa829 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/RedHat.rst @@ -11,6 +11,4 @@ OS Version Control Plane Cluster Nodes .. [1] This version of RHEL does not support vLLM installation via Omnia. -.. note:: - * Always deploy the DVD Edition of the OS on cluster nodes to access offline repos. - * For RHEL 8.5 and below, ensure that RHEL subscription is enabled OR sshpass is available to install or download to the control plane (from any local repository). +.. note:: Always deploy the DVD Edition of the OS on cluster nodes to access offline repos. \ No newline at end of file diff --git a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst index ff7067389..49f36ef12 100644 --- a/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst +++ b/docs/source/Overview/SupportMatrix/OperatingSystems/Ubuntu.rst @@ -8,4 +8,6 @@ OS Version Control Plane Cluster Nodes 22.04 Yes Yes ========== ============= ============= -.. [1] This version of Ubuntu does not support vLLM installation via Omnia. \ No newline at end of file +.. [1] This version of Ubuntu does not support vLLM installation via Omnia. + +.. note:: Only the live-server version of Ubuntu for provisioning via Omnia. \ No newline at end of file diff --git a/docs/source/Roles/Accelerator/index.rst b/docs/source/Roles/Accelerator/index.rst index b063a9b5d..7aea495f6 100644 --- a/docs/source/Roles/Accelerator/index.rst +++ b/docs/source/Roles/Accelerator/index.rst @@ -33,7 +33,7 @@ Enter all required parameters in ``input/accelerator_config.yml``. .. note:: * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``accelerator.yml`` on RHEL target nodes. * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - * If ``cuda_toolkit_path`` is provided in ``input/provision_config.yml`` and NVIDIA GPUs are available on the target nodes, CUDA packages will be deployed post provisioning without user intervention during the execution of ``provision.yml``. + * If ``cuda_toolkit_path`` is provided in ``input/provision_config.yml`` and NVIDIA GPUs are available on the target nodes, CUDA packages will be deployed post provisioning without user intervention during the execution of ``discovery_provision.yml``. * AMD ROCm driver installation is not supported by Omnia on Rocky cluster nodes. To install all the latest GPU drivers and toolkits, run: :: diff --git a/docs/source/Roles/Network/index.rst b/docs/source/Roles/Network/index.rst index 66aff73d4..7527b9b60 100644 --- a/docs/source/Roles/Network/index.rst +++ b/docs/source/Roles/Network/index.rst @@ -7,7 +7,7 @@ In your HPC cluster, connect the Mellanox InfiniBand switches using the Fat-Tree * From Omnia 1.4, the Subnet Manager runs on the target Infiniband switches and not the control plane. - * When ``ib_nic_subnet`` is provided in ``input/provision_config.yml``, the infiniband NIC on target nodes are assigned IPv4 addresses within the subnet without user intervention during the execution of ``provision.yml``. + * When ``ib_nic_subnet`` is provided in ``input/provision_config.yml``, the infiniband NIC on target nodes are assigned IPv4 addresses within the subnet without user intervention during the execution of ``discovery_provision.yml``. Some of the network features Omnia offers are: diff --git a/docs/source/Roles/Telemetry/Visualizations/index.rst b/docs/source/Roles/Telemetry/Visualizations/index.rst index 290bd5803..7e21364af 100644 --- a/docs/source/Roles/Telemetry/Visualizations/index.rst +++ b/docs/source/Roles/Telemetry/Visualizations/index.rst @@ -3,7 +3,7 @@ Acquiring telemetry data for iDRAC and Omnia Using `Texas Technical University data visualization lab `_, data polled from iDRAC and Slurm can be processed to generate live graphs. These Graphs can be accessed on the Grafana UI. -Once ``provision.yml`` is executed and Grafana is set up, use ``telemetry.yml`` to initiate the Graphs. Data polled via Slurm and iDRAC is streamed into internal databases. This data is processed to create parallel coordinate graphs. +Once ``discovery_provision.yml`` is executed and Grafana is set up, use ``telemetry.yml`` to initiate the Graphs. Data polled via Slurm and iDRAC is streamed into internal databases. This data is processed to create parallel coordinate graphs. .. note:: This feature only works on nodes using iDRACs with a datacenter license running a minimum firmware of 4.0. diff --git a/docs/source/Roles/Telemetry/index.rst b/docs/source/Roles/Telemetry/index.rst index f651b1917..cd1c76443 100644 --- a/docs/source/Roles/Telemetry/index.rst +++ b/docs/source/Roles/Telemetry/index.rst @@ -12,7 +12,7 @@ To initiate telemetry support, fill out the following parameters in ``input/tele .. [1] Boolean parameters do not need to be passed with double or single quotes. -Once you have executed ``provision.yml`` and has also provisioned the cluster, initiate telemetry on the cluster as part of ``omnia.yml``, which configures the cluster with scheduler, storage and authentication using the below command. :: +Once you have executed ``discovery_provision.yml`` and has also provisioned the cluster, initiate telemetry on the cluster as part of ``omnia.yml``, which configures the cluster with scheduler, storage and authentication using the below command. :: ansible-playbook omnia.yml -i inventory diff --git a/docs/source/Roles/Utils/OSPackageUpdate.rst b/docs/source/Roles/Utils/OSPackageUpdate.rst index 57f53394e..efc904b18 100644 --- a/docs/source/Roles/Utils/OSPackageUpdate.rst +++ b/docs/source/Roles/Utils/OSPackageUpdate.rst @@ -47,7 +47,7 @@ To customize the package update, enter the following parameters in ``utils/packa | | * ``os`` | | | * ``other`` <- Default | +------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| nodelist | Comma separated list of all target nodes in the cluster. | +| nodelist | comma-separated list of all target nodes in the cluster. | | ``string`` | | | Required | **Default value**: ``all`` | +------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/Roles/Utils/rhsm_subscription.rst b/docs/source/Roles/Utils/rhsm_subscription.rst index b56e846d3..93bd7c6ad 100644 --- a/docs/source/Roles/Utils/rhsm_subscription.rst +++ b/docs/source/Roles/Utils/rhsm_subscription.rst @@ -29,7 +29,7 @@ Red Hat Subscription | ``string`` | If the quantity is provided, it is used to consume multiple entitlements from a pool (the pool must support this). | | Optional | | +--------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ -| redhat_subscription_repos | The list of repositories to enable or disable.When providing multiple values, a YAML list or a comma separated list are accepted. | +| redhat_subscription_repos | The list of repositories to enable or disable.When providing multiple values, a YAML list or a comma-separated list are accepted. | | ``string`` | | | Optional | | +--------------------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index 9a8fc6c00..89105f606 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -40,6 +40,18 @@ Required (Mapping discovery mechanism)","* The mapping file consists of the Serv * Ensure that the admin IP addresses provided are within the ``admin_static_ranges``. * A sample file is provided here: examples/pxe_mapping_file.csv. * The headers of the CSV are SERVICE_TAG,ADMIN_MAC,HOSTNAME,ADMIN_IP,BMC_IP." +"**enable_switch_based** + +``boolean`` [1]_ + +Required (Switch based discovery mechanism)","* Indicates whether target nodes should be discovered via switch details or not. Set to true when discovering nodes via switch details. +* When set to true, node discovery will not take place via BMC. Therefore, it is mandatory to provide BMC network details like ``nic_name``, ``netmask_bits``, ``static_range``, and ``dynamic_range`` are provided in the ``input/network_spec.yml`` file. +* To discover nodes via switch details AND BMC, run the ``discovery_provision.yml`` playbook twice: Once with ``enable_switch_based`` set to true and once with ``enable_switch_based`` set to false. + +Accepted values: + +* ``true`` +* ``false`` <- Default" "**switch_based_details** ``JSON List`` @@ -64,7 +76,8 @@ Required (Switch based discovery mechanism)","* JSON list of switches to query f Optional","* User defined disk partition applied to remote servers. * The disk partition desired_capacity has to be provided in MB. * Valid mount_point values accepted for disk partition are /home, /var, /tmp, /usr, swap. -* Default partition size provided for /boot is 1024MB, /boot/efi is 256MB and the remaining space to / partition. +* Default partition size provided for RHEL/Rocky is /boot: 1024MB, /boot/efi: 256MB and remaining space to / partition. +* Default partition size provided for Ubuntu is /boot: 2148MB, /boot/efi: 1124MB and remaining space to / partition. * Values are accepted in the form of JSON list such as: , - { mount_point: ""/home"", desired_capacity: ""102400"" } diff --git a/docs/source/Troubleshooting/FAQ.rst b/docs/source/Troubleshooting/FAQ.rst index 37864b26c..bb98944f1 100644 --- a/docs/source/Troubleshooting/FAQ.rst +++ b/docs/source/Troubleshooting/FAQ.rst @@ -51,7 +51,7 @@ Frequently asked questions cd utils ansible-playbook control_plane_cleanup.yml -3. Re-run the provision tool (``ansible-playbook provision.yml``). +3. Re-run the provision tool (``ansible-playbook discovery_provision.yml``). ⦾ **What to do if playbook execution fails due to external (network, hardware etc) failure:** @@ -91,7 +91,7 @@ Re-run the playbook whose execution failed once the issue is resolved. * Configure the first PXE device to be active for PXE booting. * PXE boot the target node manually. -⦾ **Why does the provision.yml fail at 'provision validation: Install common packages for provision' on RHEL nodes running 8.5 or earlier?** +⦾ **Why does the discovery_provision.yml fail at 'provision validation: Install common packages for provision' on RHEL nodes running 8.5 or earlier?** .. image:: ../images/RedHat_provisionerror_sshpass.PNG @@ -179,7 +179,7 @@ This can only be achieved using local repos specified in rhel_repo_local_path ( Omnia does not validate the input of ``rhel_repo_local_path``. -**Resolution**: Ensure the correct values are passed before re-running ``provision.yml``. +**Resolution**: Ensure the correct values are passed before re-running ``discovery_provision.yml``. ⦾ **How to add a new node for provisioning** @@ -188,11 +188,11 @@ Omnia does not validate the input of ``rhel_repo_local_path``. * Update the existing mapping file by appending the new entry (without the disrupting the older entries) or provide a new mapping file by pointing ``pxe_mapping_file_path`` in ``provision_config.yml`` to the new location. - * Run ``provision.yml``. + * Run ``discovery_provision.yml``. 2. Using the switch IP: - * Run ``provision.yml`` once the switch has discovered the potential new node. + * Run ``discovery_provision.yml`` once the switch has discovered the potential new node. ⦾ **Why does the task: 'BeeGFS: Rebuilding BeeGFS client module' fail?** diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index 041f32a2c..3128d0c26 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -17,7 +17,7 @@ Omnia does not maintain any order when assigning hostnames to target nodes. **Resolution**: This will be addressed in a later release. -⦾ **Why does the task Assign admin NIC IP fail during provision.yml with errors?** +⦾ **Why does the task Assign admin NIC IP fail during discovery_provision.yml with errors?** .. image:: ../images/AdminNICErrors.png diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst index 35033069a..1e0cebdd0 100644 --- a/docs/source/limitations.rst +++ b/docs/source/limitations.rst @@ -1,7 +1,7 @@ Limitations =========== -- Once ``provision.yml`` is used to configure devices, it is +- Once ``discovery_provision.yml`` is used to configure devices, it is recommended to avoid rebooting the control plane. - Omnia supports adding only 1000 nodes when discovered via BMC. - Removal of Slurm and Kubernetes component roles are not supported. From 9f56444706e738b42d83da04a6b09628c2d6b72f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 16:35:54 +0530 Subject: [PATCH 271/309] Updating documentation Signed-off-by: goveac --- .../installprovisiontool.rst | 2 +- docs/source/Tables/Provision_config.csv | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 0cbf85625..c074b3047 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -1,7 +1,7 @@ Provisioning the cluster -------------------------- -Edit the ``input/provision_config.yml``, ``input/provision_config.yml`` file to update the required variables. A list of the variables required is available by `discovery mechanism `_. +Edit the ``input/provision_config.yml``, ``input/provision_config.yml``, and ``input/network_spec.yml`` files to update the required variables. A list of the variables required is available by `discovery mechanism `_. .. note:: The first PXE device on target nodes should be the designated active NIC for PXE booting. diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index 89105f606..7b8f7d780 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -44,11 +44,16 @@ Required (Mapping discovery mechanism)","* The mapping file consists of the Serv ``boolean`` [1]_ -Required (Switch based discovery mechanism)","* Indicates whether target nodes should be discovered via switch details or not. Set to true when discovering nodes via switch details. -* When set to true, node discovery will not take place via BMC. Therefore, it is mandatory to provide BMC network details like ``nic_name``, ``netmask_bits``, ``static_range``, and ``dynamic_range`` are provided in the ``input/network_spec.yml`` file. -* To discover nodes via switch details AND BMC, run the ``discovery_provision.yml`` playbook twice: Once with ``enable_switch_based`` set to true and once with ``enable_switch_based`` set to false. +Required (Switch based discovery mechanism)","* Variable indicates whether switch based discovery should be enabled to discover the nodes +* To enable switch based discovery, set ``enable_switch_based`` to true. +* If ``enable_switch_based`` is set to true,the following inputs should be provided: + * ``switch_based_details`` should be provided in ``provision_config.yml`` + * ``switch_snmp3_username`` and ``switch_snmp3_password`` should be provided in ``provision_config_credentials.yml`` + * ``bmc_network`` details with ``nic_name``, ``netmask_bits``, ``static_range``, and ``dynamic_range`` should be provided in network_spec.yml +.. caution:: If ``enable_switch_based`` is set to true, bmc discovery will be skipped. +* For enabling bmc discovery, set ``enable_switch_based`` to false and provide bmc_network details in ``network_spec.yml`` +* Accepted values: -Accepted values: * ``true`` * ``false`` <- Default" @@ -60,13 +65,13 @@ Required (Switch based discovery mechanism)","* JSON list of switches to query f * Split port ranges are not accepted here. (Ex: 10:5-10:10 will not be valid). * Example: :: -  - { ip: 172.96.28.12, ports: '1-48,49:3,50' } + - { ip: 172.96.28.12, ports: '1-48,49:3,50' } -* Example with 2 switches: :: -  - { ip: 172.96.28.12, ports: '1-48,49:3,50' } +* Example with 2 switches: :: -  - { ip: 172.96.28.14, ports: '1,2,3,5' } + - { ip: 172.96.28.12, ports: '1-48,49:3,50' } + - { ip: 172.96.28.14, ports: '1,2,3,5' } " "**disk_partition** From 4a80f33a086b54f0685961c4977c079a3063cbef Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 16:42:00 +0530 Subject: [PATCH 272/309] Updating documentation Signed-off-by: goveac --- docs/source/Tables/Provision_config.csv | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index 7b8f7d780..86aa83db0 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -47,6 +47,7 @@ Required (Mapping discovery mechanism)","* The mapping file consists of the Serv Required (Switch based discovery mechanism)","* Variable indicates whether switch based discovery should be enabled to discover the nodes * To enable switch based discovery, set ``enable_switch_based`` to true. * If ``enable_switch_based`` is set to true,the following inputs should be provided: + * ``switch_based_details`` should be provided in ``provision_config.yml`` * ``switch_snmp3_username`` and ``switch_snmp3_password`` should be provided in ``provision_config_credentials.yml`` * ``bmc_network`` details with ``nic_name``, ``netmask_bits``, ``static_range``, and ``dynamic_range`` should be provided in network_spec.yml @@ -55,8 +56,8 @@ Required (Switch based discovery mechanism)","* Variable indicates whether switc * Accepted values: -* ``true`` -* ``false`` <- Default" + * ``true`` + * ``false`` <- Default" "**switch_based_details** ``JSON List`` From cb027388e95ce6c6f8b7c9500d3da1390c9a2a81 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 16:56:30 +0530 Subject: [PATCH 273/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/switch-based.rst | 10 ++++------ .../InstallingProvisionTool/installprovisiontool.rst | 2 +- docs/source/Tables/Provision_config.csv | 5 +++-- docs/source/_static/theme.css | 2 ++ 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index f089a9e03..fcb0fa91a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -3,10 +3,12 @@ switch_based **Pre requisites** -* IP address for ToR switch needs to be provided. +* Set the value of ``enable_switch_based`` to true in ``input/provision_config.yml``. Additionally, ensure that the variable ``switch_based_details`` in ``input/provision_config.yml`` is populated with the IP address and port details of the ToR switch. * Switch port range where all BMC NICs are connected should be provided. +* BMC credentials should be the same across all servers and provided as input to Omnia. All BMC network details should be provided in ``input/network_spec.yml``. + * SNMP v3 should be enabled on the switch and the credentials should be provided in ``input/provision_config_credentials.yml``. * Non-admin user credentials for the switch need to be provided. @@ -33,15 +35,11 @@ switch_based racadm set iDRAC.IPMILan.Enable 1 racadm get iDRAC.IPMILan -* BMC credentials should be the same across all servers and provided as input to Omnia. All BMC network details should be provided in ``input/network_spec.yml``. - * Target servers should be configured to boot in PXE mode with appropriate NIC as the first boot device. * Set the IP address of the control plane. The control plane NIC connected to remote servers (through the switch) should be configured with two IPs (BMC IP and admin IP) in a shared LOM or hybrid set up. In the case dedicated network topology, a single IP (admin IP) is required. .. image:: ../../../images/ControlPlaneNic.png -* Ensure that the variable ``switch_based_details`` in ``input/provision_config.yml`` is provided. Addtionally, set the value of ``enable_switch_based`` to true in ``input/provision_config.yml``. - .. caution:: * Do not use daisy chain ports or the port used to connect to the control plane in ``switch_based_details`` in ``input/provision_config.yml``. This can cause IP conflicts on servers attached to potential target ports. * Omnia does not validate SNMP switch credentials, if the provision tool is run with incorrect credentials, use the clean-up script and re-run the provision tool with the correct credentials. @@ -50,7 +48,7 @@ switch_based .. note:: * If any of the target nodes have a pre-provisioned BMC IP, ensure that these IPs are not part of the ``static_range`` specified in ``input/network_spec.yml`` under the ``bmc_network`` to avoid any bmc IP conflicts. - * Even if ``switch_based_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the ``bmc_network`` before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. + * In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index c074b3047..f27c02b74 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -115,7 +115,7 @@ After successfully running ``discovery_provision.yml``, go to `Building Clusters .. caution:: - * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. If the new environment variables still do not come into effect, enable manually using ``source /etc/profile.d + * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. If the new environment variables still do not come into effect, enable manually using ``source /etc/profile.d/xcat.sh``. * To avoid breaking the passwordless SSH channel on the control plane, do not run ``ssh-keygen`` commands post execution of ``discovery_provision.yml`` to create a new key. * Do not delete the following directories: - ``/root/xcat`` diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index 86aa83db0..c10df1a29 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -44,7 +44,7 @@ Required (Mapping discovery mechanism)","* The mapping file consists of the Serv ``boolean`` [1]_ -Required (Switch based discovery mechanism)","* Variable indicates whether switch based discovery should be enabled to discover the nodes +Required","* Variable indicates whether switch based discovery should be enabled to discover the nodes * To enable switch based discovery, set ``enable_switch_based`` to true. * If ``enable_switch_based`` is set to true,the following inputs should be provided: @@ -62,7 +62,8 @@ Required (Switch based discovery mechanism)","* Variable indicates whether switc ``JSON List`` -Required (Switch based discovery mechanism)","* JSON list of switches to query for target nodes. +Optional","* JSON list of switches to query for target nodes. +* This variable is required when nodes are to be discovered via switch details. * Split port ranges are not accepted here. (Ex: 10:5-10:10 will not be valid). * Example: :: diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index 8c5defa5c..aea68ffff 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -76,6 +76,8 @@ .wy-nav-content .highlight, .wy-nav-content .rst-content .warning { background: rgba(238, 238, 238, 0.78); + width: 575px; + overflow-x: unset; } From 6ffd76b88d7937b42b2a7530b0dc1b3e268b22d4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 17:03:46 +0530 Subject: [PATCH 274/309] Updating documentation Signed-off-by: goveac --- docs/source/Tables/Provision_config.csv | 3 ++- docs/source/_static/theme.css | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index c10df1a29..cdb3766b9 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -36,7 +36,8 @@ Required","* Domain name the user intends to configure on the cluster. ``string`` -Required (Mapping discovery mechanism)","* The mapping file consists of the Service tag, Admin MAC,Hostname and its respective admin IP address and/or BMC IP. +Optional","* The mapping file consists of the Service tag, Admin MAC,Hostname and its respective admin IP address and/or BMC IP. +* This variable is required to discover nodes using a mapping file. * Ensure that the admin IP addresses provided are within the ``admin_static_ranges``. * A sample file is provided here: examples/pxe_mapping_file.csv. * The headers of the CSV are SERVICE_TAG,ADMIN_MAC,HOSTNAME,ADMIN_IP,BMC_IP." diff --git a/docs/source/_static/theme.css b/docs/source/_static/theme.css index aea68ffff..21345929e 100644 --- a/docs/source/_static/theme.css +++ b/docs/source/_static/theme.css @@ -3,7 +3,8 @@ } .wy-nav-content { background-color: #ffffff; - width: 1000px; + width: 1000px; !important; + max-width: 1500px; } .wy-side-nav-search img { display: block; From 801680c2a608e970f50b8a139825cdd32db0fce4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 17:10:31 +0530 Subject: [PATCH 275/309] Updating documentation Signed-off-by: goveac --- docs/source/_static/sphinx-argparse.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index a5e7e6bcd..1f57c8147 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -12,7 +12,7 @@ } .rst-content div[class^=highlight], .rst-content pre.literal-block { - width: 575px; + width: 700px; overflow-x: unset; } @@ -26,6 +26,6 @@ table-layout: fixed; block-size: fit-content; overflow: visible !important; - max-width: 750px; + max-width: 900px; } From 75c47aaf727f73adc54929c0c16a761894efb58c Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 17:16:02 +0530 Subject: [PATCH 276/309] Updating documentation Signed-off-by: goveac --- docs/source/Tables/Provision_creds.csv | 6 ++++-- docs/source/_static/sphinx-argparse.css | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/Tables/Provision_creds.csv b/docs/source/Tables/Provision_creds.csv index ca9b374c8..9f9261d5b 100644 --- a/docs/source/Tables/Provision_creds.csv +++ b/docs/source/Tables/Provision_creds.csv @@ -29,14 +29,16 @@ Required","* The password set on target iDRACs. ``string`` -Optional (Required for Switch based discovery mechanism)","* Non-admin SNMPv3 credentials of the PXE switch. +Optional ","* Non-admin SNMPv3 credentials of the PXE switch. +* This variable is required when discovering nodes via switch details. * If multiple switches are provided, ensure the credentials are same across switches. * Username must not contain -,\, ',""" "**switch_snmp3_password** ``string`` -Optional (Required for Switch based discovery mechanism)","* Non-admin SNMPv3 credentials of the PXE switch. +Optional","* Non-admin SNMPv3 credentials of the PXE switch. +* This variable is required when discovering nodes via switch details. * If multiple switches are provided, ensure the credentials are same across switches. * Password must not contain -,\, ',""" "**docker_username** diff --git a/docs/source/_static/sphinx-argparse.css b/docs/source/_static/sphinx-argparse.css index 1f57c8147..4ce786632 100644 --- a/docs/source/_static/sphinx-argparse.css +++ b/docs/source/_static/sphinx-argparse.css @@ -26,6 +26,6 @@ table-layout: fixed; block-size: fit-content; overflow: visible !important; - max-width: 900px; + max-width: 900px; !important; } From 2a9c26da40360d7823992e0ff341cd073eef90ee Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 26 Mar 2024 17:17:53 +0530 Subject: [PATCH 277/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/provisionparams.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index d1d2f4edd..c51357452 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -25,7 +25,8 @@ Fill in all required parameters in ``input/provision_config.yml``, ``provision_c Update the ``input/network_spec.yml`` file for all networks available for use by the control plane. - * The following ``admin_nic`` details are mandatory. + * The following ``admin_nic`` details are mandatory: + * ``nic_name``: The name of the NIC on which the administrative network is accessible to the control plane. * ``netmask_bits``: The 32-bit "mask" used to divide an IP address into subnets and specify the network's available hosts. * ``static_range``: The static range of IPs to be provisioned on target nodes. From 5b02dd37ebb88bbbd9da92953e6817c690b4360f Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 11:03:29 +0530 Subject: [PATCH 278/309] Updating documentation Signed-off-by: goveac --- .../installprovisiontool.rst | 2 -- .../LocalRepo/Prerequisite.rst | 16 +++++++++++++++- docs/source/Tables/security_config_ldap.csv | 7 +------ 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index f27c02b74..f4d5b9835 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -72,8 +72,6 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, * Discovers all target servers. - .. note:: Even if ``switch_based_details`` are provided in ``input/provision_config.yml``, a BMC discovery job task is run on the ``static_range`` and ``dynamic_range`` provided in ``input/network_spec.yml`` against the ``bmc_network`` before the switch based discovery job. If there is any overlap in the values provided, duplicate node objects may be created in the database. Ensure mindful IP range inputs to avoid duplicates. In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. - * PostgreSQL database is set up with all relevant cluster information such as MAC IDs, hostname, admin IP, BMC IPs etc. * Configures the control plane with NTP services for cluster node synchronization. diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index 77f643dbb..2ad0de2ca 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -27,4 +27,18 @@ Therefore, for the image of ``calico/cni`` version ``1.2`` available on ``quay.i server1.omnia.test:5001/calico/cni:v1.2 -Omnia will not be able to configure access to any registries that do not follow this naming convention. Do not include any other extraneous information in the registry name. \ No newline at end of file +Omnia will not be able to configure access to any registries that do not follow this naming convention. Do not include any other extraneous information in the registry name. + +There are two ways to pull images from the user registries in the form of a digest: + + * Update the digest value to the listed image in the registry. All images to be pulled are listed in ``input/config///.json``. A sample of the listing is shown below: :: + + { + "package": "gcr.io/knative-releases/knative.dev/serving/cmd/webhook", + "digest": ".1305209ce498caf783f39c8f3e85df..35ece6947033bf50b0b627983fd65953", + "type": "image" + + }, + + + * While pushing the image to the user registry, create a tag and update the JSON file to take the tag value instead of the digest. \ No newline at end of file diff --git a/docs/source/Tables/security_config_ldap.csv b/docs/source/Tables/security_config_ldap.csv index 298d2d338..309838726 100644 --- a/docs/source/Tables/security_config_ldap.csv +++ b/docs/source/Tables/security_config_ldap.csv @@ -16,12 +16,7 @@ "tls_certificate_key ``string`` Optional ",The private key that matches the LDAP certificate. -"user_home_dir - ``string`` - Required ","This variable accepts the user home directory path for ldap configuration. If nfs mount is created for user home, make sure you provide the LDAP users mount home directory path. - - **Default value**: ``/home`` " -"openldap_db_username +"openldap_db_username ``string`` Required "," The username used to manage the LDAP database. From c3c2e408a78eee269617908109382d4cff479bda Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 13:32:48 +0530 Subject: [PATCH 279/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/BuildingClusters/NFS.rst | 16 +++++++++++----- .../BuildingClusters/installscheduler.rst | 17 +++++++---------- .../DiscoveryMechanisms/bmc.rst | 11 +++++++---- .../DiscoveryMechanisms/switch-based.rst | 2 +- .../installprovisiontool.rst | 15 ++++++++++++--- .../provisionprereqs.rst | 11 +---------- docs/source/Tables/Provision_config.csv | 8 ++++---- 7 files changed, 43 insertions(+), 37 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 05f96e84f..6d1140fac 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -34,19 +34,25 @@ Network File System (NFS) is a networking protocol for distributed file sharing. - **nfs_server**: Indicates whether an external NFS server is available (``false``) or an NFS server will need to be created (``true``). + - **slurm_share**: Indicates that the target cluster uses Slurm. + + - **k8s_share**: Indicates that the target cluster uses Kubernetes. + + .. note:: To install any Benchmarking software like UCX or OpenMPI, at least **slurm_share** or **k8s_share** should be set to true. If both are set to true, a higher precedence is given to **slurm_share**. + To configure all cluster nodes to access a single external NFS server export, use the below sample: :: - - { server_ip: 10.5.0.101, server_share_path: "/mnt/share", client_share_path: "/home", client_mount_options: "nosuid,rw,sync,hard", nfs_server: true } + - { server_ip: 10.5.0.101, server_share_path: "/mnt/share", client_share_path: "/home", client_mount_options: "nosuid,rw,sync,hard", nfs_server: true, slurm_share: true, k8s_share: true } To configure the cluster nodes to access a new NFS server on the control plane as well as an external NFS server, use the below example: :: - - { server_ip: localhost, server_share_path: "/mnt/share1", client_share_path: "/home", client_mount_options: "nosuid,rw,sync,hard", nfs_server: true } - - { server_ip: 198.168.0.1, server_share_path: "/mnt/share2", client_share_path: "/mnt/mount2", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false } + - { server_ip: localhost, server_share_path: "/mnt/share1", client_share_path: "/home", client_mount_options: "nosuid,rw,sync,hard", nfs_server: true, slurm_share: true, k8s_share: true } + - { server_ip: 198.168.0.1, server_share_path: "/mnt/share2", client_share_path: "/mnt/mount2", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false, slurm_share: true, k8s_share: true } To configure the cluster nodes to access new NFS server exports on the cluster nodes, use the below sample: :: - - { server_ip: 198.168.0.1, server_share_path: "/mnt/share1", client_share_path: "/mnt/mount1", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false } - - { server_ip: 198.168.0.2, server_share_path: "/mnt/share2", client_share_path: "/mnt/mount2", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false } + - { server_ip: 198.168.0.1, server_share_path: "/mnt/share1", client_share_path: "/mnt/mount1", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false, slurm_share: true, k8s_share: true } + - { server_ip: 198.168.0.2, server_share_path: "/mnt/share2", client_share_path: "/mnt/mount2", client_mount_options: "nosuid,rw,sync,hard", nfs_server: false, slurm_share: true, k8s_share: true } * Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ diff --git a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst index 149c24bbf..01f84ce94 100644 --- a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst +++ b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst @@ -17,8 +17,9 @@ Building clusters 3. ``omnia.yml`` is a wrapper playbook comprising of: i. ``security.yml``: This playbook sets up centralized authentication (LDAP/FreeIPA) on the cluster. For more information, `click here. `_ - ii. ``scheduler.yml``: This playbook sets up job schedulers (Slurm or Kubernetes) on the cluster. - iii. ``telemetry.yml``: This playbook sets up `Omnia telemetry and/or iDRAC telemetry <../../Roles/Telemetry/index.html>`_. It also installs `Grafana `_ and `Loki `_ as Kubernetes pods. + ii. ``storage.yml``: This playbook sets up storage tools like `BeeGFS `_ and `NFS `_. + iii. ``scheduler.yml``: This playbook sets up job schedulers (Slurm or Kubernetes) on the cluster. + iv. ``telemetry.yml``: This playbook sets up `Omnia telemetry and/or iDRAC telemetry <../../Roles/Telemetry/index.html>`_. It also installs `Grafana `_ and `Loki `_ as Kubernetes pods. To run ``omnia.yml``: :: @@ -26,7 +27,6 @@ To run ``omnia.yml``: :: .. note:: - * To visualize the cluster (Slurm/Kubernetes) metrics on Grafana (On the control plane) during the run of ``omnia.yml``, add the parameters ``grafana_username`` and ``grafana_password`` (That is ``ansible-playbook omnia.yml -i inventory -e grafana_username="" -e grafana_password=""``). * For a Kubernetes cluster installation, ensure that the inventory includes an ``[etcd]`` entry. etcd is a consistent and highly-available key value store used as Kubernetes' backing store for all cluster data. For more information, `click here. `_ * If you want to view or edit the ``omnia_config.yml`` file, run the following command: @@ -61,15 +61,12 @@ To ensure security while running jobs on the cluster, users can be assigned perm -**Running Slurm MPI jobs on clusters** +**Configuring UCX and OpenMPI on the cluster** -To enhance the productivity of the cluster, Slurm allows users to run jobs in a parallel-computing architecture. This is used to efficiently utilize all available computing resources. `Click here for more information. <../Benchmarks/index.html>`_ +If a local repository for UCX and OpenMPI has been configured on the cluster, the following configurations take place when running ``omnia.yml`` or ``scheduler.yml``.OpenMPI -.. note:: - - * Omnia does not install MPI packages by default. Users hoping to leverage the Slurm-based MPI execution feature are required to install the relevant packages from a source of their choosing. For information on setting up Intel OneAPI on the cluster, `click here <../Benchmarks/OneAPI.html>`_. - * Ensure there is an NFS node on which to host slurm scripts to run. - * Running jobs as individual users (and not as root) requires that passwordSSH be enabled between cluster nodes for the user. + * **UCX** and **OpenMPI for Slurm (if Slurm is installed)** will be compiled and installed on the NFS share (based on the ``share_path`` provided in ``input/omnia_config.yml``). + * diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index d5a411d7a..4f42775e1 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -10,7 +10,6 @@ For automatic provisioning of servers and discovery, the BMC method can be used. * To assign IPs on the BMC network while discovering servers using a BMC details, target servers should be in DHCP mode or switch details should be provided. - * BMC credentials should be the same across all servers and provided as input to Omnia in the parameters explained below. * Target servers should be configured to boot in PXE mode with the appropriate NIC as the first boot device. @@ -31,10 +30,14 @@ For automatic provisioning of servers and discovery, the BMC method can be used. * BMC network details should be provided in the ``input/network_spec.yml`` file. *When entering details in ``input/network_spec.yml``* -* Ensure that the netmask bits for the BMC network and the admin network are the same. -* The static and dynamic ranges for the BMC network accepts multiple comma-separated ranges. -* The network gateways on both admin and BMC networks are optional. + * Ensure that the netmask bits for the BMC network and the admin network are the same. + + * The static and dynamic ranges for the BMC network accepts multiple comma-separated ranges. + + * The network gateways on both admin and BMC networks are optional. + +.. note:: If the value of ``enable_switch_based`` is set to true, nodes will not To continue to the next steps: diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index fcb0fa91a..487dbe101 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -48,7 +48,7 @@ switch_based .. note:: * If any of the target nodes have a pre-provisioned BMC IP, ensure that these IPs are not part of the ``static_range`` specified in ``input/network_spec.yml`` under the ``bmc_network`` to avoid any bmc IP conflicts. - * In case of a duplicate node object, bmc nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. + * In case of a duplicate node object, duplicate BMC nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. Nodes discovered via mapping will not be deleted. To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index f4d5b9835..a27f38739 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -12,13 +12,19 @@ Optional configurations managed by the provision tool **Using multiple versions of a given OS** -Omnia now supports deploying different versions of the same OS. With each run of ``discovery_provision.yml``, a new deployable OS image is created with a distinct type (rocky, Ubuntu, or RHEL) and version (8.0, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 8.7, 20.04, 22.04) depending on the values provided in ``input/provision_config.yml``. +Omnia now supports deploying different versions of the same OS. With each run of ``discovery_provision.yml``, a new deployable OS image is created with a distinct type: + + * Rocky: 8.6, 8.7, 8.8 + * RHEL: 8.6, 8.7, 8.8 + * Ubuntu: 20.04, 22.04 + +depending on the values provided in ``input/software_config.json``. .. note:: While Omnia deploys the minimal version of the OS, the multiple version feature requires that the Rocky full (DVD) version of the OS be provided. **Disk partitioning** - Omnia now allows for customization of disk partitions applied to remote servers. The disk partition ``desired_capacity`` has to be provided in MB. Valid ``mount_point`` values accepted for disk partition are ``/home``, ``/var``, ``/tmp``, ``/usr``, ``swap``. Default partition size provided for ``/boot`` is 1024MB, ``/boot/efi`` is 256MB and the remaining space to ``/`` partition. Values are accepted in the form of JSON list such as: + Omnia now allows for customization of disk partitions applied to remote servers. The disk partition ``desired_capacity`` has to be provided in MB. Valid ``mount_point`` values accepted for disk partition are ``/home``, ``/var``, ``/tmp``, ``/usr``, ``swap``. The default partition size provided for RHEL/Rocky is /boot: 1024MB, /boot/efi: 256MB and remaining space to / partition. Default partition size provided for Ubuntu is /boot: 2148MB, /boot/efi: 1124MB and remaining space to / partition. Values are accepted in the form of JSON list such as: :: @@ -113,7 +119,10 @@ After successfully running ``discovery_provision.yml``, go to `Building Clusters .. caution:: - * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. If the new environment variables still do not come into effect, enable manually using ``source /etc/profile.d/xcat.sh``. + * Once xCAT is installed, restart your SSH session to the control plane to ensure that the newly set up environment variables come into effect. If the new environment variables still do not come into effect, enable manually using: :: + + source /etc/profile.d/xcat.sh + * To avoid breaking the passwordless SSH channel on the control plane, do not run ``ssh-keygen`` commands post execution of ``discovery_provision.yml`` to create a new key. * Do not delete the following directories: - ``/root/xcat`` diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 8f96c446e..6ad9d667a 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -89,7 +89,6 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf .. note:: * Enable a repository from your RHEL subscription, run the following commands: :: - subscription-manager repos --enable=codeready-builder-for-rhel-8-x86_64-rpms subscription-manager repos --enable=rhel-8-for-x86_64-appstream-rpms subscription-manager repos --enable=rhel-8-for-x86_64-baseos-rpms @@ -115,15 +114,7 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf gpgcheck=0 - [RHEL-8-crb] - name=Red Hat CRB repo - - baseurl=http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.6/CRB/x86_64/os/ - - enabled=1 - - gpgcheck=0 * Verify your changes by running: :: @@ -134,7 +125,7 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf repo id repo name RHEL-8-appstream-partners Red Hat Enterprise Linux 8.6.0 Partners (AppStream) RHEL-8-baseos-partners Red Hat Enterprise Linux 8.6.0 Partners (BaseOS) - RHEL-8-crb-partners Red Hat Enterprise Linux 8.6.0 Partners (CRB) + .. note:: diff --git a/docs/source/Tables/Provision_config.csv b/docs/source/Tables/Provision_config.csv index cdb3766b9..d193f6f8f 100644 --- a/docs/source/Tables/Provision_config.csv +++ b/docs/source/Tables/Provision_config.csv @@ -36,8 +36,8 @@ Required","* Domain name the user intends to configure on the cluster. ``string`` -Optional","* The mapping file consists of the Service tag, Admin MAC,Hostname and its respective admin IP address and/or BMC IP. -* This variable is required to discover nodes using a mapping file. +Optional","* This variable is required to discover nodes using a mapping file. +* The mapping file consists of the Service tag, Admin MAC,Hostname and its respective admin IP address and/or BMC IP. * Ensure that the admin IP addresses provided are within the ``admin_static_ranges``. * A sample file is provided here: examples/pxe_mapping_file.csv. * The headers of the CSV are SERVICE_TAG,ADMIN_MAC,HOSTNAME,ADMIN_IP,BMC_IP." @@ -63,8 +63,8 @@ Required","* Variable indicates whether switch based discovery should be enabled ``JSON List`` -Optional","* JSON list of switches to query for target nodes. -* This variable is required when nodes are to be discovered via switch details. +Optional","* This variable is required when nodes are to be discovered via switch details (that is ``enable_switch_based`` is set to true). +* JSON list of switches to query for target nodes. * Split port ranges are not accepted here. (Ex: 10:5-10:10 will not be valid). * Example: :: From 15d7c63f211f6c65ef6ae137acd4b717396e34fe Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 14:41:02 +0530 Subject: [PATCH 280/309] Updating documentation Signed-off-by: goveac --- .../source/InstallationGuides/BuildingClusters/NFS.rst | 4 ---- docs/source/Tables/scheduler_k8s.csv | 10 +--------- docs/source/Tables/scheduler_slurm.csv | 9 --------- docs/source/Tables/storage_config.csv | 1 - 4 files changed, 1 insertion(+), 23 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/NFS.rst b/docs/source/InstallationGuides/BuildingClusters/NFS.rst index 6d1140fac..6decf0699 100644 --- a/docs/source/InstallationGuides/BuildingClusters/NFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/NFS.rst @@ -56,11 +56,7 @@ Network File System (NFS) is a networking protocol for distributed file sharing. * Ensure that an NFS local repository is created by including ``{"name": "nfs"},`` in ``input/software_config.json``. For more information, `click here. <../InstallationGuides/LocalRepo/index.html>`_ -* Enter the value of ``share_path`` in ``input/omnia_config.yml``. * If the intended cluster will run Slurm, set the value of ``Slurm_installation_type`` in ``input/omnia_config.yml`` to ``nfs_share``. - -.. note:: Ensure that the value of ``share_path`` provided matches at least one value of ``client_share_path`` provided in ``nfs_client_params`` in ``input/storage_config.yml``. - * If an external NFS share is used, make sure that ``/etc/exports`` on the NFS server is populated with the same paths listed as ``server_share_path`` in the ``nfs_client_params`` in ``input/storage_config.yml``. * Omnia supports all NFS mount options. Without user input, the default mount options are nosuid,rw,sync,hard,intr. diff --git a/docs/source/Tables/scheduler_k8s.csv b/docs/source/Tables/scheduler_k8s.csv index 6bbb86507..f72dee12c 100644 --- a/docs/source/Tables/scheduler_k8s.csv +++ b/docs/source/Tables/scheduler_k8s.csv @@ -37,20 +37,12 @@ ``string`` - Optional ","* Indicates whether the slurm installation will support configless or nfs mode -* If set to ``nfs_share``, ensure that a ``share_path`` is provided. + Optional ","* Indicates whether the slurm installation will support configless or nfs mode. Choices: * ``nfs_share`` <- default * ``configless`` " -"**share_path** - - ``string`` - - Optional ","* Path to directory which will be shared across all nodes in the cluster. -* If omitted, ``/mnt/share`` is provided. -Default value: ""/home/omnia-share""" "**k8s_service_addresses** ``string`` diff --git a/docs/source/Tables/scheduler_slurm.csv b/docs/source/Tables/scheduler_slurm.csv index ebaa8e38a..ddd8ad040 100644 --- a/docs/source/Tables/scheduler_slurm.csv +++ b/docs/source/Tables/scheduler_slurm.csv @@ -38,19 +38,10 @@ ``string`` Optional ","* Indicates whether the slurm installation will support configless or nfs mode -* If set to ``nfs_share``, ensure that a ``share_path`` is provided. - Choices: * ``nfs_share`` <- default * ``configless`` " -"**share_path** - - ``string`` - - Optional ","* Path to directory which will be shared across all nodes in the cluster. -* If omitted, ``/mnt/share`` is provided. -**Default value**: ""/home/omnia-share""" "**restart_slurm_services** ``boolean`` diff --git a/docs/source/Tables/storage_config.csv b/docs/source/Tables/storage_config.csv index 2cfb4421d..9803f40ed 100644 --- a/docs/source/Tables/storage_config.csv +++ b/docs/source/Tables/storage_config.csv @@ -6,7 +6,6 @@ Required ","* This JSON list contains all parameters required to set up NFS. * For a bolt-on set up where there is a pre-existing NFS export, set ``nfs_server`` to ``false``. * When ``nfs_server`` is set to ``true``, an NFS share is created on the control plane for access by all cluster nodes. -* Ensure that the value of ``share_path`` in ``input/omnia_config.yml`` matches at least one of the ``client_share_path`` values in the JSON list provided. * For more information on the different kinds of configuration available, `click here. `_" "beegfs_rdma_support ``boolean`` From 6786b0279663fb09faed944c83d0bc5f19207a38 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 14:53:03 +0530 Subject: [PATCH 281/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 4 ++-- docs/source/Tables/Provision_creds.csv | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index a27f38739..55b6dcaeb 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -24,12 +24,12 @@ depending on the values provided in ``input/software_config.json``. **Disk partitioning** - Omnia now allows for customization of disk partitions applied to remote servers. The disk partition ``desired_capacity`` has to be provided in MB. Valid ``mount_point`` values accepted for disk partition are ``/home``, ``/var``, ``/tmp``, ``/usr``, ``swap``. The default partition size provided for RHEL/Rocky is /boot: 1024MB, /boot/efi: 256MB and remaining space to / partition. Default partition size provided for Ubuntu is /boot: 2148MB, /boot/efi: 1124MB and remaining space to / partition. Values are accepted in the form of JSON list such as: + Omnia now allows for customization of disk partitions applied to remote servers. The disk partition ``desired_capacity`` has to be provided in MB. Valid ``mount_point`` values accepted for disk partition are ``/var``, ``/tmp``, ``/usr``, ``swap``. The default partition size provided for RHEL/Rocky is /boot: 1024MB, /boot/efi: 256MB and remaining space to / partition. Default partition size provided for Ubuntu is /boot: 2148MB, /boot/efi: 1124MB and remaining space to / partition. Values are accepted in the form of JSON list such as: :: disk_partition: - - { mount_point: "/home", desired_capacity: "102400" } + - { mount_point: "/var", desired_capacity: "102400" } - { mount_point: "swap", desired_capacity: "10240" } diff --git a/docs/source/Tables/Provision_creds.csv b/docs/source/Tables/Provision_creds.csv index 9f9261d5b..481ec82a8 100644 --- a/docs/source/Tables/Provision_creds.csv +++ b/docs/source/Tables/Provision_creds.csv @@ -29,16 +29,16 @@ Required","* The password set on target iDRACs. ``string`` -Optional ","* Non-admin SNMPv3 credentials of the PXE switch. -* This variable is required when discovering nodes via switch details. +Optional ","* This variable is required when discovering nodes via switch details. +* Non-admin SNMPv3 credentials of the PXE switch. * If multiple switches are provided, ensure the credentials are same across switches. * Username must not contain -,\, ',""" "**switch_snmp3_password** ``string`` -Optional","* Non-admin SNMPv3 credentials of the PXE switch. -* This variable is required when discovering nodes via switch details. +Optional","* This variable is required when discovering nodes via switch details. +* Non-admin SNMPv3 credentials of the PXE switch. * If multiple switches are provided, ensure the credentials are same across switches. * Password must not contain -,\, ',""" "**docker_username** From bbeb3375a3616e147abcba9ba81989ab15ec8623 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 14:54:22 +0530 Subject: [PATCH 282/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/DiscoveryMechanisms/bmc.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 4f42775e1..7b93bf9c4 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -29,8 +29,7 @@ For automatic provisioning of servers and discovery, the BMC method can be used. * BMC network details should be provided in the ``input/network_spec.yml`` file. -*When entering details in ``input/network_spec.yml``* - +When entering details in ``input/network_spec.yml``: * Ensure that the netmask bits for the BMC network and the admin network are the same. * The static and dynamic ranges for the BMC network accepts multiple comma-separated ranges. From dec0dffda349371fabba9c8368fafee1b3e467a8 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 14:55:22 +0530 Subject: [PATCH 283/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/DiscoveryMechanisms/bmc.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst index 7b93bf9c4..bc1c8ca27 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/bmc.rst @@ -36,7 +36,7 @@ When entering details in ``input/network_spec.yml``: * The network gateways on both admin and BMC networks are optional. -.. note:: If the value of ``enable_switch_based`` is set to true, nodes will not +.. note:: If the value of ``enable_switch_based`` is set to true, nodes will not be discovered via BMC irrespective of the contents in ``input/network_spec.yml``. To continue to the next steps: From e1b7ef111d4ed486ce6229b6e10b19676326d8ba Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 15:05:07 +0530 Subject: [PATCH 284/309] Updating documentation Signed-off-by: goveac --- .../DiscoveryMechanisms/switch-based.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst index 487dbe101..d8ba5e699 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/switch-based.rst @@ -48,7 +48,7 @@ switch_based .. note:: * If any of the target nodes have a pre-provisioned BMC IP, ensure that these IPs are not part of the ``static_range`` specified in ``input/network_spec.yml`` under the ``bmc_network`` to avoid any bmc IP conflicts. - * In case of a duplicate node object, duplicate BMC nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. Nodes discovered via mapping will not be deleted. + * In case of a duplicate node object, duplicate BMC nodes will be deleted automatically by the **duplicate_node_cleanup** service that runs every 30 minutes. When nodes are discovered via mapping and switch details, the nodes discovered via switch details will not be deleted. Delete the node manually `using the delete node playbook. <../../deletenode.html#delete-provisioned-node>`_ To clear the configuration on Omnia provisioned switches and ports, `click here <../../../Roles/Utils/portcleanup.html>`_. From 969ade7e50923f1826cfca69af9951ad67a2de33 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 15:21:47 +0530 Subject: [PATCH 285/309] Updating documentation Signed-off-by: goveac --- .../BuildingClusters/installscheduler.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst index 01f84ce94..87d9b89e9 100644 --- a/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst +++ b/docs/source/InstallationGuides/BuildingClusters/installscheduler.rst @@ -63,10 +63,12 @@ To ensure security while running jobs on the cluster, users can be assigned perm **Configuring UCX and OpenMPI on the cluster** -If a local repository for UCX and OpenMPI has been configured on the cluster, the following configurations take place when running ``omnia.yml`` or ``scheduler.yml``.OpenMPI +If a local repository for UCX and OpenMPI has been configured on the cluster, the following configurations take place when running ``omnia.yml`` or ``scheduler.yml``. - * **UCX** and **OpenMPI for Slurm (if Slurm is installed)** will be compiled and installed on the NFS share (based on the ``share_path`` provided in ``input/omnia_config.yml``). - * + * **UCX** will be compiled and installed on the NFS share (based on the ``client_share_path`` provided in the ``nfs_client_params`` in ``input/storage_config.yml``). + * If the cluster uses Slurm and UCX, OpenMPI is configured to compile with the UCX and Slurm on the NFS share (based on the ``client_share_path`` provided in the ``nfs_client_params`` in ``input/storage_config.yml``). + * All corresponding compiled UCX and OpenMPI files will be saved to the ``/compile`` directory on the nfs share. + * All corresponding UCX and OpenMPI executables will be saved to the ``/benchmarks/`` directory on the nfs share. From cd8c859dc909728a5eed3ba92867790d60569bea Mon Sep 17 00:00:00 2001 From: cgoveas Date: Wed, 27 Mar 2024 17:09:18 +0530 Subject: [PATCH 286/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/provisionprereqs.rst | 2 +- docs/source/InstallationGuides/RunningInit/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 6ad9d667a..6d478da43 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -1,7 +1,7 @@ Before you run the provision tool --------------------------------- -* (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14.14 `_ and `Python 3.9 `_ are installed on the system. +* (Recommended) Run ``prereq.sh`` to get the system ready to deploy Omnia. Alternatively, ensure that `Ansible 2.14 `_ and `Python 3.9 `_ are installed on the system. * All target bare-metal servers should be reachable to the chosen control plane. diff --git a/docs/source/InstallationGuides/RunningInit/index.rst b/docs/source/InstallationGuides/RunningInit/index.rst index 26883c481..93f9f8770 100644 --- a/docs/source/InstallationGuides/RunningInit/index.rst +++ b/docs/source/InstallationGuides/RunningInit/index.rst @@ -1,7 +1,7 @@ Running prereq.sh ================= -``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.14.14). :: +``prereq.sh`` is used to install the software utilized by Omnia on the control plane including Python (3.9), Ansible (2.14). :: cd omnia ./prereq.sh From 569cdc38c36ab4f79a27a57e3eb14589d1feb2fa Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:01:00 +0530 Subject: [PATCH 287/309] Updating documentation Signed-off-by: goveac --- .../BuildingClusters/Authentication.rst | 3 - .../BuildingClusters/BeeGFS.rst | 3 - .../BuildingClusters/schedulerprereqs.rst | 4 - .../ConfiguringStorage/index.rst | 4 +- .../DiscoveryMechanisms/index.rst | 4 +- .../DiscoveryMechanisms/mappingfile.rst | 4 +- .../provisionparams.rst | 7 +- .../provisionprereqs.rst | 48 +------ .../LocalRepo/Prerequisite.rst | 45 ++++++- docs/source/Roles/Accelerator/index.rst | 7 +- docs/source/Roles/Security/index.rst | 4 - docs/source/Roles/index.rst | 1 - docs/source/Troubleshooting/FAQ.rst | 35 ++--- docs/source/Troubleshooting/knownissues.rst | 125 ++---------------- docs/source/bestpractices.rst | 2 +- docs/source/limitations.rst | 22 +-- docs/source/samplefiles.rst | 41 +++--- 17 files changed, 98 insertions(+), 261 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index 8f747666b..c8b3751c9 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -3,9 +3,6 @@ Centralized authentication on the cluster The security feature allows users to set up FreeIPA and LDAP to help authenticate into HPC clusters. -.. note:: - * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``security.yml`` on RHEL target nodes. - * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. Configuring FreeIPA/LDAP security diff --git a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst index d361344e3..33c4b17af 100644 --- a/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst +++ b/docs/source/InstallationGuides/BuildingClusters/BeeGFS.rst @@ -43,9 +43,6 @@ To open the ports required, use the following steps: -* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to set up BeeGFS on RHEL cluster nodes. - -* For RHEL cluster nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all cluster nodes. Every cluster node will require a RedHat subscription. .. note:: BeeGFS services over RDMA is only supported on RHEL 8.3 and above due to limitations on BeeGFS. When setting up your cluster with RDMA support, check the BeeGFS documentation to provide appropriate values in ``input/storage_config.yml``. diff --git a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst index 9970de71e..ca4f361a3 100644 --- a/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst +++ b/docs/source/InstallationGuides/BuildingClusters/schedulerprereqs.rst @@ -17,10 +17,6 @@ Before you build clusters * Users should also ensure that all repos are available on the cluster nodes running RHEL. -* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``omnia.yml`` on RHEL cluster nodes. - -* For RHEL cluster nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - diff --git a/docs/source/InstallationGuides/ConfiguringStorage/index.rst b/docs/source/InstallationGuides/ConfiguringStorage/index.rst index 1bca4c0fb..8ca9be7ad 100644 --- a/docs/source/InstallationGuides/ConfiguringStorage/index.rst +++ b/docs/source/InstallationGuides/ConfiguringStorage/index.rst @@ -1,5 +1,5 @@ -Configuring storage -===================== +Configuring PowerVault +======================= **Configuring Powervault storage** diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst index 32bd7328c..7f061d48f 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/index.rst @@ -40,8 +40,8 @@ Manually collect PXE NIC information for target servers and manually define them :: SERVICE_TAG,HOSTNAME,ADMIN_MAC,ADMIN_IP,BMC_IP - 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 - V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 + XXXXXXXX,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 + XXXXXXXX,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 **Pros** diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst index f769923ec..b485d9d15 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/DiscoveryMechanisms/mappingfile.rst @@ -8,8 +8,8 @@ Manually collect PXE NIC information for target servers and define them to Omnia :: SERVICE_TAG,HOSTNAME,ADMIN_MAC,ADMIN_IP,BMC_IP - 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 - V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 + XXXXXXXX,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 + XXXXXXXX,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 .. note:: * The header fields mentioned above are case sensitive. diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index c51357452..b7e10f093 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -42,6 +42,10 @@ Update the ``input/network_spec.yml`` file for all networks available for use by * BMC network details are not required when target nodes are discovered using a mapping file. * If ``bmc_network`` properties are provided, target nodes will be discovered using the BMC method in addition to the methods whose details are explicitly provided in ``provision_config.yml``. +.. caution:: + * Do not assign the subnet 10.4.0.0/24 to any interfaces in the network as nerdctl uses it by default. + * If a DNS server is available on the network, ensure that the ranges provided in the ``input/network_spec.yml`` file do not include the IP address of the DNS server. + * All provided network ranges and nic IP addresses should be distinct with no overlap. A sample is provided below: :: @@ -86,8 +90,7 @@ A sample is provided below: :: * The strings ``admin_network`` and ``bmc_network`` in the ``input/network_spec.yml`` file should not be edited. Also, the properties ``nic_name``, ``static_range``, and ``dynamic_range`` cannot be edited on subsequent runs of the provision tool. * Netmask bits are mandatory and should be same for both the ``admin_network`` and ``bmc_network`` (ie between 1 and 32; 1 and 32 are acceptable values). - * Do not assign the subnet 10.4.0.0/24 to any interfaces in the network as nerdctl uses it by default. - * Ensure that the CIDR is aligned with the ``netmask_bits`` provided. + * Ensure that the CIDR is aligned with the ``netmask_bits`` provided. * The ``discover_ranges`` property of the ``bmc_network`` can accept multiple comma-separated ranges. * The ``VLAN`` property is optional but should be between 0 and 4095 (0 and 4095 are not acceptable values). diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst index 6d478da43..52e1d4a20 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionprereqs.rst @@ -67,7 +67,7 @@ Note the compatibility between cluster OS and control plane OS below: | Ubuntu | Rocky | No | +---------------------+--------------------+------------------+ -.. [1] Ensure that control planes running RHEL have an active subscription or are configured to access local repositories. The following repositories should be enabled on the control plane: **AppStream**, **Code Ready Builder (CRB)**, **BaseOS**. For RHEL control planes running 8.5 and below, ensure that sshpass is additionally available to install or download to the control plane (from any local repository). +.. [1] Ensure that control planes running RHEL have an active subscription or are configured to access local repositories. The following repositories should be enabled on the control plane: **AppStream**, **BaseOS**. * Ensure that all connection names under the network manager match their corresponding device names. To verify network connection names: :: @@ -82,52 +82,6 @@ In the event of a mismatch, edit the file ``/etc/sysconfig/network-scripts/ifcf * When discovering nodes via a mapping file, all target nodes should be set up in PXE mode before running the playbook. -* Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``discovery_provision.yml`` on RHEL target nodes. - -* For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - -.. note:: - * Enable a repository from your RHEL subscription, run the following commands: :: - - subscription-manager repos --enable=rhel-8-for-x86_64-appstream-rpms - subscription-manager repos --enable=rhel-8-for-x86_64-baseos-rpms - - * Enable an offline repository by creating a ``.repo`` file in ``/etc/yum.repos.d/``. Refer the below sample content: :: - - [RHEL-8-appstream] - - name=Red Hat AppStream repo - - baseurl=http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.6/AppStream/x86_64/os/ - - enabled=1 - - gpgcheck=0 - - [RHEL-8-baseos] - - name=Red Hat BaseOS repo - - baseurl=http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.6/BaseOS/x86_64/os/ - - enabled=1 - - gpgcheck=0 - - - - * Verify your changes by running: :: - - yum repolist enabled - Updating Subscription Management repositories. - Unable to read consumer identity - This system is not registered with an entitlement server. You can use subscription-manager to register. - repo id repo name - RHEL-8-appstream-partners Red Hat Enterprise Linux 8.6.0 Partners (AppStream) - RHEL-8-baseos-partners Red Hat Enterprise Linux 8.6.0 Partners (BaseOS) - - - .. note:: * After configuration and installation of the cluster, changing the control plane is not supported. If you need to change the control plane, you must redeploy the entire cluster. diff --git a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst index 2ad0de2ca..f98daeab3 100644 --- a/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst +++ b/docs/source/InstallationGuides/LocalRepo/Prerequisite.rst @@ -41,4 +41,47 @@ There are two ways to pull images from the user registries in the form of a dige }, - * While pushing the image to the user registry, create a tag and update the JSON file to take the tag value instead of the digest. \ No newline at end of file + * While pushing the image to the user registry, create a tag and update the JSON file to take the tag value instead of the digest. + + +.. note:: + * Enable a repository from your RHEL subscription, run the following commands: :: + + subscription-manager repos --enable=rhel-8-for-x86_64-appstream-rpms + subscription-manager repos --enable=rhel-8-for-x86_64-baseos-rpms + + * Enable an offline repository by creating a ``.repo`` file in ``/etc/yum.repos.d/``. Refer the below sample content: :: + + [RHEL-8-appstream] + + name=Red Hat AppStream repo + + baseurl=http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.6/AppStream/x86_64/os/ + + enabled=1 + + gpgcheck=0 + + [RHEL-8-baseos] + + name=Red Hat BaseOS repo + + baseurl=http://xx.yy.zz/pub/Distros/RedHat/RHEL8/8.6/BaseOS/x86_64/os/ + + enabled=1 + + gpgcheck=0 + + + + * Verify your changes by running: :: + + yum repolist enabled + Updating Subscription Management repositories. + Unable to read consumer identity + This system is not registered with an entitlement server. You can use subscription-manager to register. + repo id repo name + RHEL-8-appstream-partners Red Hat Enterprise Linux 8.6.0 Partners (AppStream) + RHEL-8-baseos-partners Red Hat Enterprise Linux 8.6.0 Partners (BaseOS) + + diff --git a/docs/source/Roles/Accelerator/index.rst b/docs/source/Roles/Accelerator/index.rst index 7aea495f6..95d05256c 100644 --- a/docs/source/Roles/Accelerator/index.rst +++ b/docs/source/Roles/Accelerator/index.rst @@ -3,12 +3,14 @@ GPU accelerator configuration The accelerator role allows users to set up the `AMD ROCm `_ platform or the `CUDA Nvidia toolkit `_. These tools allow users to unlock the potential of installed GPUs. +Ensure that CUDA and ROCm local repositories are configured using the `local_repo.yml script. <../../InstallationGuides/LocalRepo/index.html>`_ + Enter all required parameters in ``input/accelerator_config.yml``. +----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Parameters | Details | +======================+=========================================================================================================================================================================================================================================================================================================================================================================================================================================+ -| amd_gpu_version | This variable accepts the amd gpu version for the RHEL specific OS version. Verify if the version provided is present in the repo for the OS version on your node. Verify the url for the compatible version: https://repo.radeon.com/amdgpu/ . If 'latest' is provided in the variable and the cluster os version is rhel 8.5. Then the url transforms to https://repo.radeon.com/amdgpu/latest/rhel/8.5/main/x86_64/ | +| amd_gpu_version | This variable accepts the amd gpu version for the RHEL specific OS version. Verify if the version provided is present in the repo for the OS version on your node. Verify the url for the compatible version: https://repo.radeon.com/amdgpu/ . If 'latest' is provided in the variable and the cluster os version is rhel 8.5. Then the url transforms to https://repo.radeon.com/amdgpu/latest/rhel/8.5/main/x86_64/ | | ``string`` | | | Optional | **Default values**: ``22.20.3`` | +----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -33,7 +35,6 @@ Enter all required parameters in ``input/accelerator_config.yml``. .. note:: * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``accelerator.yml`` on RHEL target nodes. * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - * If ``cuda_toolkit_path`` is provided in ``input/provision_config.yml`` and NVIDIA GPUs are available on the target nodes, CUDA packages will be deployed post provisioning without user intervention during the execution of ``discovery_provision.yml``. * AMD ROCm driver installation is not supported by Omnia on Rocky cluster nodes. To install all the latest GPU drivers and toolkits, run: :: @@ -41,9 +42,9 @@ To install all the latest GPU drivers and toolkits, run: :: cd accelerator ansible-playbook accelerator.yml -i inventory -(where inventory consists of manager, cluster and login nodes) The following configurations take place when running ``accelerator.yml`` + i. Servers with AMD GPUs are identified and the latest GPU drivers and ROCm platforms are downloaded and installed. ii. Servers with NVIDIA GPUs are identified and the specified CUDA toolkit is downloaded and installed. iii. For the rare servers with both NVIDIA and AMD GPUs installed, all the above mentioned download-ables are installed to the server. diff --git a/docs/source/Roles/Security/index.rst b/docs/source/Roles/Security/index.rst index a021429bb..907d04b50 100644 --- a/docs/source/Roles/Security/index.rst +++ b/docs/source/Roles/Security/index.rst @@ -3,10 +3,6 @@ Centralized authentication on the cluster The security feature allows users to set up FreeIPA and LDAP to help authenticate into HPC clusters. -.. note:: - * Nodes provisioned using the Omnia provision tool do not require a RedHat subscription to run ``security.yml`` on RHEL target nodes. - * For RHEL target nodes not provisioned by Omnia, ensure that RedHat subscription is enabled on all target nodes. Every target node will require a RedHat subscription. - Configuring FreeIPA/LDAP security ________________________________ diff --git a/docs/source/Roles/index.rst b/docs/source/Roles/index.rst index 189cf12a8..124ca7f09 100644 --- a/docs/source/Roles/index.rst +++ b/docs/source/Roles/index.rst @@ -8,7 +8,6 @@ Below is a list of all Omnia's features: .. toctree:: - Network/index Security/index Storage/index Accelerator/index diff --git a/docs/source/Troubleshooting/FAQ.rst b/docs/source/Troubleshooting/FAQ.rst index bb98944f1..6f72be912 100644 --- a/docs/source/Troubleshooting/FAQ.rst +++ b/docs/source/Troubleshooting/FAQ.rst @@ -45,7 +45,7 @@ Frequently asked questions .. image:: ../images/PXEBootFail.png -1. Rectify any probable causes like incorrect/unavailable credentials (``switch_snmp3_username`` and ``switch_snmp3_password`` provided in ``input/provision_config.yml``), network glitches or incorrect switch IP/port details. +1. Rectify any probable causes like incorrect/unavailable credentials (``switch_snmp3_username`` and ``switch_snmp3_password`` provided in ``input/provision_config.yml``), network glitches, having multiple NICs with the same IP address as the control plane, or incorrect switch IP/port details. 2. Run the clean up script by: :: cd utils @@ -84,25 +84,13 @@ Re-run the playbook whose execution failed once the issue is resolved. **Causes**: * Nodes do not have their first PXE device set as designated active NIC for PXE booting. - * Nodes that have been discovered via SNMP or mapping file have not been PXE booted. + * Nodes that have been discovered via multiple discovery mechanisms may list multiple times. Duplicate node entries will not list MAC addresses. **Resolution**: * Configure the first PXE device to be active for PXE booting. * PXE boot the target node manually. - -⦾ **Why does the discovery_provision.yml fail at 'provision validation: Install common packages for provision' on RHEL nodes running 8.5 or earlier?** - -.. image:: ../images/RedHat_provisionerror_sshpass.PNG - -**Potential Cause**: - * sshpass is not available in any of the repositories on the control plane. - -**Resolution**: - - * Enable RedHat subscription or ensure that sshpass is available to install or download to the control plane (from any local repository). - -.. note:: This error can also take place when task ``cluster_preperation : Install sshpass`` is executed during ``omnia.yml``. + * Duplicate node objects (identified by service tag) will be deleted automatically. To manually delete node objects, use ``utils/delete_node.yml``. ⦾ What to do if user login fails when accessing a cluster node: @@ -125,10 +113,14 @@ Re-run the playbook whose execution failed once the issue is resolved. **Resolution**: If ``enable_omnia_nfs`` is true in ``input/omnia_config.yml``, follow the below steps to configure an NFS share on your LDAP server: + - From the kube_control_plane: + 1. Add the LDAP server IP address to ``/etc/exports``. 2. Run ``exportfs -ra`` to enable the NFS configuration. + - From the LDAP server: + 1. Add the required fstab entries in ``/etc/fstab`` (The corresponding entry will be available on the compute nodes in ``/etc/fstab``) 2. Mount the NFS share using ``mount manager_ip: /home/omnia-share /home/omnia-share`` @@ -156,9 +148,9 @@ For many of Omnia's features to work, RHEL control planes need access to the fol 1. AppStream 2. BaseOS - 3. CRB -This can only be achieved using local repos specified in rhel_repo_local_path (``input/provision_config.yml``) OR having an active, available RedHat subscription. + +This can only be achieved using local repos specified in rhel_repo_local_path (``input/provision_config.yml``). .. note:: To enable the repositories, run the following commands: :: @@ -239,19 +231,10 @@ Omnia does not validate the input of ``rhel_repo_local_path``. **Resolution**: Manually input the username and password to your docker account on the control plane. - -⦾ **Is Disabling 2FA supported by Omnia?** - -* Disabling 2FA is not supported by Omnia and must be manually disabled. - ⦾ **Is provisioning servers using BOSS controller supported by Omnia?** Provisioning server using BOSS controller is now supported by Omnia 1.2.1. -⦾ **How many IPs are required within the PXE NIC range?** - -Ensure that the number of IPs available between ``pxe_nic_start_range`` and ``pxe_nic_end_range`` is double the number of iDRACs available to account for potential stale entries in the mapping DB. - ⦾ **What are the licenses required when deploying a cluster through Omnia?** While Omnia playbooks are licensed by Apache 2.0, Omnia deploys multiple softwares that are licensed separately by their respective developer communities. For a comprehensive list of software and their licenses, `click here <../Overview/SupportMatrix/omniainstalledsoftware.html>`_ . diff --git a/docs/source/Troubleshooting/knownissues.rst b/docs/source/Troubleshooting/knownissues.rst index 3128d0c26..e397335e3 100644 --- a/docs/source/Troubleshooting/knownissues.rst +++ b/docs/source/Troubleshooting/knownissues.rst @@ -7,44 +7,17 @@ Due to internal MAC ID conflicts on the target nodes, the MAC address will be li .. image:: ../images/MACConflict.png -⦾ **Hostname assignment by Omnia is not sequential (that is from 1-xx) when discovering nodes via BMC or switch-based methods** - -Omnia does not maintain any order when assigning hostnames to target nodes. - -⦾ **cluster nodes get updated to Rocky 8.8 automatically irrespective of the input parameters provided to provision_config.yml when provision_os is Rocky.** - -**Potential Cause:** In Rocky Linux, online repos are enabled by default, and they always point to the latest Rocky repository (currently Rocky Linux 8.8). - -**Resolution**: This will be addressed in a later release. ⦾ **Why does the task Assign admin NIC IP fail during discovery_provision.yml with errors?** -.. image:: ../images/AdminNICErrors.png +.. image:: ../images/AdminNICErrors.png **Potential Cause:** Omnia validates the admin NIC IP on the control plane. If the user has not assigned an admin NIC IP in case of dedicated network interface type, an error message is returned. There is a parsing logic that is being applied on the blank IP and hence, the error displays twice. **Resolution**: Ensure a control plane IP is assigned to the admin NIC. -⦾ **Kubernetes pods on the kube_control_plane are in CreateContainerConfigError and Calico Pods are in CrashLoopBackoff error after running omnia.yml (version 1.5 and below).** - -**Potential Cause:** - -Calico pods are configured with the NIC name of the kube_control_plane. If the NIC name of the other nodes are not the same, the pods will throw an error and retry later. - -**Workaround:** - -The manager and cluster nodes should have connectivity over the same admin NIC. - -⦾ **Why does the task ``cluster_preperation : Install sshpass`` fail during ``omnia.yml`` on cluster nodes running RHEL 8.5 and below versions.** - -**Potential Cause**: - * sshpass is not available in any of the repositories on the control plane. - -**Resolution**: - - * Enable RedHat subscription or ensure that sshpass is available to install or download to the control plane (from any local repository). -⦾ **Why are some target servers not reachable after running PXE booting them?** +⦾ **Why are some target servers not reachable after PXE booting them?** **Potential Causes**: @@ -59,23 +32,6 @@ The manager and cluster nodes should have connectivity over the same admin NIC. 2. Hard-reboot the server to bring up the server and verify that the boot process runs smoothly. (If it gets stuck again, disable PXE and try provisioning the server via iDRAC.) -⦾ **Why does the task 'Provision: Fetch the available subnets and netmasks' fail with 'no ipv4_secondaries present'?** - -.. image:: ../images/SharedLomError.png - -**Potential Cause**: If a shared LOM environment is in use, the management network/host network NIC may only have one IP assigned to it. - -**Resolution**: Ensure that the NIC used for host and data connections has 2 IPs assigned to it. - -⦾ **Why does provisioning RHEL 8.3 fail on some nodes with "dasbus.error.DBusError: 'NoneType' object has no attribute 'set_property'"?** - -This error is known to RHEL and is being addressed `here `_. Red Hat has offered a user intervention `here `_. Omnia recommends that in the event of this failure, any OS other than RHEL 8.3. - -⦾ **Why is the Infiniband NIC down after provisioning the server?** - -For servers running Rocky, enable the Infiniband NIC manually, use ``ifup ``. - -Alternatively, run ``network.yml`` or ``post_provision.yml`` (Only if the nodes are provisioned using Omnia) to activate the NIC. ⦾ **Why does the Task [infiniband_switch_config : Authentication failure response] fail with the message 'Status code was -1 and not [302]: Request failed: ' on Infiniband Switches when running infiniband_switch_config.yml?** @@ -91,9 +47,6 @@ To correct the issue, run: ``json-gw enable`` (To enable the JSON gateway) -⦾ **Why does the task 'Initialize kubeadm' fail while running monitor.yml?** - -This issue is caused by incompatibility between Rocky 8.7 and kubernetes due to cri-o. For more information, `click here `_. ⦾ **Why does PXE boot fail with tftp timeout or service timeout errors?** @@ -114,7 +67,7 @@ This issue is caused by incompatibility between Rocky 8.7 and kubernetes due to 2. Check if other systems except for the control plane have xcatd running. If yes, then stop the xCAT service using the following commands: ``systemctl stop xcatd``. -3. On the server, go to ``BIOS Setup -> Network Settings -> PXE Device``. For each listed device (typically 4), configure an active NIC under ``PXE device settings`` +3. On the server, go to **BIOS Setup -> Network Settings -> PXE Device**. For each listed device (typically 4), configure an active NIC under ``PXE device settings`` ⦾ **Why do Kubernetes Pods show "ImagePullBack" or "ErrPullImage" errors in their status?** @@ -145,17 +98,6 @@ Alternatively, run the task manually: :: cd omnia/utils/cluster ansible-playbook gather_facts_resolution.yml -⦾ **What to do after a reboot if kubectl commands return: ``The connection to the server head_node_ip:port was refused - did you specify the right host or port?``** - - -On the control plane or the kube_control_plane, run the following commands: :: - - swapoff -a - - systemctl restart kubelet - - - ⦾ **What to do if the nodes in a Kubernetes cluster reboot:** @@ -192,20 +134,7 @@ Wait for 15 minutes after the Kubernetes cluster reboots. Next, verify the statu 2. On the management node, edit the ``omnia_config.yml`` file to change the Kubernetes Pod Network CIDR. The suggested IP range is 192.168.0.0/16. Ensure that the IP provided is not in use on your host network. -3. Set ``scheduler_type: "k8s"`` in ``input/omnia_config.yml`` and run ``omnia.yml``. - -⦾ **Why does pulling images to create the Kubeflow timeout causing the 'Apply Kubeflow Configuration' task to fail? (version 1.5 and below)** - - -**Potential Cause**: Unstable or slow Internet connectivity. - -**Resolution**: - -1. Complete the PXE booting/format the OS on the manager and cluster nodes. - -2. In the omnia_config.yml file, change the k8s_cni variable value from ``calico`` to ``flannel``. - -3. Run the Kubernetes and Kubeflow playbooks. +3. List k8s in ``input/software_config.json`` and re-run ``omnia.yml``. ⦾ **What to do if pulling the Kserve inference model fail with "Unable to fetch image "kserve/sklearnserver:v0.11.2": failed to resolve image to digest: Get "https://index.docker.io/v2/": dial tcp 3.219.239.5:443: i/o timeout."?** @@ -298,11 +227,11 @@ Recommended Actions: - slurmctl restart slurmctld on kube_control_plane + slurmctl restart slurmctld on slurm_control_node - systemctl restart slurmdbd on kube_control_plane + systemctl restart slurmdbd on slurm_control_node - systemctl restart slurmd on compute node + systemctl restart slurmd on slurm_node @@ -364,29 +293,11 @@ Recommended Actions: 3. For connecting to PowerVault (Data Connection) -⦾ **Why do pods and images appear to get deleted automatically?** - - -**Potential Cause**: - -Lack of space in the root partition (/) causes Linux to clear files automatically (Use ``df -h`` to diagnose the issue). - - **Resolution**: - -* Delete large, unused files to clear the root partition (Use the command ``find / -xdev -size +5M | xargs ls -lh | sort -n -k5`` to identify these files). Before running ``monitor.yml``, it is recommended to have a minimum of 50% free space in the root partition. - -* Once the partition is cleared, run ``kubeadm reset -f`` - -* Re-run ``monitor.yml`` - - ⦾ **What to do when the JupyterHub or Prometheus UI is not accessible:** Run the command ``kubectl get pods namespace default`` to ensure **nfs-client** pod and all Prometheus server pods are in the **Running** state. - - ⦾ **What to do if PowerVault throws the error: ``Error: The specified disk is not available. - Unavailable disk (0.x) in disk range '0.x-x'``:** 1. Verify that the disk in question is not part of any pool: ``show disks`` @@ -448,7 +359,7 @@ At any given time only one type of disk group can be created on the system. That ⦾ **Why does the task 'security: Authenticate as admin' fail?** **Potential Cause**: -The required services are not running on the node. Verify the service status using::: +The required services are not running on the node. Verify the service status using: :: systemctl status sssd-kcm.socket @@ -456,7 +367,7 @@ The required services are not running on the node. Verify the service status usi **Resolution**: -* Restart the services using::: +* Restart the services using: :: systemctl start sssd-kcm.socket systemctl start sssd.service @@ -466,31 +377,19 @@ The required services are not running on the node. Verify the service status usi ansible-playbook omnia.yml -⦾ **Why does installing FreeIPA fail on RHEL servers?** - -.. image:: ../images/FreeIPA_RHEL_Error.png - -**Potential Causes**: Required repositories may not be enabled by your red hat subscription. - -**Resolution**: Enable all required repositories via your red hat subscription. - - ⦾ **Why would FreeIPA server/client installation fail? (version 1.5 and below)** **Potential Cause**: -The hostnames of the manager and login nodes are not set in the correct format. +The hostnames of the auth server nodes are not set in the correct format. **Resolution**: -If you have enabled the option to install the login node in the cluster, set the hostnames of the nodes in the format: *hostname.domainname*. For example, *manager.omnia.test* is a valid hostname for the login node. **Note**: To find the cause for the failure of the FreeIPA server and client installation, see *ipaserver-install.log* in the kube_control_plane or */var/log/ipaclient-install.log* in the login node. - -⦾ **Why does FreeIPA installation fail on the control plane when the public NIC provided is static?** +If you have enabled the option to install the login node in the cluster, set the hostnames of the nodes in the format: *hostname.domainname*. For example, *authserver_node.omnia.test* is a valid hostname for the auth server node. -**Potential Cause**: The network config file for the public NIC on the control plane does not define any DNS entries. +.. note:: To find the cause for the failure of the FreeIPA server and client installation, see *ipaserver-install.log* in the auth server. -**Resolution**: Ensure the fields ``DNS1`` and ``DNS2`` are updated appropriately in the file ``/etc/sysconfig/network-scripts/ifcfg-``. ⦾ **What to do when JupyterHub pods are in 'ImagePullBackOff' or 'ErrImagePull' status after executing jupyterhub.yml:** diff --git a/docs/source/bestpractices.rst b/docs/source/bestpractices.rst index 09981f851..bd3e36daa 100644 --- a/docs/source/bestpractices.rst +++ b/docs/source/bestpractices.rst @@ -9,5 +9,5 @@ Best Practices * Review the prerequisites before running Omnia Scripts. * Ensure that the firefox version being used on the control plane is the latest available. This can be achieved using ``dnf update firefox -y`` * It is recommended to configure devices using Omnia playbooks for better interoperability and ease of access. -* Ensure that the ``/var`` partition has adequate space to complete commands. +* Ensure that the ``/var`` partition has adequate space to complete commands and store images. * Run ``yum update --security`` routinely on the control plane for the latest security updates. \ No newline at end of file diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst index 1e0cebdd0..4046bfc05 100644 --- a/docs/source/limitations.rst +++ b/docs/source/limitations.rst @@ -1,30 +1,13 @@ Limitations =========== -- Once ``discovery_provision.yml`` is used to configure devices, it is - recommended to avoid rebooting the control plane. - Omnia supports adding only 1000 nodes when discovered via BMC. -- Removal of Slurm and Kubernetes component roles are not supported. - However, the scheduler type can be customized by setting ``scheduler_type`` in ``input/omnia_config.yml`` prior to running ``omnia.yml``. -- After installing the Omnia control plane, changing the kube_control_plane - is not supported. If you need to change the kube_control_plane, you must - redeploy the entire cluster. - Dell Technologies provides support to the Dell-developed modules of Omnia. All the other third-party tools deployed by Omnia are outside the support scope. -- To change the Kubernetes single node cluster to a multi-node cluster - or change a multi-node cluster to a single node cluster, you must - either redeploy the entire cluster or run ``kubeadm reset -f`` on all - the nodes of the cluster. Then set ``scheduler_type:k8s`` in ``input/omnia_config.yml`` prior to running ``omnia.yml``. - In a single node cluster, the login node and Slurm functionalities are not applicable. However, Omnia installs FreeIPA Server and Slurm on the single node. -- To change the Kubernetes version from 1.16 to 1.19 or 1.19 to 1.16, - you must redeploy the entire cluster. -- The Kubernetes pods will not be able to access the Internet or start - when firewalld is enabled on the node. This is a limitation in - Kubernetes. So, the firewalld daemon will be disabled on all the - nodes as part of omnia.yml execution. - Only one storage instance (Powervault) is currently supported in the HPC cluster. - Omnia supports only basic telemetry configurations. Changing data @@ -32,7 +15,4 @@ Limitations - Slurm cluster metrics will only be fetched from clusters configured by Omnia. - All iDRACs must have the same username and password. -- OpenSUSE Leap 15.3 is not supported on the Control Plane. -- Omnia might contain some unused MACs since LOM switch have both iDRAC MACs as well as ethernet MACs, PXE NIC ranges should contain IPs that are double the iDRACs present. -- FreeIPA authentication is not supported on the control plane. -- Currently, Omnia only supports the splitting of switch ports. Switch ports cannot be un-split using this script. +- Currently, Omnia only supports the splitting of switch ports. Switch ports cannot be un-split using the `switch configuration script `_. diff --git a/docs/source/samplefiles.rst b/docs/source/samplefiles.rst index 8bf2be3d9..4f5a05461 100644 --- a/docs/source/samplefiles.rst +++ b/docs/source/samplefiles.rst @@ -12,60 +12,49 @@ inventory file [slurm_control_node] - # node1 - - [slurmdbd] - - #node2 + 10.5.1.101 [slurm_node] - #node3 + 10.5.1.103 - #node4 + 10.5.1.104 [login] - #node5 + 10.5.1.105 #General Cluster Storage - #NFS node - - [nfs] - - #node10 - - - [auth_server] - #node12 + 10.5.1.106 #AI Scheduler: Kubernetes [kube_control_plane] - # node1 + 10.5.1.101 [etcd] - # node1 + 10.5.1.101 [kube_node] - # node2 + 10.5.1.102 - # node3 + 10.5.1.103 - # node4 + 10.5.1.104 - # node5 + 10.5.1.105 - # node6 + 10.5.1.106 +.. note:: The auth_server is common to both slurm and kubernetes clusters. pxe_mapping_file.csv @@ -74,8 +63,8 @@ pxe_mapping_file.csv :: SERVICE_TAG,HOSTNAME,ADMIN_MAC,ADMIN_IP,BMC_IP - 6XCVT4,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 - V345H5,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 + XXXXXXX,n1,xx:yy:zz:aa:bb:cc,10.5.0.101,10.3.0.101 + XXXXXXX,n2,aa:bb:cc:dd:ee:ff,10.5.0.102,10.3.0.102 switch_inventory From b279c12745fa49dd49d114a2499e4d2d7d516333 Mon Sep 17 00:00:00 2001 From: goveac Date: Thu, 28 Mar 2024 11:02:47 +0530 Subject: [PATCH 288/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Utils/OSPackageUpdate.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Utils/OSPackageUpdate.rst b/docs/source/Roles/Utils/OSPackageUpdate.rst index efc904b18..5456c0ada 100644 --- a/docs/source/Roles/Utils/OSPackageUpdate.rst +++ b/docs/source/Roles/Utils/OSPackageUpdate.rst @@ -5,7 +5,7 @@ To install multiple packages on target nodes in a bulk operation, the ``package_ **Prerequisites** - * All target nodes should be running RHEL or Rocky (Versions 8.4, 8.5 or 8.6). + * All target nodes should be running RHEL or Rocky. * Download the packages (RPMs) for the target nodes and place them in this folder: ``/install/post/otherpkgs//x86_64/custom_software/Packages``. .. note:: Do not use ISO files for updates or package installations. From 8474fc35ef652c7175fb65533f005d23ba8cfdd3 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:08:46 +0530 Subject: [PATCH 289/309] Updating documentation Signed-off-by: goveac --- .../BuildingClusters/Authentication.rst | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index c8b3751c9..642995c0b 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -186,3 +186,37 @@ The inventory should contain auth_server as per the inventory file in `samplefil .. caution:: No users will be created by Omnia. + +Setting up Passwordless SSH +---------------------------- + +Once user accounts are created, admins can enable passwordless SSH for users to run HPC jobs on the cluster nodes. + +.. note:: Once user accounts are created on the auth server, use the accounts to login to the cluster nodes to reset the password and create a corresponding home directory. + +To customize your setup of passwordless ssh, input parameters in ``input/passwordless_ssh_config.yml``. + ++-----------------------+--------------------------------------------------------------------------------------------------------------------+ +| Parameter | Details | ++=======================+====================================================================================================================+ +| user_name | The list of users that requires passwordless SSH. Separate the list of users using a comma. | +| ``string`` | Eg: ``user1,user2,user3`` | +| Required | | ++-----------------------+--------------------------------------------------------------------------------------------------------------------+ +| authentication_type | Indicates whether LDAP or FreeIPA is in use on the cluster. | +| ``string`` | | +| Required | Choices: | +| | | +| | * ``freeipa`` <- Default | +| | | +| | * ``ldap`` | ++-----------------------+--------------------------------------------------------------------------------------------------------------------+ + + +Use the below command to enable passwordless SSH: :: + + ansible-playbook user_passwordless_ssh.yml -i inventory + +Where inventory follows the format defined under inventory file in the provided `Sample Files. <../../samplefiles.html>`_ The inventory file is case-sensitive. Follow the casing provided in the sample file link. + +.. caution:: Do not run ssh-keygen commands after passwordless SSH is set up on the nodes. \ No newline at end of file From 711cc367e1a4d7f5a9881fd309783c70b2bca8d4 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:33:24 +0530 Subject: [PATCH 290/309] Updating documentation Signed-off-by: goveac --- .../InstallationGuides/BuildingClusters/Authentication.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst index 642995c0b..b9b3b7c80 100644 --- a/docs/source/InstallationGuides/BuildingClusters/Authentication.rst +++ b/docs/source/InstallationGuides/BuildingClusters/Authentication.rst @@ -199,7 +199,7 @@ To customize your setup of passwordless ssh, input parameters in ``input/passwor +-----------------------+--------------------------------------------------------------------------------------------------------------------+ | Parameter | Details | +=======================+====================================================================================================================+ -| user_name | The list of users that requires passwordless SSH. Separate the list of users using a comma. | +| user_name | The list of users that requires password-less SSH. Separate the list of users using a comma. | | ``string`` | Eg: ``user1,user2,user3`` | | Required | | +-----------------------+--------------------------------------------------------------------------------------------------------------------+ @@ -207,9 +207,9 @@ To customize your setup of passwordless ssh, input parameters in ``input/passwor | ``string`` | | | Required | Choices: | | | | -| | * ``freeipa`` <- Default | +| | * ``freeipa`` | | | | -| | * ``ldap`` | +| | * ``ldap`` <- Default | +-----------------------+--------------------------------------------------------------------------------------------------------------------+ From 97d7b916c8287bd69a4a3ac577657682fbdef1bc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:41:03 +0530 Subject: [PATCH 291/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/deletenode.rst | 2 +- docs/source/limitations.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst index 5318e5c23..dd784f034 100644 --- a/docs/source/InstallationGuides/deletenode.rst +++ b/docs/source/InstallationGuides/deletenode.rst @@ -98,7 +98,7 @@ Run the playbook using the following commands: :: To skip confirmation while running the playbook, use ``ansible-playbook delete_node.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. -The inventory file passed for ``delete_node.yml`` should follow one of the below formats: :: +The inventory file passed for ``delete_node.yml`` should follow one of the below formats. Passed inventory files should exclusively contain either service tags or admin IPs. Do not provide a mix of both in a single inventory file.: :: [nodes] {ip address} diff --git a/docs/source/limitations.rst b/docs/source/limitations.rst index 4046bfc05..1cb9d0b20 100644 --- a/docs/source/limitations.rst +++ b/docs/source/limitations.rst @@ -16,3 +16,4 @@ Limitations by Omnia. - All iDRACs must have the same username and password. - Currently, Omnia only supports the splitting of switch ports. Switch ports cannot be un-split using the `switch configuration script `_. +- The IP subnet 10.4.0.0 cannot be used for any networks on the Omnia cluster as it is reserved for Nerdctl. \ No newline at end of file From 829f9b4a01129dfa808e65c83e36d0ae7c45fdb1 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:49:00 +0530 Subject: [PATCH 292/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/deletenode.rst | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/docs/source/InstallationGuides/deletenode.rst b/docs/source/InstallationGuides/deletenode.rst index dd784f034..64972031e 100644 --- a/docs/source/InstallationGuides/deletenode.rst +++ b/docs/source/InstallationGuides/deletenode.rst @@ -7,7 +7,7 @@ Use this playbook to remove slurm and kubernetes configuration from slurm or kub **Configurations performed by the playbook** - * The node is removed from the Slurm and Kubernetes cluster. + * Nodes specified in the slurm_node group or kube_node group in the inventory file will be removed from the slurm and kubernetes cluster respectively. * Slurm and Kubernetes services are stopped and uninstalled. OS startup service list will be updated to disable Slurm and Kubernetes. **To run the playbook** @@ -17,12 +17,11 @@ Run the playbook using the following commands: :: cd utils ansible-playbook remove_node_configuration.yml -i inventory -To specify only Slurm or Kubernetes nodes while running the playbook, use the tags ``slurm_node`` or ``kube_node``. That is: - -To remove only slurm nodes, use ``ansible-playbook remove_node_configuration.yml -i inventory --tags slurm_node``. -To remove only kubernetes nodes, use ``ansible-playbook remove_node_configuration.yml -i inventory --tags kube_node``. - -To skip confirmation while running the playbook, use ``ansible-playbook remove_node_configuration.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. +* To specify only Slurm or Kubernetes nodes while running the playbook, use the tags ``slurm_node`` or ``kube_node``. That is: +* To remove only slurm nodes, use ``ansible-playbook remove_node_configuration.yml -i inventory --tags slurm_node``. +* To remove only kubernetes nodes, use ``ansible-playbook remove_node_configuration.yml -i inventory --tags kube_node``. +* Passed inventory files should exclusively contain either service tags or admin IPs. Do not provide a mix of both in a single inventory file. +* To skip confirmation while running the playbook, use ``ansible-playbook remove_node_configuration.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. @@ -51,7 +50,7 @@ To reset only kubernetes nodes, use ``ansible-playbook reset_cluster_configurati To skip confirmation while running the playbook, use ``ansible-playbook reset_cluster_configuration.yml -i inventory --extra-vars skip_confirmation=yes`` or ``ansible-playbook remove_node_configuration.yml -i inventory -e skip_confirmation=yes``. -The inventory file passed for ``reset_cluster_configuration`` should follow the below format: +The inventory file passed for ``reset_cluster_configuration`` should follow the below format. Passed inventory files should exclusively contain either service tags or admin IPs. Do not provide a mix of both in a single inventory file.: *For a slurm cluster* :: @@ -113,10 +112,9 @@ The inventory file passed for ``delete_node.yml`` should follow one of the below {service tag} -.. note:: When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. - - - +.. note:: + * When the node is added or deleted, the autogenerated inventories: ``amd_gpu``, ``nvidia_gpu``, ``amd_cpu``, and ``intel_cpu`` should be updated for the latest changes. + * Nodes passed in the above inventory will be removed from the cluster. To reprovision the node, use the `add node script. ` From 3adb114bca7688314b7a20dd470532fdc4e20767 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:50:35 +0530 Subject: [PATCH 293/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/reprovisioningthecluster.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/InstallationGuides/reprovisioningthecluster.rst b/docs/source/InstallationGuides/reprovisioningthecluster.rst index 36d196fd2..5e4ce461a 100644 --- a/docs/source/InstallationGuides/reprovisioningthecluster.rst +++ b/docs/source/InstallationGuides/reprovisioningthecluster.rst @@ -29,6 +29,9 @@ If a re-deployment with no modifications are required :: [auth_server] 10.5.0.101 + [etcd] + 10.5.0.110 + *Updated kubernetes inventory with the new node information* @@ -47,6 +50,9 @@ If a re-deployment with no modifications are required :: [auth_server] 10.5.0.101 + [etcd] + 10.5.0.110 + *Existing Slurm inventory* :: From 58a66dc9ecc5a87da309cfe2db3aad58949870ac Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:52:13 +0530 Subject: [PATCH 294/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/addinganewnode.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/addinganewnode.rst b/docs/source/InstallationGuides/addinganewnode.rst index 67ce4a464..913c8885a 100644 --- a/docs/source/InstallationGuides/addinganewnode.rst +++ b/docs/source/InstallationGuides/addinganewnode.rst @@ -64,7 +64,7 @@ Verify that the node has been provisioned successfully by `checking the Omnia no [etcd] - # node1 + 10.5.0.110 @@ -86,7 +86,7 @@ Verify that the node has been provisioned successfully by `checking the Omnia no [etcd] - # node1 + 10.5.0.110 *Existing Slurm inventory* From cdf55396c598329276461f83ab121d972303e8bc Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 11:53:45 +0530 Subject: [PATCH 295/309] Updating documentation Signed-off-by: goveac --- docs/source/InstallationGuides/reprovisioningthecluster.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/InstallationGuides/reprovisioningthecluster.rst b/docs/source/InstallationGuides/reprovisioningthecluster.rst index 5e4ce461a..c6eb5a2f6 100644 --- a/docs/source/InstallationGuides/reprovisioningthecluster.rst +++ b/docs/source/InstallationGuides/reprovisioningthecluster.rst @@ -91,6 +91,7 @@ If a re-deployment with no modifications are required :: 10.5.0.101 + In the above examples, nodes 10.5.0.105 and 10.5.0.106 have been added to the cluster as compute nodes. .. note:: From a0217a17dd41d6ec3cc950aab4bb0af5c584ef1a Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 12:19:18 +0530 Subject: [PATCH 296/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/provisionparams.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst index b7e10f093..fac828ea7 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/provisionparams.rst @@ -44,8 +44,8 @@ Update the ``input/network_spec.yml`` file for all networks available for use by .. caution:: * Do not assign the subnet 10.4.0.0/24 to any interfaces in the network as nerdctl uses it by default. - * If a DNS server is available on the network, ensure that the ranges provided in the ``input/network_spec.yml`` file do not include the IP address of the DNS server. - * All provided network ranges and nic IP addresses should be distinct with no overlap. + * If a DNS server is available on the network, ensure that the ranges provided in the ``input/network_spec.yml`` file do not include the IP ranges of the DNS server. + * All provided network ranges and nic IP addresses should be distinct with no overlap in the ``input/network_spec.yml``. A sample is provided below: :: From 370033b4ef5c9bcb389d18cc32d39ae657bddad0 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 14:06:35 +0530 Subject: [PATCH 297/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 4 +++- docs/source/InstallationGuides/PostProvisionScript.rst | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index 55b6dcaeb..e23f81c39 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -64,7 +64,9 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, .. note:: * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. - * Nodes must be booted and the service tag must be in the DB for nodes to list in the Inventory file. + * For a node's service tag to list in an inventory file, two conditions must be met: + * Node status in DB is "booted". + * Node's service tag information is present in DB. * Nodes are not removed from the inventory files even if they are physically disconnected. Ensure to run the `delete node playbook <../deletenode.html#delete-provisioned-node>`_ to remove the node. * To regenerate an inventory file, use the playbook ``omnia/utils/inventory_tagging.yml``. diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index 9810b8756..28ce415fc 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -37,7 +37,9 @@ When ``discovery_provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_taggi .. note:: * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. - * Nodes must be booted and the service tag must be in the DB for nodes to list in the Inventory file. + * For a node's service tag to list in an inventory file, two conditions must be met: + * Node status in DB is "booted". + * Node's service tag information is present in DB. * To regenerate an inventory file, use the playbook ``utils/inventory_tagging.yml``. From 7b5518a9b751905cec80cb8ca959c8455bf0366e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 14:17:24 +0530 Subject: [PATCH 298/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 3 ++- docs/source/InstallationGuides/PostProvisionScript.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index e23f81c39..ca1fc4cc9 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -65,7 +65,8 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. * For a node's service tag to list in an inventory file, two conditions must be met: - * Node status in DB is "booted". + + * Node status must be "booted" in DB. * Node's service tag information is present in DB. * Nodes are not removed from the inventory files even if they are physically disconnected. Ensure to run the `delete node playbook <../deletenode.html#delete-provisioned-node>`_ to remove the node. * To regenerate an inventory file, use the playbook ``omnia/utils/inventory_tagging.yml``. diff --git a/docs/source/InstallationGuides/PostProvisionScript.rst b/docs/source/InstallationGuides/PostProvisionScript.rst index 28ce415fc..313d39bc3 100644 --- a/docs/source/InstallationGuides/PostProvisionScript.rst +++ b/docs/source/InstallationGuides/PostProvisionScript.rst @@ -38,7 +38,8 @@ When ``discovery_provision.yml``, ``prepare_cp.yml``, or ``utils/inventory_taggi * Service tags will only be written into the inventory files after the nodes are successfully PXE booted post provisioning. * For a node's service tag to list in an inventory file, two conditions must be met: - * Node status in DB is "booted". + + * Node status must be "booted" in DB. * Node's service tag information is present in DB. * To regenerate an inventory file, use the playbook ``utils/inventory_tagging.yml``. From 1dac6b8a992aec0e310bfa15b7cf601820c6c825 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 14:38:50 +0530 Subject: [PATCH 299/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/installprovisiontool.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst index ca1fc4cc9..662572363 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/installprovisiontool.rst @@ -53,7 +53,7 @@ To deploy the Omnia provision tool, ensure that ``input/provision_config.yml``, * Verifies and updates firewall settings. * Installs xCAT. * Configures Omnia databases basis ``input/network_spec.yml``. - * Creates an inventory of all nodes in the cluster at ``/opt/omnia/omnia_inventory/``. This inventory will list nodes based on the type of CPUs and GPUs they have. The inventory files are: + * Creates empty inventory files in the control plane at ``/opt/omnia/omnia_inventory/``. These inventory files will be filled with information of compute node service tag post provisioning based on type of CPUs and GPUs they have. The inventory files are: * ``compute_cpu_amd`` * ``compute_cpu_intel`` From 6c45326be2d1fe7768908a4c35d4ee3a8cd002a7 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 15:42:11 +0530 Subject: [PATCH 300/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index 960e35691..d65462780 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -10,6 +10,17 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. * Update the ``input/config///jupyter.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. +* Ensure that NFS has been deployed on the cluster using ``storage.yml`` followed by ``scheduler.yml`` or ``omnia.yml``. Verify that the required NFS storage provisioner is deployed using the below command: :: + + [root@node3 ~]# kubectl get pod -A + NAMESPACE NAME READY STATUS RESTARTS AGE + default nfs-omnia-nfs-subdir-external-provisioner-54785fccd-9mp8z 1/1 Running 1 (12m ago) 3h24m + +* Verify that the default storage class is set to nfs_client for dynamic persistent volume provisioning. :: + + [root@node3 ~]# kubectl get storageclass + NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE + nfs-client (default) cluster.local/nfs-omnia-nfs-subdir-external-provisioner Delete Immediate true 17h **Deploying Jupyterhub** @@ -66,7 +77,7 @@ The IP address is listed against ``proxy-public``. **Clearing Jupyterhub configuration** -Clear the existing configuration by running the below commands: :: +Clear the existing configuration by running the below command: :: kubectl delete ns jupyterhub - kubectl delete pv jupyterhub-pv + From 12c21e996cf9ae749e6e7f9706a74230a63140e2 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 15:56:40 +0530 Subject: [PATCH 301/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index d65462780..e1030d158 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -8,7 +8,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Ensure the kubernetes cluster is setup and working. * Ensure the inventory file includes a ``kube_node`` group listing all cluster nodes. * Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. -* Update the ``input/config///jupyter.json`` file with the correct jupyter helm chart version required. The default value is **3.2.0**. +* Ensure that a local Jupyterhub repository is created using `the local repository script. <../../LocalRepo/index.html>`_ * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. * Ensure that NFS has been deployed on the cluster using ``storage.yml`` followed by ``scheduler.yml`` or ``omnia.yml``. Verify that the required NFS storage provisioner is deployed using the below command: :: From 280ba44cba48c58c8c67949e2078c4b6362f4828 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 16:03:18 +0530 Subject: [PATCH 302/309] Updating documentation Signed-off-by: goveac --- docs/source/Roles/Platform/InstallJupyterhub.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/Roles/Platform/InstallJupyterhub.rst b/docs/source/Roles/Platform/InstallJupyterhub.rst index e1030d158..142984a20 100644 --- a/docs/source/Roles/Platform/InstallJupyterhub.rst +++ b/docs/source/Roles/Platform/InstallJupyterhub.rst @@ -8,7 +8,7 @@ Using Helm charts, Omnia can install Jupyterhub on Kubernetes clusters. Once Jup * Ensure the kubernetes cluster is setup and working. * Ensure the inventory file includes a ``kube_node`` group listing all cluster nodes. * Review the ``tools/jupyter_config.yml`` file to ensure that the deployment meets your requirements. If not, modify the file. -* Ensure that a local Jupyterhub repository is created using `the local repository script. <../../LocalRepo/index.html>`_ +* Ensure that a local Jupyterhub repository is created using `the local repository script. <../../InstallationGuides/LocalRepo/index.html>`_ * Omnia deploys the ``quay.io/jupyterhub/k8s-singleuser-sample:3.2.0`` image irrespective of whether the intended notebooks are CPU-only, NVidia GPU, or AMD GPU. To use a custom image, modify the ``omnia/tools/roles/jupyter_config.yml`` file. * Ensure that NFS has been deployed on the cluster using ``storage.yml`` followed by ``scheduler.yml`` or ``omnia.yml``. Verify that the required NFS storage provisioner is deployed using the below command: :: From 5981d1da5c0223f778fee6a8e09d689b0cae2679 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Thu, 28 Mar 2024 18:25:01 +0530 Subject: [PATCH 303/309] Updating documentation Signed-off-by: goveac --- docs/source/Overview/architecture.rst | 5 ----- 1 file changed, 5 deletions(-) diff --git a/docs/source/Overview/architecture.rst b/docs/source/Overview/architecture.rst index ccff83af3..b0a55ac78 100644 --- a/docs/source/Overview/architecture.rst +++ b/docs/source/Overview/architecture.rst @@ -6,11 +6,6 @@ Architecture Omnia stack ----------- -**Kubernetes** - .. image:: ../images/omnia-k8s.png - -**Slurm** - .. image:: ../images/omnia-slurm.png From 248df002b3624f562a5d54fbf2f300d4e7848b70 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 1 Apr 2024 14:15:39 +0530 Subject: [PATCH 304/309] Updating documentation Signed-off-by: goveac --- docs/source/Overview/newfeatures.rst | 71 +++++++++------------------ docs/source/Overview/releasenotes.rst | 23 ++++++++- 2 files changed, 44 insertions(+), 50 deletions(-) diff --git a/docs/source/Overview/newfeatures.rst b/docs/source/Overview/newfeatures.rst index 5c52c0b14..aafbef930 100644 --- a/docs/source/Overview/newfeatures.rst +++ b/docs/source/Overview/newfeatures.rst @@ -1,52 +1,25 @@ New Features =========== -* `Extensive Telemetry and Monitoring <../Roles/Telemetry/index.html>`_ has been added to the Omnia stack, intended for consumption by customers that are using Dell systems and Omnia to provide SaaS/IaaS solutions. These include, but are not limited to: - - – CPU Utilization and status - - – GPU utilization - - – Node Count - - – Network Packet I/O - - – HDD capacity and free space - - – Memory capacity and utilization - - – Queued and Running Job Count - - – User Count - - – Cluster HW Health Checks (PCIE, NVLINK, BMC, Temps) - - – Cluster SW Health Checks (dmesg, BeeGFS, k8s nodes/pods, mySQL on control plane) - -* Metrics are extracted using a combination of the following: PSUtil, Smartctl, beegfs-ctl, nvidia-smi, rocm-smi. - -* Telemetry and health checks can be optionally disabled. - -* `Log Aggregation <../Logging/ControlPlaneLogs.html>`_ via xCAT syslog: - - – Aggregated on control plane, grouping default is “severity” with others available. - - – Uses Grafani-Loki for viewing. - -* Hardware Support: Intel E810 NIC, ConnectX-5/6 NICs. - - * Omnia github now hosts a “genesis” image with this functionality baked in for initial bootup. - -* Host aliasing for Scheduler and IPA authentication. - -* Login and kube_control_plane access from both public and private NIC. - -* Validation check enhancements: - - * Rearranged to occur as early as possible. - - * Isolate checks when running smaller playbooks. - -* Docker Registry Creation. - -* Integration of apptainer for `containerized HPC benchmark execution <../InstallationGuides/Benchmarks/index.html>`_. +* WACO support with Ubuntu 22.04 OS: + * Local repository and registry creation for packages and container images. + * Cluster provision with Ubuntu 22.04 OS. + * AMD GPU driver and ROCm installation. + * Broadcom RoCE driver installation. + * IP configuration on the additional NICs: IPv4 support + * Kubernetes installation. + * NFS client/server configuration. + * OpenLDAP support with documented support for replication. + * AI Software Stack support including the installation of the following tools: + * Jupyter notebook + * Kubeflow + * Kserve + * Pytorch + * Tensorflow + * vLLM (MI210x support) + +* Additional Features + * RHEL 8.8 support + * OFED Installation + * CUDA Driver installation + * Add/remove nodes to the cluster. diff --git a/docs/source/Overview/releasenotes.rst b/docs/source/Overview/releasenotes.rst index 1a7f6c6fc..330734821 100644 --- a/docs/source/Overview/releasenotes.rst +++ b/docs/source/Overview/releasenotes.rst @@ -4,7 +4,28 @@ Releases 1.6 ---- -TBD +* WACO support with Ubuntu 22.04 OS: + * `Local repository and registry creation for packages and container images. <../InstallationGuides/LocalRepo/index.html>`_ + * `Cluster provision with Ubuntu 22.04 OS. <../InstallationGuides/InstallingProvisionTool/index.html>`_ + * `AMD GPU driver and ROCm installation. <../Roles/Accelerator/index.html>`_ + * `Broadcom RoCE driver installation. <../InstallationGuides/LocalRepo/index.html>`_ + * `IP configuration on the additional NICs: IPv4 support <../InstallationGuides/InstallingProvisionTool/AdditionalNIC.html>`_ + * `Kubernetes installation. <../InstallationGuides/BuildingClusters/index.html>`_ + * `NFS client/server configuration. <../InstallationGuides/BuildingClusters/NFS.html>`_ + * `OpenLDAP support with documented support for replication. <../Roles/Security/index.html>`_ + * AI Software Stack support including the installation of the following tools: + * `Jupyter notebook <../Roles/Platform/InstallJupyterhub.html>`_ + * `Kubeflow <../Roles/Platform/kubeflow.html>`_ + * `Kserve <../Roles/Platform/kserve.html>`_ + * `Pytorch <../Roles/Platform/Pytorch.html>`_ + * `Tensorflow <../Roles/Platform/Tensorflow.html>`_ + * `vLLM (MI210x support) <../Roles/Platform/SetupvLLM.html>`_ + +* Additional Features + * `RHEL 8.8 support `_ + * `OFED Installation <../InstallationGuides/LocalRepo/index.html>`_ + * `CUDA Driver installation <../Roles/Accelerator/index.html>`_ + * `Add <../InstallationGuides/addinganewnode.html>`_ / `remove <../InstallationGuides/deletenode.html>`_ nodes to the cluster. 1.5 ---- From b661100061026c2a40a3d5759fa965fc77abde00 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 1 Apr 2024 14:21:56 +0530 Subject: [PATCH 305/309] Updating documentation Signed-off-by: goveac --- docs/source/Overview/releasenotes.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/source/Overview/releasenotes.rst b/docs/source/Overview/releasenotes.rst index 330734821..82eafb7a2 100644 --- a/docs/source/Overview/releasenotes.rst +++ b/docs/source/Overview/releasenotes.rst @@ -14,11 +14,17 @@ Releases * `NFS client/server configuration. <../InstallationGuides/BuildingClusters/NFS.html>`_ * `OpenLDAP support with documented support for replication. <../Roles/Security/index.html>`_ * AI Software Stack support including the installation of the following tools: + * `Jupyter notebook <../Roles/Platform/InstallJupyterhub.html>`_ + * `Kubeflow <../Roles/Platform/kubeflow.html>`_ + * `Kserve <../Roles/Platform/kserve.html>`_ + * `Pytorch <../Roles/Platform/Pytorch.html>`_ - * `Tensorflow <../Roles/Platform/Tensorflow.html>`_ + + * `Tensorflow <../Roles/Platform/TensorFlow.html>`_ + * `vLLM (MI210x support) <../Roles/Platform/SetupvLLM.html>`_ * Additional Features From 41c817304112aec62c3e3afc1a57f3211d6d4f73 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 1 Apr 2024 17:13:16 +0530 Subject: [PATCH 306/309] Updating documentation Signed-off-by: goveac --- .../LocalRepo/RunningLocalRepo.rst | 45 +++++++++++++++++++ docs/source/Tables/local_repo_config.csv | 4 +- 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst new file mode 100644 index 000000000..b016293a4 --- /dev/null +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -0,0 +1,45 @@ +Running local repo +------------------ + +The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. + +**Configurations made by the playbook** +* A registry is created on the control plane at :5001. +* If ``repo_config`` in ``local_repo_config.yml`` is set to ``always`` or ``partial``, all images present in the ``input/config//`` folder will be downloaded to the control plane. + + * If the image is defined using a tag, the image will be tagged using :5001/: and pushed to the Omnia local registry. + * If the image is defined using a digest, the image will be tagged using :5001/:omnia and pushed to the Omnia local registry.repositories + +* When ``repo_config`` in ``local_repo_config.yml`` is set to ``always``, the control plane is set as the default registry mirror. +* When ``repo_config`` in ``local_repo_config`` is set to ``partial``, the ``user_registry`` (if defined) and the control plane are set as default registry mirrors. + +To create local repositories, run the following commands: :: + + cd local_repo + ansible-playbook local_repo.yml + +Verify changes made by the playbook by running ``cat /etc/containerd/certs.d/_default/hosts.toml`` on compute nodes. + +To fetch images from the ``user_registry`` or the Omnia local registry, run the below commands: + + * Images defined with versions: ``nerdctl pull /:`` + * Images defined with digests: ``nerdctl pull /:omnia`` + +.. note:: + + * After ``local_repo.yml`` has run, the value of ``repo_config`` in ``input/software_config.json`` cannot be updated without running the `control_plane_cleanup.yml <../CleanUpScript.html>`_ script first. + * For images coming from ``gcr.io``, digests are defined as tags are not available. Omnia gives a custom tag of ‘omnia’ to these images. If such images need to be taken from the ``user_registry``, use one of the below steps: + * Append 'omnia' to the end of the image name while pushing images to the ``user_registry``. Update the image definition in ``input/config///.json`` to follow the same nomenclature. + * If a different tag is provided, update the digest value in ``input/config///.json`` as per the image digest in the ``user_directory``. To get the updated digest from the ``user_registry``, use the below steps: + * Check the tag of image: ``curl -k https:///v2//tags/list`` + * Check the digest of the tag: ``curl -H -k https:///v2//manifests/omnia`` + +**Update local repositories** + +This playbook updates all local repositories configured on a provisioned cluster after local repositories have been configured. + +To run the playbook: :: + + cd utils + ansible-playbook update_user_repo.yml -i inventory + diff --git a/docs/source/Tables/local_repo_config.csv b/docs/source/Tables/local_repo_config.csv index 904575d6b..5a4870691 100644 --- a/docs/source/Tables/local_repo_config.csv +++ b/docs/source/Tables/local_repo_config.csv @@ -33,9 +33,9 @@ Optional","* This variable accepts the repository urls of the user which contain Optional","* This variable accepts the registry url along with port of the user which contains the images required for cluster. -* When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. +* When ``repo_config`` is always, the list given in ``user_registry`` will be configured on the control plane and packages required for cluster will be downloaded into a local repository. If the same repository is available in both the ``user_repo_url`` and the ``user_registry``, the repository will be configured using the values in ``user_registry``. -* When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. +* When ``repo_config`` is partial, a local registry is created on the control plane containing packages that are not part of the ``user_registry``. Images listed in ``user_registry`` are directly configured as a mirror on compute nodes. Compute nodes are expected to connect to the URLs in the ``user_registry`` via http_proxy. * When ``repo_config`` is never, no local registry is created and packages/images are downloaded on all cluster nodes. From 04a03b7abf1e17b53a902f7084a5a008a8571ba6 Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 1 Apr 2024 17:30:52 +0530 Subject: [PATCH 307/309] Updating documentation Signed-off-by: goveac --- .../InstallingProvisionTool/AdditionalNIC.rst | 6 ++++-- .../LocalRepo/RunningLocalRepo.rst | 13 +++++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst index c21fc8302..55f8cb05e 100644 --- a/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst +++ b/docs/source/InstallationGuides/InstallingProvisionTool/AdditionalNIC.rst @@ -14,10 +14,12 @@ After running ``discovery_provision.yml`` or ``discovery_provision.yml`` and the * ``dynamic_range``: The dynamic range of IPs to be provisioned on target nodes. * ``correlation_to_admin``: Boolean value used to indicate whether all other networks specified in the file (eg: ``bmc_network``) should be correlated to the admin network. For eg: if a target node is assigned the IP xx.yy.0.5 on the admin network, it will be assigned the IP aa.bb.0.5 on the BMC network. This value is irrelevant when discovering nodes using a mapping file. * ``admin_uncorrelated_node_start_ip``: If ``correlation_to_admin`` is set to true but correlated IPs are not available on non-admin networks, provide an IP within the ``static_range`` of the admin network that can be used to assign admin static IPs to uncorrelated nodes. If this is empty, then the first IP in the ``static_range`` of the admin network is taken by default. This value is irrelevant when discovering nodes using a mapping file. + * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. This property is not supported on clusters running Ubuntu. + + *The below properties are only applicable to additional NICs* * ``CIDR``: Classless or Classless Inter-Domain Routing (CIDR) addresses use variable length subnet masking (VLSM) to alter the ratio between the network and host address bits in an IP address. * ``MTU``: Maximum transmission unit (MTU) is a measurement in bytes of the largest data packets that an Internet-connected device can accept. * ``DNS``: A DNS server is a computer equipped with a database that stores the public IP addresses linked to the domain names of websites, enabling users to reach websites using their IP addresses. - * ``VLAN``: A 12-bit field that identifies a virtual LAN (VLAN) and specifies the VLAN that an Ethernet frame belongs to. .. note:: @@ -77,7 +79,7 @@ Use the below commands to assign IPs to the NICs: :: cd nic_update ansible-playbook nic_update -i inventory -Where the inventory file passed includes user-defined groups,servers associated with them, and a mapping from the groups specified and the categories in ``input/server_spec.yml``. Below is a sample: :: +Where the inventory file passed includes user-defined groups,servers associated with them, and a mapping from the groups specified and the categories in ``input/server_spec.yml`` under [:vars]. Below is a sample: :: [waco1] 10.5.0.3 diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index b016293a4..8404a609d 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -4,13 +4,19 @@ Running local repo The local repository feature will help create offline repositories on the control plane which all the cluster nodes will access. **Configurations made by the playbook** + * A registry is created on the control plane at :5001. + * If ``repo_config`` in ``local_repo_config.yml`` is set to ``always`` or ``partial``, all images present in the ``input/config//`` folder will be downloaded to the control plane. + * If the image is defined using a tag, the image will be tagged using :5001/: and pushed to the Omnia local registry. + * If the image is defined using a digest, the image will be tagged using :5001/:omnia and pushed to the Omnia local registry.repositories + * When ``repo_config`` in ``local_repo_config.yml`` is set to ``always``, the control plane is set as the default registry mirror. + * When ``repo_config`` in ``local_repo_config`` is set to ``partial``, the ``user_registry`` (if defined) and the control plane are set as default registry mirrors. To create local repositories, run the following commands: :: @@ -27,13 +33,20 @@ To fetch images from the ``user_registry`` or the Omnia local registry, run the .. note:: + * After ``local_repo.yml`` has run, the value of ``repo_config`` in ``input/software_config.json`` cannot be updated without running the `control_plane_cleanup.yml <../CleanUpScript.html>`_ script first. + * For images coming from ``gcr.io``, digests are defined as tags are not available. Omnia gives a custom tag of ‘omnia’ to these images. If such images need to be taken from the ``user_registry``, use one of the below steps: + * Append 'omnia' to the end of the image name while pushing images to the ``user_registry``. Update the image definition in ``input/config///.json`` to follow the same nomenclature. + * If a different tag is provided, update the digest value in ``input/config///.json`` as per the image digest in the ``user_directory``. To get the updated digest from the ``user_registry``, use the below steps: + * Check the tag of image: ``curl -k https:///v2//tags/list`` + * Check the digest of the tag: ``curl -H -k https:///v2//manifests/omnia`` + **Update local repositories** This playbook updates all local repositories configured on a provisioned cluster after local repositories have been configured. From 43a56cea8da7cbda60be0ef1eef4746d7ad368fe Mon Sep 17 00:00:00 2001 From: cgoveas Date: Mon, 1 Apr 2024 17:35:44 +0530 Subject: [PATCH 308/309] Updating documentation Signed-off-by: goveac --- .../LocalRepo/RunningLocalRepo.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst index 8404a609d..4e98c0f8e 100644 --- a/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst +++ b/docs/source/InstallationGuides/LocalRepo/RunningLocalRepo.rst @@ -5,19 +5,19 @@ The local repository feature will help create offline repositories on the contro **Configurations made by the playbook** -* A registry is created on the control plane at :5001. + * A registry is created on the control plane at :5001. -* If ``repo_config`` in ``local_repo_config.yml`` is set to ``always`` or ``partial``, all images present in the ``input/config//`` folder will be downloaded to the control plane. + * If ``repo_config`` in ``local_repo_config.yml`` is set to ``always`` or ``partial``, all images present in the ``input/config//`` folder will be downloaded to the control plane. - * If the image is defined using a tag, the image will be tagged using :5001/: and pushed to the Omnia local registry. + * If the image is defined using a tag, the image will be tagged using :5001/: and pushed to the Omnia local registry. - * If the image is defined using a digest, the image will be tagged using :5001/:omnia and pushed to the Omnia local registry.repositories + * If the image is defined using a digest, the image will be tagged using :5001/:omnia and pushed to the Omnia local registry.repositories -* When ``repo_config`` in ``local_repo_config.yml`` is set to ``always``, the control plane is set as the default registry mirror. + * When ``repo_config`` in ``local_repo_config.yml`` is set to ``always``, the control plane is set as the default registry mirror. -* When ``repo_config`` in ``local_repo_config`` is set to ``partial``, the ``user_registry`` (if defined) and the control plane are set as default registry mirrors. + * When ``repo_config`` in ``local_repo_config`` is set to ``partial``, the ``user_registry`` (if defined) and the control plane are set as default registry mirrors. To create local repositories, run the following commands: :: From df44068c54b9dd997f60c8cc73dd2f34eec0508e Mon Sep 17 00:00:00 2001 From: cgoveas Date: Tue, 2 Apr 2024 10:23:00 +0530 Subject: [PATCH 309/309] Updating documentation Signed-off-by: goveac --- docs/source/Troubleshooting/troubleshootingguide.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/source/Troubleshooting/troubleshootingguide.rst b/docs/source/Troubleshooting/troubleshootingguide.rst index c8255a3a1..e752f1fc3 100644 --- a/docs/source/Troubleshooting/troubleshootingguide.rst +++ b/docs/source/Troubleshooting/troubleshootingguide.rst @@ -1,6 +1,11 @@ Troubleshooting guide ============================ +Troubleshooting Kubeadm +------------------------ + +For a complete guide to troubleshooting kubeadm, `click here. `_ + Connecting to internal databases ------------------------------------ * TimescaleDB