├── ansible ├── compute.yaml ├── roles │ ├── http │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── httpd.conf.j2 │ ├── dhcp │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── dhcpd.conf.j2 │ ├── proxy │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── haproxy.conf.j2 │ ├── dns │ │ ├── templates │ │ │ ├── zones.j2 │ │ │ ├── reverse.dns.j2 │ │ │ ├── forward.dns.j2 │ │ │ └── named.conf.j2 │ │ ├── handlers │ │ │ └── main.yml │ │ └── tasks │ │ │ └── main.yml │ ├── pxe │ │ ├── handlers │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── pxe.config.j2 │ │ │ ├── default.j2 │ │ │ ├── ks.j2 │ │ │ └── menu.j2 │ │ └── tasks │ │ │ └── main.yml │ ├── rhel_compute │ │ ├── .travis.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── README.md │ ├── ignition │ │ ├── templates │ │ │ └── install-config.j2 │ │ └── tasks │ │ │ └── main.yml │ └── bootstrap │ │ ├── tasks │ │ └── main.yml │ │ └── README.md ├── inventory │ ├── rh_rhel_worker │ └── rhel_inv_file ├── ocp.yaml ├── README.md └── generated_inventory ├── examples ├── multipath.conf ├── FC6510 ├── S3048 ├── S5232F-2 └── S5232F-1 ├── sample_yaml ├── storage │ ├── unity │ │ ├── emptysecret.yaml │ │ ├── pod.yaml │ │ ├── snapshot.yaml │ │ ├── dyfcpvc.yaml │ │ ├── dynfspvc.yaml │ │ ├── dyiscsipvc.yaml │ │ ├── newiscsipvc.yaml │ │ ├── secret.json │ │ ├── regpvc.yaml │ │ ├── restore.yaml │ │ ├── dyfcpod.yaml │ │ ├── dynfspod.yaml │ │ ├── dyiscsipod.yaml │ │ ├── restorepod.yaml │ │ ├── newiscsipod.yaml │ │ └── unity_v140_ops_46.yaml │ ├── isilon │ │ ├── isilon-secret.yaml │ │ ├── snapshot.yaml │ │ ├── dynfspvc.yaml │ │ ├── dynfsreg.yaml │ │ ├── restore.yaml │ │ ├── restorepod.yaml │ │ ├── dynfspod.yaml │ │ └── isilon_v140_ops_46.yaml │ ├── powermax │ │ ├── secret.yaml │ │ ├── snapshot.yaml │ │ ├── dyfcpvc.yaml │ │ ├── dyiscsipvc.yaml │ │ ├── restore.yaml │ │ ├── restorepod.yaml │ │ ├── dyfcpod.yaml │ │ ├── dyiscsipod.yaml │ │ ├── powermax_v150_fc_ops_46.yaml │ │ └── powermax_v150_iscsi_ops_46.yaml │ ├── ocs │ │ ├── ocsfs.yaml │ │ ├── ocsrbd.yaml │ │ ├── ocsfspod.yaml │ │ └── ocsrbdpod.yaml │ └── multipathd │ │ └── multipathmc.yaml ├── velero │ ├── pvc.yaml │ └── pod.yaml └── sriov │ ├── compute-1.sriov.pod.yaml │ ├── compute-1.sriov.network.yaml │ └── compute-1.network.node.policy.yaml ├── python ├── nodes.yaml ├── log_config.py ├── nodes.py ├── helper.py └── generate_inventory_file.py ├── README.md └── LICENSE /ansible/compute.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: workers 3 | become: yes 4 | roles: 5 | - rhel_compute 6 | -------------------------------------------------------------------------------- /examples/multipath.conf: -------------------------------------------------------------------------------- 1 | defaults { 2 | find_multipaths yes 3 | user_friendly_names yes 4 | } 5 | 6 | 7 | blacklist { 8 | } 9 | -------------------------------------------------------------------------------- /ansible/roles/http/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for http 3 | - name: restart http service 4 | systemd: name=httpd state=restarted 5 | listen: "restart httpd" 6 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/emptysecret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: unity-certs-0 5 | namespace: unity 6 | type: Opaque 7 | data: 8 | cert-0: "" 9 | -------------------------------------------------------------------------------- /ansible/inventory/rh_rhel_worker: -------------------------------------------------------------------------------- 1 | [all:vars] 2 | ansible_user=ansible 3 | ansible_become=True 4 | openshift_kubeconfig_path="/home/ansible/kubeconfig" 5 | [new_workers] 6 | compute-3.example.com 7 | -------------------------------------------------------------------------------- /ansible/ocp.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | - hosts: csah 3 | become: yes 4 | roles: 5 | - http 6 | - dhcp 7 | - dns 8 | - proxy 9 | - ignition 10 | - pxe 11 | - bootstrap 12 | -------------------------------------------------------------------------------- /ansible/roles/dhcp/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for dhcp 3 | - name: restart dhcp service 4 | systemd: 5 | name: dhcpd 6 | state: restarted 7 | listen: "restart dhcp" 8 | -------------------------------------------------------------------------------- /ansible/roles/proxy/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for proxy 3 | - name: restart HAPROXY 4 | systemd: 5 | name: haproxy 6 | state: restarted 7 | listen: "haproxy restart" 8 | -------------------------------------------------------------------------------- /ansible/inventory/rhel_inv_file: -------------------------------------------------------------------------------- 1 | workers: 2 | hosts: compute-3.example.com 3 | vars: 4 | subscription_user: smuser 5 | subscription_pass: smpassword 6 | pool_id: *********************** 7 | -------------------------------------------------------------------------------- /ansible/README.md: -------------------------------------------------------------------------------- 1 | ## Execute Playbook by following steps as below 2 | 3 | - Refer to Chapter 3 in [Dell EMC Ready Stack for Red Hat OpenShift Container Platform 4.6](https://infohub.delltechnologies.com/t/guides-45) 4 | -------------------------------------------------------------------------------- /ansible/roles/dns/templates/zones.j2: -------------------------------------------------------------------------------- 1 | zone "{{ ansible_domain }}" IN { 2 | type master; 3 | file "{{ ansible_domain }}"; 4 | }; 5 | 6 | zone "{{ arpa_name }}" { 7 | type master; 8 | file "{{ arpa_name }}"; 9 | }; 10 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/isilon-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: isilon-creds 5 | namespace: isilon 6 | type: Opaque 7 | data: 8 | username: 9 | password: 10 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: powermax-creds 5 | namespace: powermax 6 | type: Opaque 7 | data: 8 | username: 9 | password: 10 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: image-registry-pod 5 | namespace: unity 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: image-registry.openshift-image-registry.svc:5000/openshift/nginxnfs 10 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/snapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1beta1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: powermax-snapshot 5 | spec: 6 | volumeSnapshotClassName: powermax-snapclass 7 | source: 8 | persistentVolumeClaimName: dynamic-fc-powermax-pvc 9 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/snapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1beta1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: unity-snapshot 5 | namespace: unity 6 | spec: 7 | volumeSnapshotClassName: unity-snap 8 | source: 9 | persistentVolumeClaimName: dynamic-iscsi-unity-pvc 10 | -------------------------------------------------------------------------------- /ansible/roles/dns/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for bind 3 | - name: restart bind service 4 | systemd: name=named state=restarted 5 | listen: "restart named" 6 | 7 | - name: reload NetworkManager 8 | systemd: name=NetworkManager state=restarted 9 | listen: "reload NetworkManager" 10 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/snapshot.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: snapshot.storage.k8s.io/v1beta1 2 | kind: VolumeSnapshot 3 | metadata: 4 | name: isilon-snapshot 5 | namespace: isilon 6 | spec: 7 | volumeSnapshotClassName: isilon-snap 8 | source: 9 | persistentVolumeClaimName: dynamic-nfs-isilon-pvc 10 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/dyfcpvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-fc-unity-pvc 5 | namespace: unity 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 6Gi 12 | storageClassName: unity-fc 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/dynfspvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-nfs-unity-pvc 5 | namespace: unity 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 4Gi 12 | storageClassName: unity-nfs 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/dynfspvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-nfs-isilon-pvc 5 | namespace: isilon 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 4Gi 12 | storageClassName: isilon-nfs 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/dyiscsipvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-iscsi-unity-pvc 5 | namespace: unity 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 7Gi 12 | storageClassName: unity-iscsi 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/newiscsipvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-new-iscsi-unity-pvc 5 | namespace: unity 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | storageClassName: unity-iscsi 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/dyfcpvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-fc-powermax-pvc 5 | namespace: powermax 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 6Gi 12 | storageClassName: powermax-bronze 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/secret.json: -------------------------------------------------------------------------------- 1 | { 2 | "storageArrayList": [ 3 | { 4 | "username": "admin", 5 | "password": "admin" 6 | "restGateway": "https://IP address", 7 | "arrayId": "xxxxxxxxxxxx", 8 | "insecure": true, 9 | "isDefaultArray": true 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/dyiscsipvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-iscsi-powermax-pvc 5 | namespace: powermax 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 6Gi 12 | storageClassName: powermax-iscsi 13 | -------------------------------------------------------------------------------- /ansible/roles/pxe/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers file for pxe 3 | - name: restart dhcp service 4 | systemd: 5 | name: dhcpd 6 | state: restarted 7 | listen: "restart dhcp" 8 | 9 | - name: restart xinetd service 10 | systemd: 11 | name: xinetd 12 | state: restarted 13 | listen: "restart xinetd" 14 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/regpvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: dynamic-nfs-image-registry 5 | namespace: openshift-image-registry 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 120Gi 12 | storageClassName: unity-nfs 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/dynfsreg.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: isilon-nfs-image-registry 5 | namespace: openshift-image-registry 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 130Gi 12 | storageClassName: isilon-nfs 13 | -------------------------------------------------------------------------------- /sample_yaml/storage/ocs/ocsfs.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: ocsfspvc 5 | namespace: ocs 6 | spec: 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 10Gi 12 | storageClassName: ocs-storagecluster-cephfs 13 | volumeMode: Filesystem 14 | -------------------------------------------------------------------------------- /sample_yaml/storage/ocs/ocsrbd.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: ocsrbdpvc 5 | namespace: ocs 6 | spec: 7 | accessModes: 8 | - ReadWriteOnce 9 | resources: 10 | requests: 11 | storage: 10Gi 12 | storageClassName: ocs-storagecluster-ceph-rbd 13 | volumeMode: Filesystem 14 | -------------------------------------------------------------------------------- /ansible/roles/pxe/templates/pxe.config.j2: -------------------------------------------------------------------------------- 1 | class "pxeclients" { 2 | match if substring (option vendor-class-identifier, 0, 9) = "PXEClient"; 3 | next-server {{ ansible_default_ipv4.address }}; 4 | if option architecture-type = 00:07 { 5 | filename "uefi/shim.efi"; 6 | } 7 | else { 8 | filename "bios/pxelinux.0"; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /sample_yaml/velero/pvc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: velero-bkpone-pvc 5 | namespace: test-velero 6 | labels: 7 | velero: test-velero 8 | velero.io/csi-volumesnapshot-class: "true" 9 | spec: 10 | accessModes: 11 | - ReadWriteOnce 12 | resources: 13 | requests: 14 | storage: 2Gi 15 | storageClassName: unity-fc 16 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/restore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: isilon-restore 5 | spec: 6 | storageClassName: isilon-nfs 7 | dataSource: 8 | name: isilon-snapshot 9 | kind: VolumeSnapshot 10 | apiGroup: snapshot.storage.k8s.io 11 | accessModes: 12 | - ReadWriteMany 13 | resources: 14 | requests: 15 | storage: 4Gi 16 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/restore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: unity-restore 5 | spec: 6 | storageClassName: unity-iscsi 7 | dataSource: 8 | name: unity-snapshot 9 | kind: VolumeSnapshot 10 | apiGroup: snapshot.storage.k8s.io 11 | accessModes: 12 | - ReadWriteOnce 13 | resources: 14 | requests: 15 | storage: 7Gi 16 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/restore.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolumeClaim 3 | metadata: 4 | name: powermax-restore 5 | spec: 6 | storageClassName: powermax-bronze 7 | dataSource: 8 | name: powermax-snapshot 9 | kind: VolumeSnapshot 10 | apiGroup: snapshot.storage.k8s.io 11 | accessModes: 12 | - ReadWriteOnce 13 | resources: 14 | requests: 15 | storage: 6Gi 16 | -------------------------------------------------------------------------------- /sample_yaml/sriov/compute-1.sriov.pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: compute-1-pod 5 | namespace: sriov-network-operator 6 | annotations: 7 | k8s.v1.cni.cncf.io/networks: compute-1-vf0-sriov-network 8 | spec: 9 | nodeSelector: 10 | kubernetes.io/hostname: compute-1.example.com 11 | containers: 12 | - name: example-pod 13 | command: ["/bin/bash", "-c", "sleep 2000000000000"] 14 | image: centos/tools 15 | -------------------------------------------------------------------------------- /sample_yaml/sriov/compute-1.sriov.network.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: sriovnetwork.openshift.io/v1 2 | kind: SriovNetwork 3 | metadata: 4 | name: compute-1-vf0-sriov-network 5 | namespace: sriov-network-operator 6 | spec: 7 | resourceName: compute_1_net_devices 8 | networkNamespace: sriov-network-operator 9 | ipam: '{"type":"static","addresses": [{"address":"192.168.150.51/24", "gateway":"192.168.150.1"}],"routes": [{"dst":"192.168.50.0/24","gw":"192.168.150.1"}]}' 10 | capabilities: '{"mac": true, "ips": true}' 11 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/restorepod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: restore-pod 5 | namespace: isilon 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: restore-pvc 16 | volumes: 17 | - name: restore-pvc 18 | persistentVolumeClaim: 19 | claimName: isilon-restore 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/restorepod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: restore-pod 5 | namespace: powermax 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-fc-snapshot 16 | volumes: 17 | - name: dy-fc-snapshot 18 | persistentVolumeClaim: 19 | claimName: powermax-restore 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/dyfcpod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: dynamic-fc-unity-pod 5 | namespace: unity 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-fc-unity 16 | volumes: 17 | - name: dy-fc-unity 18 | persistentVolumeClaim: 19 | claimName: dynamic-fc-unity-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/dynfspod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: dynamic-nfs-unity-pod 5 | namespace: unity 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-nfs-unity 16 | volumes: 17 | - name: dy-nfs-unity 18 | persistentVolumeClaim: 19 | claimName: dynamic-nfs-unity-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/dynfspod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: dynamic-nfs-isilon-pod 5 | namespace: isilon 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-nfs-isilon 16 | volumes: 17 | - name: dy-nfs-isilon 18 | persistentVolumeClaim: 19 | claimName: dynamic-nfs-isilon-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/dyfcpod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: dynamic-fc-powermax-pod 5 | namespace: powermax 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-fc-powermax 16 | volumes: 17 | - name: dy-fc-powermax 18 | persistentVolumeClaim: 19 | claimName: dynamic-fc-powermax-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/dyiscsipod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: dynamic-iscsi-unity-pod 5 | namespace: unity 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-iscsi-unity 16 | volumes: 17 | - name: dy-iscsi-unity 18 | persistentVolumeClaim: 19 | claimName: dynamic-iscsi-unity-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/sriov/compute-1.network.node.policy.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: sriovnetwork.openshift.io/v1 2 | kind: SriovNetworkNodePolicy 3 | metadata: 4 | name: compute-1-network-node-policy 5 | namespace: sriov-network-operator 6 | spec: 7 | resourceName: compute_1_net_devices 8 | nodeSelector: 9 | kubernetes.io/hostname: compute-1.example.com 10 | priority: 10 11 | mtu: 1500 12 | numVfs: 5 13 | nicSelector: 14 | pfNames: ["eno1","eno2"] 15 | rootDevices: ["0000:1a:00.1","0000:1a:00.2"] 16 | deviceType: netdevice 17 | isRdma: false 18 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/dyiscsipod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: dynamic-iscsi-powermax-pod 5 | namespace: powermax 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: nginx:latest 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dy-iscsi-powermax 16 | volumes: 17 | - name: dy-iscsi-powermax 18 | persistentVolumeClaim: 19 | claimName: dynamic-iscsi-powermax-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/velero/pod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: velero-bkpone-pod 5 | namespace: test-velero 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: image-registry.openshift-image-registry.svc:5000/openshift/nginxnfs 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: velero 16 | volumes: 17 | - name: velero 18 | persistentVolumeClaim: 19 | claimName: velero-bkpone-pvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/ocs/ocsfspod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: ocsfspod 5 | namespace: ocs 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: image-registry.openshift-image-registry.svc:5000/openshift/nginxnfs 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dynamic-ocs-fs-vol 16 | volumes: 17 | - name: dynamic-ocs-fs-vol 18 | persistentVolumeClaim: 19 | claimName: ocsfspvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/ocs/ocsrbdpod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: ocsrbdpod 5 | namespace: ocs 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | image: image-registry.openshift-image-registry.svc:5000/openshift/nginxnfs 10 | ports: 11 | - containerPort: 80 12 | name: "http-server" 13 | volumeMounts: 14 | - mountPath: "/usr/share/nginx/html" 15 | name: dynamic-ocs-rbd-vol 16 | volumes: 17 | - name: dynamic-ocs-rbd-vol 18 | persistentVolumeClaim: 19 | claimName: ocsrbdpvc 20 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/restorepod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: restore-pod 5 | namespace: unity 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | #image: nginx:latest 10 | image: image-registry.openshift-image-registry.svc:5000/openshift/nginxnfs 11 | ports: 12 | - containerPort: 80 13 | name: "http-server" 14 | volumeMounts: 15 | - mountPath: "/usr/share/nginx/html" 16 | name: restore-pvc 17 | volumes: 18 | - name: restore-pvc 19 | persistentVolumeClaim: 20 | claimName: unity-restore 21 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/newiscsipod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Pod 3 | metadata: 4 | name: new-iscsi-pvc 5 | namespace: unity 6 | spec: 7 | containers: 8 | - name: task-pv-container 9 | #image: nginx:latest 10 | image: image-registry.openshift-image-registry.svc:5000/openshift/nginxnfs 11 | ports: 12 | - containerPort: 80 13 | name: "http-server" 14 | volumeMounts: 15 | - mountPath: "/usr/share/nginx/html" 16 | name: restore-pvc 17 | volumes: 18 | - name: restore-pvc 19 | persistentVolumeClaim: 20 | claimName: dynamic-new-iscsi-unity-pvc 21 | -------------------------------------------------------------------------------- /sample_yaml/storage/multipathd/multipathmc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: machineconfiguration.openshift.io/v1 2 | kind: MachineConfig 3 | metadata: 4 | name: workers-multipath-conf-default 5 | labels: 6 | machineconfiguration.openshift.io/role: worker 7 | spec: 8 | config: 9 | ignition: 10 | version: 3.1.0 11 | storage: 12 | files: 13 | - contents: 14 | source: data:text/plain;charset=utf-8;base64,ZGVmYXVsdHMgewp1c2VyX2ZyaWVuZGx5X25hbWVzIHllcwpmaW5kX211bHRpcGF0aHMgeWVzCn0KCmJsYWNrbGlzdCB7Cn0K 15 | verification: {} 16 | filesystem: root 17 | mode: 400 18 | path: /etc/multipath.conf 19 | -------------------------------------------------------------------------------- /python/nodes.yaml: -------------------------------------------------------------------------------- 1 | bootstrap_kvm: 2 | - name: bootstrap 3 | ip_os: 192.168.46.19 4 | control_nodes: 5 | - name: etcd-0 6 | ip_os: 192.168.46.21 7 | ip_idrac: 192.168.34.21 8 | - name: etcd-1 9 | ip_os: 192.168.46.22 10 | ip_idrac: 192.168.34.22 11 | - name: etcd-2 12 | ip_os: 192.168.46.23 13 | ip_idrac: 192.168.34.23 14 | compute_nodes: 15 | - name: compute-1 16 | ip_os: 192.168.46.24 17 | ip_idrac: 192.168.34.24 18 | os: rhcos 19 | - name: compute-2 20 | ip_os: 192.168.46.25 21 | ip_idrac: 192.168.34.25 22 | os: rhcos 23 | - name: compute-3 24 | ip_os: 192.168.46.27 25 | ip_idrac: 192.168.34.27 26 | os: rhel 27 | -------------------------------------------------------------------------------- /ansible/roles/rhel_compute/.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: python 3 | python: "2.7" 4 | 5 | # Use the new container infrastructure 6 | sudo: false 7 | 8 | # Install ansible 9 | addons: 10 | apt: 11 | packages: 12 | - python-pip 13 | 14 | install: 15 | # Install ansible 16 | - pip install ansible 17 | 18 | # Check ansible version 19 | - ansible --version 20 | 21 | # Create ansible.cfg with correct roles_path 22 | - printf '[defaults]\nroles_path=../' >ansible.cfg 23 | 24 | script: 25 | # Basic role syntax check 26 | - ansible-playbook tests/test.yml -i tests/inventory --syntax-check 27 | 28 | notifications: 29 | webhooks: https://galaxy.ansible.com/api/v1/notifications/ -------------------------------------------------------------------------------- /ansible/roles/dhcp/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for dhcp 3 | - debug: 4 | msg: "{{ ansible_hostname }}" 5 | 6 | - debug: 7 | msg: "{{ ansible_default_ipv4 }}" 8 | 9 | - debug: 10 | msg: "{{ ansible_domain }}" 11 | 12 | - name: install dhcp server 13 | yum: 14 | name: dhcp 15 | state: latest 16 | 17 | - name: add firewalld service for dhcp 18 | firewalld: 19 | service: dhcp 20 | permanent: yes 21 | immediate: yes 22 | state: enabled 23 | 24 | - name: generate dhcpd config 25 | template: 26 | src: dhcpd.conf.j2 27 | dest: /etc/dhcp/dhcpd.conf 28 | notify: "restart dhcp" 29 | 30 | - name: enable and start dhcpd serviec 31 | systemd: 32 | name: dhcpd 33 | enabled: yes 34 | state: started 35 | -------------------------------------------------------------------------------- /python/log_config.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | def log_setup(log_file='default.log', debug=''): 4 | """ 5 | log setup along with log file and level. 6 | 7 | """ 8 | log_level = logging.DEBUG if debug else logging.INFO 9 | logging.basicConfig(filename=log_file, level=log_level, 10 | format=("[%(levelname)s] %(name)s " 11 | "%(funcName)s(): %(message)s")) 12 | logging.info('setting log file as: {}'.format(log_file)) 13 | sh = logging.StreamHandler() 14 | sh_formatter = logging.Formatter("%(message)s") 15 | sh.setFormatter(sh_formatter) 16 | logging.getLogger().addHandler(sh) 17 | 18 | def main(): 19 | pass 20 | 21 | 22 | if __name__ == "__main__": 23 | main() 24 | -------------------------------------------------------------------------------- /ansible/roles/ignition/templates/install-config.j2: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | baseDomain: {{ ansible_domain }} 3 | compute: 4 | {% if cluster_install == '6+ node' %} 5 | - hyperthreading: Enabled 6 | name: worker 7 | replicas: {{ num_of_compute_nodes }} 8 | {% else %} 9 | - name: worker 10 | platform: {} 11 | replicas: 0 12 | {% endif %} 13 | controlPlane: 14 | hyperthreading: Enabled 15 | name: master 16 | replicas: {{ num_of_control_nodes }} 17 | metadata: 18 | name: {{ cluster }} 19 | networking: 20 | clusterNetworks: 21 | - cidr: {{ cluster_network_cidr }} 22 | hostPrefix: {{ host_prefix }} 23 | networkType: OpenShiftSDN 24 | serviceNetwork: 25 | - {{ service_network_cidr }} 26 | platform: 27 | none: {} 28 | pullSecret: '{{ pull_secret.stdout }}' 29 | sshkey: '{{ ssh_key.stdout }}' 30 | -------------------------------------------------------------------------------- /ansible/roles/rhel_compute/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for management 3 | - name: register to pool id 4 | redhat_subscription: 5 | state: present 6 | username: "{{ subscription_user }}" 7 | password: "{{ subscription_pass }}" 8 | pool_ids: 9 | - "{{ pool_id }}" 10 | 11 | - name: enable repositories in worker nodes 12 | rhsm_repository: 13 | name: "{{ item }}" 14 | state: enabled 15 | loop: 16 | - rhel-7-server-extras-rpms 17 | - rhel-7-server-rpms 18 | - rhel-7-server-ose-4.6-rpms 19 | - rhel-7-fast-datapath-rpms 20 | - rhel-7-server-optional-rpms 21 | 22 | - name: disable firewalld in worker nodes 23 | systemd: 24 | name: firewalld 25 | state: stopped 26 | enabled: no 27 | 28 | - name: copy kubeconfig file 29 | copy: 30 | src: /home/ansible/kubeconfig 31 | dest: /home/ansible/ 32 | owner: ansible 33 | group: ansible 34 | mode: '0644' 35 | -------------------------------------------------------------------------------- /ansible/roles/proxy/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for proxy 3 | - name: set proxy variable 4 | set_fact: 5 | proxy: "{{ proxy }}" 6 | 7 | - name: install {{ proxy }} 8 | yum: 9 | name: "{{ proxy }}" 10 | state: latest 11 | 12 | - name: allow OCP ports to listen via http 13 | seport: 14 | ports: "{{ item }}" 15 | proto: tcp 16 | setype: http_port_t 17 | state: present 18 | with_items: 19 | - 6443 20 | - 443 21 | - 22623 22 | - 80 23 | 24 | - name: allow OCP ports through firewalld 25 | firewalld: 26 | port: "{{ item }}/tcp" 27 | permanent: yes 28 | state: enabled 29 | immediate: yes 30 | with_items: 31 | - 6443 32 | - 443 33 | - 22623 34 | - 80 35 | 36 | - name: enable {{ proxy }} service 37 | systemd: 38 | name: "{{ proxy }}" 39 | enabled: yes 40 | state: started 41 | 42 | - name: generate haproxy config file 43 | template: 44 | src: haproxy.conf.j2 45 | dest: "{{ haproxy_conf }}" 46 | notify: haproxy restart 47 | when: proxy == "haproxy" 48 | -------------------------------------------------------------------------------- /ansible/roles/pxe/templates/default.j2: -------------------------------------------------------------------------------- 1 | default vesamenu.c32 2 | prompt 0timeout 300 3 | ONTIMEOUT local 4 | MENU MARGIN 10 5 | MENU ROWS 16 6 | MENU TABMSGROW 21 7 | MENU TIMEOUTROW 26 8 | MENU COLOR BORDER 30;44 #20ffffff #00000000 none 9 | MENU COLOR SCROLLBAR 30;44 #20ffffff #00000000 none 10 | MENU COLOR TITLE 0 #ffffffff #00000000 none 11 | MENU COLOR SEL 30;47 #40000000 #20ffffff 12 | MENU BACKGROUND redhat.jpg 13 | MENU TITLE PXE MenuLABEL local 14 | menu label Boot from ^local drive 15 | localboot 0xffff 16 | LABEL Bootstrap 17 | KERNEL {{ os }}/{{ version }}/{{ kernel_file }} 18 | APPEND initrd={{ os }}/{{ version }}/{{ initramfs }} ip=dhcp nomodeset rd.neednet=1 coreos.inst.insecure coreos.live.rootfs_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ rootfs }} coreos.inst=yes coreos.inst.install_dev=sda coreos.inst.image_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ uefi_file }} coreos.inst.ignition_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ http_ignition }}/bootstrap.ign 19 | -------------------------------------------------------------------------------- /ansible/roles/dns/templates/reverse.dns.j2: -------------------------------------------------------------------------------- 1 | $ORIGIN {{ arpa_name }}. 2 | $TTL 86400 3 | @ IN SOA {{ ansible_hostname }}.{{ ansible_domain }}. {{ ansible_domain }}. ( 4 | 50 ; serial 5 | 604800 ; Refresh after 1 week 6 | 3600 ; Retry after 1 hour 7 | 604800 ; Expire after 1 week 8 | 86400 ; Minimum TTL of 1 day 9 | ) 10 | @ IN NS {{ ansible_hostname }}.{{ ansible_domain }}. 11 | 12 | {% if bootstrap_node is defined %} 13 | {% for node in bootstrap_node %} 14 | {% set last_octet = '.'.join(node.ip.split('.')[-(strip_last_octets|int):][::-1]) %} 15 | {{ last_octet }} IN PTR {{ node.name }}.{{ ansible_domain }}. 16 | {% endfor %} 17 | {% endif %} 18 | 19 | {% for node in control_nodes %} 20 | {% set last_octet = '.'.join(node.ip.split('.')[-(strip_last_octets|int):][::-1]) %} 21 | {{ last_octet }} IN PTR {{ node.name }}.{{ ansible_domain }}. 22 | {% endfor %} 23 | 24 | {% if compute_nodes is defined %} 25 | {% for node in compute_nodes %} 26 | {% set last_octet = '.'.join(node.ip.split('.')[-(strip_last_octets|int):][::-1]) %} 27 | {{ last_octet }} IN PTR {{ node.name }}.{{ ansible_domain }}. 28 | {% endfor %} 29 | {% endif %} 30 | -------------------------------------------------------------------------------- /sample_yaml/storage/unity/unity_v140_ops_46.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.dell.com/v1 2 | kind: CSIUnity 3 | metadata: 4 | name: unity 5 | namespace: unity 6 | spec: 7 | driver: 8 | configVersion: v3 9 | replicas: 2 10 | common: 11 | image: "dellemc/csi-unity:v1.4.0.000R" 12 | imagePullPolicy: IfNotPresent 13 | envs: 14 | - name: X_CSI_UNITY_DEBUG 15 | value: "true" 16 | sideCars: 17 | - name: provisioner 18 | args: ["--volume-name-prefix=csiunity"] 19 | - name: snapshotter 20 | args: ["--snapshot-name-prefix=csiunitysnap"] 21 | storageClass: 22 | - name: fc 23 | reclaimPolicy: "Delete" 24 | allowVolumeExpansion: true 25 | parameters: 26 | storagePool: pool_2 27 | arrayId: "APM00193820970" 28 | protocol: "FC" 29 | - name: iscsi 30 | reclaimPolicy: "Delete" 31 | allowVolumeExpansion: true 32 | parameters: 33 | storagePool: pool_2 34 | arrayId: "APM00193820970" 35 | protocol: "iSCSI" 36 | - name: nfs 37 | reclaimPolicy: "Delete" 38 | allowVolumeExpansion: true 39 | parameters: 40 | storagePool: pool_2 41 | arrayId: "APM00193820970" 42 | protocol: "NFS" 43 | hostIoSize: "8192" 44 | nasServer: nas_1 45 | snapshotClass: 46 | - name: snap 47 | parameters: 48 | retentionDuration: "" 49 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for bootstrap 3 | - name: install kvm pre-requisite packages 4 | yum: 5 | name: ['qemu-kvm', 'libvirt', 'libvirt-python', 'libguestfs-tools', 'virt-install', 'virt-viewer'] 6 | state: latest 7 | 8 | - name: enable libvirtd service 9 | systemd: 10 | name: libvirtd 11 | enabled: yes 12 | state: started 13 | 14 | - name: get bootstrap node details 15 | set_fact: 16 | bootstrap_info: "{{ hostvars[inventory_hostname]['bootstrap_node'] }}" 17 | when: bootstrap_node is defined 18 | 19 | - name: get bootstrap mac address 20 | set_fact: 21 | bootstrap_mac_info: "{{ bootstrap_info[0].mac }}" 22 | when: bootstrap_node is defined 23 | 24 | - name: bootstrap kvm command 25 | set_fact: 26 | command: "KVM Command: virt-install --name bootstrapkvm --ram 20480 --vcpu 8 --disk path=/home/bootstrapvm-disk.qcow2,format=qcow2,size=200 --os-variant generic --network=bridge=br0,model=virtio,mac={{ bootstrap_mac_info }} --pxe --boot hd,network" 27 | when: bootstrap_node is defined 28 | 29 | - name: create a file to save bootstrap command 30 | file: 31 | path: "{{ software_src }}/bootstrap_command" 32 | state: touch 33 | when: bootstrap_node is defined 34 | 35 | - name: add bootstrap command in file 36 | blockinfile: 37 | path: "{{ software_src }}/bootstrap_command" 38 | block: | 39 | "{{ command }}" 40 | when: bootstrap_node is defined 41 | -------------------------------------------------------------------------------- /ansible/roles/bootstrap/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /ansible/roles/rhel_compute/README.md: -------------------------------------------------------------------------------- 1 | Role Name 2 | ========= 3 | 4 | A brief description of the role goes here. 5 | 6 | Requirements 7 | ------------ 8 | 9 | Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required. 10 | 11 | Role Variables 12 | -------------- 13 | 14 | A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well. 15 | 16 | Dependencies 17 | ------------ 18 | 19 | A list of other roles hosted on Galaxy should go here, plus any details in regards to parameters that may need to be set for other roles, or variables that are used from other roles. 20 | 21 | Example Playbook 22 | ---------------- 23 | 24 | Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too: 25 | 26 | - hosts: servers 27 | roles: 28 | - { role: username.rolename, x: 42 } 29 | 30 | License 31 | ------- 32 | 33 | BSD 34 | 35 | Author Information 36 | ------------------ 37 | 38 | An optional section for the role authors to include contact information, or a website (HTML is not allowed). 39 | -------------------------------------------------------------------------------- /ansible/roles/dhcp/templates/dhcpd.conf.j2: -------------------------------------------------------------------------------- 1 | # 2 | # DHCP Server Configuration file. 3 | # see /usr/share/doc/dhcp-server/dhcpd.conf.example 4 | # see dhcpd.conf(5) man page 5 | # 6 | # 7 | option space pxelinux; 8 | option pxelinux.magic code 208 = string; 9 | option pxelinux.configfile code 209 = text; 10 | option pxelinux.pathprefix code 210 = text; 11 | option pxelinux.reboottime code 211 = unsigned integer 32; 12 | option architecture-type code 93 = unsigned integer 16; 13 | option domain-name "{{ ansible_domain }}, {{ cluster }}.{{ ansible_domain }}"; 14 | 15 | default-lease-time {{ default_lease_time }}; 16 | max-lease-time {{ max_lease_time }}; 17 | 18 | {% if bootstrap_node is defined %} 19 | {% for node in bootstrap_node %} 20 | host {{ node.name }}{ 21 | hardware ethernet {{ node.mac }}; 22 | fixed-address {{ node.ip }}; 23 | } 24 | 25 | {% endfor %} 26 | {% endif %} 27 | 28 | {% for node in control_nodes %} 29 | host {{ node.name }}{ 30 | hardware ethernet {{ node.mac }}; 31 | fixed-address {{ node.ip }}; 32 | } 33 | 34 | {% endfor %} 35 | 36 | {% if compute_nodes is defined %} 37 | {% for node in compute_nodes %} 38 | host {{ node.name }}{ 39 | hardware ethernet {{ node.mac }}; 40 | fixed-address {{ node.ip }}; 41 | } 42 | 43 | {% endfor %} 44 | {% endif %} 45 | 46 | 47 | subnet {{ ansible_default_ipv4.network }} netmask {{ ansible_default_ipv4.netmask}} { 48 | option broadcast-address {{ ansible_default_ipv4.broadcast }}; 49 | option routers {{ ansible_default_ipv4.gateway }}; 50 | option domain-name-servers {{ ansible_default_ipv4.address }}; 51 | } 52 | -------------------------------------------------------------------------------- /ansible/roles/dns/templates/forward.dns.j2: -------------------------------------------------------------------------------- 1 | $ORIGIN {{ ansible_domain }}. 2 | $TTL 8600 3 | @ IN SOA {{ ansible_hostname }}.{{ ansible_domain }}. {{ ansible_domain }}. ( 4 | 50 ; serial 5 | 604800 ; Refresh after 1 week 6 | 3600 ; Retry after 1 hour 7 | 604800 ; Expire after 1 week 8 | 86400 ; Minimum TTL of 1 day 9 | ) 10 | IN NS {{ ansible_hostname }}.{{ ansible_domain}}. 11 | 12 | {{ ansible_hostname }} IN A {{ ansible_default_ipv4.address }} 13 | 14 | {% if bootstrap_node is defined %} 15 | {% for node in bootstrap_node %} 16 | {{ node.name }} IN A {{ node.ip }} 17 | {% endfor %} 18 | {% endif %} 19 | 20 | {% for node in control_nodes %} 21 | {{ node.name }} IN A {{ node.ip }} 22 | {% endfor %} 23 | 24 | {% if compute_nodes is defined %} 25 | {% for node in compute_nodes %} 26 | {{ node.name }} IN A {{ node.ip }} 27 | {% endfor %} 28 | {% endif %} 29 | 30 | $ORIGIN {{ cluster }}.{{ ansible_domain }}. 31 | 32 | {% if bootstrap_node is defined %} 33 | {% for node in bootstrap_node %} 34 | {{ node.name }} IN CNAME {{ node.name }}.{{ ansible_domain }}. 35 | {% endfor %} 36 | {% endif %} 37 | 38 | 39 | {% for node in control_nodes %} 40 | {{ node.name }} IN CNAME {{ node.name }}.{{ ansible_domain }}. 41 | {% endfor %} 42 | 43 | {% if compute_nodes is defined %} 44 | {% for node in compute_nodes %} 45 | {{ node.name }} IN CNAME {{ node.name }}.{{ ansible_domain }}. 46 | {% endfor %} 47 | {% endif %} 48 | 49 | 50 | *.apps IN A {{ ansible_default_ipv4.address }} 51 | api IN A {{ ansible_default_ipv4.address }} 52 | api-int IN A {{ ansible_default_ipv4.address }} 53 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/powermax_v150_fc_ops_46.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.dell.com/v1 2 | kind: CSIPowerMax 3 | metadata: 4 | name: powermax 5 | namespace: powermax 6 | spec: 7 | driver: 8 | # Config version for CSI PowerMax v1.5 driver 9 | configVersion: v4 10 | # Controller count. Don't increase it 11 | replicas: 2 12 | forceUpdate: false 13 | common: 14 | # Image for CSI PowerMax driver v1.5 15 | image: dellemc/csi-powermax:v1.5.0.000R 16 | imagePullPolicy: IfNotPresent 17 | envs: 18 | # Unisphere IP 19 | # If using PowerMax reverseproxy, leave it unchanged 20 | - name: X_CSI_POWERMAX_ENDPOINT 21 | value: "https://192.168.46.26:8443/" 22 | # Change this to a 3 character prefix unique for this cluster 23 | - name: X_CSI_K8S_CLUSTER_PREFIX 24 | value: "OCP" 25 | # Preferred transport protocol (FC/ISCSI) 26 | - name: "X_CSI_TRANSPORT_PROTOCOL" 27 | value: "FC" 28 | # Set this value to a higher number (max 50) if you are using the proxy 29 | - name: "X_CSI_GRPC_MAX_THREADS" 30 | value: "4" 31 | node: 32 | envs: 33 | # Enable ISCSI CHAP Authentication 34 | - name: "X_CSI_POWERMAX_ISCSI_ENABLE_CHAP" 35 | value: "false" 36 | storageClass: 37 | - name: bronze 38 | reclaimPolicy: Delete 39 | volumeBindingMode: "Immediate" 40 | allowVolumeExpansion: true 41 | parameters: 42 | # Replace the SYMID with the Symmetrix ID of the PowerMax array 43 | SYMID: "000197900896" 44 | # Replace the SRP with the name of the Storage Resource Pool on the PowerMax array 45 | SRP: SRP_1 46 | ServiceLevel: Bronze 47 | snapshotClass: 48 | - name: snapclass 49 | -------------------------------------------------------------------------------- /ansible/roles/dns/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for bind 3 | - name: identify number of '255' in {{ ansible_default_ipv4.netmask }} 4 | set_fact: 5 | striped_netmask: "{{ ansible_default_ipv4.netmask | regex_findall('(255)') |length }}" 6 | 7 | - debug: 8 | msg: custom netmask is {{ striped_netmask|int }} 9 | 10 | - name: number of octets to remove 11 | set_fact: 12 | strip_last_octets: "{{ 4 - striped_netmask|int }}" 13 | 14 | - debug: 15 | msg: last {{ strip_last_octets }} octet(s) in reverse order will be added in reverse zone file for {{ ansible_default_ipv4.network }} 16 | 17 | - name: set reverse zone name prefix 18 | set_fact: 19 | arpa_name_prefix: "{{ ansible_default_ipv4.network.split('.')[:striped_netmask|int][::-1] }}" 20 | 21 | - name: set reverse zone file name 22 | set_fact: 23 | arpa_name: "{{ arpa_name_prefix | join('.') }}.in-addr.arpa" 24 | 25 | - debug: 26 | msg: reverse zone name is {{ arpa_name }} 27 | 28 | - name: install dns 29 | yum: 30 | name: bind 31 | state: latest 32 | 33 | - name: enable firewalld bind service 34 | firewalld: 35 | service: dns 36 | permanent: yes 37 | immediate: yes 38 | state: enabled 39 | 40 | - name: generate dns config 41 | template: 42 | src: named.conf.j2 43 | dest: /etc/named.conf 44 | notify: "restart named" 45 | 46 | - name: generate zone config file 47 | template: 48 | src: zones.j2 49 | dest: /var/named/{{ cluster }}.zones 50 | 51 | - name: generate forward zone file 52 | template: 53 | src: forward.dns.j2 54 | dest: /var/named/{{ ansible_domain }} 55 | notify: "restart named" 56 | 57 | - name: generate reverse zone file 58 | template: 59 | src: reverse.dns.j2 60 | dest: /var/named/{{ arpa_name }} 61 | notify: "restart named" 62 | 63 | - name: enable and start bind service 64 | systemd: 65 | name: named 66 | enabled: yes 67 | state: started 68 | -------------------------------------------------------------------------------- /ansible/roles/http/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for http 3 | - name: install http 4 | yum: 5 | name: httpd 6 | state: latest 7 | 8 | - name: allow http to listen on port {{ http_port }} 9 | seport: 10 | ports: "{{ http_port }}" 11 | proto: tcp 12 | setype: http_port_t 13 | state: present 14 | 15 | - name: allow {{ http_port }} through firewall 16 | firewalld: 17 | port: "{{ http_port }}/tcp" 18 | permanent: yes 19 | immediate: yes 20 | state: enabled 21 | 22 | - name: generate httpd config 23 | template: 24 | src: httpd.conf.j2 25 | dest: /etc/httpd/conf/httpd.conf 26 | notify: "restart httpd" 27 | 28 | - name: enable and start service 29 | systemd: 30 | name: httpd 31 | enabled: yes 32 | state: started 33 | 34 | - name: create directory for rhcos software 35 | file: 36 | path: /var/www/html/{{ os }}/{{ version }} 37 | state: directory 38 | register: http_os_dir 39 | 40 | - name: create directories for rhel os and kickstart 41 | file: 42 | path: /var/www/html/{{ item }} 43 | state: directory 44 | loop: 45 | - kickstart 46 | - rhel 47 | - "{{ http_ignition }}" 48 | 49 | - name: copy rhcos bare metal uefi files to http location 50 | copy: 51 | src: "{{ item.src }}" 52 | dest: "{{ http_os_dir.path }}/{{ item.dest }}" 53 | with_items: 54 | - { src: "{{ software_src }}/{{ uefi_file }}", dest: "{{ uefi_file }}" } 55 | - { src: "{{ software_src }}/{{ initramfs }}", dest: "{{ initramfs }}" } 56 | - { src: "{{ software_src }}/{{ rootfs }}", dest: "{{ rootfs }}" } 57 | 58 | - name: mount rhel iso file 59 | mount: 60 | path: /mnt 61 | src: "{{ software_src }}/{{ rhel_os }}" 62 | fstype: iso9660 63 | opts: loop,ro 64 | state: mounted 65 | 66 | - name: copy rhel os contents to http dir 67 | shell: 'cp -r /mnt/* /var/www/html/rhel/' 68 | 69 | - name: unmount rhel iso file 70 | mount: 71 | path: /mnt 72 | state: unmounted 73 | -------------------------------------------------------------------------------- /sample_yaml/storage/powermax/powermax_v150_iscsi_ops_46.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.dell.com/v1 2 | kind: CSIPowerMax 3 | metadata: 4 | name: powermax 5 | namespace: powermax 6 | spec: 7 | driver: 8 | # Config version for CSI PowerMax v1.5 driver 9 | configVersion: v4 10 | # Controller count. Don't increase it 11 | replicas: 2 12 | forceUpdate: false 13 | common: 14 | # Image for CSI PowerMax driver v1.5 15 | image: dellemc/csi-powermax:v1.5.0.000R 16 | imagePullPolicy: IfNotPresent 17 | envs: 18 | # Unisphere IP 19 | # If using PowerMax reverseproxy, leave it unchanged 20 | - name: X_CSI_POWERMAX_ENDPOINT 21 | value: "https://192.168.46.26:8443/" 22 | # Change this to a 3 character prefix unique for this cluster 23 | - name: X_CSI_K8S_CLUSTER_PREFIX 24 | value: "OCP" 25 | # Preferred transport protocol (FC/ISCSI) 26 | - name: "X_CSI_TRANSPORT_PROTOCOL" 27 | value: "ISCSI" 28 | # iSCSI port group name 29 | - name: "X_CSI_POWERMAX_PORTGROUPS" 30 | value: "SEPort" 31 | - name: "X_CSI_POWERMAX_ARRAYS" 32 | value: "" 33 | # Set this value to a higher number (max 50) if you are using the proxy 34 | - name: "X_CSI_GRPC_MAX_THREADS" 35 | value: "4" 36 | node: 37 | envs: 38 | # Enable ISCSI CHAP Authentication 39 | - name: "X_CSI_POWERMAX_ISCSI_ENABLE_CHAP" 40 | value: "false" 41 | storageClass: 42 | - name: iscsi 43 | reclaimPolicy: Delete 44 | volumeBindingMode: "Immediate" 45 | allowVolumeExpansion: true 46 | parameters: 47 | # Replace the SYMID with the Symmetrix ID of the PowerMax array 48 | SYMID: "000197900896" 49 | # Replace the SRP with the name of the Storage Resource Pool on the PowerMax array 50 | SRP: SRP_1 51 | ServiceLevel: Bronze 52 | snapshotClass: 53 | - name: snap 54 | -------------------------------------------------------------------------------- /sample_yaml/storage/isilon/isilon_v140_ops_46.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.dell.com/v1 2 | kind: CSIIsilon 3 | metadata: 4 | name: isilon 5 | namespace: isilon 6 | spec: 7 | driver: 8 | # Config version for CSI PowerScale v1.4.0 driver 9 | configVersion: v4 10 | replicas: 2 11 | forceUpdate: false 12 | common: 13 | # Image for CSI PowerScale driver v1.4.0 14 | image: "dellemc/csi-isilon:v1.4.0.000R" 15 | imagePullPolicy: IfNotPresent 16 | envs: 17 | - name: X_CSI_VERBOSE 18 | value: "1" 19 | - name: X_CSI_ISI_ENDPOINT 20 | value: 192.168.182.85 21 | - name: X_CSI_ISI_PORT 22 | value: "8080" 23 | - name: X_CSI_ISI_PATH 24 | value: "/ifs" 25 | - name: X_CSI_ISILON_NO_PROBE_ON_START 26 | value: "false" 27 | - name: X_CSI_ISI_AUTOPROBE 28 | value: "true" 29 | - name: X_CSI_ISI_INSECURE 30 | value: "true" 31 | - name: X_CSI_DEBUG 32 | value: "false" 33 | - name: X_CSI_CUSTOM_TOPOLOGY_ENABLED 34 | value: "false" 35 | controller: 36 | envs: 37 | - name: X_CSI_ISI_QUOTA_ENABLED 38 | value: "true" 39 | - name: X_CSI_ISI_ACCESS_ZONE 40 | value: System 41 | node: 42 | envs: 43 | - name: X_CSI_ISILON_NFS_V3 44 | value: "false" 45 | sideCars: 46 | - name: provisioner 47 | args: ["--volume-name-prefix=csipscale"] 48 | storageClass: 49 | # The storageClass name will have a prefix "isilon" 50 | - name: nfs 51 | reclaimPolicy: "Delete" 52 | allowVolumeExpansion: true 53 | volumeBindingMode: WaitForFirstConsumer 54 | parameters: 55 | AccessZone: "System" 56 | IsiPath: "/ifs" 57 | AzServiceIP: 192.168.182.85 58 | RootClientEnabled: "false" 59 | snapshotClass: 60 | # The volumeSnapshotClass name will have a prefix "isilon" 61 | - name: snap 62 | parameters: 63 | IsiPath: "/ifs" 64 | -------------------------------------------------------------------------------- /ansible/roles/dns/templates/named.conf.j2: -------------------------------------------------------------------------------- 1 | // 2 | // named.conf 3 | // 4 | // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS 5 | // server as a caching only nameserver (as a localhost DNS resolver only). 6 | // 7 | // See /usr/share/doc/bind*/sample/ for example named configuration files. 8 | // 9 | // See the BIND Administrator's Reference Manual (ARM) for details about the 10 | // configuration located in /usr/share/doc/bind-{version}/Bv9ARM.html 11 | 12 | options { 13 | listen-on port 53 { {{ ansible_default_ipv4.address }}; }; 14 | listen-on-v6 port 53 { ::1; }; 15 | directory "/var/named"; 16 | dump-file "/var/named/data/cache_dump.db"; 17 | statistics-file "/var/named/data/named_stats.txt"; 18 | memstatistics-file "/var/named/data/named_mem_stats.txt"; 19 | recursing-file "/var/named/data/named.recursing"; 20 | secroots-file "/var/named/data/named.secroots"; 21 | allow-query { any; }; 22 | 23 | /* 24 | - If you are building an AUTHORITATIVE DNS server, do NOT enable recursion. 25 | - If you are building a RECURSIVE (caching) DNS server, you need to enable 26 | recursion. 27 | - If your recursive DNS server has a public IP address, you MUST enable access 28 | control to limit queries to your legitimate users. Failing to do so will 29 | cause your server to become part of large scale DNS amplification 30 | attacks. Implementing BCP38 within your network would greatly 31 | reduce such attack surface 32 | */ 33 | recursion yes; 34 | 35 | dnssec-enable yes; 36 | dnssec-validation yes; 37 | 38 | /* Path to ISC DLV key */ 39 | bindkeys-file "/etc/named.iscdlv.key"; 40 | 41 | managed-keys-directory "/var/named/dynamic"; 42 | 43 | pid-file "/run/named/named.pid"; 44 | session-keyfile "/run/named/session.key"; 45 | }; 46 | 47 | logging { 48 | channel default_debug { 49 | file "data/named.run"; 50 | severity dynamic; 51 | }; 52 | }; 53 | 54 | zone "." IN { 55 | type hint; 56 | file "named.ca"; 57 | }; 58 | 59 | include "/etc/named.rfc1912.zones"; 60 | include "/etc/named.root.key"; 61 | include "{{ default_zone_file }}"; 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Master branch is updated with OCP46 contents 2 | ``` 3 | For OCP 43 CSI contents - Refer to https://github.com/dell-esg/openshift-bare-metal and checkout branch ocp43_csi 4 | ``` 5 | 6 | ``` 7 | $ python3 generate_inventory_file.py -h 8 | usage: generate_inventory_file.py [-h] [--run | --add] --ver {4.6} --nodes NODES [--id_user ID_USER] [--id_pass ID_PASS] [--debug] 9 | 10 | Generate Inventory 11 | 12 | optional arguments: 13 | -h, --help show this help message and exit 14 | --run generate inventory file 15 | --add number of worker nodes 16 | --ver {4.6} specify OpenShift version 17 | --nodes NODES nodes inventory file 18 | --id_user ID_USER specify idrac user 19 | --id_pass ID_PASS specify idrac user 20 | --debug specify debug logs 21 | ``` 22 | 23 | - run option will generate inventory file 24 | - add option will add new worker nodes to an already existing inventory file. 25 | - ver option will specify OpenShift version. Current supported version is 4.6 only. 26 | - nodes option is a YAML file with nodes information. 27 | Note: Refer to sample file under /python/nodes.yaml 28 | - specify common idrac user and password using --id_user and --id_pass arguments. 29 | Note: Ignore --id_user and --id_pass arguments when it is not same across all nodes. 30 | - debug enables logging.debug level for the execution 31 | 32 | 33 | Switch Config 34 | > - Switches S3048, S5232F config files are saved in examples directory 35 | > - S5232F x 2 configured in VLTi 36 | > - S3048 used for iDRAC purposes 37 | 38 | Python Script - Pre-Reqs 39 | > - RHEL OS (Tested in 7.9) 40 | > - Python3 41 | > - access to appropriate repositories. Refer to deployment guide Chapter 3. 42 | 43 | Python Script - Output 44 | > - An inventory file used by ansible to execute roles defined in ocp.yml 45 | > - Script log file (*Inventory.log by default*) 46 | 47 | Ansible Playbooks - Pre-Reqs 48 | > - RedHat subscription (to download ansible rpm and pullsecret for OCP 4.6) 49 | > - Inventory File (generated using python script) 50 | 51 | Ansible Playbooks - Execution 52 | > - cd *git clone dir/containers/ansible* 53 | > - *ansible-playbook -i 'Path to inventory file path generated using python script' ocp.yml* 54 | 55 | Ansible Playbooks - Output 56 | > - Services such as *DNS/DHCP/PXE/TFTP/HAProxy* are configured in local node using the inventory file generated. 57 | 58 | -------------------------------------------------------------------------------- /ansible/generated_inventory: -------------------------------------------------------------------------------- 1 | csah: 2 | hosts: csah.example.com 3 | vars: 4 | proxy: haproxy 5 | haproxy_conf: /etc/haproxy/haproxy.cfg 6 | master_ports: 7 | - port: 6443 8 | description: apiserver 9 | - port: 22623 10 | description: configserver 11 | worker_ports: 12 | - port: 80 13 | description: http 14 | - port: 443 15 | description: https 16 | default_lease_time: 8000 17 | max_lease_time: 72000 18 | software_src: /home/ansible/files 19 | openshift_installer: openshift-install-linux.tar.gz 20 | initramfs: rhcos-live-initramfs.x86_64.img 21 | kernel_file: rhcos-live-kernel-x86_64 22 | uefi_file: rhcos-metal.x86_64.raw.gz 23 | rootfs: rhcos-live-rootfs.x86_64.img 24 | rhel_os: rhel-server-7.9-x86_64-dvd.iso 25 | pull_secret_file: pullsecret 26 | bootstrap_node: 27 | - name: bootstrap 28 | ip: 192.168.46.19 29 | mac: 52:54:00:96:59:56 30 | control_nodes: 31 | - name: etcd-0 32 | ip: 192.168.46.21 33 | mac: B8:59:9F:C0:36:46 34 | bond: bond0 35 | primary: ens2f0 36 | backup: ens2f1 37 | options: mode=active-backup 38 | - name: etcd-1 39 | ip: 192.168.46.22 40 | mac: B8:59:9F:C0:35:66 41 | bond: bond0 42 | primary: ens2f0 43 | backup: ens2f1 44 | options: mode=active-backup 45 | - name: etcd-2 46 | ip: 192.168.46.23 47 | mac: B8:59:9F:C0:34:C6 48 | bond: bond0 49 | primary: ens2f0 50 | backup: ens2f1 51 | options: mode=active-backup 52 | num_of_control_nodes: 3 53 | compute_nodes: 54 | - name: compute-1 55 | ip: 192.168.46.24 56 | mac: B8:59:9F:C0:36:3E 57 | bond: bond0 58 | primary: ens2f0 59 | backup: ens2f1 60 | options: mode=active-backup 61 | interfaces: 62 | - ens2f0 63 | os: rhcos 64 | - name: compute-2 65 | ip: 192.168.46.25 66 | mac: B8:59:9F:C0:35:E6 67 | bond: bond0 68 | primary: ens2f0 69 | backup: ens2f1 70 | options: mode=active-backup 71 | interfaces: 72 | - ens2f0 73 | os: rhcos 74 | - name: compute-3 75 | ip: 192.168.46.27 76 | mac: B8:59:9F:C0:35:26 77 | bond: bond0 78 | primary: p2p1 79 | backup: p2p2 80 | options: mode=active-backup 81 | interfaces: 82 | - em1 83 | - em2 84 | - p2p1 85 | - p2p2 86 | os: rhel 87 | num_of_compute_nodes: 3 88 | cluster_install: 6+ node 89 | master_install_device: nvme0n1 90 | worker_install_device: nvme0n1 91 | default_zone_file: /var/named/ocp.zones 92 | cluster: ocp 93 | http_port: 8080 94 | os: rhcos 95 | http_ignition: ignition 96 | version: 4.6 97 | install_user: core 98 | install_dir: openshift 99 | cluster_network_cidr: 10.128.0.0/14 100 | host_prefix: 23 101 | service_network_cidr: 172.30.0.0/16 102 | -------------------------------------------------------------------------------- /examples/FC6510: -------------------------------------------------------------------------------- 1 | R3FC:FID128:admin> cfgshow 2 | Defined configuration: 3 | cfg: ZONE_CONFIG 4 | R3W0Unity; R31Unity; R3W2Unity; R3W0PMAX; R3W1PMAX; R3W2PMAX 5 | zone: R31Unity 6 | R3W1; Unity 7 | zone: R3W0PMAX 8 | R3W0; PMAX_FA_1; PMAX_FA_2 9 | zone: R3W0Unity 10 | R3W0; Unity 11 | zone: R3W1PMAX 12 | R3W1; PMAX_FA_1; PMAX_FA_2 13 | zone: R3W2PMAX 14 | R3W2; PMAX_FA_1; PMAX_FA_2 15 | zone: R3W2Unity 16 | R3W2; Unity 17 | alias: PMAX_FA_1 18 | 50:00:09:73:b0:0e:00:05; 50:00:09:73:b0:0e:00:04 19 | alias: PMAX_FA_2 20 | 50:00:09:73:b0:0e:00:45; 50:00:09:73:b0:0e:00:44 21 | alias: R3W0 21:00:00:24:ff:48:b5:3a; 21:00:00:24:ff:48:b5:3b; 22 | 21:00:00:1b:32:8b:df:c4; 21:01:00:1b:32:ab:df:c4 23 | alias: R3W1 20:00:00:24:ff:4f:97:a6; 20:00:00:24:ff:4f:97:a7; 24 | 10:00:00:90:fa:9b:6f:fa; 10:00:00:90:fa:9b:6f:fb 25 | alias: R3W2 10:00:00:00:c9:b8:2e:4c; 10:00:00:00:c9:b8:2e:4d; 26 | 10:00:00:00:c9:71:5d:88; 10:00:00:00:c9:71:5d:89 27 | alias: Unity 50:06:01:62:49:e0:3a:cf; 50:06:01:63:49:e0:3a:cf; 28 | 50:06:01:6a:49:e0:3a:cf; 50:06:01:6b:49:e0:3a:cf 29 | 30 | Effective configuration: 31 | cfg: ZONE_CONFIG 32 | zone: R31Unity 33 | 20:00:00:24:ff:4f:97:a6 34 | 20:00:00:24:ff:4f:97:a7 35 | 10:00:00:90:fa:9b:6f:fa 36 | 10:00:00:90:fa:9b:6f:fb 37 | 50:06:01:62:49:e0:3a:cf 38 | 50:06:01:63:49:e0:3a:cf 39 | 50:06:01:6a:49:e0:3a:cf 40 | 50:06:01:6b:49:e0:3a:cf 41 | zone: R3W0PMAX 42 | 21:00:00:24:ff:48:b5:3a 43 | 21:00:00:24:ff:48:b5:3b 44 | 21:00:00:1b:32:8b:df:c4 45 | 21:01:00:1b:32:ab:df:c4 46 | 50:00:09:73:b0:0e:00:05 47 | 50:00:09:73:b0:0e:00:04 48 | 50:00:09:73:b0:0e:00:45 49 | 50:00:09:73:b0:0e:00:44 50 | zone: R3W0Unity 51 | 21:00:00:24:ff:48:b5:3a 52 | 21:00:00:24:ff:48:b5:3b 53 | 21:00:00:1b:32:8b:df:c4 54 | 21:01:00:1b:32:ab:df:c4 55 | 50:06:01:62:49:e0:3a:cf 56 | 50:06:01:63:49:e0:3a:cf 57 | 50:06:01:6a:49:e0:3a:cf 58 | 50:06:01:6b:49:e0:3a:cf 59 | zone: R3W1PMAX 60 | 20:00:00:24:ff:4f:97:a6 61 | 20:00:00:24:ff:4f:97:a7 62 | 10:00:00:90:fa:9b:6f:fa 63 | 10:00:00:90:fa:9b:6f:fb 64 | 50:00:09:73:b0:0e:00:05 65 | 50:00:09:73:b0:0e:00:04 66 | 50:00:09:73:b0:0e:00:45 67 | 50:00:09:73:b0:0e:00:44 68 | zone: R3W2PMAX 69 | 10:00:00:00:c9:b8:2e:4c 70 | 10:00:00:00:c9:b8:2e:4d 71 | 10:00:00:00:c9:71:5d:88 72 | 10:00:00:00:c9:71:5d:89 73 | 50:00:09:73:b0:0e:00:05 74 | 50:00:09:73:b0:0e:00:04 75 | 50:00:09:73:b0:0e:00:45 76 | 50:00:09:73:b0:0e:00:44 77 | zone: R3W2Unity 78 | 10:00:00:00:c9:b8:2e:4c 79 | 10:00:00:00:c9:b8:2e:4d 80 | 10:00:00:00:c9:71:5d:88 81 | 10:00:00:00:c9:71:5d:89 82 | 50:06:01:62:49:e0:3a:cf 83 | 50:06:01:63:49:e0:3a:cf 84 | 50:06:01:6a:49:e0:3a:cf 85 | 50:06:01:6b:49:e0:3a:cf 86 | -------------------------------------------------------------------------------- /ansible/roles/proxy/templates/haproxy.conf.j2: -------------------------------------------------------------------------------- 1 | #--------------------------------------------------------------------- 2 | # Example configuration for a possible web application. See the 3 | # full configuration options online. 4 | # 5 | # https://www.haproxy.org/download/1.8/doc/configuration.txt 6 | # 7 | #--------------------------------------------------------------------- 8 | 9 | #--------------------------------------------------------------------- 10 | # Global settings 11 | #--------------------------------------------------------------------- 12 | global 13 | # to have these messages end up in /var/log/haproxy.log you will 14 | # need to: 15 | # 16 | # 1) configure syslog to accept network log events. This is done 17 | # by adding the '-r' option to the SYSLOGD_OPTIONS in 18 | # /etc/sysconfig/syslog 19 | # 20 | # 2) configure local2 events to go to the /var/log/haproxy.log 21 | # file. A line like the following can be added to 22 | # /etc/sysconfig/syslog 23 | # 24 | # local2.* /var/log/haproxy.log 25 | # 26 | log 127.0.0.1 local2 27 | 28 | chroot /var/lib/haproxy 29 | pidfile /var/run/haproxy.pid 30 | maxconn 4000 31 | user haproxy 32 | group haproxy 33 | daemon 34 | 35 | # turn on stats unix socket 36 | stats socket /var/lib/haproxy/stats 37 | 38 | # utilize system-wide crypto-policies 39 | # ssl-default-bind-ciphers PROFILE=SYSTEM 40 | # ssl-default-server-ciphers PROFILE=SYSTEM 41 | 42 | #--------------------------------------------------------------------- 43 | # common defaults that all the 'listen' and 'backend' sections will 44 | # use if not designated in their block 45 | #--------------------------------------------------------------------- 46 | defaults 47 | mode http 48 | log global 49 | option httplog 50 | option dontlognull 51 | option http-server-close 52 | option forwardfor except 127.0.0.0/8 53 | option redispatch 54 | retries 3 55 | timeout http-request 10s 56 | timeout queue 1m 57 | timeout connect 10s 58 | timeout client 1m 59 | timeout server 1m 60 | timeout http-keep-alive 10s 61 | timeout check 10s 62 | maxconn 3000 63 | 64 | {% for port in master_ports %} 65 | frontend {{ port.description }} 66 | bind *:{{ port.port }} 67 | default_backend {{ port.description }} 68 | mode tcp 69 | option tcplog 70 | 71 | backend {{ port.description }} 72 | balance roundrobin 73 | mode tcp 74 | {% if bootstrap_node is defined %} 75 | {% for node in bootstrap_node %} 76 | server {{ node.name }} {{ node.ip }}:{{ port.port }} check 77 | {% endfor %} 78 | {% endif %} 79 | {% for node in control_nodes %} 80 | server {{ node.name }} {{ node.ip }}:{{ port.port }} check 81 | {% endfor %} 82 | 83 | {% endfor %} 84 | 85 | {% for port in worker_ports %} 86 | frontend {{ port.description }} 87 | bind *:{{ port.port }} 88 | default_backend {{ port.description }} 89 | mode tcp 90 | option tcplog 91 | 92 | backend {{ port.description }} 93 | balance roundrobin 94 | mode tcp 95 | {% if cluster_install == '3 node' %} 96 | {% for node in control_nodes %} 97 | server {{ node.name }} {{ node.ip }}:{{ port.port }} check 98 | {% endfor %} 99 | {% else %} 100 | {% for node in compute_nodes %} 101 | server {{ node.name }} {{ node.ip }}:{{ port.port }} check 102 | {% endfor %} 103 | {% endif %} 104 | 105 | {% endfor %} 106 | -------------------------------------------------------------------------------- /ansible/roles/pxe/templates/ks.j2: -------------------------------------------------------------------------------- 1 | #version=DEVEL 2 | # X Window System configuration information 3 | xconfig --startxonboot 4 | # License agreement 5 | eula --agreed 6 | # System authorization information 7 | auth --enableshadow --passalgo=sha512 8 | # Use CDROM installation media 9 | url --url http://{{ ansible_default_ipv4.address }}:{{ http_port }}/rhel 10 | # Run the Setup Agent on first boot 11 | firstboot --enable 12 | # System services 13 | services --enabled="chronyd" 14 | # Keyboard layouts 15 | keyboard --vckeymap=us --xlayouts='us' 16 | # System language 17 | lang en_US.UTF-8 18 | 19 | ignoredisk --only-use={{ worker_install_device }} 20 | # Network information 21 | {% for interface in item.interfaces %} 22 | network --bootproto=dhcp --device={{ interface }} --onboot=off --ipv6=auto 23 | {% endfor %} 24 | network --hostname={{ item.name }}.{{ ansible_domain }} 25 | 26 | # Root password 27 | rootpw --plaintext password 28 | # System timezone 29 | timezone America/New_York --isUtc 30 | user --name=user --plaintext --password=password 31 | user --name=ansible --plaintext --password=password 32 | # System bootloader configuration 33 | bootloader --append=" crashkernel=auto" --location=mbr --boot-drive={{ worker_install_device }} 34 | # Partition clearing information 35 | clearpart --all --initlabel --drives={{ worker_install_device }} 36 | # Disk partitioning information 37 | part /boot/efi --fstype="efi" --ondisk={{ worker_install_device }} --size=200 --fsoptions="umask=0077,shortname=winnt" 38 | part /boot --fstype="xfs" --ondisk={{ worker_install_device }} --size=1024 39 | part pv.265 --fstype="lvmpv" --ondisk={{ worker_install_device }} --size=1024 --grow 40 | volgroup rhel --pesize=4096 pv.265 41 | logvol swap --fstype="swap" --size=4096 --name=swap --vgname=rhel 42 | logvol / --fstype="xfs" --grow --maxsize=51200 --size=1024 --name=root --vgname=rhel 43 | logvol /home --fstype="xfs" --grow --maxsize=102400 --size=1024 --name=home --vgname=rhel 44 | logvol /var --fstype="xfs" --grow --size=1024 --name=var --vgname=rhel 45 | 46 | %packages 47 | @^graphical-server-environment 48 | @base 49 | @core 50 | @desktop-debugging 51 | @dial-up 52 | @fonts 53 | @gnome-desktop 54 | @guest-agents 55 | @guest-desktop-agents 56 | @hardware-monitoring 57 | @input-methods 58 | @internet-browser 59 | @multimedia 60 | @print-client 61 | @x11 62 | chrony 63 | git 64 | kexec-tools 65 | 66 | %end 67 | 68 | %addon com_redhat_kdump --enable --reserve-mb=auto 69 | %end 70 | 71 | #create bonding by NetworkManager 72 | %post --nochroot --log=/mnt/sysimage/root/ks-post-log.log 73 | 74 | #configure networking 75 | {% if item.bond is defined %} 76 | nmcli conn add type bond ifname {{ item.bond }} con-name {{ item.bond }} bond.options "lacp_rate=1,miimon=100,mode=802.3ad,xmit_hash_policy=layer3+4" 77 | nmcli conn add type ethernet ifname {{ item.primary }} master {{ item.bond }} 78 | nmcli conn add type ethernet ifname {{ item.backup }} master {{ item.bond }} 79 | nmcli conn mod {{ item.bond }} ipv4.method manual ipv4.addresses {{ item.ip }}/{{ net_mask_cidr }} connection.autoconnect yes ipv4.gateway {{ ansible_default_ipv4.gateway }} ipv4.dns {{ ansible_default_ipv4.address }} ipv4.dns-search {{ ansible_domain }} 80 | {% else %} 81 | nmcli con add type ethernet ifname {{ item.interface }} con-name {{ item.interface }} 82 | nmcli con mod {{ item.interface }} ipv4.method manual ipv4.addresses {{ item.ip }}/{{ net_mask_cidr }} connection.autoconnect yes ipv4.gateway {{ ansible_default_ipv4.gateway }} ipv4.dns {{ ansible_default_ipv4.address }} ipv4.dns-search {{ ansible_domain }} 83 | {% endif %} 84 | 85 | #copy network configuration files to the install image 86 | rm -rf /mnt/sysimage/etc/sysconfig/network-scripts/ifcfg-* 87 | cp -p /etc/sysconfig/network-scripts/ifcfg-* /mnt/sysimage/etc/sysconfig/network-scripts/ 88 | 89 | #add ansible user sudo permission 90 | echo "ansible ALL=(ALL) NOPASSWD: ALL" > /mnt/sysimage/etc/sudoers.d/ansible 91 | 92 | %end 93 | -------------------------------------------------------------------------------- /ansible/roles/pxe/templates/menu.j2: -------------------------------------------------------------------------------- 1 | {% for node in control_nodes %} 2 | {% if node.bond is defined %} 3 | menuentry '{{ node.name }}' --class fedora --class gnu-linux --class gnu --class os { 4 | linuxefi {{ os }}/{{ version }}/{{ kernel_file }} nomodeset rd.neednet=1 coreos.inst.insecure coreos.live.rootfs_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ rootfs }} coreos.inst=yes coreos.inst.install_dev={{ master_install_device }} coreos.inst.image_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ uefi_file }} coreos.inst.ignition_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ http_ignition }}/master.ign ip={{ node.ip}}::{{ ansible_default_ipv4.gateway }}:{{ ansible_default_ipv4.netmask }}:{{ node.name }}.{{ ansible_domain }}:{{ node.bond }}:none bond={{ node.bond }}:{{ node.primary }},{{ node.backup }}:{{ node.options }} nameserver={{ ansible_default_ipv4.address }} 5 | initrdefi {{ os }}/{{ version }}/{{ initramfs }} 6 | } 7 | {% else %} 8 | menuentry '{{ node.name }}' --class fedora --class gnu-linux --class gnu --class os { 9 | linuxefi {{ os }}/{{ version }}/{{ kernel_file }} nomodeset rd.neednet=1 coreos.inst.insecure coreos.live.rootfs_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ rootfs }} coreos.inst=yes coreos.inst.install_dev={{ master_install_device }} coreos.inst.image_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ uefi_file }} coreos.inst.ignition_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ http_ignition }}/master.ign ip={{ node.ip}}::{{ ansible_default_ipv4.gateway }}:{{ ansible_default_ipv4.netmask }}:{{ node.name }}.{{ ansible_domain }}:{{ node.interface }}:none nameserver={{ ansible_default_ipv4.address }} 10 | initrdefi {{ os }}/{{ version }}/{{ initramfs }} 11 | } 12 | {% endif %} 13 | {% endfor %} 14 | 15 | {% if compute_nodes is defined %} 16 | {% for node in compute_nodes %} 17 | {% if node.os == 'rhel' %} 18 | menuentry '{{ node.name }}' --class fedora --class gnu-linux --class gnu --class os { 19 | linuxefi rhel/vmlinuz ip=dhcp inst.ks=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/kickstart/{{ node.name }}.ks.cfg 20 | initrdefi rhel/initrd.img 21 | } 22 | {% elif node.os == 'rhcos' and node.bond is defined %} 23 | menuentry '{{ node.name }}' --class fedora --class gnu-linux --class gnu --class os { 24 | linuxefi {{ os }}/{{ version }}/{{ kernel_file }} nomodeset rd.neednet=1 coreos.inst.insecure coreos.live.rootfs_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ rootfs }} coreos.inst=yes coreos.inst.install_dev={{ worker_install_device }} coreos.inst.image_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ uefi_file }} coreos.inst.ignition_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ http_ignition }}/worker.ign ip={{ node.ip}}::{{ ansible_default_ipv4.gateway }}:{{ ansible_default_ipv4.netmask }}:{{ node.name }}.{{ ansible_domain }}:{{ node.bond }}:none bond={{ node.bond }}:{{ node.primary }},{{ node.backup }}:{{ node.options }} nameserver={{ ansible_default_ipv4.address }} 25 | initrdefi {{ os }}/{{ version }}/{{ initramfs }} 26 | } 27 | {% elif node.os == 'rhcos' and node.bond is not defined %} 28 | menuentry '{{ node.name }}' --class fedora --class gnu-linux --class gnu --class os { 29 | linuxefi {{ os }}/{{ version }}/{{ kernel_file }} nomodeset rd.neednet=1 coreos.inst.insecure coreos.live.rootfs_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ rootfs }} coreos.inst=yes coreos.inst.install_dev={{ worker_install_device }} coreos.inst.image_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ os }}/{{ version }}/{{ uefi_file }} coreos.inst.ignition_url=http://{{ ansible_default_ipv4.address }}:{{ http_port }}/{{ http_ignition }}/worker.ign ip={{ node.ip}}::{{ ansible_default_ipv4.gateway }}:{{ ansible_default_ipv4.netmask }}:{{ node.name }}.{{ ansible_domain }}:{{ node.interface }}:none nameserver={{ ansible_default_ipv4.address }} 30 | initrdefi {{ os }}/{{ version }}/{{ initramfs }} 31 | } 32 | {% endif %} 33 | {% endfor %} 34 | {% endif %} 35 | -------------------------------------------------------------------------------- /ansible/roles/pxe/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for pxe 3 | - name: install pxe pre-requisite packages 4 | yum: 5 | name: ['tftp-server', 'xinetd', 'syslinux'] 6 | state: latest 7 | 8 | - name: enable services 9 | systemd: 10 | name: "{{ item }}" 11 | enabled: yes 12 | state: started 13 | with_items: 14 | - xinetd 15 | - tftp 16 | 17 | - name: add firewalld service for tftp 18 | firewalld: 19 | service: tftp 20 | permanent: yes 21 | immediate: yes 22 | state: enabled 23 | 24 | - name: update dhcpd config file with pxe details 25 | blockinfile: 26 | path: /etc/dhcp/dhcpd.conf 27 | insertafter: "subnet" 28 | block: "{{ lookup('template', 'pxe.config.j2') }}" 29 | notify: "restart dhcp" 30 | 31 | - name: create required directories for pxe uefi/bios 32 | file: 33 | path: "/var/lib/tftpboot/{{ item }}" 34 | state: directory 35 | with_items: 36 | - uefi 37 | - rhcos 38 | - rhcos/{{ version }} 39 | - rhel 40 | - bios 41 | - bios/pxelinux.cfg 42 | - bios/rhcos 43 | - bios/rhcos/{{ version }} 44 | 45 | - name: copy required files for pxe uefi/bios 46 | copy: 47 | src: "{{ item.src }}" 48 | dest: "/var/lib/tftpboot/{{ item.dest }}" 49 | remote_src: yes 50 | with_items: 51 | - { src: "{{ software_src }}/{{ kernel_file }}", dest: "rhcos/{{ version }}/{{ kernel_file }}" } 52 | - { src: "{{ software_src }}/{{ initramfs }}", dest: "rhcos/{{ version }}/{{ initramfs }}" } 53 | - { src: "{{ software_src }}/{{ rootfs }}", dest: "rhcos/{{ version }}/{{ rootfs }}" } 54 | - { src: /boot/efi/EFI/redhat/shimx64.efi, dest: uefi/shim.efi } 55 | - { src: /boot/efi/EFI/redhat/grubx64.efi, dest: uefi/grubx64.efi } 56 | - { src: /var/www/html/rhel/images/pxeboot/vmlinuz, dest: rhel/vmlinuz } 57 | - { src: /var/www/html/rhel/images/pxeboot/initrd.img, dest: rhel/initrd.img } 58 | - { src: /var/www/html/rhel/isolinux/vesamenu.c32, dest: bios/vesamenu.c32 } 59 | - { src: /usr/share/syslinux/pxelinux.0, dest: bios/pxelinux.0 } 60 | - { src: "{{ software_src }}/{{ kernel_file }}", dest: "bios/rhcos/{{ version }}/{{ kernel_file }}" } 61 | - { src: "{{ software_src }}/{{ initramfs }}", dest: "bios/rhcos/{{ version }}/{{ initramfs }}" } 62 | - { src: "{{ software_src }}/{{ rootfs }}", dest: "bios/rhcos/{{ version }}/{{ rootfs }}" } 63 | 64 | 65 | - name: display network cidr 66 | set_fact: 67 | net_mask: "{{ ansible_default_ipv4.network }}/{{ ansible_default_ipv4.netmask }}" 68 | 69 | - name: display cidr 70 | set_fact: 71 | net_mask_cidr: "{{ net_mask | ipaddr('prefix') }}" 72 | 73 | - name: get worker nodes details 74 | set_fact: 75 | nodes: "{{ hostvars[inventory_hostname]['compute_nodes'] }}" 76 | when: cluster_install == '6+ node' 77 | 78 | - name: dispay compute node names 79 | debug: 80 | msg: "{{ item.name }}" 81 | loop: "{{ nodes }}" 82 | when: cluster_install == '6+ node' 83 | 84 | - name: dispay rhel compute node names 85 | debug: 86 | msg: "{{ item.name }}" 87 | loop: "{{ nodes }}" 88 | when: cluster_install == '6+ node' and item.os == 'rhel' 89 | 90 | - name: generate kickstart files 91 | template: 92 | src: ks.j2 93 | dest: /var/www/html/kickstart/{{ item.name }}.ks.cfg 94 | loop: "{{ nodes }}" 95 | when: cluster_install == '6+ node' and item.os == 'rhel' 96 | 97 | - name: generate pxe menu grub.cfg file 98 | template: 99 | src: menu.j2 100 | dest: /var/lib/tftpboot/uefi/grub.cfg 101 | mode: 0755 102 | 103 | - name: generate pxe menu bios menu 104 | template: 105 | src: default.j2 106 | dest: /var/lib/tftpboot/bios/pxelinux.cfg/default 107 | mode: 0755 108 | 109 | - name: create tftp file under /etc/xinetd.d 110 | copy: 111 | dest: "/etc/xinetd.d/tftp" 112 | content: | 113 | service tftp 114 | { 115 | socket_type = dgram 116 | protocol = udp 117 | wait = yes 118 | user = root 119 | server = /usr/sbin/in.tftpd 120 | server_args = -s /var/lib/tftpboot 121 | disable = no 122 | } 123 | notify: "restart xinetd" 124 | -------------------------------------------------------------------------------- /ansible/roles/ignition/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # tasks file for ignition 3 | - name: install openshift rpms 4 | yum: 5 | name: "{{ item }}" 6 | state: latest 7 | loop: 8 | - openshift-ansible 9 | - openshift-clients 10 | 11 | - name: create openshift installer user - {{ install_user }} 12 | user: 13 | name: "{{ install_user }}" 14 | state: present 15 | shell: /bin/bash 16 | createhome: yes 17 | 18 | - name: check if ssh-keygen already exists for user - {{ install_user }} 19 | stat: 20 | path: /home/{{ install_user }}/.ssh/id_rsa 21 | register: ssh_keygen_result 22 | 23 | - name: start ssh-agent as user {{ install_user }} 24 | shell: | 25 | ssh-keygen -t rsa -b 4096 -N '' -f ~/.ssh/id_rsa 26 | eval "$(ssh-agent -s)" 27 | ssh-add ~/.ssh/id_rsa 28 | become: yes 29 | become_user: "{{ install_user }}" 30 | when: ssh_keygen_result.stat.exists == false 31 | 32 | - name: create openshift install directory under /home/{{ install_user }} 33 | file: 34 | path: /home/{{ install_user }}/{{ install_dir }} 35 | state: directory 36 | mode: '0755' 37 | owner: "{{ install_user }}" 38 | group: "{{ install_user }}" 39 | register: ocp_install_dir 40 | 41 | - name: check openshift-install tool in /home/{{ install_user }} 42 | stat: 43 | path: /home/{{ install_user }}/openshift-install 44 | register: openshiftinstaller 45 | 46 | - name: copy openshift-install tool to /home/{{ install_user }} 47 | unarchive: 48 | src: "{{ software_src }}/{{ openshift_installer }}" 49 | dest: /home/{{ install_user }} 50 | remote_src: yes 51 | owner: "{{ install_user }}" 52 | group: "{{ install_user }}" 53 | when: not openshiftinstaller.stat.exists 54 | 55 | - name: read contents of pull secret key 56 | shell: cat "{{ software_src }}/{{ pull_secret_file }}" 57 | register: pull_secret 58 | 59 | - name: read contents of ssh key file for user {{ install_user }} 60 | shell: cat /home/{{ install_user }}/.ssh/id_rsa.pub 61 | register: ssh_key 62 | 63 | - name: export kubeconfig 64 | blockinfile: 65 | path: /home/{{ install_user }}/.bash_profile 66 | insertafter: EOF 67 | block: | 68 | export KUBECONFIG={{ ocp_install_dir.path }}/auth/kubeconfig 69 | export PATH=$PATH:/home/{{ install_user }} 70 | owner: "{{ install_user }}" 71 | group: "{{ install_user }}" 72 | 73 | - name: generate install config file 74 | template: 75 | src: install-config.j2 76 | dest: "/home/{{ install_user }}/install-config.yaml" 77 | owner: "{{ install_user }}" 78 | group: "{{ install_user }}" 79 | 80 | - name: copy install-config yaml file to installation directory 81 | copy: 82 | src: "/home/{{ install_user }}/install-config.yaml" 83 | dest: "{{ ocp_install_dir.path }}" 84 | remote_src: yes 85 | owner: "{{ install_user }}" 86 | group: "{{ install_user }}" 87 | 88 | - name: check ignition files in {{ ocp_install_dir.path }} 89 | stat: 90 | path: "{{ ocp_install_dir.path }}/{{ item }}" 91 | loop: 92 | - master.ign 93 | - worker.ign 94 | - bootstrap.ign 95 | register: ign 96 | 97 | - name: generate manifests directory in {{ ocp_install_dir.path }} 98 | become: yes 99 | become_user: "{{ install_user }}" 100 | shell: | 101 | cd {{ ocp_install_dir.path }} 102 | /home/{{ install_user }}/openshift-install create manifests --dir={{ ocp_install_dir.path }} 103 | when: not ign.results[0].stat.exists or not ign.results[1].stat.exists or not ign.results[2].stat.exists 104 | 105 | - name: check manifest directory in {{ ocp_install_dir.path }} 106 | stat: 107 | path: "{{ ocp_install_dir.path }}/manifests" 108 | register: manifest_dir 109 | 110 | - name: backup openshift and manifest directory 111 | copy: 112 | src: "{{ ocp_install_dir.path }}/{{ item }}" 113 | dest: /var/www/html/ 114 | remote_src: yes 115 | directory_mode: yes 116 | loop: 117 | - openshift 118 | - manifests 119 | when: manifest_dir.stat.exists and manifest_dir.stat.isdir 120 | 121 | - name: generate ignition config files 122 | become: yes 123 | become_user: "{{ install_user }}" 124 | shell: | 125 | cd {{ ocp_install_dir.path }} 126 | /home/{{ install_user }}/openshift-install create ignition-configs --dir={{ ocp_install_dir.path }} 127 | when: not ign.results[0].stat.exists or not ign.results[1].stat.exists or not ign.results[2].stat.exists 128 | register: create_ignition 129 | 130 | - name: copy ignition config files to /var/www/html/{{http_ignition}} 131 | copy: 132 | src: "{{ ocp_install_dir.path }}/{{ item }}" 133 | dest: /var/www/html/{{ http_ignition }} 134 | remote_src: yes 135 | loop: 136 | - master.ign 137 | - worker.ign 138 | - bootstrap.ign 139 | 140 | - name: copy kubeconfig file to /home/ansible 141 | copy: 142 | src: "{{ ocp_install_dir.path }}/auth/{{ item }}" 143 | dest: /home/ansible 144 | remote_src: yes 145 | loop: 146 | - kubeconfig 147 | - kubeadmin-password 148 | 149 | - name: copy core user ssh key to /home/ansible 150 | copy: 151 | src: /home/core/.ssh/id_rsa.pub 152 | dest: /home/ansible/core_id_rsa.pub 153 | remote_src: yes 154 | -------------------------------------------------------------------------------- /examples/S3048: -------------------------------------------------------------------------------- 1 | ! Version 10.5.1.0 2 | ! Last configuration change at Feb 25 15:33:51 2020 3 | ! 4 | ip vrf default 5 | ! 6 | hostname S3048 7 | iscsi enable 8 | iscsi target port 860 9 | iscsi target port 3260 10 | system-user linuxadmin password $6$5DdOHYg5$JCE1vMSmkQOrbh31U74PIPv7lyOgRmba1IxhkYibppMXs1KM4Y.gbTPcxyMP/PHUkMc5rdk/ZLv9Sfv3ALtB61 11 | username admin password $6$q9QBeYjZ$jfxzVqGhkxX3smxJSH9DDz7/3OJc6m5wjF8nnLD7/VKx8SloIhp4NoGZs0I/UNwh8WVuxwfd9q4pWIgNs5BKH. role sysadmin priv-lvl 15 12 | aaa authentication login default local 13 | aaa authentication login console local 14 | ! 15 | wred m 16 | ! 17 | class-map type application class-iscsi 18 | ! 19 | policy-map type application policy-iscsi 20 | ! 21 | interface vlan1 22 | no shutdown 23 | ! 24 | interface vlan34 25 | description iDRACs 26 | no shutdown 27 | ! 28 | interface vlan47 29 | description "storage network" 30 | shutdown 31 | ip address 192.168.47.4/24 32 | ! 33 | interface vlan461 34 | description "OCP 4.3" 35 | no shutdown 36 | ip address 192.168.46.5/26 37 | ! 38 | interface port-channel51 39 | description Up-S5232F-1 40 | no shutdown 41 | switchport mode trunk 42 | switchport trunk allowed vlan 34,47,461 43 | mtu 9216 44 | lacp fallback enable 45 | lacp fallback preemption disable 46 | lacp fallback timeout 100 47 | vlt-port-channel 51 48 | ! 49 | interface mgmt1/1/1 50 | no shutdown 51 | no ip address dhcp 52 | ip address 192.168.33.46/24 53 | ipv6 address autoconfig 54 | ! 55 | interface ethernet1/1/1 56 | no shutdown 57 | switchport access vlan 34 58 | flowcontrol receive on 59 | ! 60 | interface ethernet1/1/2 61 | no shutdown 62 | switchport access vlan 34 63 | flowcontrol receive on 64 | ! 65 | interface ethernet1/1/3 66 | no shutdown 67 | switchport access vlan 34 68 | flowcontrol receive on 69 | ! 70 | interface ethernet1/1/4 71 | no shutdown 72 | switchport access vlan 34 73 | flowcontrol receive on 74 | ! 75 | interface ethernet1/1/5 76 | no shutdown 77 | switchport access vlan 34 78 | flowcontrol receive on 79 | ! 80 | interface ethernet1/1/6 81 | no shutdown 82 | switchport access vlan 34 83 | flowcontrol receive on 84 | ! 85 | interface ethernet1/1/7 86 | no shutdown 87 | switchport access vlan 34 88 | flowcontrol receive on 89 | ! 90 | interface ethernet1/1/8 91 | no shutdown 92 | switchport access vlan 34 93 | flowcontrol receive on 94 | ! 95 | interface ethernet1/1/9 96 | no shutdown 97 | switchport access vlan 34 98 | flowcontrol receive on 99 | ! 100 | interface ethernet1/1/10 101 | no shutdown 102 | switchport access vlan 34 103 | flowcontrol receive on 104 | ! 105 | interface ethernet1/1/11 106 | no shutdown 107 | switchport access vlan 34 108 | flowcontrol receive on 109 | ! 110 | interface ethernet1/1/12 111 | no shutdown 112 | switchport access vlan 34 113 | flowcontrol receive on 114 | ! 115 | interface ethernet1/1/13 116 | no shutdown 117 | switchport access vlan 34 118 | flowcontrol receive on 119 | ! 120 | interface ethernet1/1/14 121 | no shutdown 122 | switchport access vlan 34 123 | flowcontrol receive on 124 | ! 125 | interface ethernet1/1/15 126 | no shutdown 127 | switchport access vlan 34 128 | flowcontrol receive on 129 | ! 130 | interface ethernet1/1/16 131 | no shutdown 132 | switchport access vlan 34 133 | flowcontrol receive on 134 | ! 135 | interface ethernet1/1/17 136 | no shutdown 137 | switchport access vlan 461 138 | flowcontrol receive on 139 | ! 140 | interface ethernet1/1/18 141 | no shutdown 142 | switchport access vlan 461 143 | flowcontrol receive on 144 | ! 145 | interface ethernet1/1/19 146 | no shutdown 147 | switchport access vlan 461 148 | flowcontrol receive on 149 | ! 150 | interface ethernet1/1/20 151 | no shutdown 152 | switchport access vlan 461 153 | flowcontrol receive on 154 | ! 155 | interface ethernet1/1/21 156 | no shutdown 157 | switchport access vlan 461 158 | flowcontrol receive on 159 | ! 160 | interface ethernet1/1/22 161 | no shutdown 162 | switchport access vlan 461 163 | flowcontrol receive on 164 | ! 165 | interface ethernet1/1/23 166 | no shutdown 167 | switchport access vlan 461 168 | flowcontrol receive on 169 | ! 170 | interface ethernet1/1/24 171 | no shutdown 172 | switchport access vlan 461 173 | flowcontrol receive on 174 | ! 175 | interface ethernet1/1/25 176 | no shutdown 177 | switchport access vlan 461 178 | flowcontrol receive on 179 | ! 180 | interface ethernet1/1/26 181 | no shutdown 182 | switchport access vlan 461 183 | flowcontrol receive on 184 | ! 185 | interface ethernet1/1/27 186 | no shutdown 187 | switchport access vlan 461 188 | flowcontrol receive on 189 | ! 190 | interface ethernet1/1/28 191 | no shutdown 192 | switchport access vlan 461 193 | flowcontrol receive on 194 | ! 195 | interface ethernet1/1/29 196 | no shutdown 197 | switchport access vlan 461 198 | flowcontrol receive on 199 | ! 200 | interface ethernet1/1/30 201 | no shutdown 202 | switchport access vlan 461 203 | flowcontrol receive on 204 | ! 205 | interface ethernet1/1/31 206 | no shutdown 207 | switchport access vlan 461 208 | flowcontrol receive on 209 | ! 210 | interface ethernet1/1/32 211 | no shutdown 212 | switchport access vlan 461 213 | flowcontrol receive on 214 | ! 215 | interface ethernet1/1/33 216 | no shutdown 217 | switchport access vlan 47 218 | flowcontrol receive on 219 | ! 220 | interface ethernet1/1/34 221 | no shutdown 222 | switchport access vlan 47 223 | flowcontrol receive on 224 | ! 225 | interface ethernet1/1/35 226 | no shutdown 227 | switchport access vlan 47 228 | flowcontrol receive on 229 | ! 230 | interface ethernet1/1/36 231 | no shutdown 232 | switchport access vlan 47 233 | flowcontrol receive on 234 | ! 235 | interface ethernet1/1/37 236 | no shutdown 237 | switchport access vlan 47 238 | flowcontrol receive on 239 | ! 240 | interface ethernet1/1/38 241 | no shutdown 242 | switchport access vlan 47 243 | flowcontrol receive on 244 | ! 245 | interface ethernet1/1/39 246 | no shutdown 247 | switchport access vlan 47 248 | flowcontrol receive on 249 | ! 250 | interface ethernet1/1/40 251 | no shutdown 252 | switchport access vlan 47 253 | flowcontrol receive on 254 | ! 255 | interface ethernet1/1/41 256 | no shutdown 257 | switchport access vlan 47 258 | flowcontrol receive on 259 | ! 260 | interface ethernet1/1/42 261 | no shutdown 262 | switchport access vlan 47 263 | flowcontrol receive on 264 | ! 265 | interface ethernet1/1/43 266 | no shutdown 267 | switchport access vlan 47 268 | flowcontrol receive on 269 | ! 270 | interface ethernet1/1/44 271 | no shutdown 272 | switchport access vlan 47 273 | flowcontrol receive on 274 | ! 275 | interface ethernet1/1/45 276 | no shutdown 277 | switchport access vlan 47 278 | flowcontrol receive on 279 | ! 280 | interface ethernet1/1/46 281 | no shutdown 282 | switchport access vlan 47 283 | flowcontrol receive on 284 | ! 285 | interface ethernet1/1/47 286 | no shutdown 287 | switchport access vlan 1 288 | flowcontrol receive on 289 | ! 290 | interface ethernet1/1/48 291 | no shutdown 292 | switchport access vlan 1 293 | flowcontrol receive on 294 | ! 295 | interface ethernet1/1/49 296 | no shutdown 297 | switchport access vlan 1 298 | flowcontrol receive on 299 | ! 300 | interface ethernet1/1/50 301 | no shutdown 302 | switchport access vlan 1 303 | flowcontrol receive on 304 | ! 305 | interface ethernet1/1/51 306 | description Uplink-po51 307 | no shutdown 308 | channel-group 51 mode active 309 | no switchport 310 | mtu 9216 311 | flowcontrol receive on 312 | ! 313 | interface ethernet1/1/52 314 | description Uplink-po51 315 | no shutdown 316 | channel-group 51 mode active 317 | no switchport 318 | mtu 9216 319 | flowcontrol receive on 320 | ! 321 | management route 0.0.0.0/0 192.168.33.1 322 | ! 323 | snmp-server contact "Contact Support" 324 | ! 325 | telemetry 326 | -------------------------------------------------------------------------------- /python/nodes.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | from helper import check_ip_ping, get_ip, get_user_response, set_values, validate_ip, \ 4 | get_idrac_creds, get_network_devices, map_interfaces_network, get_mac_address, \ 5 | get_network_device_mac, generate_network_devices_menu, get_device_enumeration 6 | 7 | 8 | 9 | def get_worker_os(): 10 | supported_os = ['rhel', 'rhcos'] 11 | logging.info('supported OS include {}'.format(supported_os)) 12 | os = input('enter the worker OS: ') 13 | while os not in supported_os: 14 | logging.error('Supported OS should be \'rhcos\' or \'rhel\'') 15 | os = input('enter the worker OS: ') 16 | 17 | return os 18 | 19 | 20 | def set_network_details(node_type='', node_name='', ip='', mac='', bond_name='', 21 | primary='', backup='', interfaces='', inventory='', os=''): 22 | """ 23 | get bond details and user interfaces used for bond 24 | """ 25 | devices = [] 26 | node_keys = ['name', 'ip', 'mac', 'bond', 'primary', 'backup', 'options'] 27 | node_values = [] 28 | bond_options = 'mode=active-backup' 29 | bond_interfaces = '{},{}'.format(primary, backup) 30 | node_values.append(node_name) 31 | node_values.append(ip) 32 | node_values.append(mac) 33 | node_values.append(bond_name) 34 | node_values.append(primary) 35 | node_values.append(backup) 36 | node_values.append(bond_options) 37 | 38 | if node_type == 'compute_nodes': 39 | node_keys = ['name', 'ip', 'mac', 'bond', 'primary', 'backup', 'options', 'interfaces', 'os'] 40 | node_values.append(interfaces) 41 | node_values.append(os) 42 | logging.debug('adding interfaces in {} node: {}'.format(node_name, interfaces)) 43 | 44 | node_pairs = dict(zip(node_keys, node_values)) 45 | logging.debug('node_values {} {} {}'.format(node_type, node_values, node_pairs)) 46 | inventory['csah']['vars'][node_type].append(node_pairs) 47 | 48 | return inventory 49 | 50 | def get_nodes_info(node_type='', inventory='', add=False, idrac_user='', idrac_pass='', nodes_info=''): 51 | 52 | if add: 53 | nodes_count = len(nodes_info['new_compute_nodes']) 54 | else: 55 | nodes_count = len(nodes_info['control_nodes']) if node_type == 'control_nodes' else len(nodes_info['compute_nodes']) 56 | 57 | bonding = input('Do you want to perform bonding for \'{}\' (y/NO): '.format(node_type)) 58 | valid_responses = ['y', 'NO'] 59 | 60 | while bonding not in valid_responses: 61 | logging.error('Invalid option provided. Enter \'y\' or \'NO\'') 62 | bonding = input('Do you want to perform bonding (y/NO): ') 63 | 64 | all_compute_nodes = ['compute_nodes', 'new_compute_nodes'] 65 | 66 | for num in range(nodes_count): 67 | values = [] 68 | devices = None 69 | map_devices = None 70 | interfaces_enumeration = [] 71 | mac = '' 72 | name = nodes_info[node_type][num]['name'] 73 | os_ip = nodes_info[node_type][num]['ip_os'] 74 | os_ip = validate_ip(os_ip) 75 | idrac_ip = nodes_info[node_type][num]['ip_idrac'] 76 | response = check_ip_ping(idrac_ip) 77 | 78 | if node_type in all_compute_nodes: 79 | os = nodes_info[node_type][num]['os'] 80 | else: 81 | os = 'rhcos' 82 | 83 | if response != 0: 84 | get_user_response(message='idrac ip {} not pingeable'.format(idrac_ip)) 85 | else: 86 | if idrac_user and idrac_pass: 87 | user, passwd = idrac_user, idrac_pass 88 | else: 89 | user, passwd = get_idrac_creds(idrac_ip) 90 | 91 | base_api_url = 'https://{}/redfish/v1/Systems/System.Embedded.1/EthernetInterfaces'.format(idrac_ip) 92 | devices = get_network_devices(user, passwd, base_api_url) 93 | 94 | if devices: 95 | map_devices = map_interfaces_network(devices) 96 | 97 | logging.info('select network interfaces for node {}'.format(name)) 98 | if map_devices: 99 | if bonding == 'y': 100 | mac = get_network_device_mac(map_devices, user, passwd, base_api_url) 101 | bond_name = 'bond0' 102 | active_bond_device = generate_network_devices_menu(map_devices, purpose='{} active bond interface'.format(name)) 103 | logging.debug('selected {} active bond interface: {}'.format(name, active_bond_device)) 104 | active_bond_enumeration = get_device_enumeration(active_bond_device, os=os) 105 | logging.debug('{} active bond enumeration: {}'.format(name, active_bond_enumeration)) 106 | backup_bond_device = generate_network_devices_menu(map_devices, purpose='{} backup bond interface'.format(name)) 107 | logging.debug('selected {} backup bond interface: {}'.format(name, backup_bond_device)) 108 | backup_bond_enumeration = get_device_enumeration(backup_bond_device, os=os) 109 | logging.debug('{} backup bond enumeration: {}'.format(name, backup_bond_enumeration)) 110 | logging.debug('interfaces: {}'.format(devices)) 111 | logging.debug('map interfaces: {}'.format(map_devices)) 112 | 113 | if node_type in all_compute_nodes and os == 'rhel': 114 | for device in map_devices: 115 | interface_enumeration = get_device_enumeration(device, os=os) 116 | interfaces_enumeration.append(interface_enumeration) 117 | else: 118 | interfaces_enumeration.append(active_bond_enumeration) 119 | 120 | nodes = 'control_nodes' if node_type == 'control_nodes' else 'compute_nodes' 121 | inventory = set_network_details(node_type=nodes, node_name=name, ip=os_ip, mac=mac, 122 | bond_name=bond_name, primary=active_bond_enumeration, 123 | backup=backup_bond_enumeration, interfaces=interfaces_enumeration, 124 | inventory=inventory, os=os) 125 | 126 | else: 127 | nic_device = generate_network_devices_menu(map_devices, purpose='{} nic port'.format(name)) 128 | logging.debug('selected {} as nic port: {}'.format(name, nic_device)) 129 | nic_device_enumeration = get_device_enumeration(nic_device, os=os) 130 | logging.debug('{} nic device enumeration: {}'.format(name, nic_device_enumeration)) 131 | nic_mac = get_mac_address(nic_device, base_api_url, user, passwd) 132 | logging.debug('{} nic mac address: {}'.format(name, nic_mac)) 133 | node_keys = ['name','ip','mac','interface','os'] 134 | 135 | if node_type in all_compute_nodes and os == 'rhel': 136 | node_keys = ['name','ip','mac','interface','os','interfaces'] 137 | for device in map_devices: 138 | interface_enumeration = get_device_enumeration(device, os='rhel') 139 | interfaces_enumeration.append(interface_enumeration) 140 | node_values = [name, os_ip, nic_mac, nic_device_enumeration, os, interfaces_enumeration] 141 | else: 142 | interfaces_enumeration.append(nic_device_enumeration) 143 | node_values = [name, os_ip, nic_mac, nic_device_enumeration, os] 144 | 145 | logging.debug('{} node values: {}'.format(name, node_values)) 146 | node_pairs = dict(zip(node_keys, node_values)) 147 | inventory['csah']['vars'][node_type].append(node_pairs) 148 | 149 | if node_type in all_compute_nodes and add: 150 | try: 151 | compute_nodes_count = inventory['csah']['vars']['num_of_compute_nodes'] 152 | except KeyError: 153 | inventory['csah']['vars']['num_of_compute_nodes'] = 0 154 | compute_nodes_count = 0 155 | new_compute_nodes_count = compute_nodes_count + nodes_count 156 | inventory['csah']['vars']['num_of_compute_nodes'] = new_compute_nodes_count 157 | 158 | return inventory 159 | -------------------------------------------------------------------------------- /examples/S5232F-2: -------------------------------------------------------------------------------- 1 | ! Version 10.5.1.0 2 | ! Last configuration change at Feb 25 15:33:01 2020 3 | ! 4 | ip vrf default 5 | ! 6 | no ip igmp snooping enable 7 | interface breakout 1/1/1 map 100g-1x 8 | interface breakout 1/1/2 map 100g-1x 9 | interface breakout 1/1/3 map 100g-1x 10 | interface breakout 1/1/4 map 100g-1x 11 | interface breakout 1/1/5 map 100g-1x 12 | interface breakout 1/1/6 map 100g-1x 13 | interface breakout 1/1/7 map 100g-1x 14 | interface breakout 1/1/8 map 100g-1x 15 | interface breakout 1/1/9 map 100g-1x 16 | interface breakout 1/1/10 map 100g-1x 17 | interface breakout 1/1/11 map 100g-1x 18 | interface breakout 1/1/12 map 100g-1x 19 | interface breakout 1/1/13 map 100g-1x 20 | interface breakout 1/1/14 map 100g-1x 21 | interface breakout 1/1/15 map 100g-1x 22 | interface breakout 1/1/16 map 100g-1x 23 | interface breakout 1/1/17 map 100g-1x 24 | interface breakout 1/1/18 map 100g-1x 25 | interface breakout 1/1/19 map 100g-1x 26 | interface breakout 1/1/20 map 100g-1x 27 | interface breakout 1/1/21 map 100g-1x 28 | interface breakout 1/1/22 map 100g-1x 29 | interface breakout 1/1/23 map 100g-1x 30 | interface breakout 1/1/24 map 100g-1x 31 | interface breakout 1/1/25 map 100g-1x 32 | interface breakout 1/1/26 map 100g-1x 33 | interface breakout 1/1/27 map 100g-1x 34 | interface breakout 1/1/28 map 100g-1x 35 | interface breakout 1/1/29 map 100g-1x 36 | interface breakout 1/1/30 map 100g-1x 37 | interface breakout 1/1/31 map 100g-1x 38 | interface breakout 1/1/32 map 100g-1x 39 | hostname S5232F-2 40 | no multicast snooping flood-restrict 41 | iscsi target port 860 42 | iscsi target port 3260 43 | system-user linuxadmin password $6$5DdOHYg5$JCE1vMSmkQOrbh31U74PIPv7lyOgRmba1IxhkYibppMXs1KM4Y.gbTPcxyMP/PHUkMc5rdk/ZLv9Sfv3ALtB61 44 | no ipv6 mld snooping enable 45 | spanning-tree mode rstp 46 | username admin password $6$q9QBeYjZ$jfxzVqGhkxX3smxJSH9DDz7/3OJc6m5wjF8nnLD7/VKx8SloIhp4NoGZs0I/UNwh8WVuxwfd9q4pWIgNs5BKH. role sysadmin priv-lvl 15 47 | aaa authentication login default local 48 | aaa authentication login console local 49 | ! 50 | class-map type application class-iscsi 51 | ! 52 | policy-map type application policy-iscsi 53 | ! 54 | interface vlan1 55 | no shutdown 56 | ! 57 | interface vlan32 58 | no shutdown 59 | ! 60 | interface vlan34 61 | description iDRACs 62 | no shutdown 63 | ! 64 | interface vlan47 65 | shutdown 66 | ! 67 | interface vlan461 68 | description R3-RHOCP 69 | no shutdown 70 | ip address 192.168.46.4/26 71 | ! 72 | interface port-channel1 73 | no shutdown 74 | switchport access vlan 461 75 | mtu 9216 76 | lacp fallback enable 77 | lacp fallback preemption disable 78 | lacp fallback timeout 100 79 | vlt-port-channel 1 80 | ! 81 | interface port-channel2 82 | no shutdown 83 | switchport access vlan 461 84 | mtu 9216 85 | lacp fallback enable 86 | lacp fallback preemption disable 87 | lacp fallback timeout 100 88 | vlt-port-channel 2 89 | ! 90 | interface port-channel3 91 | no shutdown 92 | switchport access vlan 461 93 | mtu 9216 94 | lacp fallback enable 95 | lacp fallback preemption disable 96 | lacp fallback timeout 100 97 | vlt-port-channel 3 98 | ! 99 | interface port-channel4 100 | no shutdown 101 | switchport access vlan 461 102 | mtu 9216 103 | lacp fallback enable 104 | lacp fallback preemption disable 105 | lacp fallback timeout 100 106 | vlt-port-channel 4 107 | ! 108 | interface port-channel5 109 | no shutdown 110 | switchport access vlan 461 111 | mtu 9216 112 | lacp fallback enable 113 | lacp fallback preemption disable 114 | lacp fallback timeout 100 115 | vlt-port-channel 5 116 | ! 117 | interface port-channel6 118 | no shutdown 119 | switchport access vlan 461 120 | mtu 9216 121 | lacp fallback enable 122 | lacp fallback preemption disable 123 | lacp fallback timeout 100 124 | vlt-port-channel 6 125 | ! 126 | interface port-channel7 127 | no shutdown 128 | switchport access vlan 461 129 | mtu 9216 130 | lacp fallback enable 131 | lacp fallback preemption disable 132 | lacp fallback timeout 100 133 | vlt-port-channel 7 134 | ! 135 | interface port-channel8 136 | no shutdown 137 | switchport access vlan 461 138 | mtu 9216 139 | lacp fallback enable 140 | lacp fallback preemption disable 141 | lacp fallback timeout 100 142 | vlt-port-channel 8 143 | ! 144 | interface port-channel9 145 | no shutdown 146 | switchport access vlan 461 147 | mtu 9216 148 | lacp fallback enable 149 | lacp fallback preemption disable 150 | lacp fallback timeout 100 151 | vlt-port-channel 9 152 | ! 153 | interface port-channel10 154 | no shutdown 155 | switchport access vlan 461 156 | mtu 9216 157 | lacp fallback enable 158 | lacp fallback preemption disable 159 | lacp fallback timeout 100 160 | vlt-port-channel 10 161 | ! 162 | interface port-channel11 163 | no shutdown 164 | switchport access vlan 461 165 | mtu 9216 166 | lacp fallback enable 167 | lacp fallback preemption disable 168 | lacp fallback timeout 100 169 | vlt-port-channel 11 170 | ! 171 | interface port-channel34 172 | description down-S3048 173 | no shutdown 174 | switchport mode trunk 175 | switchport trunk allowed vlan 34,47,461 176 | mtu 9216 177 | vlt-port-channel 34 178 | ! 179 | interface port-channel100 180 | description Uplink-R4-S5232F 181 | no shutdown 182 | switchport mode trunk 183 | switchport trunk allowed vlan 32,34,47,461 184 | mtu 9216 185 | vlt-port-channel 100 186 | ! 187 | interface mgmt1/1/1 188 | no shutdown 189 | no ip address dhcp 190 | ip address 192.168.33.45/24 191 | ipv6 address autoconfig 192 | ! 193 | interface ethernet1/1/1 194 | description r3csah->p2p2 195 | no shutdown 196 | channel-group 1 mode active 197 | no switchport 198 | mtu 9216 199 | flowcontrol receive on 200 | flowcontrol transmit on 201 | ! 202 | interface ethernet1/1/2 203 | description r3m1->p2p2 204 | no shutdown 205 | channel-group 2 mode active 206 | no switchport 207 | mtu 9216 208 | flowcontrol receive on 209 | flowcontrol transmit on 210 | ! 211 | interface ethernet1/1/3 212 | description r3m2->p2p2 213 | no shutdown 214 | channel-group 3 mode active 215 | no switchport 216 | mtu 9216 217 | flowcontrol receive on 218 | flowcontrol transmit on 219 | ! 220 | interface ethernet1/1/4 221 | description r3m3->p2p2 222 | no shutdown 223 | channel-group 4 mode active 224 | no switchport 225 | mtu 9216 226 | flowcontrol receive on 227 | flowcontrol transmit on 228 | ! 229 | interface ethernet1/1/5 230 | no shutdown 231 | channel-group 5 mode active 232 | no switchport 233 | mtu 9216 234 | flowcontrol receive on 235 | flowcontrol transmit on 236 | ! 237 | interface ethernet1/1/6 238 | description r3w2->p2p2 239 | no shutdown 240 | channel-group 6 mode active 241 | no switchport 242 | mtu 9216 243 | flowcontrol receive on 244 | flowcontrol transmit on 245 | ! 246 | interface ethernet1/1/7 247 | description r3bsw3->p2p2 248 | no shutdown 249 | channel-group 7 mode active 250 | no switchport 251 | mtu 9216 252 | flowcontrol receive on 253 | flowcontrol transmit on 254 | ! 255 | interface ethernet1/1/8 256 | shutdown 257 | channel-group 8 mode active 258 | no switchport 259 | mtu 9216 260 | flowcontrol receive on 261 | flowcontrol transmit on 262 | ! 263 | interface ethernet1/1/9 264 | shutdown 265 | channel-group 9 mode active 266 | no switchport 267 | mtu 9216 268 | flowcontrol receive off 269 | ! 270 | interface ethernet1/1/10 271 | shutdown 272 | channel-group 10 mode active 273 | no switchport 274 | mtu 9216 275 | flowcontrol receive off 276 | ! 277 | interface ethernet1/1/11 278 | no shutdown 279 | switchport access vlan 461 280 | flowcontrol receive on 281 | flowcontrol transmit on 282 | ! 283 | interface ethernet1/1/12 284 | no shutdown 285 | switchport access vlan 1 286 | flowcontrol receive off 287 | ! 288 | interface ethernet1/1/13 289 | no shutdown 290 | switchport access vlan 1 291 | flowcontrol receive off 292 | ! 293 | interface ethernet1/1/14 294 | no shutdown 295 | switchport access vlan 1 296 | flowcontrol receive off 297 | ! 298 | interface ethernet1/1/15 299 | no shutdown 300 | switchport access vlan 1 301 | flowcontrol receive off 302 | ! 303 | interface ethernet1/1/16 304 | no shutdown 305 | switchport access vlan 1 306 | flowcontrol receive off 307 | ! 308 | interface ethernet1/1/17 309 | no shutdown 310 | switchport access vlan 1 311 | flowcontrol receive off 312 | ! 313 | interface ethernet1/1/18 314 | no shutdown 315 | switchport access vlan 1 316 | flowcontrol receive off 317 | ! 318 | interface ethernet1/1/19 319 | no shutdown 320 | switchport access vlan 1 321 | flowcontrol receive off 322 | ! 323 | interface ethernet1/1/20 324 | no shutdown 325 | switchport access vlan 1 326 | flowcontrol receive off 327 | ! 328 | interface ethernet1/1/21 329 | no shutdown 330 | switchport access vlan 1 331 | flowcontrol receive off 332 | ! 333 | interface ethernet1/1/22 334 | no shutdown 335 | switchport access vlan 1 336 | flowcontrol receive off 337 | ! 338 | interface ethernet1/1/23 339 | no shutdown 340 | switchport access vlan 1 341 | flowcontrol receive off 342 | ! 343 | interface ethernet1/1/24 344 | no shutdown 345 | switchport access vlan 1 346 | flowcontrol receive off 347 | ! 348 | interface ethernet1/1/25 349 | no shutdown 350 | switchport access vlan 1 351 | flowcontrol receive off 352 | ! 353 | interface ethernet1/1/26 354 | no shutdown 355 | switchport access vlan 1 356 | flowcontrol receive off 357 | ! 358 | interface ethernet1/1/27 359 | no shutdown 360 | switchport access vlan 1 361 | flowcontrol receive off 362 | ! 363 | interface ethernet1/1/28 364 | no shutdown 365 | switchport access vlan 1 366 | flowcontrol receive off 367 | ! 368 | interface ethernet1/1/29 369 | no shutdown 370 | switchport access vlan 1 371 | flowcontrol receive off 372 | ! 373 | interface ethernet1/1/30 374 | description Up-po100 375 | no shutdown 376 | channel-group 100 mode active 377 | no switchport 378 | mtu 9216 379 | flowcontrol receive on 380 | flowcontrol transmit on 381 | ! 382 | interface ethernet1/1/31 383 | description VLTi 384 | no shutdown 385 | no switchport 386 | flowcontrol receive off 387 | ! 388 | interface ethernet1/1/32 389 | description VLTi 390 | no shutdown 391 | no switchport 392 | flowcontrol receive off 393 | ! 394 | interface ethernet1/1/33 395 | description iSCSI-47 396 | no shutdown 397 | switchport access vlan 47 398 | mtu 9216 399 | flowcontrol receive off 400 | ! 401 | interface ethernet1/1/34 402 | description Down-S3048 403 | no shutdown 404 | channel-group 34 mode active 405 | no switchport 406 | mtu 9216 407 | flowcontrol receive on 408 | flowcontrol transmit on 409 | ! 410 | management route 0.0.0.0/0 192.168.33.1 411 | ! 412 | vlt-domain 1 413 | backup destination 192.168.33.44 414 | discovery-interface ethernet1/1/31-1/1/32 415 | peer-routing 416 | primary-priority 65535 417 | vlt-mac 00:33:03:03:03:aa 418 | ! 419 | snmp-server contact "Contact Support" 420 | ! 421 | telemetry 422 | -------------------------------------------------------------------------------- /examples/S5232F-1: -------------------------------------------------------------------------------- 1 | ! Version 10.5.1.0 2 | ! Last configuration change at Feb 25 15:06:23 2020 3 | ! 4 | ip vrf default 5 | ! 6 | no ip igmp snooping enable 7 | interface breakout 1/1/1 map 100g-1x 8 | interface breakout 1/1/2 map 100g-1x 9 | interface breakout 1/1/3 map 100g-1x 10 | interface breakout 1/1/4 map 100g-1x 11 | interface breakout 1/1/5 map 100g-1x 12 | interface breakout 1/1/6 map 100g-1x 13 | interface breakout 1/1/7 map 100g-1x 14 | interface breakout 1/1/8 map 100g-1x 15 | interface breakout 1/1/9 map 100g-1x 16 | interface breakout 1/1/10 map 100g-1x 17 | interface breakout 1/1/11 map 100g-1x 18 | interface breakout 1/1/12 map 100g-1x 19 | interface breakout 1/1/13 map 100g-1x 20 | interface breakout 1/1/14 map 100g-1x 21 | interface breakout 1/1/15 map 100g-1x 22 | interface breakout 1/1/16 map 100g-1x 23 | interface breakout 1/1/17 map 100g-1x 24 | interface breakout 1/1/18 map 100g-1x 25 | interface breakout 1/1/19 map 100g-1x 26 | interface breakout 1/1/20 map 100g-1x 27 | interface breakout 1/1/21 map 100g-1x 28 | interface breakout 1/1/22 map 100g-1x 29 | interface breakout 1/1/23 map 100g-1x 30 | interface breakout 1/1/24 map 100g-1x 31 | interface breakout 1/1/25 map 100g-1x 32 | interface breakout 1/1/26 map 100g-1x 33 | interface breakout 1/1/27 map 100g-1x 34 | interface breakout 1/1/28 map 100g-1x 35 | interface breakout 1/1/29 map 100g-1x 36 | interface breakout 1/1/30 map 100g-1x 37 | interface breakout 1/1/31 map 100g-1x 38 | interface breakout 1/1/32 map 100g-1x 39 | hostname S5232F-1 40 | no multicast snooping flood-restrict 41 | iscsi target port 860 42 | iscsi target port 3260 43 | system-user linuxadmin password $6$h7FDkFKa$UMENTFKvxaBbIbGrTPQpocbyZCZ7zDUa5l5fqsJazcN6sWiXJGdVfhIhbmaTMZ.BzSDVsgdLBabI.pyS/cKlQ/ 44 | no ipv6 mld snooping enable 45 | spanning-tree mode rstp 46 | spanning-tree rstp priority 28672 47 | username admin password $6$q9QBeYjZ$jfxzVqGhkxX3smxJSH9DDz7/3OJc6m5wjF8nnLD7/VKx8SloIhp4NoGZs0I/UNwh8WVuxwfd9q4pWIgNs5BKH. role sysadmin priv-lvl 15 48 | aaa authentication login default local 49 | aaa authentication login console local 50 | ! 51 | class-map type application class-iscsi 52 | ! 53 | policy-map type application policy-iscsi 54 | ! 55 | interface vlan1 56 | no shutdown 57 | ! 58 | interface vlan32 59 | no shutdown 60 | ! 61 | interface vlan34 62 | description iDRACs 63 | no shutdown 64 | ! 65 | interface vlan47 66 | shutdown 67 | mtu 9216 68 | ! 69 | interface vlan461 70 | description R3-RHOCP 71 | no shutdown 72 | ip address 192.168.46.3/26 73 | ! 74 | interface port-channel1 75 | no shutdown 76 | switchport access vlan 461 77 | mtu 9216 78 | lacp fallback enable 79 | lacp fallback preemption disable 80 | lacp fallback timeout 100 81 | vlt-port-channel 1 82 | ! 83 | interface port-channel2 84 | no shutdown 85 | switchport access vlan 461 86 | mtu 9216 87 | lacp fallback enable 88 | lacp fallback preemption disable 89 | lacp fallback timeout 100 90 | vlt-port-channel 2 91 | ! 92 | interface port-channel3 93 | no shutdown 94 | switchport access vlan 461 95 | mtu 9216 96 | lacp fallback enable 97 | lacp fallback preemption disable 98 | lacp fallback timeout 100 99 | vlt-port-channel 3 100 | ! 101 | interface port-channel4 102 | no shutdown 103 | switchport access vlan 461 104 | mtu 9216 105 | lacp fallback enable 106 | lacp fallback preemption disable 107 | lacp fallback timeout 100 108 | vlt-port-channel 4 109 | ! 110 | interface port-channel5 111 | no shutdown 112 | switchport access vlan 461 113 | mtu 9216 114 | lacp fallback enable 115 | lacp fallback preemption disable 116 | lacp fallback timeout 100 117 | vlt-port-channel 5 118 | ! 119 | interface port-channel6 120 | no shutdown 121 | switchport access vlan 461 122 | mtu 9216 123 | lacp fallback enable 124 | lacp fallback preemption disable 125 | lacp fallback timeout 100 126 | vlt-port-channel 6 127 | ! 128 | interface port-channel7 129 | no shutdown 130 | switchport access vlan 461 131 | mtu 9216 132 | lacp fallback enable 133 | lacp fallback preemption disable 134 | lacp fallback timeout 100 135 | vlt-port-channel 7 136 | ! 137 | interface port-channel8 138 | no shutdown 139 | switchport access vlan 461 140 | mtu 9216 141 | lacp fallback enable 142 | lacp fallback preemption disable 143 | lacp fallback timeout 100 144 | vlt-port-channel 8 145 | ! 146 | interface port-channel9 147 | no shutdown 148 | switchport access vlan 461 149 | mtu 9216 150 | lacp fallback enable 151 | lacp fallback preemption disable 152 | lacp fallback timeout 100 153 | vlt-port-channel 9 154 | ! 155 | interface port-channel10 156 | no shutdown 157 | switchport access vlan 461 158 | mtu 9216 159 | lacp fallback enable 160 | lacp fallback preemption disable 161 | lacp fallback timeout 100 162 | vlt-port-channel 10 163 | ! 164 | interface port-channel11 165 | no shutdown 166 | switchport access vlan 461 167 | mtu 9216 168 | lacp fallback enable 169 | lacp fallback preemption disable 170 | lacp fallback timeout 100 171 | vlt-port-channel 11 172 | ! 173 | interface port-channel34 174 | description down-S3048 175 | no shutdown 176 | switchport mode trunk 177 | switchport trunk allowed vlan 34,47,461 178 | mtu 9216 179 | vlt-port-channel 34 180 | ! 181 | interface port-channel100 182 | description Uplink-R4-S5232F 183 | no shutdown 184 | switchport mode trunk 185 | switchport access vlan 1 186 | switchport trunk allowed vlan 32,34,47,461 187 | mtu 9216 188 | vlt-port-channel 100 189 | ! 190 | interface mgmt1/1/1 191 | no shutdown 192 | no ip address dhcp 193 | ip address 192.168.33.44/24 194 | ipv6 address autoconfig 195 | ! 196 | interface ethernet1/1/1 197 | description r3csah->p2p1 198 | no shutdown 199 | channel-group 1 mode active 200 | no switchport 201 | mtu 9216 202 | flowcontrol receive on 203 | flowcontrol transmit on 204 | ! 205 | interface ethernet1/1/2 206 | description r3m1->p2p1 207 | no shutdown 208 | channel-group 2 mode active 209 | no switchport 210 | mtu 9216 211 | flowcontrol receive on 212 | flowcontrol transmit on 213 | lacp port-priority 32002 214 | ! 215 | interface ethernet1/1/3 216 | description r3m2->p2p1 217 | no shutdown 218 | channel-group 3 mode active 219 | no switchport 220 | mtu 9216 221 | flowcontrol receive on 222 | flowcontrol transmit on 223 | lacp port-priority 32003 224 | ! 225 | interface ethernet1/1/4 226 | description r3m3->p2p1 227 | no shutdown 228 | channel-group 4 mode active 229 | no switchport 230 | mtu 9216 231 | flowcontrol receive on 232 | flowcontrol transmit on 233 | lacp port-priority 32004 234 | ! 235 | interface ethernet1/1/5 236 | description r3w1->p2p1 237 | no shutdown 238 | channel-group 5 mode active 239 | no switchport 240 | mtu 9216 241 | flowcontrol receive on 242 | flowcontrol transmit on 243 | lacp port-priority 32005 244 | ! 245 | interface ethernet1/1/6 246 | description r3w2->p2p1 247 | no shutdown 248 | channel-group 6 mode active 249 | no switchport 250 | mtu 9216 251 | flowcontrol receive on 252 | flowcontrol transmit on 253 | lacp port-priority 32006 254 | ! 255 | interface ethernet1/1/7 256 | description r3bsw3->p2p1 257 | no shutdown 258 | channel-group 7 mode active 259 | no switchport 260 | mtu 9216 261 | flowcontrol receive on 262 | flowcontrol transmit on 263 | lacp port-priority 32007 264 | ! 265 | interface ethernet1/1/8 266 | no shutdown 267 | switchport access vlan 461 268 | mtu 9216 269 | flowcontrol receive on 270 | flowcontrol transmit on 271 | ! 272 | interface ethernet1/1/9 273 | no shutdown 274 | switchport access vlan 461 275 | mtu 9216 276 | flowcontrol receive on 277 | flowcontrol transmit on 278 | ! 279 | interface ethernet1/1/10 280 | no shutdown 281 | switchport access vlan 461 282 | mtu 9216 283 | flowcontrol receive on 284 | flowcontrol transmit on 285 | ! 286 | interface ethernet1/1/11 287 | no shutdown 288 | switchport access vlan 461 289 | flowcontrol receive on 290 | flowcontrol transmit on 291 | ! 292 | interface ethernet1/1/12 293 | shutdown 294 | switchport access vlan 1 295 | flowcontrol receive off 296 | ! 297 | interface ethernet1/1/13 298 | shutdown 299 | switchport access vlan 1 300 | flowcontrol receive off 301 | ! 302 | interface ethernet1/1/14 303 | shutdown 304 | switchport access vlan 1 305 | flowcontrol receive off 306 | ! 307 | interface ethernet1/1/15 308 | shutdown 309 | switchport access vlan 1 310 | flowcontrol receive off 311 | ! 312 | interface ethernet1/1/16 313 | shutdown 314 | switchport access vlan 1 315 | flowcontrol receive off 316 | ! 317 | interface ethernet1/1/17 318 | no shutdown 319 | switchport access vlan 1 320 | flowcontrol receive off 321 | ! 322 | interface ethernet1/1/18 323 | no shutdown 324 | switchport access vlan 1 325 | flowcontrol receive off 326 | ! 327 | interface ethernet1/1/19 328 | no shutdown 329 | switchport access vlan 1 330 | flowcontrol receive off 331 | ! 332 | interface ethernet1/1/20 333 | no shutdown 334 | switchport access vlan 1 335 | flowcontrol receive off 336 | ! 337 | interface ethernet1/1/21 338 | no shutdown 339 | switchport access vlan 1 340 | flowcontrol receive off 341 | ! 342 | interface ethernet1/1/22 343 | no shutdown 344 | switchport access vlan 1 345 | flowcontrol receive off 346 | ! 347 | interface ethernet1/1/23 348 | no shutdown 349 | switchport access vlan 1 350 | flowcontrol receive off 351 | ! 352 | interface ethernet1/1/24 353 | no shutdown 354 | switchport access vlan 1 355 | flowcontrol receive off 356 | ! 357 | interface ethernet1/1/25 358 | no shutdown 359 | switchport access vlan 1 360 | flowcontrol receive off 361 | ! 362 | interface ethernet1/1/26 363 | no shutdown 364 | switchport access vlan 1 365 | flowcontrol receive off 366 | ! 367 | interface ethernet1/1/27 368 | no shutdown 369 | switchport access vlan 1 370 | flowcontrol receive off 371 | ! 372 | interface ethernet1/1/28 373 | no shutdown 374 | switchport access vlan 1 375 | flowcontrol receive off 376 | ! 377 | interface ethernet1/1/29 378 | no shutdown 379 | switchport access vlan 1 380 | flowcontrol receive off 381 | ! 382 | interface ethernet1/1/30 383 | description Up-po100 384 | no shutdown 385 | channel-group 100 mode active 386 | no switchport 387 | mtu 9216 388 | flowcontrol receive on 389 | flowcontrol transmit on 390 | ! 391 | interface ethernet1/1/31 392 | description VLTi 393 | no shutdown 394 | no switchport 395 | flowcontrol receive off 396 | ! 397 | interface ethernet1/1/32 398 | description VLTi 399 | no shutdown 400 | no switchport 401 | flowcontrol receive off 402 | ! 403 | interface ethernet1/1/33 404 | description iSCSI-47 405 | no shutdown 406 | switchport access vlan 47 407 | mtu 9216 408 | flowcontrol receive off 409 | ! 410 | interface ethernet1/1/34 411 | description Down-S3048 412 | no shutdown 413 | channel-group 34 mode active 414 | no switchport 415 | mtu 9216 416 | flowcontrol receive on 417 | flowcontrol transmit on 418 | ! 419 | management route 0.0.0.0/0 192.168.33.1 420 | ! 421 | vlt-domain 1 422 | backup destination 192.168.33.45 423 | discovery-interface ethernet1/1/31-1/1/32 424 | peer-routing 425 | vlt-mac 00:33:03:03:03:aa 426 | ! 427 | snmp-server contact "Contact Support" 428 | ! 429 | telemetry 430 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | Copyright (c) 2017 Intel Corporation 180 | 181 | Licensed under the Apache License, Version 2.0 (the "License"); 182 | you may not use this file except in compliance with the License. 183 | You may obtain a copy of the License at 184 | 185 | http://www.apache.org/licenses/LICENSE-2.0 186 | 187 | Unless required by applicable law or agreed to in writing, software 188 | distributed under the License is distributed on an "AS IS" BASIS, 189 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 190 | See the License for the specific language governing permissions and 191 | limitations under the License. 192 | -------------------------------------------------------------------------------- /python/helper.py: -------------------------------------------------------------------------------- 1 | import ipaddress 2 | import getpass 3 | import hashlib 4 | import json 5 | import logging 6 | import os 7 | import re 8 | import requests 9 | import sys 10 | import time 11 | 12 | from urllib.request import urlopen 13 | from urllib.error import HTTPError 14 | from urllib3.exceptions import InsecureRequestWarning 15 | 16 | 17 | def get_user_response(message=''): 18 | """ 19 | User response invoked when error exists 20 | 21 | """ 22 | valid_responses = ['y', 'NO'] 23 | response = '' 24 | while response not in valid_responses: 25 | logging.error('{}'.format(message)) 26 | response = input('Do you want to continue (y/NO): ') 27 | if response not in valid_responses: 28 | logging.info('Valid responses are \'y\' or \'NO\'') 29 | 30 | if response == 'NO': 31 | logging.info('QUITTING!!') 32 | sys.exit() 33 | 34 | 35 | def create_dir(directory): 36 | """ 37 | create directory recursively 38 | 39 | """ 40 | try: 41 | os.makedirs(directory) 42 | logging.info('successfully created directory {}'.format(directory)) 43 | except OSError: 44 | logging.error('creating directory {} failed'.format(directory)) 45 | 46 | def check_path(path, isfile=False, isdir=False): 47 | """ 48 | returns if path given is a file or directory 49 | 50 | """ 51 | 52 | return os.path.isfile(path) if isfile else os.path.isdir(path) 53 | 54 | def set_values(user_input, default, check=''): 55 | """ 56 | sets default value if user input is empty value. 57 | ensures integer value if necessary 58 | 59 | """ 60 | if check == 'integer' and user_input != '': 61 | user_input = check_user_input_if_integer(user_input) 62 | 63 | return default if not user_input else user_input 64 | 65 | def validate_url(url): 66 | """ 67 | validates url and checks if any HTTP Errors 68 | 69 | """ 70 | url_verify = '' 71 | 72 | try: 73 | url_verify = urlopen(url) 74 | except HTTPError: 75 | get_user_response(message='Error validating URL: {}'.format(url)) 76 | 77 | return url_verify 78 | 79 | def check_user_input_if_integer(user_input): 80 | """ 81 | check if user input is integer and not any other data type 82 | 83 | """ 84 | integer_input = '' 85 | while not integer_input: 86 | try: 87 | integer_input = int(user_input) 88 | except ValueError: 89 | logging.warn('only integer number accepted') 90 | user_input = input('enter a number: ') 91 | 92 | return integer_input 93 | 94 | def get_ip(node_name='', ip_type=''): 95 | """ 96 | get the ip address of a node 97 | 98 | """ 99 | ip = '' 100 | 101 | while True: 102 | ip = input('ip address for {} in {} node: '.format(ip_type, node_name)) 103 | ip_check = validate_ip(ip) 104 | if ip_check: 105 | break 106 | else: 107 | logging.warn('ip address should be in format: x.x.x.x') 108 | 109 | return ip 110 | 111 | def validate_file(directory, filename, url): 112 | re_hash = '' 113 | hash_value = False 114 | logging.info('validating file {} in {}'.format(filename, directory)) 115 | 116 | with open('{}/{}'.format(directory, filename), 'rb') as f: 117 | bytes = f.read() 118 | re_hash = hashlib.sha256(bytes).hexdigest() 119 | logging.info('sha256 for file {} is {}'.format(filename, re_hash)) 120 | 121 | with open('{}/rhcos.txt'.format(directory)) as f: 122 | if re_hash and re_hash in f.read(): 123 | logging.info('sha256sum for file {} is validated in rhcos.txt'.format(filename)) 124 | hash_value = True 125 | 126 | if not hash_value: 127 | with open('{}/client.txt'.format(directory)) as f: 128 | if re_hash and re_hash in f.read(): 129 | logging.info('sha256sum for file {} is validated in client.txt'.format(filename)) 130 | hash_value = True 131 | 132 | return hash_value 133 | 134 | def validate_ip(ip): 135 | """ 136 | validates ip address format 137 | 138 | """ 139 | valid_ip = '' 140 | try: 141 | valid_ip = str(ipaddress.ip_address(ip)) 142 | except ValueError: 143 | logging.error('ip address \'{}\' is not valid: '.format(ip)) 144 | 145 | return valid_ip 146 | 147 | def validate_port(port): 148 | """ 149 | validate ports to ensure HAProxy ports are not reused 150 | 151 | """ 152 | invalid_ports = [80, 443, 6443, 22623] 153 | while True: 154 | try: 155 | check_for_string = port.isdigit() 156 | if not check_for_string: 157 | logging.warn('port has to be an integer') 158 | else: 159 | invalid_ports.index(int(port)) 160 | logging.warn('ports {} are not allowed'.format(invalid_ports)) 161 | port = input('enter a port: ') 162 | except AttributeError: 163 | break 164 | except ValueError: 165 | break 166 | 167 | return port 168 | 169 | def validate_network_cidr(network_cidr): 170 | """ 171 | validate ip address with cidr format. defaults to /24 if only IP is given 172 | 173 | """ 174 | compressed_network_cidr = '' 175 | while True: 176 | try: 177 | compressed_network_cidr = ipaddress.ip_network(network_cidr) 178 | break 179 | except ValueError: 180 | logging.warn('input should be in format x.x.x.x/x') 181 | network_cidr = input('enter the network cidr: ') 182 | 183 | return compressed_network_cidr.compressed 184 | 185 | 186 | def validate_cidr(cidr): 187 | """ 188 | validates subnet in cidr format. 189 | 190 | """ 191 | check_integer = '' 192 | while not check_integer: 193 | check_integer = check_user_input_if_integer(cidr) 194 | if check_integer and check_integer < 32: 195 | pass 196 | else: 197 | cidr = input('user input has to be an integer and less than 32: ') 198 | 199 | return cidr 200 | 201 | def check_ip_ping(ip): 202 | 203 | command = 'ping -c 3 {} > /dev/null'.format(ip) 204 | response = os.system(command) 205 | 206 | return response 207 | 208 | def get_idrac_creds(ip): 209 | user = input('enter the idrac user for {}: '.format(ip)) 210 | passwd = getpass.getpass('enter the idrac password for {}: '.format(ip)) 211 | 212 | return user, passwd 213 | 214 | def map_interfaces_network(network_devices): 215 | devices = [] 216 | if network_devices: 217 | for network_device in network_devices: 218 | device = list(map(lambda interface: interface.encode('ascii'), network_device.values())) 219 | try: 220 | devices.append(device[0].decode("utf-8").split('/')[-1]) 221 | except IndexError: 222 | logging.error('Did not find any network devices') 223 | 224 | return devices 225 | 226 | def connect_to_idrac(user, passwd, base_api_url): 227 | """ 228 | establishes connection to idrac 229 | 230 | """ 231 | requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning) 232 | response = '' 233 | status_code = None 234 | try: 235 | response = requests.get(base_api_url, verify=False, auth=(user, passwd), 236 | timeout=5) 237 | except requests.exceptions.ConnectTimeout: 238 | logging.info('timeout') 239 | get_user_response(message='connecting to idrac timeout') 240 | except Exception as e: 241 | logging.error('{}'.format(e)) 242 | get_user_response(message='connecting to idrac unknown exception occurred') 243 | 244 | try: 245 | status_code = response.status_code 246 | except AttributeError: 247 | logging.error('could not get idrac response status code') 248 | 249 | return None 250 | 251 | return response if status_code == 200 else None 252 | 253 | def get_network_devices(user, passwd, base_api_url): 254 | """ 255 | get list of network devices from iDRAC 256 | 257 | """ 258 | network_devices = '' 259 | response = connect_to_idrac(user, passwd, base_api_url) 260 | if response and response.json(): 261 | network_devices_info = response.json() 262 | try: 263 | network_devices = network_devices_info[u'Members'] 264 | except KeyError: 265 | network_devices = '' 266 | get_user_response(message='could not get network devices info') 267 | else: 268 | get_user_response(message='idrac connection status code is 401') 269 | 270 | return network_devices 271 | 272 | def generate_network_devices_menu(devices, purpose=''): 273 | """ 274 | generate a list of network devices menu obtained from iDRAC 275 | 276 | """ 277 | menu = {} 278 | i = 1 279 | choice = '' 280 | devices.sort() 281 | for device in devices: 282 | menu[int(i)] = device 283 | i += 1 284 | while True: 285 | options = menu.keys() 286 | for entry in options: 287 | logging.info('{} -> {}'.format(entry, menu[entry])) 288 | choice = input('Select the interface used by {}: '.format(purpose)) 289 | try: 290 | menu[int(choice)] 291 | break 292 | except KeyError: 293 | logging.warn('Invalid option') 294 | continue 295 | except ValueError: 296 | logging.warn('Input option should be integer and not string') 297 | continue 298 | 299 | selected_network_device = menu[int(choice)] 300 | logging.info('selected interface is: {}'.format(menu[int(choice)])) 301 | 302 | return selected_network_device 303 | 304 | def get_mac_address(selected_network_device, base_api_url, user, passwd): 305 | """ 306 | get mac address for a selected network device 307 | 308 | """ 309 | url = '{}/{}'.format(base_api_url, selected_network_device) 310 | device_mac_address = '' 311 | try: 312 | response = requests.get(url, verify=False, auth=(user, passwd), 313 | timeout=5) 314 | except requests.exceptions.ConnectionTimeout: 315 | logging.error('failed to establish connection to get mac address') 316 | 317 | try: 318 | network_device_info = response.json() 319 | except ValueError: 320 | logging.error('check URL, iDRAC user and password may be invalid') 321 | logging.info('{}'.format(url)) 322 | 323 | try: 324 | device_mac_address = network_device_info[u'MACAddress'] 325 | except KeyError: 326 | logging.error('No MAC Address found for network devices') 327 | logging.info('{}'.format(selected_network_device)) 328 | 329 | return device_mac_address 330 | 331 | def get_network_device_mac(devices, user, passwd, base_api_url): 332 | """ 333 | lists available network devices from iDRAC 334 | generates a menu of network devices 335 | obtains mac address for the network device 336 | 337 | """ 338 | network_device_mac_address = '' 339 | 340 | if devices: 341 | selected_network_device = generate_network_devices_menu(devices, purpose='DHCP') 342 | network_device_mac_address = get_mac_address(selected_network_device, base_api_url, user, passwd) 343 | 344 | if network_device_mac_address: 345 | logging.info('device {} mac address is {}'.format(selected_network_device, network_device_mac_address)) 346 | 347 | return network_device_mac_address 348 | 349 | def get_device_enumeration(device, os=''): 350 | integrated_nic_pattern = 'Integrated' 351 | nic_slot_pattern = 'NIC.Slot.' 352 | enumeration = '' 353 | 354 | if integrated_nic_pattern in device: 355 | enumeration_postfix = device.split('NIC.Integrated.1-')[1].split('-')[0] 356 | if os == 'rhcos': 357 | enumeration = 'eno' + enumeration_postfix 358 | if os == 'rhel': 359 | enumeration = 'em' + enumeration_postfix 360 | 361 | if nic_slot_pattern in device: 362 | slot_number = device.split('NIC.Slot.')[1].split('-')[0] 363 | port_number = device.split('NIC.Slot.')[1].split('-')[1] 364 | if os == 'rhcos': 365 | enumeration = 'ens' + slot_number + 'f' + str(int(port_number)-1) 366 | if os == 'rhel': 367 | enumeration = 'p' + slot_number + 'p' + port_number 368 | 369 | return enumeration 370 | 371 | 372 | def main(): 373 | pass 374 | 375 | if __name__ == "__main__": 376 | main() 377 | -------------------------------------------------------------------------------- /ansible/roles/http/templates/httpd.conf.j2: -------------------------------------------------------------------------------- 1 | # 2 | # This is the main Apache HTTP server configuration file. It contains the 3 | # configuration directives that give the server its instructions. 4 | # See for detailed information. 5 | # In particular, see 6 | # 7 | # for a discussion of each configuration directive. 8 | # 9 | # See the httpd.conf(5) man page for more information on this configuration, 10 | # and httpd.service(8) on using and configuring the httpd service. 11 | # 12 | # Do NOT simply read the instructions in here without understanding 13 | # what they do. They're here only as hints or reminders. If you are unsure 14 | # consult the online docs. You have been warned. 15 | # 16 | # Configuration and logfile names: If the filenames you specify for many 17 | # of the server's control files begin with "/" (or "drive:/" for Win32), the 18 | # server will use that explicit path. If the filenames do *not* begin 19 | # with "/", the value of ServerRoot is prepended -- so 'log/access_log' 20 | # with ServerRoot set to '/www' will be interpreted by the 21 | # server as '/www/log/access_log', where as '/log/access_log' will be 22 | # interpreted as '/log/access_log'. 23 | 24 | # 25 | # ServerRoot: The top of the directory tree under which the server's 26 | # configuration, error, and log files are kept. 27 | # 28 | # Do not add a slash at the end of the directory path. If you point 29 | # ServerRoot at a non-local disk, be sure to specify a local disk on the 30 | # Mutex directive, if file-based mutexes are used. If you wish to share the 31 | # same ServerRoot for multiple httpd daemons, you will need to change at 32 | # least PidFile. 33 | # 34 | ServerRoot "/etc/httpd" 35 | 36 | # 37 | # Listen: Allows you to bind Apache to specific IP addresses and/or 38 | # ports, instead of the default. See also the 39 | # directive. 40 | # 41 | # Change this to Listen on specific IP addresses as shown below to 42 | # prevent Apache from glomming onto all bound IP addresses. 43 | # 44 | #Listen 12.34.56.78:80 45 | Listen {{ http_port }} 46 | 47 | # 48 | # Dynamic Shared Object (DSO) Support 49 | # 50 | # To be able to use the functionality of a module which was built as a DSO you 51 | # have to place corresponding `LoadModule' lines at this location so the 52 | # directives contained in it are actually available _before_ they are used. 53 | # Statically compiled modules (those listed by `httpd -l') do not need 54 | # to be loaded here. 55 | # 56 | # Example: 57 | # LoadModule foo_module modules/mod_foo.so 58 | # 59 | Include conf.modules.d/*.conf 60 | 61 | # 62 | # If you wish httpd to run as a different user or group, you must run 63 | # httpd as root initially and it will switch. 64 | # 65 | # User/Group: The name (or #number) of the user/group to run httpd as. 66 | # It is usually good practice to create a dedicated user and group for 67 | # running httpd, as with most system services. 68 | # 69 | User apache 70 | Group apache 71 | 72 | # 'Main' server configuration 73 | # 74 | # The directives in this section set up the values used by the 'main' 75 | # server, which responds to any requests that aren't handled by a 76 | # definition. These values also provide defaults for 77 | # any containers you may define later in the file. 78 | # 79 | # All of these directives may appear inside containers, 80 | # in which case these default settings will be overridden for the 81 | # virtual host being defined. 82 | # 83 | 84 | # 85 | # ServerAdmin: Your address, where problems with the server should be 86 | # e-mailed. This address appears on some server-generated pages, such 87 | # as error documents. e.g. admin@your-domain.com 88 | # 89 | ServerAdmin root@localhost 90 | 91 | # 92 | # ServerName gives the name and port that the server uses to identify itself. 93 | # This can often be determined automatically, but we recommend you specify 94 | # it explicitly to prevent problems during startup. 95 | # 96 | # If your host doesn't have a registered DNS name, enter its IP address here. 97 | # 98 | #ServerName www.example.com:80 99 | 100 | # 101 | # Deny access to the entirety of your server's filesystem. You must 102 | # explicitly permit access to web content directories in other 103 | # blocks below. 104 | # 105 | 106 | AllowOverride none 107 | Require all denied 108 | 109 | 110 | # 111 | # Note that from this point forward you must specifically allow 112 | # particular features to be enabled - so if something's not working as 113 | # you might expect, make sure that you have specifically enabled it 114 | # below. 115 | # 116 | 117 | # 118 | # DocumentRoot: The directory out of which you will serve your 119 | # documents. By default, all requests are taken from this directory, but 120 | # symbolic links and aliases may be used to point to other locations. 121 | # 122 | DocumentRoot "/var/www/html" 123 | 124 | # 125 | # Relax access to content within /var/www. 126 | # 127 | 128 | AllowOverride None 129 | # Allow open access: 130 | Require all granted 131 | 132 | 133 | # Further relax access to the default document root: 134 | 135 | # 136 | # Possible values for the Options directive are "None", "All", 137 | # or any combination of: 138 | # Indexes Includes FollowSymLinks SymLinksifOwnerMatch ExecCGI MultiViews 139 | # 140 | # Note that "MultiViews" must be named *explicitly* --- "Options All" 141 | # doesn't give it to you. 142 | # 143 | # The Options directive is both complicated and important. Please see 144 | # http://httpd.apache.org/docs/2.4/mod/core.html#options 145 | # for more information. 146 | # 147 | Options Indexes FollowSymLinks 148 | 149 | # 150 | # AllowOverride controls what directives may be placed in .htaccess files. 151 | # It can be "All", "None", or any combination of the keywords: 152 | # Options FileInfo AuthConfig Limit 153 | # 154 | AllowOverride None 155 | 156 | # 157 | # Controls who can get stuff from this server. 158 | # 159 | Require all granted 160 | 161 | 162 | # 163 | # DirectoryIndex: sets the file that Apache will serve if a directory 164 | # is requested. 165 | # 166 | 167 | DirectoryIndex index.html 168 | 169 | 170 | # 171 | # The following lines prevent .htaccess and .htpasswd files from being 172 | # viewed by Web clients. 173 | # 174 | 175 | Require all denied 176 | 177 | 178 | # 179 | # ErrorLog: The location of the error log file. 180 | # If you do not specify an ErrorLog directive within a 181 | # container, error messages relating to that virtual host will be 182 | # logged here. If you *do* define an error logfile for a 183 | # container, that host's errors will be logged there and not here. 184 | # 185 | ErrorLog "logs/error_log" 186 | 187 | # 188 | # LogLevel: Control the number of messages logged to the error_log. 189 | # Possible values include: debug, info, notice, warn, error, crit, 190 | # alert, emerg. 191 | # 192 | LogLevel warn 193 | 194 | 195 | # 196 | # The following directives define some format nicknames for use with 197 | # a CustomLog directive (see below). 198 | # 199 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined 200 | LogFormat "%h %l %u %t \"%r\" %>s %b" common 201 | 202 | 203 | # You need to enable mod_logio.c to use %I and %O 204 | LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio 205 | 206 | 207 | # 208 | # The location and format of the access logfile (Common Logfile Format). 209 | # If you do not define any access logfiles within a 210 | # container, they will be logged here. Contrariwise, if you *do* 211 | # define per- access logfiles, transactions will be 212 | # logged therein and *not* in this file. 213 | # 214 | #CustomLog "logs/access_log" common 215 | 216 | # 217 | # If you prefer a logfile with access, agent, and referer information 218 | # (Combined Logfile Format) you can use the following directive. 219 | # 220 | CustomLog "logs/access_log" combined 221 | 222 | 223 | 224 | # 225 | # Redirect: Allows you to tell clients about documents that used to 226 | # exist in your server's namespace, but do not anymore. The client 227 | # will make a new request for the document at its new location. 228 | # Example: 229 | # Redirect permanent /foo http://www.example.com/bar 230 | 231 | # 232 | # Alias: Maps web paths into filesystem paths and is used to 233 | # access content that does not live under the DocumentRoot. 234 | # Example: 235 | # Alias /webpath /full/filesystem/path 236 | # 237 | # If you include a trailing / on /webpath then the server will 238 | # require it to be present in the URL. You will also likely 239 | # need to provide a section to allow access to 240 | # the filesystem path. 241 | 242 | # 243 | # ScriptAlias: This controls which directories contain server scripts. 244 | # ScriptAliases are essentially the same as Aliases, except that 245 | # documents in the target directory are treated as applications and 246 | # run by the server when requested rather than as documents sent to the 247 | # client. The same rules about trailing "/" apply to ScriptAlias 248 | # directives as to Alias. 249 | # 250 | ScriptAlias /cgi-bin/ "/var/www/cgi-bin/" 251 | 252 | 253 | 254 | # 255 | # "/var/www/cgi-bin" should be changed to whatever your ScriptAliased 256 | # CGI directory exists, if you have that configured. 257 | # 258 | 259 | AllowOverride None 260 | Options None 261 | Require all granted 262 | 263 | 264 | 265 | # 266 | # TypesConfig points to the file containing the list of mappings from 267 | # filename extension to MIME-type. 268 | # 269 | TypesConfig /etc/mime.types 270 | 271 | # 272 | # AddType allows you to add to or override the MIME configuration 273 | # file specified in TypesConfig for specific file types. 274 | # 275 | #AddType application/x-gzip .tgz 276 | # 277 | # AddEncoding allows you to have certain browsers uncompress 278 | # information on the fly. Note: Not all browsers support this. 279 | # 280 | #AddEncoding x-compress .Z 281 | #AddEncoding x-gzip .gz .tgz 282 | # 283 | # If the AddEncoding directives above are commented-out, then you 284 | # probably should define those extensions to indicate media types: 285 | # 286 | AddType application/x-compress .Z 287 | AddType application/x-gzip .gz .tgz 288 | 289 | # 290 | # AddHandler allows you to map certain file extensions to "handlers": 291 | # actions unrelated to filetype. These can be either built into the server 292 | # or added with the Action directive (see below) 293 | # 294 | # To use CGI scripts outside of ScriptAliased directories: 295 | # (You will also need to add "ExecCGI" to the "Options" directive.) 296 | # 297 | #AddHandler cgi-script .cgi 298 | 299 | # For type maps (negotiated resources): 300 | #AddHandler type-map var 301 | 302 | # 303 | # Filters allow you to process content before it is sent to the client. 304 | # 305 | # To parse .shtml files for server-side includes (SSI): 306 | # (You will also need to add "Includes" to the "Options" directive.) 307 | # 308 | AddType text/html .shtml 309 | AddOutputFilter INCLUDES .shtml 310 | 311 | 312 | # 313 | # Specify a default charset for all content served; this enables 314 | # interpretation of all content as UTF-8 by default. To use the 315 | # default browser choice (ISO-8859-1), or to allow the META tags 316 | # in HTML content to override this choice, comment out this 317 | # directive: 318 | # 319 | AddDefaultCharset UTF-8 320 | 321 | 322 | # 323 | # The mod_mime_magic module allows the server to use various hints from the 324 | # contents of the file itself to determine its type. The MIMEMagicFile 325 | # directive tells the module where the hint definitions are located. 326 | # 327 | MIMEMagicFile conf/magic 328 | 329 | 330 | # 331 | # Customizable error responses come in three flavors: 332 | # 1) plain text 2) local redirects 3) external redirects 333 | # 334 | # Some examples: 335 | #ErrorDocument 500 "The server made a boo boo." 336 | #ErrorDocument 404 /missing.html 337 | #ErrorDocument 404 "/cgi-bin/missing_handler.pl" 338 | #ErrorDocument 402 http://www.example.com/subscription_info.html 339 | # 340 | 341 | # 342 | # EnableMMAP and EnableSendfile: On systems that support it, 343 | # memory-mapping or the sendfile syscall may be used to deliver 344 | # files. This usually improves server performance, but must 345 | # be turned off when serving from networked-mounted 346 | # filesystems or if support for these functions is otherwise 347 | # broken on your system. 348 | # Defaults if commented: EnableMMAP On, EnableSendfile Off 349 | # 350 | #EnableMMAP off 351 | EnableSendfile on 352 | 353 | # Supplemental configuration 354 | # 355 | # Load config files in the "/etc/httpd/conf.d" directory, if any. 356 | IncludeOptional conf.d/*.conf 357 | -------------------------------------------------------------------------------- /python/generate_inventory_file.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import os 3 | import logging 4 | import socket 5 | import sys 6 | import yaml 7 | 8 | from random import randint 9 | from urllib.request import urlopen 10 | from urllib.request import urlretrieve 11 | 12 | from log_config import log_setup 13 | from helper import create_dir, check_path, get_ip, get_network_device_mac, \ 14 | set_values, validate_cidr, validate_ip, validate_file, \ 15 | validate_network_cidr, validate_port, validate_url, \ 16 | check_user_input_if_integer, check_ip_ping, get_network_devices, \ 17 | map_interfaces_network, get_idrac_creds, generate_network_devices_menu, \ 18 | get_device_enumeration, get_user_response, get_mac_address 19 | 20 | from nodes import get_nodes_info 21 | 22 | class InventoryFile: 23 | def __init__(self, inventory_dict = {}, id_user='', id_pass='', version='', nodes_inventory=''): 24 | self.inventory_dict = inventory_dict 25 | self.id_user = id_user 26 | self.id_pass = id_pass 27 | self.version = version 28 | self.nodes_inventory = nodes_inventory 29 | self.nodes_inv = '' 30 | self.software_dir = '' 31 | self.input_choice = '' 32 | self.cluster_install = 0 33 | self.ocp_client_base_url = 'https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest-{}'.format(self.version) 34 | self.ocp_rhcos_base_url = 'https://mirror.openshift.com/pub/openshift-v4/dependencies/rhcos/{}/latest'.format(self.version) 35 | self.ocp_urls = {'openshift_installer': '{}/openshift-install-linux.tar.gz'.format(self.ocp_client_base_url), 36 | 'initramfs': '{}/rhcos-live-initramfs.x86_64.img'.format(self.ocp_rhcos_base_url), 37 | 'kernel_file': '{}/rhcos-live-kernel-x86_64'.format(self.ocp_rhcos_base_url), 38 | 'uefi_file': '{}/rhcos-metal.x86_64.raw.gz'.format(self.ocp_rhcos_base_url), 39 | 'rootfs': '{}/rhcos-live-rootfs.x86_64.img'.format(self.ocp_rhcos_base_url)} 40 | self.task_inputs = """ 41 | 1: download OpenShift software 42 | 2: cluster install 43 | 3: disk info 44 | 4: bind 45 | 5: http 46 | 6: ignition config 47 | 7: print inventory 48 | 8: generate inventory file 49 | 9: Exit 50 | """ 51 | 52 | def clear_screen(self): 53 | """ 54 | performs clean screen 55 | 56 | """ 57 | os.system('clear') 58 | 59 | def set_keys(self): 60 | """ 61 | sets the initial keys for the inventory file 62 | 63 | """ 64 | self.inventory_dict['csah'] = {'hosts': '{}'.format(socket.getfqdn()), 'vars': {}} 65 | 66 | def set_nodes_inventory(self): 67 | nodes_inventory_check = check_path(self.nodes_inventory, isfile=True) 68 | 69 | if nodes_inventory_check: 70 | with open(r'{}'.format(self.nodes_inventory)) as nodes_inv: 71 | self.nodes_inv = yaml.load(nodes_inv, Loader=yaml.FullLoader) 72 | else: 73 | logging.error('incorrect nodes inventory specified: {}'.format(self.nodes_inventory)) 74 | sys.exit() 75 | 76 | def generate_inputs_menu(self): 77 | """ 78 | generates a menu of tasks for user input for each task 79 | 80 | """ 81 | self.clear_screen() 82 | self.input_choice = '' 83 | valid_choices = range(1,10) 84 | while self.input_choice not in valid_choices: 85 | logging.info('{}'.format(self.task_inputs)) 86 | try: 87 | self.input_choice = int(input('task choice for necessary inputs: ')) 88 | if self.input_choice not in valid_choices: 89 | logging.warn('Invalid choice. Valid choice is an integer from 1-9') 90 | except ValueError: 91 | logging.error('Strings not a valid choice') 92 | 93 | logging.debug('user choice is {}'.format(self.input_choice)) 94 | self.get_user_inputs_for_task() 95 | 96 | def get_user_inputs_for_task(self): 97 | """ 98 | performs tasks based on user input 99 | 100 | """ 101 | if self.input_choice == 9: 102 | sys.exit() 103 | elif self.input_choice == 1: 104 | self.get_software_download_dir() 105 | self.get_software() 106 | elif self.input_choice == 2: 107 | self.get_cluster_nodes() 108 | elif self.input_choice == 3: 109 | self.get_disk_name() 110 | elif self.input_choice == 4: 111 | self.get_dns_details() 112 | elif self.input_choice == 5: 113 | self.get_http_details() 114 | elif self.input_choice == 6: 115 | self.get_ignition_details() 116 | elif self.input_choice == 7: 117 | self.display_inventory() 118 | elif self.input_choice == 8: 119 | self.yaml_inventory(inventory_file='generated_inventory') 120 | sys.exit() 121 | self.generate_inputs_menu() 122 | 123 | def get_software_download_dir(self): 124 | """ 125 | get software download directory to download OCP software bits 126 | 127 | """ 128 | self.clear_screen() 129 | default = '/home/ansible/files' 130 | self.software_dir = input('provide complete path of directory to download OCP {} software bits\n' 131 | 'default [/home/ansible/files]: '.format(self.version)) 132 | self.software_dir = set_values(self.software_dir, default) 133 | dest_path_exist = check_path(self.software_dir, isdir=True) 134 | if dest_path_exist: 135 | logging.info('directory {} already exists'.format(self.software_dir)) 136 | else: 137 | logging.info('Creating directory {}'.format(self.software_dir)) 138 | create_dir(self.software_dir) 139 | 140 | self.inventory_dict['csah']['vars']['software_src'] = self.software_dir 141 | 142 | def get_software(self): 143 | """ 144 | performs OCP software bits download from the base urls 145 | specified in the class __init__ 146 | 147 | """ 148 | 149 | logging.info('downloading OCP {} software bits into {}'.format(self.software_dir, self.version)) 150 | urlretrieve('{}/sha256sum.txt'.format(self.ocp_client_base_url),'{}/client.txt'.format(self.software_dir)) 151 | urlretrieve('{}/sha256sum.txt'.format(self.ocp_rhcos_base_url),'{}/rhcos.txt'.format(self.software_dir)) 152 | shasum = False 153 | for url_key in self.ocp_urls.keys(): 154 | url = self.ocp_urls[url_key] 155 | dest_name = url.split('/')[-1] 156 | dest_path = self.software_dir + '/' + dest_name 157 | dest_path_exist = check_path(dest_path, isfile=True) 158 | url_check = '' 159 | if dest_path_exist: 160 | logging.info('file {} already exists in {}'.format(dest_name, self.software_dir)) 161 | shasum = validate_file(self.software_dir, dest_name, self.ocp_rhcos_base_url) 162 | self.inventory_dict['csah']['vars'][url_key] = dest_name 163 | else: 164 | url_check = validate_url(url) 165 | if url_check == '': 166 | logging.error('file {} in {} is not available'.format(dest_name, url_key)) 167 | self.inventory_dict['csah']['vars'][url_key] = '' 168 | 169 | if not shasum: 170 | url_check = validate_url(url) 171 | if url_check == '': 172 | logging.error('file {} in {} is not available'.format(dest_name, url_key)) 173 | self.inventory_dict['csah']['vars'][url_key] = '' 174 | 175 | if url_check != '' and url_check.code == 200 and not shasum: 176 | logging.info('downloading {}'.format(dest_name)) 177 | urlretrieve('{}'.format(url),'{}/{}'.format(self.software_dir, dest_name)) 178 | self.inventory_dict['csah']['vars'][url_key] = dest_name 179 | 180 | def get_cluster_nodes(self): 181 | supported_install = """ 182 | 1. 3 node (control/compute in control nodes) 183 | 2. 6+ node (3 control and 3+ compute) 184 | """ 185 | logging.info('supported cluster install options: {}'.format(supported_install)) 186 | valid_choices = [1, 2] 187 | while self.cluster_install not in valid_choices: 188 | try: 189 | self.cluster_install = int(input('enter cluster install option: ')) 190 | logging.info('option selected: {}'.format(self.cluster_install)) 191 | except ValueError: 192 | logging.error('valid choices are: {}'.format(valid_choices)) 193 | 194 | 195 | self.get_bootstrap_node() 196 | self.get_master_nodes() 197 | if self.cluster_install == 2: 198 | self.get_worker_nodes() 199 | self.inventory_dict['csah']['vars']['cluster_install'] = '6+ node' 200 | else: 201 | self.inventory_dict['csah']['vars']['cluster_install'] = '3 node' 202 | 203 | 204 | def get_bootstrap_node(self): 205 | """ 206 | get details about bootstrap node 207 | 208 | """ 209 | bootstrap_mac = '' 210 | bootstrap_devices = None 211 | self.clear_screen() 212 | bootstrap_name = self.nodes_inv['bootstrap_kvm'][0]['name'] 213 | bootstrap_os_ip = self.nodes_inv['bootstrap_kvm'][0]['ip_os'] 214 | bootstrap_mac = "52:54:00:{}:{}:{}".format(randint(10,99),randint(10,99),randint(10,99)) 215 | logging.debug('adding bootstrap_node values as name: {} ip: {} mac: {}'.format(bootstrap_name, bootstrap_os_ip, 216 | bootstrap_mac)) 217 | self.inventory_dict['csah']['vars']['bootstrap_node'] = [] 218 | bootstrap_keys = ['name','ip','mac'] 219 | bootstrap_values = [bootstrap_name, bootstrap_os_ip, bootstrap_mac] 220 | bootstrap_pairs = dict(zip(bootstrap_keys, bootstrap_values)) 221 | self.inventory_dict['csah']['vars']['bootstrap_node'].append(bootstrap_pairs) 222 | 223 | def get_master_nodes(self): 224 | """ 225 | get details about master node 226 | 227 | """ 228 | self.clear_screen() 229 | self.inventory_dict['csah']['vars']['control_nodes'] = [] 230 | self.inventory_dict['csah']['vars']['num_of_control_nodes'] = len(self.nodes_inv['control_nodes']) 231 | self.inventory_dict = get_nodes_info(node_type='control_nodes', inventory=self.inventory_dict, idrac_user=self.id_user, 232 | idrac_pass=self.id_pass, nodes_info=self.nodes_inv) 233 | 234 | def get_worker_nodes(self): 235 | """ 236 | get details about worker node 237 | 238 | """ 239 | self.clear_screen() 240 | self.inventory_dict['csah']['vars']['compute_nodes'] = [] 241 | self.inventory_dict['csah']['vars']['num_of_compute_nodes'] = len(self.nodes_inv['compute_nodes']) 242 | self.inventory_dict = get_nodes_info(node_type='compute_nodes', inventory=self.inventory_dict, idrac_user=self.id_user, 243 | idrac_pass=self.id_pass, nodes_info=self.nodes_inv) 244 | 245 | def add_new_worker_nodes(self): 246 | """ 247 | get new worker nodes added to inventory file 248 | 249 | """ 250 | current_inventory_file = input('Enter complete path to existing inventory file: ') 251 | file_exists = os.path.exists('{}'.format(current_inventory_file)) 252 | if file_exists: 253 | with open('{}'.format(current_inventory_file), 'r') as file: 254 | self.inventory_dict = yaml.load(file, Loader=yaml.FullLoader) 255 | 256 | try: 257 | self.inventory_dict['csah']['vars']['compute_nodes'] 258 | except KeyError: 259 | logging.error('Inventory file does not contain worker nodes info') 260 | self.inventory_dict['csah']['vars']['cluster_install'] = '6+ node' 261 | self.inventory_dict['csah']['vars']['compute_nodes'] = [] 262 | default = 'nvme0n1' 263 | worker_install_device = input('specify the compute node device that will be installed\n' 264 | 'default [nvme0n1]: ') 265 | worker_install_device = set_values(worker_install_device, default) 266 | self.inventory_dict['csah']['vars']['worker_install_device'] = worker_install_device 267 | 268 | self.inventory_dict = get_nodes_info(node_type='new_compute_nodes', inventory=self.inventory_dict, add=True, 269 | idrac_user=self.id_user, idrac_pass=self.id_pass, nodes_info=self.nodes_inv) 270 | self.yaml_inventory(inventory_file=current_inventory_file) 271 | 272 | sys.exit(2) 273 | else: 274 | logging.error('incorrect file path specified') 275 | sys.exit(2) 276 | 277 | def dhcp_lease_times(self): 278 | """ 279 | get dhcp lease times 280 | 281 | """ 282 | self.clear_screen() 283 | self.inventory_dict['csah']['vars']['default_lease_time'] = 8000 284 | self.inventory_dict['csah']['vars']['max_lease_time'] = 72000 285 | 286 | def get_dns_details(self): 287 | """ 288 | get zone config file and cluster name used by DNS 289 | 290 | """ 291 | self.clear_screen() 292 | cluster_name = input('specify cluster name \n' 293 | 'default [ocp]: ') 294 | default = 'ocp' 295 | cluster_name = set_values(cluster_name, default) 296 | zone_file = input('specify zone file \n' 297 | 'default [/var/named/{}.zones]: '.format(cluster_name)) 298 | default = '/var/named/{}.zones'.format(cluster_name) 299 | zone_file = set_values(zone_file, default) 300 | logging.info('adding zone_file: {} cluster: {}'.format(zone_file, cluster_name)) 301 | self.inventory_dict['csah']['vars']['default_zone_file'] = zone_file 302 | self.inventory_dict['csah']['vars']['cluster'] = cluster_name 303 | 304 | def get_http_details(self): 305 | """ 306 | get http details and directories names created under /var/www/html 307 | 308 | """ 309 | self.clear_screen() 310 | port = input('enter http port \n' 311 | 'default [8080]: ') 312 | default = 8080 313 | port = set_values(port, default) 314 | port = validate_port(port) 315 | ignition_dir = input('specify dir where ignition files will be placed \n' 316 | 'directory will be created under /var/www/html \n' 317 | 'default [ignition]: ') 318 | default = 'ignition' 319 | ignition_dir = set_values(ignition_dir, default) 320 | logging.info('adding http_port: {} http_ignition: {} version: {}'.format(port, ignition_dir, self.version)) 321 | self.inventory_dict['csah']['vars']['http_port'] = int(port) 322 | self.inventory_dict['csah']['vars']['os'] = 'rhcos' 323 | self.inventory_dict['csah']['vars']['http_ignition'] = ignition_dir 324 | self.inventory_dict['csah']['vars']['version'] = self.version 325 | 326 | def get_disk_name(self): 327 | """ 328 | disknames used for each node type. 329 | 330 | """ 331 | self.clear_screen() 332 | default = 'nvme0n1' 333 | logging.info('ensure disknames are absolutely available. Otherwise OpenShift install fails') 334 | master_install_device = input('specify the control plane device that will be installed\n' 335 | 'default [nvme0n1]: ') 336 | master_install_device = set_values(master_install_device, default) 337 | self.inventory_dict['csah']['vars']['master_install_device'] = master_install_device 338 | if self.cluster_install == 1: 339 | pass 340 | else: 341 | worker_install_device = input('specify the compute node device that will be installed\n' 342 | 'default [nvme0n1]: ') 343 | worker_install_device = set_values(worker_install_device, default) 344 | logging.info('adding master_install_device: {} worker_install_device: {}'.format(master_install_device, 345 | worker_install_device)) 346 | self.inventory_dict['csah']['vars']['worker_install_device'] = worker_install_device 347 | 348 | def set_haproxy(self): 349 | """ 350 | sets default values for haproxy 351 | 352 | """ 353 | logging.info('currently only haproxy is supported for load balancing') 354 | self.inventory_dict['csah']['vars']['proxy'] = 'haproxy' 355 | self.inventory_dict['csah']['vars']['haproxy_conf'] = '/etc/haproxy/haproxy.cfg' 356 | self.inventory_dict['csah']['vars']['master_ports'] = [{'port': 6443, 'description': 'apiserver'}, 357 | {'port': 22623 , 'description': 'configserver'}] 358 | self.inventory_dict['csah']['vars']['worker_ports'] = [{'port': 80, 'description': 'http'}, 359 | {'port': 443, 'description': 'https'}] 360 | 361 | def get_ignition_details(self): 362 | """ 363 | get details from users used for install-config.yaml file 364 | 365 | """ 366 | self.clear_screen() 367 | default = 'core' 368 | install_user = input('enter the user used to install openshift\n' 369 | 'DONOT CHANGE THIS VALUE\n' 370 | 'default [core]: ') 371 | install_user = set_values(install_user, default) 372 | default = 'openshift' 373 | install_dir = input('enter the directory where openshift installs\n' 374 | 'directory will be created under /home/core\n' 375 | 'default [openshift]: ') 376 | install_dir = set_values(install_dir, default) 377 | default = '10.128.0.0/14' 378 | pod_network_cidr = input('enter the pod network cidr\n' 379 | 'default [10.128.0.0/14]: ') 380 | pod_network_cidr = set_values(pod_network_cidr, default) 381 | logging.info('pod network cidr: {}'.format(pod_network_cidr)) 382 | pod_network_cidr = validate_network_cidr(pod_network_cidr) 383 | default = 23 384 | host_prefix = input('specify cidr notation for number of ips in each node: \n' 385 | 'cidr number should be an integer and less than 32\n' 386 | 'default [23]: ') 387 | host_prefix = set_values(host_prefix, default) 388 | host_prefix = validate_cidr(host_prefix) 389 | default = '172.30.0.0/16' 390 | service_network_cidr = input('specify the service network cidr\n' 391 | 'default [172.30.0.0/16]: ') 392 | service_network_cidr = set_values(service_network_cidr, default) 393 | service_network_cidr = validate_network_cidr(service_network_cidr) 394 | logging.info('adding install_user: {} install_dir: {} cluster_network_cidr: {}\ 395 | host_prefix: {} service_network_cidr: {}'.format(install_user, install_dir, 396 | pod_network_cidr, host_prefix, 397 | service_network_cidr)) 398 | self.inventory_dict['csah']['vars']['install_user'] = install_user 399 | self.inventory_dict['csah']['vars']['install_dir'] = install_dir 400 | self.inventory_dict['csah']['vars']['cluster_network_cidr'] = pod_network_cidr 401 | self.inventory_dict['csah']['vars']['host_prefix'] = int(host_prefix) 402 | self.inventory_dict['csah']['vars']['service_network_cidr'] = service_network_cidr 403 | 404 | def yaml_inventory(self, inventory_file=''): 405 | """ 406 | generate yaml file using user inputs 407 | 408 | """ 409 | with open(inventory_file, 'w') as invfile: 410 | yaml.dump(self.inventory_dict, invfile, default_flow_style=False, sort_keys=False) 411 | 412 | def display_inventory(self): 413 | """ 414 | display current user input details 415 | 416 | """ 417 | self.clear_screen() 418 | logging.info(yaml.dump(self.inventory_dict, sort_keys=False, default_flow_style=False)) 419 | input('Press Enter to continue ') 420 | 421 | def run(self): 422 | self.set_keys() 423 | self.set_haproxy() 424 | self.dhcp_lease_times() 425 | self.set_nodes_inventory() 426 | self.generate_inputs_menu() 427 | 428 | 429 | def main(): 430 | parser = argparse.ArgumentParser(description="Generate Inventory") 431 | group = parser.add_mutually_exclusive_group() 432 | group.add_argument('--run', help='generate inventory file', action='store_true', required=False) 433 | group.add_argument('--add', help='number of worker nodes', action='store_true', required=False) 434 | parser.add_argument('--ver', type=float, help='specify OpenShift version', required=True, choices=[4.6], default=4.6) 435 | parser.add_argument('--nodes', help='nodes inventory file', required=True) 436 | parser.add_argument('--id_user', help='specify idrac user', required=False) 437 | parser.add_argument('--id_pass', help='specify idrac user', required=False) 438 | parser.add_argument('--debug', help='specify debug logs', action='store_true', required=False) 439 | if len(sys.argv) == 1: 440 | parser.print_help(sys.stderr) 441 | sys.exit() 442 | args = parser.parse_args() 443 | log_setup(log_file='inventory.log', debug=args.debug) 444 | gen_inv_file = InventoryFile(id_user=args.id_user, id_pass=args.id_pass, version=args.ver, nodes_inventory=args.nodes) 445 | if args.run: 446 | gen_inv_file.run() 447 | 448 | if args.add: 449 | gen_inv_file.set_nodes_inventory() 450 | gen_inv_file.add_new_worker_nodes() 451 | 452 | 453 | if __name__ == "__main__": 454 | main() 455 | --------------------------------------------------------------------------------