diff --git a/oai-helm/5g_params.yaml b/oai-helm/5g_params.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3b110ea89b5655741e5ae6ebb7a1b6bb2baa2fc5 --- /dev/null +++ b/oai-helm/5g_params.yaml @@ -0,0 +1,8 @@ +ssh_keys: +- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDrcvnKVl3o2cN7YFmajQ2RqGGRVgL0OhdkQCXpehJSL/7rxD0rURlUCipqAvqzDQ0UvfPDxWKOJSxhZRY0SCOlb4W6WNBW7hTE31AjS0YtH/JUimc99567y3F1937sy3nzt4yAlIAoI3y7ZZKJI4EP29A47TZ2WbAuQhI/TsDbJmNpXLB0XtBvzTMJuPffwJep0nWp2nYyv21NBBk5rQF6yTi2dDJ3DwcatfaIv5o0UeI07mbyEmxV2hVrIxPKv3KG65dBvbvF+sjdFMp0tJUfqDn/FJso+jqlwmmvrtk+8bmhL7vzzMyUXyfCjUV2G+u0GOPjl3Q+rnxjCsl2yEib +k8s-namespace: oai +vnf: +- member-vnf-index: gnbsim + vimAccountId: b0fe741c-37d9-4f42-bce7-b163122a9790 +- member-vnf-index: ext-server + vimAccountId: 74c9e008-28ce-45c4-9634-9aec3177fb76 diff --git a/oai-helm/5gcore_ns/5gcore_nsd.yaml b/oai-helm/5gcore_ns/5gcore_nsd.yaml new file mode 100644 index 0000000000000000000000000000000000000000..de20b1a89eb81882126a270acc0fe612d8a3b2fc --- /dev/null +++ b/oai-helm/5gcore_ns/5gcore_nsd.yaml @@ -0,0 +1,59 @@ +nsd: + nsd: + - description: NS with 1 VNF for gnbsim, 1 VNF for ext server, 1 PNF for VyOS router and 1 KNF for 5G OAI Core + df: + - id: default-df + vnf-profile: + - id: gnbsim + virtual-link-connectivity: + - constituent-cpd-id: + - constituent-base-element-id: gnbsim + constituent-cpd-id: vnf-mgmt-ext + virtual-link-profile-id: mgmtnet + - constituent-cpd-id: + - constituent-base-element-id: gnbsim + constituent-cpd-id: vnf-internal-ext + ip-address: 192.168.1.5 + virtual-link-profile-id: datanet + vnfd-id: gnbsim-vnf + - id: ext-server + virtual-link-connectivity: + - constituent-cpd-id: + - constituent-base-element-id: ext-server + constituent-cpd-id: vnf-mgmt-ext + virtual-link-profile-id: mgmtnet + - constituent-cpd-id: + - constituent-base-element-id: ext-server + constituent-cpd-id: vnf-internal-ext + ip-address: 192.168.1.6 + virtual-link-profile-id: datanet + vnfd-id: ext-dn-vnf + - id: vyos-pnf + virtual-link-connectivity: + - constituent-cpd-id: + - constituent-base-element-id: vyos-pnf + constituent-cpd-id: gateway_public-ext + virtual-link-profile-id: mgmtnet + vnfd-id: vyos_pnf + - id: 5gcore_knf + virtual-link-connectivity: + - constituent-cpd-id: + - constituent-base-element-id: 5gcore_knf + constituent-cpd-id: mgmt-ext + virtual-link-profile-id: mgmtnet + vnfd-id: oai_knf + id: 5gcore-ns + name: 5gcore-ns + version: 1.0 + virtual-link-desc: + - id: mgmtnet + mgmt-network: true + vim-network-name: osm-ext + - id: datanet + vim-network-name: 5g-inter-vm + vnfd-id: + - gnbsim-vnf + - oai_knf + - ext-dn-vnf + - vyos_pnf + diff --git a/oai-helm/README.md b/oai-helm/README.md new file mode 100644 index 0000000000000000000000000000000000000000..74ead57e7e44b1977e75cd2e4688bff850554e0d --- /dev/null +++ b/oai-helm/README.md @@ -0,0 +1,113 @@ +# OAI 5G Core deployment using helm-based EE + +This guide is intended to give all the considerations and descriptors needed to deploy a 5G Core, a gnbsim to emulate access (gNB and UE) and a external network to test. This guide also includes a PNF VyOS Router and its configuration to ensure the connectivity between elements in this architecture. + +## Architecture + +This architecture considers: + +![architecture](img/architecture.png) + +- gnbsim: the open source software to emulate gNB and UE, it's used to connect a gNB and register a UE to the 5G Core. In this case we're deploying it as a VNF. +- 5gcore: The open source project created by OAI (Open Air Interface), it deploys the 5G SA core including NF like NRF, AMF, SMF, UDR, UDM, UPF. In this case we're going to deploy it as a CNF. +- ext-dn: this is the external network we're implementing to test the 5G core, it implements an iperf server to test from the UE. In this case we're deploying it as a VNF. + +## Preparation + +### Infrastructure preparation + +#### Openstack + +Two networks should be defined, one for 5gcore and other for communication between access and external-network: + +- 5g-core-cp: 192.168.18.0/24 (could be shorter), gateway and port-security in the VMs must be disabled +- 5g-inter-vm: 192.168.1.0/29, gateway and port-security in the VMs must be disabled + +#### Kubernetes cluster + +Since 5G Core is going to be deployed on a K8s cluster, take note of what you need in your K8s Cluster first: + +1. K8s cluster must have multus and macvlan installed since 5G core needs PODs with two interfaces. +2. Worker nodes must have one additional interface (ens8) in the network 192.168.18.0/24 (could be shorter), for example worker01 could have 192.168.18.3, worker02 could have 192.168.18.4 and so on. + +#### PNF + +VyOS Router will provide connectivity. It must have 3 interfaces: + +- One should be the default for 5g-core-cp network: 192.168.18.129 +- One should be the default for 5g-inter-vm network: 192.168.1.1 +- One for management, this depends on the infra and will be used to connect from OSM. + +You could use the infra.sh script to create PDU in OSM. You also have the pdu.yaml file, make sure to put there the management IP you have for your VyOS VM. Specific configuration for this deployment will be performed from OSM later. + +## Launching the network service (NS) + +Make sure that VNF/KNF packages are already onboarded in OSM (osm nfpkg-list), if not, you can create them: +``` +osm nfpkg-create gnbsim_vnf +osm nfpkg-create ext-dn_vnf +osm nfpkg-create oai_knf +osm nfpkg-create vyos_ns +``` +Make sure that NS package is already onboarded in OSM (osm nspkg-list), if not, you can create it: +``` +osm nspkg-create 5gcore_ns +``` +Then you have the 5g_core.yaml file which passes additional configuration to the NS, in this case: + +- ssh_keys: this ssh key is of the server we'll be using to ssh to the VNF gnbsim and ext-dn. Another option is using cloud-init to set a password. +- k8s-namespace: a specific namespace is used to deploy the 5G Core in K8s cluster. +- vimAccountId: a different VIM is used to deploy gnbsim and ext-server. +``` +ssh_keys: +- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDrcvnKVl3o2cN7YFmajQ2RqGGRVgL0OhdkQCXpehJSL/7rxD0rURlUCipqAvqzDQ0UvfPDxWKOJSxhZRY0SCOlb4W6WNBW7hTE31AjS0YtH/JUimc99567y3F1937sy3nzt4yAlIAoI3y7ZZKJI4EP29A47TZ2WbAuQhI/TsDbJmNpXLB0XtBvzTMJuPffwJep0nWp2nYyv21NBBk5rQF6yTi2dDJ3DwcatfaIv5o0UeI07mbyEmxV2hVrIxPKv3KG65dBvbvF+sjdFMp0tJUfqDn/FJso+jqlwmmvrtk+8bmhL7vzzMyUXyfCjUV2G+u0GOPjl3Q+rnxjCsl2yEib +k8s-namespace: oai +vnf: +- member-vnf-index: gnbsim + vimAccountId: b0fe741c-37d9-4f42-bce7-b163122a9790 +- member-vnf-index: ext-server + vimAccountId: 74c9e008-28ce-45c4-9634-9aec3177fb76 +``` +The command to instantiate this NS is: +``` +osm ns-create --ns_name 5g --nsd_name 5gcore-ns --vim_account whitecloud --config_file 5g_params.yaml +``` + +## Starting services from OSM + +Since Helm-based EE is used to create primitives for day-1 and day-2, we're going to use the GUI to start external server and gnbsim services: + +### Starting external server service + +First log in OSM and find the NS created, then click in "Action" and click in "Exec Primitive" + +![architecture](img/login.png) + +In the opened window select "VNF Level Primitive", "ext-server", "ext_dn_up", "file" and type "ext-dn-oai", then click in Execute: + +![architecture](img/ext-server.png) + +### Starting gnbsim service + +First log in OSM and find the NS created, then click in "Action" and click in "Exec Primitive" + +![architecture](img/login.png) + +In the opened window select "VNF Level Primitive", "gnbsim", "gnbsim_up", "file" and type "gnbsim", then click in Execute: + +![architecture](img/gnbsim.png) + +With these two primitives executed we're ready to test traffic. + +## Testing traffic + +1. Using management IP assigned to the external server proceed to ssh to the instance (remember to do it from the server you have copied the ssh keys) +2. Execute the iperf command: + ``` + docker exec -ti oai-ext-dn iperf3 -s + ``` +3. Using the management IP assigned to gnbsim proceed to ssh to the instance (remember to do it from the server you have copied the ssh keys) + ``` + docker exec -ti gnbsim iperf3 -c 192.168.70.135 -B 12.1.1.2 + ``` +4. You should be able to see traffic going from gnbsim to external server passing through 5G Core. \ No newline at end of file diff --git a/oai-helm/ext-dn_vnf/.sample_ee_vnfd.yaml.swp b/oai-helm/ext-dn_vnf/.sample_ee_vnfd.yaml.swp new file mode 100644 index 0000000000000000000000000000000000000000..27c3c82570353f02745284eb028f5ae643a57a87 Binary files /dev/null and b/oai-helm/ext-dn_vnf/.sample_ee_vnfd.yaml.swp differ diff --git a/oai-helm/ext-dn_vnf/ext-dn_vnfd.yaml b/oai-helm/ext-dn_vnf/ext-dn_vnfd.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7053886fe83c11d76d58fe2865a8c86bba3ce73c --- /dev/null +++ b/oai-helm/ext-dn_vnf/ext-dn_vnfd.yaml @@ -0,0 +1,130 @@ +vnfd: + description: ext-dn VNF with 2 networks attached + df: + - id: default-df + instantiation-level: + - id: default-instantiation-level + vdu-level: + - number-of-instances: 1 + vdu-id: ext-dn-VM + vdu-profile: + - id: ext-dn-VM + min-number-of-instances: 1 + lcm-operations-configuration: + operate-vnf-op-config: + day1-2: + - config-primitive: + - execution-environment-primitive: ext_dn_up + execution-environment-ref: ext-dn + name: ext_dn_up + parameter: + - data-type: STRING + name: file + - execution-environment-primitive: ext_dn_down + execution-environment-ref: ext-dn + name: ext_dn_down + parameter: + - data-type: STRING + name: file + - execution-environment-primitive: send_command + execution-environment-ref: ext-dn + name: send_command + parameter: + - data-type: STRING + name: file + config-access: + ssh-access: + default-user: ubuntu + required: true + execution-environment-list: + - external-connection-point-ref: vnf-mgmt-ext + helm-chart: eechart + id: ext-dn + id: ext-dn-vnf + initial-config-primitive: + - execution-environment-ref: ext-dn + name: config + parameter: + - name: ssh-hostname + value: + - name: ssh-username + value: ubuntu + seq: 1 + - execution-environment-ref: ext-dn + name: run_script + parameter: + - name: file + value: install_docker.sh + seq: 2 + - execution-environment-ref: ext-dn + name: copy_files + parameter: + - name: file + value: docker-compose.yaml + seq: 3 + ext-cpd: + - id: vnf-mgmt-ext + int-cpd: + cpd: vdu-eth0-int + vdu-id: ext-dn-VM + - id: vnf-internal-ext + int-cpd: + cpd: vdu-eth1-int + vdu-id: ext-dn-VM + id: ext-dn-vnf + mgmt-cp: vnf-mgmt-ext + product-name: ext-dn-vnf + sw-image-desc: + - id: ubuntu20.04 + image: ubuntu20.04 + name: ubuntu20.04 + - id: ubuntu20.04-azure + name: ubuntu20.04-azure + image: Canonical:0001-com-ubuntu-server-focal:20_04-lts:latest + vim-type: azure + - id: ubuntu20.04-gcp + name: ubuntu20.04-gcp + image: ubuntu-os-cloud:image-family:ubuntu-2004-lts + vim-type: gcp + vdu: + - id: ext-dn-VM + int-cpd: + - id: vdu-eth0-int + virtual-network-interface-requirement: + - name: vdu-eth0 + position: 0 + virtual-interface: + type: PARAVIRT + - id: vdu-eth1-int + port-security-enabled: false + virtual-network-interface-requirement: + - name: vdu-eth1 + position: 1 + virtual-interface: + type: PARAVIRT + - id: vdu-eth2-int + virtual-network-interface-requirement: + - name: vdu-eth2 + position: 2 + virtual-interface: + type: PARAVIRT + name: ext-dn-VM + supplemental-boot-data: + boot-data-drive: true + sw-image-desc: ubuntu20.04 + alternative-sw-image-desc: + - ubuntu20.04-azure + - ubuntu20.04-gcp + virtual-compute-desc: ext-dn-VM-compute + virtual-storage-desc: + - ext-dn-VM-storage + version: 1.0 + virtual-compute-desc: + - id: ext-dn-VM-compute + virtual-cpu: + num-virtual-cpu: 1 + virtual-memory: + size: 4.0 + virtual-storage-desc: + - id: ext-dn-VM-storage + size-of-storage: 20 diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/.helmignore b/oai-helm/ext-dn_vnf/helm-charts/eechart/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..50af0317254197a5a019f4ac2f8ecc223f93f5a7 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/Chart.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..414c5f1aa1becbd34d69342874b63db8bb1cb77c --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: OSM EE helm chart +name: eechart +version: 0.1.0 diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz b/oai-helm/ext-dn_vnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2cfb9b29533b6f6837de93a2022eec32c11b0b4b Binary files /dev/null and b/oai-helm/ext-dn_vnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz differ diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/charts/.gitkeep b/oai-helm/ext-dn_vnf/helm-charts/eechart/charts/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/docker-compose.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/docker-compose.yaml new file mode 100644 index 0000000000000000000000000000000000000000..97398b1792d7234c50ff03560c36508599ffb67f --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/docker-compose.yaml @@ -0,0 +1,224 @@ +version: '3.8' +services: + oai-nrf: + container_name: "oai-nrf" + image: oai-nrf:latest + environment: + - NRF_INTERFACE_NAME_FOR_SBI=eth0 + - NRF_INTERFACE_PORT_FOR_SBI=80 + - NRF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 + - NRF_API_VERSION=v1 + - INSTANCE=0 + - PID_DIRECTORY=/var/run + networks: + public_net: + ipv4_address: 192.168.70.130 + volumes: + - ./nrf-healthcheck.sh:/openair-nrf/bin/nrf-healthcheck.sh + healthcheck: + test: /bin/bash -c "/openair-nrf/bin/nrf-healthcheck.sh" + interval: 10s + timeout: 5s + retries: 5 + mysql: + container_name: "mysql" + image: mysql:5.7 + volumes: + - ./oai_db.sql:/docker-entrypoint-initdb.d/oai_db.sql + - ./mysql-healthcheck.sh:/tmp/mysql-healthcheck.sh + environment: + - TZ=Europe/Paris + - MYSQL_DATABASE=oai_db + - MYSQL_USER=test + - MYSQL_PASSWORD=test + - MYSQL_ROOT_PASSWORD=linux + healthcheck: + test: /bin/bash -c "/tmp/mysql-healthcheck.sh" + interval: 10s + timeout: 5s + retries: 5 + networks: + public_net: + ipv4_address: 192.168.70.131 + oai-amf: + container_name: "oai-amf" + image: oai-amf:latest + environment: + - TZ=Europe/paris + - INSTANCE=0 + - PID_DIRECTORY=/var/run + - MCC=208 + - MNC=95 + - REGION_ID=128 + - AMF_SET_ID=1 + - SERVED_GUAMI_MCC_0=208 + - SERVED_GUAMI_MNC_0=95 + - SERVED_GUAMI_REGION_ID_0=128 + - SERVED_GUAMI_AMF_SET_ID_0=1 + - SERVED_GUAMI_MCC_1=460 + - SERVED_GUAMI_MNC_1=11 + - SERVED_GUAMI_REGION_ID_1=10 + - SERVED_GUAMI_AMF_SET_ID_1=1 + - PLMN_SUPPORT_MCC=208 + - PLMN_SUPPORT_MNC=95 + - PLMN_SUPPORT_TAC=0xa000 + - SST_0=222 + - SD_0=123 + - SST_1=1 + - SD_1=12 + - AMF_INTERFACE_NAME_FOR_NGAP=eth0 + - AMF_INTERFACE_NAME_FOR_N11=eth0 + - SMF_INSTANCE_ID_0=1 + - SMF_FQDN_0=oai-smf + - SMF_IPV4_ADDR_0=0.0.0.0 + - SMF_HTTP_VERSION_0=v1 + - SELECTED_0=true + - SMF_INSTANCE_ID_1=2 + - SMF_FQDN_1=oai-smf + - SMF_IPV4_ADDR_1=0.0.0.0 + - SMF_HTTP_VERSION_1=v1 + - SELECTED_1=false + - MYSQL_SERVER=192.168.70.131 + - MYSQL_USER=root + - MYSQL_PASS=linux + - MYSQL_DB=oai_db + - OPERATOR_KEY=63bfa50ee6523365ff14c1f45f88737d + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NF_REGISTRATION=yes + - SMF_SELECTION=yes + - USE_FQDN_DNS=yes + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf + - AUSF_IPV4_ADDRESS=127.0.0.1 + - AUSF_PORT=80 + - AUSF_API_VERSION=v1 + - AUSF_FQDN=oai-ausf + depends_on: + - mysql + volumes: + - ./amf-healthcheck.sh:/openair-amf/bin/amf-healthcheck.sh + healthcheck: + test: /bin/bash -c "/openair-amf/bin/amf-healthcheck.sh" + interval: 10s + timeout: 15s + retries: 5 + networks: + public_net: + ipv4_address: 192.168.70.132 + oai-smf: + container_name: "oai-smf" + image: oai-smf:latest + environment: + - TZ=Europe/Paris + - INSTANCE=0 + - PID_DIRECTORY=/var/run + - SMF_INTERFACE_NAME_FOR_N4=eth0 + - SMF_INTERFACE_NAME_FOR_SBI=eth0 + - SMF_INTERFACE_PORT_FOR_SBI=80 + - SMF_INTERFACE_HTTP2_PORT_FOR_SBI=9090 + - SMF_API_VERSION=v1 + - DEFAULT_DNS_IPV4_ADDRESS=192.168.18.129 + - DEFAULT_DNS_SEC_IPV4_ADDRESS=192.168.18.129 + - AMF_IPV4_ADDRESS=0.0.0.0 + - AMF_PORT=80 + - AMF_API_VERSION=v1 + - AMF_FQDN=oai-amf + - UDM_IPV4_ADDRESS=127.0.0.1 + - UDM_PORT=80 + - UDM_API_VERSION=v1 + - UDM_FQDN=localhost + - UPF_IPV4_ADDRESS=192.168.70.134 + - UPF_FQDN_0=oai-spgwu + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf + - REGISTER_NRF=yes + - DISCOVER_UPF=yes + - USE_FQDN_DNS=yes + depends_on: + - oai-nrf + volumes: + - ./smf-healthcheck.sh:/openair-smf/bin/smf-healthcheck.sh + healthcheck: + test: /bin/bash -c "/openair-smf/bin/smf-healthcheck.sh" + interval: 10s + timeout: 5s + retries: 5 + networks: + public_net: + ipv4_address: 192.168.70.133 + oai-spgwu: + container_name: "oai-spgwu" + image: oai-spgwu-tiny:latest + environment: + - TZ=Europe/Paris + - PID_DIRECTORY=/var/run + - SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP=eth0 + - SGW_INTERFACE_NAME_FOR_SX=eth0 + - PGW_INTERFACE_NAME_FOR_SGI=eth0 + - NETWORK_UE_NAT_OPTION=yes + - NETWORK_UE_IP=12.1.1.0/24 + - SPGWC0_IP_ADDRESS=192.168.70.133 + - BYPASS_UL_PFCP_RULES=no + - MCC=208 + - MNC=95 + - MNC03=095 + - TAC=40960 + - GW_ID=1 + - REALM=openairinterface.org + - ENABLE_5G_FEATURES=yes + - REGISTER_NRF=yes + - USE_FQDN_NRF=yes + - UPF_FQDN_5G=oai-spgwu + - NRF_IPV4_ADDRESS=192.168.70.130 + - NRF_PORT=80 + - NRF_API_VERSION=v1 + - NRF_FQDN=oai-nrf + - NSSAI_SST_0=222 + - NSSAI_SD_0=123 + - DNN_0=default + depends_on: + - oai-nrf + cap_add: + - NET_ADMIN + - SYS_ADMIN + cap_drop: + - ALL + privileged: true + volumes: + - ./spgwu-healthcheck.sh:/openair-spgwu-tiny/bin/spgwu-healthcheck.sh + healthcheck: + test: /bin/bash -c "/openair-spgwu-tiny/bin/spgwu-healthcheck.sh" + interval: 10s + timeout: 5s + retries: 5 + networks: + public_net: + ipv4_address: 192.168.70.134 + oai-ext-dn: + image: ubuntu:bionic + privileged: true + container_name: oai-ext-dn + entrypoint: /bin/bash -c \ + "apt update; apt install -y iptables iproute2 iperf3 iputils-ping;"\ + "iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;"\ + "ip route add 12.1.1.0/24 via 192.168.70.129 dev eth0; sleep infinity" + #depends_on: + # - oai-spgwu + networks: + public_net: + ipv4_address: 192.168.70.135 +networks: + # public_net: + # external: + # name: demo-oai-public-net + public_net: + driver: bridge + name: demo-oai-public-net + ipam: + config: + - subnet: 192.168.70.128/26 + driver_opts: + com.docker.network.bridge.name: "demo-oai" diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/install.sh b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/install.sh new file mode 100755 index 0000000000000000000000000000000000000000..db8f0538a1c1e508094f2a19bb1ab1e8acbee55e --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/install.sh @@ -0,0 +1,36 @@ +#!/bin/bash +## +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +echo "Updating operating system" +apt-get update + +# Install ansible libraries +echo "Installing ansible" +apt-get install -y software-properties-common +apt-add-repository --yes --update ppa:ansible/ansible +apt install -y ansible + +# Install library to execute command remotely by ssh +echo "Installing asynssh" +python3 -m pip install asyncssh + +# Install ping system command +apt install -y iputils-ping + +# Install HTTP python library +python3 -m pip install requests + +# Install MySQL library +python3 -m pip install mysql-connector-python diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/install_docker.sh b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/install_docker.sh new file mode 100644 index 0000000000000000000000000000000000000000..c6033e5345fe03dd09550822d5f1737c9b52d6e5 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/install_docker.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -eux +sudo -s < /dev/null +apt-get -y update +apt-get -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin +groupadd docker +usermod -aG docker ubuntu +newgrp docker + +curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose +chmod +x /usr/local/bin/docker-compose + +sysctl net.ipv4.conf.all.forwarding=1 +iptables -P FORWARD ACCEPT +ip route add 192.168.18.0/24 via 192.168.1.1 dev ens4 +ip route add 12.1.1.0/24 via 192.168.1.1 dev ens4 + +EOF diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/mylib.py b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/mylib.py new file mode 100644 index 0000000000000000000000000000000000000000..c0bd3bc8cdebf42c2467d8042a095d94a6664cb3 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/mylib.py @@ -0,0 +1,80 @@ +## +# Copyright 2022 Telefonica Investigacion y Desarrollo, S.A.U. +# This file is part of OSM +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## + +import logging +import asyncio +import asyncssh +import time + + +from mysql.connector import connect, Error + +logger = logging.getLogger("osm_ee.vnf") + + +async def ssh_exec(host: str, user: str, command: str + ) -> (int, str): + """ + Execute a remote command via SSH. + """ + + try: + async with asyncssh.connect(host, + username=user, + known_hosts=None) as conn: + logger.debug("Executing command '{}'".format(command)) + result = await conn.run(command) + logger.debug("Result: {}".format(result)) + return result.exit_status, result.stderr + except Exception as e: + logger.error("Error: {}".format(repr(e))) + return -1, str(e) + + +def mysql_query(host: str, user: str, password: str, retries: int, query: str + ) -> (int, str): + """ + Execute a query to a MySQL database. + """ + + text = "" + logger.debug("Host: '{}', user: '{}', password: '{}', query: '{}'".format(host, user, password, query)) + for i in range(0, retries): + try: + with connect( + host=host, + user=user, + password=password, + ) as connection: + with connection.cursor() as cursor: + cursor.execute(query) + for (db) in cursor: + logger.debug(db) + text = text + str(db[0]) + ", " + return 0, text[0:len(text)-2] + except Error as e: + text = str(e) + logger.debug("Error: {}".format(e)) + time.sleep(3) + continue + + return -1, text diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/playbook.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/playbook.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bc6013d7e5a0557d5a41cd2211d50e85c0d71222 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/playbook.yaml @@ -0,0 +1,14 @@ +--- +- hosts: all + become: yes + tasks: + - name: Wait 120 seconds, but only start checking after 10 seconds + wait_for_connection: + delay: 20 + timeout: 120 + - name: Install packages + apt: + name: + - "{{ app }}" + state: latest + cache_valid_time: 3600 diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/run_ssh.sh b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/run_ssh.sh new file mode 100755 index 0000000000000000000000000000000000000000..8b58b3cce67868565722c481427d683a14a84fe4 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/run_ssh.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +date "+%H:%M:%S Starting $0..." +IP=$1 +USERNAME=$2 +SCRIPT=$3 +PARAMS=$4 + +DIR=$(dirname $0) + +date "+%H:%M:%S Waiting for $IP to be ready..." +i=5 +while ! ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" 'exit' ; do + date "+%H:%M:%S Error accessing $IP, retrying..." + sleep 5 + i=$(( $i - 1 )) + [ $i -ge 0 ] || exit 1 +done + +date "+%H:%M:%S SSH server is up, sending script '${DIR}/${SCRIPT}'..." +scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${DIR}/${SCRIPT} "$USERNAME"@"$IP": +if [ $? -ne 0 ]; then + date "+%H:%M:%S scp error" + exit 1 +fi +date "+%H:%M:%S OK. Setting file permissions" +ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" "chmod a+x $SCRIPT" +if [ $? -ne 0 ]; then + date "+%H:%M:%S ssh error" + exit 1 +fi + +COMMAND="./$SCRIPT" +[ ${#PARAMS} -ge 0 ] || COMMAND="${COMMAND=} $PARAMS" +date "+%H:%M:%S Running '$COMMAND' on $IP..." +ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" "$COMMAND" +if [ $? -ne 0 ]; then + date "+%H:%M:%S ssh error" + exit 1 +fi + +date "+%H:%M:%S End" +exit 0 diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/source/vnf_ee.py b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/vnf_ee.py new file mode 100644 index 0000000000000000000000000000000000000000..fea9bc751eb6e407461b40974d6cd0f2f79cb839 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/source/vnf_ee.py @@ -0,0 +1,206 @@ +## +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +import asyncio +import asyncssh +import requests +import logging +import os + + +from osm_ee.exceptions import VnfException + +import osm_ee.util.util_ee as util_ee +import osm_ee.util.util_ansible as util_ansible +import osm_ee.vnf.mylib as mylib + +class VnfEE: + + PLAYBOOK_PATH = "/app/EE/osm_ee/vnf" + SSH_SCRIPT = "/app/EE/osm_ee/vnf/run_ssh.sh" + + def __init__(self, config_params): + self.logger = logging.getLogger('osm_ee.vnf') + self.config_params = config_params + + # config method saves SSH access parameters (host and username) for future use by other methods. + # It is mandatory in any case. + async def config(self, id, params): + self.logger.debug("Execute action config, params: {}".format(params)) + # Config action is special, params are merged with previous config calls + self.config_params.update(params) + required_params = ["ssh-hostname"] + self._check_required_params(self.config_params, required_params) + yield "OK", "Configured" + + # This method implements the "run_script" primitive. Uncomment and modify it if a primitive requires executing a user + # script in the VDU. It needs "file" parameter (script's file to run, must be in "source" directory) + # and optionally "parameters" (command-line arguments for script). + async def run_script(self, id, params): + self.logger.debug("Execute action run_script, params: '{}'".format(params)) + self._check_required_params(params, ["file"]) + + command = "bash " + self.SSH_SCRIPT + " " + self.config_params["ssh-hostname"] + " " + self.config_params["ssh-username"] + " " + params["file"] + if "parameters" in params: + command += " \"" + params.get("parameters", "") + "\"" + self.logger.debug("Command: '{}'".format(command)) + return_code, stdout, stderr = await util_ee.local_async_exec(command) + if return_code != 0: + yield "ERROR", "return code {}: {}".format(return_code, stderr.decode()) + else: + yield "OK", stdout.decode() + + # This method implements the "copy_files" primitive. Uncomment and modify it if a primitive requires + # to copy files to a VNF. It needs file name parameter (file must be in "source" directory). + + async def copy_files(self, id, params): + self.logger.debug("Execute action copy_files, params: '{}'".format(params)) + self._check_required_params(params, ["file"]) + + command= "scp" + " -o StrictHostKeyChecking=no /app/EE/osm_ee/vnf/" + params["file"] + " " + self.config_params["ssh-username"] + "@" + self.config_params["ssh-hostname"] + ":" + params["file"] + self.logger.debug("Command: '{}'".format(command)) + return_code, stdout, stderr = await util_ee.local_async_exec(command) + if return_code != 0: + yield "ERROR", "return code {}: {}".format(return_code, stderr.decode()) + else: + yield "OK", stdout.decode() + + # This method implements the "ansible_playbook" primitive. Uncomment and modify it if a primitive requires + # executing an Ansible Playbook. It needs "playbook-name" parameter (playbook file, must be in "source" directory). + # async def ansible_playbook(self, id, params): + # self.logger.debug("Execute action ansible_playbook, params: '{}'".format(params)) + + # try: + # self._check_required_params(params, ["playbook-name"]) + # params["ansible_user"] = self.config_params["ssh-username"] + # inventory = self.config_params["ssh-hostname"] + "," + # playbook = self.PLAYBOOK_PATH + "/" + params["playbook-name"] + # os.environ["ANSIBLE_HOST_KEY_CHECKING"] = "False" + # return_code, stdout, stderr = await util_ansible.execute_playbook(playbook, inventory, params) + # status = "OK" if return_code == 0 else "ERROR" + # yield status, stdout + stderr + # except Exception as e: + # self.logger.debug("Error executing ansible playbook: {}".format(repr(e))) + # yield "ERROR", str(e) + + # This method implements the "ping" primitive. Uncomment and modify it if a primitive requires + # executing a local command (such as ping) on EE. It uses "ssh-hostname" as ping destination. + # async def ping(self, id, params): + # self.logger.debug("Execute action ping, params: '{}'".format(params)) + + # command = "ping -c 3 " + self.config_params["ssh-hostname"] + # return_code, stdout, stderr = await util_ee.local_async_exec(command) + # if return_code != 0: + # yield "ERROR", "return code {}: {}".format(return_code, stderr.decode()) + # else: + # yield "OK", stdout.decode() + + # This method implements the "http_check" primitive. Uncomment and modify it if a primitive requires + # executing embedded python code on VfnEE class. It requests "http:///" using a HTTP library. + # async def http_check(self, id, params): + # self.logger.debug("Execute action http_check, params: '{}'".format(params)) + + # try: + # session = requests.Session() + # url = 'http://' + self.config_params["ssh-hostname"] + # self.logger.debug("HTTP GET {}...".format(url)) + # req = session.get(url) + # self.logger.debug("{}".format(req.text)) + # if req.status_code == 200: + # yield "OK", req.text + # else: + # yield "ERROR", req.text + # except Exception as e: + # self.logger.error("HTTP error: {}".format(repr(e))) + # yield "ERROR", str(e) + + # This method implements the "touch" primitive. Uncomment and modify it if you need a primitive that + # imports a user-defined python library. It only needs "file" parameter for creating it in VDU via SSH. + # async def touch(self, id, params): + # self.logger.debug("Execute action touch, params: '{}'".format(params)) + # + # self._check_required_params(params, ["file"]) + # command = "touch" + " " + params["file"] + # return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + # if return_code != 0: + # yield "ERROR", description + # else: + # yield "OK", description + + # This method implements the "gnbsim_up" primitive. Uncomment and modify it if you need a primitive that + # starts up the gnbsim to test 5G OAI Core. It only needs "file" parameter, in this case use gnbsim. + async def ext_dn_up(self, id, params): + self.logger.debug("Execute action gnbsim_up, params: '{}'".format(params)) + + self._check_required_params(params, ["file"]) + command = "docker-compose up -d oai-ext-dn" + return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + if return_code != 0: + yield "ERROR", description + else: + yield "OK", description + + # This method implements the "gnbsim_down" primitive. Uncomment and modify it if you need a primitive that + # stops the gnbsim for testing 5G OAI Core. It only needs "file" parameter, in this case use gnbsim. + async def ext_dn_down(self, id, params): + self.logger.debug("Execute action gnbsim_down, params: '{}'".format(params)) + + self._check_required_params(params, ["file"]) + command = "docker-compose down" + return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + if return_code != 0: + yield "ERROR", description + else: + yield "OK", description + + # This method implements the "send_command" primitive. Uncomment and modify it if you need a primitive that + # sends any command to the VM through SSH. It only needs "file" parameter which contains the command to send. + async def send_command(self, id, params): + self.logger.debug("Execute action send_command, params: '{}'".format(params)) + + self._check_required_params(params, ["file"]) + command = params["file"] + return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + if return_code != 0: + yield "ERROR", description + else: + yield "OK", description + + # This method implements the "check_database" primitive. Uncomment and modify it if a primitive requires + # accessing to a service provided by a helm subchart. Access parameters are read from environment variables + # async def check_database(self, id, params): + # self.logger.debug("Execute action check_database, params: '{}'".format(params)) + + # host = os.getenv('mysql_host') + # user = os.getenv('mysql_user') + # password = os.getenv('mysql_password') + # retries = 3 + # query = "SHOW DATABASES" + # return_code, description = mylib.mysql_query(host, user, password, retries, query) + # if return_code != 0: + # yield "ERROR", description + # else: + # yield "OK", description + + + # Static method that verifies whether a parameter exists in the map + @staticmethod + def _check_required_params(params, required_params): + for required_param in required_params: + if required_param not in params: + raise VnfException("Missing required param: {}".format(required_param)) + diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/NOTES.txt b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/NOTES.txt new file mode 100755 index 0000000000000000000000000000000000000000..c52fc2c419ef6f4cccfb63fd93ca7379bfc04cf7 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "eechart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "eechart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "eechart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "eechart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/_helpers.tpl b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/_helpers.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d3e28e0260b8bff2fdef09046df0abaea885739c --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "eechart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "eechart.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "eechart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "eechart.labels" -}} +app.kubernetes.io/name: {{ include "eechart.name" . }} +helm.sh/chart: {{ include "eechart.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "eechart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "eechart.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/configmap.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/configmap.yaml new file mode 100755 index 0000000000000000000000000000000000000000..5b9634c7e1abe64c6f720f708dd5c9664e72e8cf --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "eechart.fullname" . }} +data: +{{ (.Files.Glob "source/*").AsConfig | indent 2 }} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/generator.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/generator.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96f7e237d85cecfba6f7047c169ba09fdcb8865e --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/generator.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "vnf-snmp-generator-{{ .Values.global.osm.vnf_id | lower }}" +data: + generator.yml: |- + {{ .Files.Get "snmp/generator.yml" | nindent 4}} \ No newline at end of file diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/ingress.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/ingress.yaml new file mode 100755 index 0000000000000000000000000000000000000000..264f89091bee2ba8746edc2841c275d28fef1168 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "eechart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: +{{ include "eechart.labels" . | indent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/mibs.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/mibs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e7b5eab55038ea9e0d17d7c8d0b9fc7dc15ddfe6 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/mibs.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "vnf-snmp-mibs-{{ .Values.global.osm.vnf_id | lower}}" +data: +{{ (.Files.Glob "snmp/mibs/**").AsConfig | indent 2 }} \ No newline at end of file diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/secret.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..62d4b267e8cae8df9dcdee471dcbb6a4151b040b --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "eechart.fullname" . }} +type: Opaque +data: + mysql_host: {{ .Values.mysql.fullnameOverride | b64enc | quote }} + mysql_user: {{ "root" | b64enc | quote }} + mysql_password: {{ .Values.mysql.auth.rootPassword | b64enc | quote }} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/service.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/service.yaml new file mode 100755 index 0000000000000000000000000000000000000000..88d38d66a3997c6e2a96754582736cfb065da6c2 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "eechart.fullname" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/serviceaccount.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/serviceaccount.yaml new file mode 100755 index 0000000000000000000000000000000000000000..be615a5f08c7b557446fa74e5e3619e47d2ee804 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "eechart.serviceAccountName" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +{{- end -}} diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/statefulset.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/statefulset.yaml new file mode 100755 index 0000000000000000000000000000000000000000..a13cfa6e7a767ad96ac697fe2ae406c4b9ec6f53 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/statefulset.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "eechart.fullname" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +spec: + serviceName: {{ include "eechart.fullname" . }} + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + vnf: {{ .Values.global.osm.vnf_id | lower}} + spec: + imagePullSecrets: + - name: regcred + serviceAccountName: {{ template "eechart.serviceAccountName" . }} + securityContext: + runAsUser: 0 + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + envFrom: + - secretRef: + name: {{ include "eechart.fullname" . }} + ports: + - name: grpc + containerPort: 50051 + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: osm-ee + mountPath: /app/storage + - name: osm-ee-source + mountPath: /app/EE/osm_ee/vnf + - name: snmp-config-volume + mountPath: /etc/snmp_exporter + - name: vnf-mibs + mountPath: /root/.snmp/mibs + - name: vnf-generator + mountPath: /app/vnf/generator + volumes: + - name: osm-ee-source + configMap: + name: {{ include "eechart.fullname" . }} + - name: snmp-config-volume + hostPath: + path: "/var/lib/osm/snmp_exporter/{{ .Values.global.osm.vnf_id | lower }}/" + - name: vnf-mibs + configMap: + name: "vnf-snmp-mibs-{{ .Values.global.osm.vnf_id | lower}}" + - name: vnf-generator + configMap: + name: "vnf-snmp-generator-{{ .Values.global.osm.vnf_id | lower}}" + - name: osm-ee + hostPath: + path: /var/lib/osm/osm/osm_osm_packages/_data diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/tests/test-connection.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/tests/test-connection.yaml new file mode 100755 index 0000000000000000000000000000000000000000..e52b7b8b2515729e582b5efbc22dc5a0bdb0f3b2 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "eechart.fullname" . }}-test-connection" + labels: +{{ include "eechart.labels" . | indent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "eechart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/oai-helm/ext-dn_vnf/helm-charts/eechart/values.yaml b/oai-helm/ext-dn_vnf/helm-charts/eechart/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c63644a2497f459647ee3520206e8bc8fc05b544 --- /dev/null +++ b/oai-helm/ext-dn_vnf/helm-charts/eechart/values.yaml @@ -0,0 +1,77 @@ +global: + osm: + vnf_id: AVNFId + +# Default values for eechart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: opensourcemano/api-fe + tag: latest + pullPolicy: IfNotPresent + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: false + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 50050 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +mysql: + auth: + rootPassword: "123456" + fullnameOverride: "eechart-mysql" diff --git a/oai-helm/gnbsim_vnf/.sample_ee_vnfd.yaml.swp b/oai-helm/gnbsim_vnf/.sample_ee_vnfd.yaml.swp new file mode 100644 index 0000000000000000000000000000000000000000..27c3c82570353f02745284eb028f5ae643a57a87 Binary files /dev/null and b/oai-helm/gnbsim_vnf/.sample_ee_vnfd.yaml.swp differ diff --git a/oai-helm/gnbsim_vnf/gnbsim_vnfd.yaml b/oai-helm/gnbsim_vnf/gnbsim_vnfd.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0bfa7678e9835d9ed2f94c517be88bcb54d9205f --- /dev/null +++ b/oai-helm/gnbsim_vnf/gnbsim_vnfd.yaml @@ -0,0 +1,183 @@ +vnfd: + description: gnbsim VNF with 2 networks attached + df: + - id: default-df + instantiation-level: + - id: default-instantiation-level + vdu-level: + - number-of-instances: 1 + vdu-id: gnbsim-VM + vdu-profile: + - id: gnbsim-VM + min-number-of-instances: 1 + lcm-operations-configuration: + operate-vnf-op-config: + day1-2: + - config-primitive: + - execution-environment-primitive: gnbsim_up + execution-environment-ref: gnbsim + name: gnbsim_up + parameter: + - data-type: STRING + name: file + - execution-environment-primitive: gnbsim_down + execution-environment-ref: gnbsim + name: gnbsim_down + parameter: + - data-type: STRING + name: file + - execution-environment-primitive: send_command + execution-environment-ref: gnbsim + name: send_command + parameter: + - data-type: STRING + name: file + # - execution-environment-primitive: run_script + # execution-environment-ref: gnbsim + # name: run_script + # parameter: + # - data-type: STRING + # name: file + # - data-type: STRING + # name: parameters + # - execution-environment-primitive: ansible_playbook + # execution-environment-ref: gnbsim + # name: ansible_playbook + # parameter: + # - data-type: STRING + # name: playbook-name + # - data-type: STRING + # name: app + # - execution-environment-primitive: ping + # execution-environment-ref: gnbsim + # name: ping + # - execution-environment-primitive: http_check + # execution-environment-ref: gnbsim + # name: http_check + # - execution-environment-primitive: touch + # execution-environment-ref: gnbsim + # name: touch + # parameter: + # - data-type: STRING + # name: file + # - execution-environment-primitive: check_database + # execution-environment-ref: gnbsim + # name: check_database + config-access: + ssh-access: + default-user: ubuntu + required: true + execution-environment-list: + - external-connection-point-ref: vnf-mgmt-ext + helm-chart: eechart + id: gnbsim + id: gnbsim-vnf + initial-config-primitive: + - execution-environment-ref: gnbsim + name: config + parameter: + - name: ssh-hostname + value: + - name: ssh-username + value: ubuntu + seq: 1 + - execution-environment-ref: gnbsim + name: run_script + parameter: + - name: file + value: install_docker.sh + seq: 2 + - execution-environment-ref: gnbsim + name: copy_files + parameter: + - name: file + value: docker-compose-gnbsim.yaml + seq: 3 + # - execution-environment-ref: gnbsim + # name: ansible_playbook + # parameter: + # - name: playbook-name + # value: playbook.yaml + # - name: app + # value: ntp + # seq: 3 + # - execution-environment-ref: gnbsim + # name: ping + # seq: 4 + # - execution-environment-ref: gnbsim + # name: http_check + # seq: 5 + # - execution-environment-ref: gnbsim + # name: touch + # parameter: + # - name: file + # value: myfile.txt + # seq: 3 + # - execution-environment-ref: gnbsim + # name: check_database + # seq: 7 + ext-cpd: + - id: vnf-mgmt-ext + int-cpd: + cpd: vdu-eth0-int + vdu-id: gnbsim-VM + - id: vnf-internal-ext + int-cpd: + cpd: vdu-eth1-int + vdu-id: gnbsim-VM + id: gnbsim-vnf + mgmt-cp: vnf-mgmt-ext + product-name: gnbsim-vnf + sw-image-desc: + - id: ubuntu20.04 + image: ubuntu20.04 + name: ubuntu20.04 + - id: ubuntu20.04-azure + name: ubuntu20.04-azure + image: Canonical:0001-com-ubuntu-server-focal:20_04-lts:latest + vim-type: azure + - id: ubuntu20.04-gcp + name: ubuntu20.04-gcp + image: ubuntu-os-cloud:image-family:ubuntu-2004-lts + vim-type: gcp + vdu: + - id: gnbsim-VM + int-cpd: + - id: vdu-eth0-int + virtual-network-interface-requirement: + - name: vdu-eth0 + position: 0 + virtual-interface: + type: PARAVIRT + - id: vdu-eth1-int + virtual-network-interface-requirement: + - name: vdu-eth1 + position: 1 + virtual-interface: + type: PARAVIRT + - id: vdu-eth2-int + virtual-network-interface-requirement: + - name: vdu-eth2 + position: 2 + virtual-interface: + type: PARAVIRT + name: gnbsim-VM + supplemental-boot-data: + boot-data-drive: true + sw-image-desc: ubuntu20.04 + alternative-sw-image-desc: + - ubuntu20.04-azure + - ubuntu20.04-gcp + virtual-compute-desc: gnbsim-VM-compute + virtual-storage-desc: + - gnbsim-VM-storage + version: 1.0 + virtual-compute-desc: + - id: gnbsim-VM-compute + virtual-cpu: + num-virtual-cpu: 1 + virtual-memory: + size: 4.0 + virtual-storage-desc: + - id: gnbsim-VM-storage + size-of-storage: 20 diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/.helmignore b/oai-helm/gnbsim_vnf/helm-charts/eechart/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..50af0317254197a5a019f4ac2f8ecc223f93f5a7 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/Chart.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..414c5f1aa1becbd34d69342874b63db8bb1cb77c --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: OSM EE helm chart +name: eechart +version: 0.1.0 diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz b/oai-helm/gnbsim_vnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2cfb9b29533b6f6837de93a2022eec32c11b0b4b Binary files /dev/null and b/oai-helm/gnbsim_vnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz differ diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/charts/.gitkeep b/oai-helm/gnbsim_vnf/helm-charts/eechart/charts/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/docker-compose-gnbsim.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/docker-compose-gnbsim.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3906ace5b3e178ce666001328fa549e9be79bc46 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/docker-compose-gnbsim.yaml @@ -0,0 +1,265 @@ +version: '3.8' +services: + gnbsim: + container_name: gnbsim + image: rohankharade/gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=1 + - TAC=0x0001 + - SST=222 + - SD=00007b + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000031 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=no + - NGAPPeerAddr=192.168.18.177 + - GTPuLocalAddr=192.168.69.136 + - GTPuIFname=eth0 + networks: + public_net: + ipv4_address: 192.168.69.136 + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 + gnbsim2: + container_name: gnbsim2 + image: gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=2 + - TAC=0x00a000 + - SST=222 + - SD=00007b + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000032 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=no + - NGAPPeerAddr=192.168.18.177 + - GTPuLocalAddr=192.168.69.137 + - GTPuIFname=eth0 + networks: + public_net: + ipv4_address: 192.168.69.137 + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 + gnbsim3: + container_name: gnbsim3 + image: gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=3 + - TAC=0x0001 + - SST=111 + - SD=124 + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000033 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=no + - NGAPPeerAddr=192.168.18.177 + - GTPuLocalAddr=192.168.69.138 + - GTPuIFname=eth0 + networks: + public_net: + ipv4_address: 192.168.69.138 + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 + gnbsim4: + container_name: gnbsim4 + image: gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=4 + - TAC=0x00a000 + - SST=222 + - SD=00007b + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000034 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=no + - NGAPPeerAddr=192.168.18.177 + - GTPuLocalAddr=192.168.70.139 + - GTPuIFname=eth0 + networks: + public_net: + ipv4_address: 192.168.70.139 + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 + gnbsim5: + container_name: gnbsim5 + image: gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=5 + - TAC=0x00a000 + - SST=222 + - SD=00007b + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000035 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=no + - NGAPPeerAddr=192.168.70.132 + - GTPuLocalAddr=192.168.70.140 + - GTPuIFname=eth0 + networks: + public_net: + ipv4_address: 192.168.70.140 + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 + gnbsim-fqdn: + container_name: gnbsim-fqdn + image: gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=5 + - TAC=0x00a000 + - SST=222 + - SD=00007b + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000035 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=yes + - AMF_FQDN=amf.oai-5gc.eur + - GTPuIFname=eth0 + networks: + public_net: + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 + gnbsim-vpp: + container_name: gnbsim-vpp + image: gnbsim:latest + privileged: true + environment: + - MCC=208 + - MNC=95 + - GNBID=5 + - TAC=0x00a000 + - SST=222 + - SD=00007b + - PagingDRX=v32 + - RANUENGAPID=0 + - IMEISV=35609204079514 + - MSIN=0000000035 + - RoutingIndicator=1234 + - ProtectionScheme=null + - KEY=0C0A34601D4F07677303652C0462535B + - OPc=63bfa50ee6523365ff14c1f45f88737d + - DNN=default + - URL=http://www.asnt.org:8080/ + - NRCellID=1 + - USE_FQDN=no +# - USE_FQDN=yes +# - AMF_FQDN=amf.oai-5gc.eur + - NGAPPeerAddr=192.168.71.132 + - GTPuLocalAddr=192.168.72.141 + - GTPuIFname=eth1 + networks: + public_net_core: + ipv4_address: 192.168.71.141 + public_net_access: + ipv4_address: 192.168.72.141 + healthcheck: + test: /bin/bash -c "ifconfig gtp-gnb" + interval: 10s + timeout: 5s + retries: 5 +networks: + public_net: + external: + name: demo-oai-public-net + public_net_core: + name: oai-public-core + ipam: + config: + - subnet: 192.168.71.0/24 + public_net_access: + name: oai-public-access + ipam: + config: + - subnet: 192.168.72.0/24 +# Incase the user wants docker-compose to create a bridge rather than creating the bridge manually then uncomment the below lines + public_net: + driver: bridge + name: demo-oai-public-net + ipam: + config: + - subnet: 192.168.69.128/26 + driver_opts: + com.docker.network.bridge.name: "demo-oai" diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/install.sh b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/install.sh new file mode 100755 index 0000000000000000000000000000000000000000..db8f0538a1c1e508094f2a19bb1ab1e8acbee55e --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/install.sh @@ -0,0 +1,36 @@ +#!/bin/bash +## +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +echo "Updating operating system" +apt-get update + +# Install ansible libraries +echo "Installing ansible" +apt-get install -y software-properties-common +apt-add-repository --yes --update ppa:ansible/ansible +apt install -y ansible + +# Install library to execute command remotely by ssh +echo "Installing asynssh" +python3 -m pip install asyncssh + +# Install ping system command +apt install -y iputils-ping + +# Install HTTP python library +python3 -m pip install requests + +# Install MySQL library +python3 -m pip install mysql-connector-python diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/install_docker.sh b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/install_docker.sh new file mode 100644 index 0000000000000000000000000000000000000000..4e670e7e0efcf06be26f2cb38769996770bd0660 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/install_docker.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -eux +sudo -s < /dev/null +apt-get -y update +apt-get -y install docker-ce docker-ce-cli containerd.io docker-compose-plugin +groupadd docker +usermod -aG docker ubuntu +newgrp docker + +curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose +chmod +x /usr/local/bin/docker-compose + +sysctl net.ipv4.conf.all.forwarding=1 +iptables -P FORWARD ACCEPT +ip route add 192.168.70.128/26 via 192.168.1.1 dev ens4 +ip route add 192.168.18.0/24 via 192.168.1.1 dev ens4 + +EOF diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/mylib.py b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/mylib.py new file mode 100644 index 0000000000000000000000000000000000000000..c0bd3bc8cdebf42c2467d8042a095d94a6664cb3 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/mylib.py @@ -0,0 +1,80 @@ +## +# Copyright 2022 Telefonica Investigacion y Desarrollo, S.A.U. +# This file is part of OSM +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# For those usages not covered by the Apache License, Version 2.0 please +# contact with: nfvlabs@tid.es +## + +import logging +import asyncio +import asyncssh +import time + + +from mysql.connector import connect, Error + +logger = logging.getLogger("osm_ee.vnf") + + +async def ssh_exec(host: str, user: str, command: str + ) -> (int, str): + """ + Execute a remote command via SSH. + """ + + try: + async with asyncssh.connect(host, + username=user, + known_hosts=None) as conn: + logger.debug("Executing command '{}'".format(command)) + result = await conn.run(command) + logger.debug("Result: {}".format(result)) + return result.exit_status, result.stderr + except Exception as e: + logger.error("Error: {}".format(repr(e))) + return -1, str(e) + + +def mysql_query(host: str, user: str, password: str, retries: int, query: str + ) -> (int, str): + """ + Execute a query to a MySQL database. + """ + + text = "" + logger.debug("Host: '{}', user: '{}', password: '{}', query: '{}'".format(host, user, password, query)) + for i in range(0, retries): + try: + with connect( + host=host, + user=user, + password=password, + ) as connection: + with connection.cursor() as cursor: + cursor.execute(query) + for (db) in cursor: + logger.debug(db) + text = text + str(db[0]) + ", " + return 0, text[0:len(text)-2] + except Error as e: + text = str(e) + logger.debug("Error: {}".format(e)) + time.sleep(3) + continue + + return -1, text diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/playbook.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/playbook.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bc6013d7e5a0557d5a41cd2211d50e85c0d71222 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/playbook.yaml @@ -0,0 +1,14 @@ +--- +- hosts: all + become: yes + tasks: + - name: Wait 120 seconds, but only start checking after 10 seconds + wait_for_connection: + delay: 20 + timeout: 120 + - name: Install packages + apt: + name: + - "{{ app }}" + state: latest + cache_valid_time: 3600 diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/run_ssh.sh b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/run_ssh.sh new file mode 100755 index 0000000000000000000000000000000000000000..8b58b3cce67868565722c481427d683a14a84fe4 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/run_ssh.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +date "+%H:%M:%S Starting $0..." +IP=$1 +USERNAME=$2 +SCRIPT=$3 +PARAMS=$4 + +DIR=$(dirname $0) + +date "+%H:%M:%S Waiting for $IP to be ready..." +i=5 +while ! ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" 'exit' ; do + date "+%H:%M:%S Error accessing $IP, retrying..." + sleep 5 + i=$(( $i - 1 )) + [ $i -ge 0 ] || exit 1 +done + +date "+%H:%M:%S SSH server is up, sending script '${DIR}/${SCRIPT}'..." +scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${DIR}/${SCRIPT} "$USERNAME"@"$IP": +if [ $? -ne 0 ]; then + date "+%H:%M:%S scp error" + exit 1 +fi +date "+%H:%M:%S OK. Setting file permissions" +ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" "chmod a+x $SCRIPT" +if [ $? -ne 0 ]; then + date "+%H:%M:%S ssh error" + exit 1 +fi + +COMMAND="./$SCRIPT" +[ ${#PARAMS} -ge 0 ] || COMMAND="${COMMAND=} $PARAMS" +date "+%H:%M:%S Running '$COMMAND' on $IP..." +ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" "$COMMAND" +if [ $? -ne 0 ]; then + date "+%H:%M:%S ssh error" + exit 1 +fi + +date "+%H:%M:%S End" +exit 0 diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/source/vnf_ee.py b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/vnf_ee.py new file mode 100644 index 0000000000000000000000000000000000000000..393763c8b9db899415df0dac3e8468adc487caf8 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/source/vnf_ee.py @@ -0,0 +1,206 @@ +## +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +import asyncio +import asyncssh +import requests +import logging +import os + + +from osm_ee.exceptions import VnfException + +import osm_ee.util.util_ee as util_ee +import osm_ee.util.util_ansible as util_ansible +import osm_ee.vnf.mylib as mylib + +class VnfEE: + + PLAYBOOK_PATH = "/app/EE/osm_ee/vnf" + SSH_SCRIPT = "/app/EE/osm_ee/vnf/run_ssh.sh" + + def __init__(self, config_params): + self.logger = logging.getLogger('osm_ee.vnf') + self.config_params = config_params + + # config method saves SSH access parameters (host and username) for future use by other methods. + # It is mandatory in any case. + async def config(self, id, params): + self.logger.debug("Execute action config, params: {}".format(params)) + # Config action is special, params are merged with previous config calls + self.config_params.update(params) + required_params = ["ssh-hostname"] + self._check_required_params(self.config_params, required_params) + yield "OK", "Configured" + + # This method implements the "run_script" primitive. Uncomment and modify it if a primitive requires executing a user + # script in the VDU. It needs "file" parameter (script's file to run, must be in "source" directory) + # and optionally "parameters" (command-line arguments for script). + async def run_script(self, id, params): + self.logger.debug("Execute action run_script, params: '{}'".format(params)) + self._check_required_params(params, ["file"]) + + command = "bash " + self.SSH_SCRIPT + " " + self.config_params["ssh-hostname"] + " " + self.config_params["ssh-username"] + " " + params["file"] + if "parameters" in params: + command += " \"" + params.get("parameters", "") + "\"" + self.logger.debug("Command: '{}'".format(command)) + return_code, stdout, stderr = await util_ee.local_async_exec(command) + if return_code != 0: + yield "ERROR", "return code {}: {}".format(return_code, stderr.decode()) + else: + yield "OK", stdout.decode() + + # This method implements the "copy_files" primitive. Uncomment and modify it if a primitive requires + # to copy files to a VNF. It needs file name parameter (file must be in "source" directory). + + async def copy_files(self, id, params): + self.logger.debug("Execute action copy_files, params: '{}'".format(params)) + self._check_required_params(params, ["file"]) + + command= "scp" + " -o StrictHostKeyChecking=no /app/EE/osm_ee/vnf/" + params["file"] + " " + self.config_params["ssh-username"] + "@" + self.config_params["ssh-hostname"] + ":" + params["file"] + self.logger.debug("Command: '{}'".format(command)) + return_code, stdout, stderr = await util_ee.local_async_exec(command) + if return_code != 0: + yield "ERROR", "return code {}: {}".format(return_code, stderr.decode()) + else: + yield "OK", stdout.decode() + + # This method implements the "ansible_playbook" primitive. Uncomment and modify it if a primitive requires + # executing an Ansible Playbook. It needs "playbook-name" parameter (playbook file, must be in "source" directory). + # async def ansible_playbook(self, id, params): + # self.logger.debug("Execute action ansible_playbook, params: '{}'".format(params)) + + # try: + # self._check_required_params(params, ["playbook-name"]) + # params["ansible_user"] = self.config_params["ssh-username"] + # inventory = self.config_params["ssh-hostname"] + "," + # playbook = self.PLAYBOOK_PATH + "/" + params["playbook-name"] + # os.environ["ANSIBLE_HOST_KEY_CHECKING"] = "False" + # return_code, stdout, stderr = await util_ansible.execute_playbook(playbook, inventory, params) + # status = "OK" if return_code == 0 else "ERROR" + # yield status, stdout + stderr + # except Exception as e: + # self.logger.debug("Error executing ansible playbook: {}".format(repr(e))) + # yield "ERROR", str(e) + + # This method implements the "ping" primitive. Uncomment and modify it if a primitive requires + # executing a local command (such as ping) on EE. It uses "ssh-hostname" as ping destination. + # async def ping(self, id, params): + # self.logger.debug("Execute action ping, params: '{}'".format(params)) + + # command = "ping -c 3 " + self.config_params["ssh-hostname"] + # return_code, stdout, stderr = await util_ee.local_async_exec(command) + # if return_code != 0: + # yield "ERROR", "return code {}: {}".format(return_code, stderr.decode()) + # else: + # yield "OK", stdout.decode() + + # This method implements the "http_check" primitive. Uncomment and modify it if a primitive requires + # executing embedded python code on VfnEE class. It requests "http:///" using a HTTP library. + # async def http_check(self, id, params): + # self.logger.debug("Execute action http_check, params: '{}'".format(params)) + + # try: + # session = requests.Session() + # url = 'http://' + self.config_params["ssh-hostname"] + # self.logger.debug("HTTP GET {}...".format(url)) + # req = session.get(url) + # self.logger.debug("{}".format(req.text)) + # if req.status_code == 200: + # yield "OK", req.text + # else: + # yield "ERROR", req.text + # except Exception as e: + # self.logger.error("HTTP error: {}".format(repr(e))) + # yield "ERROR", str(e) + + # This method implements the "touch" primitive. Uncomment and modify it if you need a primitive that + # imports a user-defined python library. It only needs "file" parameter for creating it in VDU via SSH. + # async def touch(self, id, params): + # self.logger.debug("Execute action touch, params: '{}'".format(params)) + # + # self._check_required_params(params, ["file"]) + # command = "touch" + " " + params["file"] + # return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + # if return_code != 0: + # yield "ERROR", description + # else: + # yield "OK", description + + # This method implements the "gnbsim_up" primitive. Uncomment and modify it if you need a primitive that + # starts up the gnbsim to test 5G OAI Core. It only needs "file" parameter, in this case use gnbsim. + async def gnbsim_up(self, id, params): + self.logger.debug("Execute action gnbsim_up, params: '{}'".format(params)) + + self._check_required_params(params, ["file"]) + command = "docker-compose -f docker-compose-gnbsim.yaml up -d" + " " + params["file"] + return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + if return_code != 0: + yield "ERROR", description + else: + yield "OK", description + + # This method implements the "gnbsim_down" primitive. Uncomment and modify it if you need a primitive that + # stops the gnbsim for testing 5G OAI Core. It only needs "file" parameter, in this case use gnbsim. + async def gnbsim_down(self, id, params): + self.logger.debug("Execute action gnbsim_down, params: '{}'".format(params)) + + self._check_required_params(params, ["file"]) + command = "docker-compose -f docker-compose-gnbsim.yaml down" + return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + if return_code != 0: + yield "ERROR", description + else: + yield "OK", description + + # This method implements the "send_command" primitive. Uncomment and modify it if you need a primitive that + # sends any command to the VM through SSH. It only needs "file" parameter which contains the command to send. + async def send_command(self, id, params): + self.logger.debug("Execute action send_command, params: '{}'".format(params)) + + self._check_required_params(params, ["file"]) + command = params["file"] + return_code, description = await mylib.ssh_exec(self.config_params["ssh-hostname"], self.config_params["ssh-username"], command) + if return_code != 0: + yield "ERROR", description + else: + yield "OK", description + + # This method implements the "check_database" primitive. Uncomment and modify it if a primitive requires + # accessing to a service provided by a helm subchart. Access parameters are read from environment variables + # async def check_database(self, id, params): + # self.logger.debug("Execute action check_database, params: '{}'".format(params)) + + # host = os.getenv('mysql_host') + # user = os.getenv('mysql_user') + # password = os.getenv('mysql_password') + # retries = 3 + # query = "SHOW DATABASES" + # return_code, description = mylib.mysql_query(host, user, password, retries, query) + # if return_code != 0: + # yield "ERROR", description + # else: + # yield "OK", description + + + # Static method that verifies whether a parameter exists in the map + @staticmethod + def _check_required_params(params, required_params): + for required_param in required_params: + if required_param not in params: + raise VnfException("Missing required param: {}".format(required_param)) + diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/NOTES.txt b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/NOTES.txt new file mode 100755 index 0000000000000000000000000000000000000000..c52fc2c419ef6f4cccfb63fd93ca7379bfc04cf7 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "eechart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "eechart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "eechart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "eechart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/_helpers.tpl b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/_helpers.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d3e28e0260b8bff2fdef09046df0abaea885739c --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "eechart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "eechart.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "eechart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "eechart.labels" -}} +app.kubernetes.io/name: {{ include "eechart.name" . }} +helm.sh/chart: {{ include "eechart.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "eechart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "eechart.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/configmap.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/configmap.yaml new file mode 100755 index 0000000000000000000000000000000000000000..5b9634c7e1abe64c6f720f708dd5c9664e72e8cf --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "eechart.fullname" . }} +data: +{{ (.Files.Glob "source/*").AsConfig | indent 2 }} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/generator.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/generator.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96f7e237d85cecfba6f7047c169ba09fdcb8865e --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/generator.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "vnf-snmp-generator-{{ .Values.global.osm.vnf_id | lower }}" +data: + generator.yml: |- + {{ .Files.Get "snmp/generator.yml" | nindent 4}} \ No newline at end of file diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/ingress.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/ingress.yaml new file mode 100755 index 0000000000000000000000000000000000000000..264f89091bee2ba8746edc2841c275d28fef1168 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "eechart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: +{{ include "eechart.labels" . | indent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/mibs.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/mibs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e7b5eab55038ea9e0d17d7c8d0b9fc7dc15ddfe6 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/mibs.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "vnf-snmp-mibs-{{ .Values.global.osm.vnf_id | lower}}" +data: +{{ (.Files.Glob "snmp/mibs/**").AsConfig | indent 2 }} \ No newline at end of file diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/secret.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..62d4b267e8cae8df9dcdee471dcbb6a4151b040b --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "eechart.fullname" . }} +type: Opaque +data: + mysql_host: {{ .Values.mysql.fullnameOverride | b64enc | quote }} + mysql_user: {{ "root" | b64enc | quote }} + mysql_password: {{ .Values.mysql.auth.rootPassword | b64enc | quote }} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/service.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/service.yaml new file mode 100755 index 0000000000000000000000000000000000000000..88d38d66a3997c6e2a96754582736cfb065da6c2 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "eechart.fullname" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/serviceaccount.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/serviceaccount.yaml new file mode 100755 index 0000000000000000000000000000000000000000..be615a5f08c7b557446fa74e5e3619e47d2ee804 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "eechart.serviceAccountName" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +{{- end -}} diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/statefulset.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/statefulset.yaml new file mode 100755 index 0000000000000000000000000000000000000000..a13cfa6e7a767ad96ac697fe2ae406c4b9ec6f53 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/statefulset.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "eechart.fullname" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +spec: + serviceName: {{ include "eechart.fullname" . }} + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + vnf: {{ .Values.global.osm.vnf_id | lower}} + spec: + imagePullSecrets: + - name: regcred + serviceAccountName: {{ template "eechart.serviceAccountName" . }} + securityContext: + runAsUser: 0 + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + envFrom: + - secretRef: + name: {{ include "eechart.fullname" . }} + ports: + - name: grpc + containerPort: 50051 + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: osm-ee + mountPath: /app/storage + - name: osm-ee-source + mountPath: /app/EE/osm_ee/vnf + - name: snmp-config-volume + mountPath: /etc/snmp_exporter + - name: vnf-mibs + mountPath: /root/.snmp/mibs + - name: vnf-generator + mountPath: /app/vnf/generator + volumes: + - name: osm-ee-source + configMap: + name: {{ include "eechart.fullname" . }} + - name: snmp-config-volume + hostPath: + path: "/var/lib/osm/snmp_exporter/{{ .Values.global.osm.vnf_id | lower }}/" + - name: vnf-mibs + configMap: + name: "vnf-snmp-mibs-{{ .Values.global.osm.vnf_id | lower}}" + - name: vnf-generator + configMap: + name: "vnf-snmp-generator-{{ .Values.global.osm.vnf_id | lower}}" + - name: osm-ee + hostPath: + path: /var/lib/osm/osm/osm_osm_packages/_data diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/tests/test-connection.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/tests/test-connection.yaml new file mode 100755 index 0000000000000000000000000000000000000000..e52b7b8b2515729e582b5efbc22dc5a0bdb0f3b2 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "eechart.fullname" . }}-test-connection" + labels: +{{ include "eechart.labels" . | indent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "eechart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/oai-helm/gnbsim_vnf/helm-charts/eechart/values.yaml b/oai-helm/gnbsim_vnf/helm-charts/eechart/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c63644a2497f459647ee3520206e8bc8fc05b544 --- /dev/null +++ b/oai-helm/gnbsim_vnf/helm-charts/eechart/values.yaml @@ -0,0 +1,77 @@ +global: + osm: + vnf_id: AVNFId + +# Default values for eechart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: opensourcemano/api-fe + tag: latest + pullPolicy: IfNotPresent + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: false + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 50050 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +mysql: + auth: + rootPassword: "123456" + fullnameOverride: "eechart-mysql" diff --git a/oai-helm/img/architecture.png b/oai-helm/img/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..a34b19ea5936c45c1d95a62d2e27334a6a769192 Binary files /dev/null and b/oai-helm/img/architecture.png differ diff --git a/oai-helm/img/ext-server.png b/oai-helm/img/ext-server.png new file mode 100644 index 0000000000000000000000000000000000000000..b92e22db624f76463c8355e5327a704a4207793a Binary files /dev/null and b/oai-helm/img/ext-server.png differ diff --git a/oai-helm/img/gnbsim.png b/oai-helm/img/gnbsim.png new file mode 100644 index 0000000000000000000000000000000000000000..c8cf695360ac53dfdea161be295a3cb42536745c Binary files /dev/null and b/oai-helm/img/gnbsim.png differ diff --git a/oai-helm/img/login.png b/oai-helm/img/login.png new file mode 100644 index 0000000000000000000000000000000000000000..716054c51e955cca3a37bd91a6baa4757ed893ae Binary files /dev/null and b/oai-helm/img/login.png differ diff --git a/oai-helm/infra.sh b/oai-helm/infra.sh new file mode 100644 index 0000000000000000000000000000000000000000..f412687690ba744e0f903ef6be1ff6d3402078ee --- /dev/null +++ b/oai-helm/infra.sh @@ -0,0 +1,4 @@ +# Add PDU, replace "etsi-openstack" for the name of the VIM you're using +VIMID=`osm vim-list | grep "etsi-openstack " | awk '{ print $4 }'` +sed -i "s/vim_accounts: .*/vim_accounts: [ $VIMID ]/" pdu.yaml +osm pdu-create --descriptor_file pdu.yaml diff --git a/oai-helm/oai_knf/oai_vnfd.yaml b/oai-helm/oai_knf/oai_vnfd.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96cef579f87ae4497e23d6111a966513ded2601d --- /dev/null +++ b/oai-helm/oai_knf/oai_vnfd.yaml @@ -0,0 +1,18 @@ +vnfd: + description: KNF with single KDU using a helm-chart for 5G OAI Core version 1.0 + df: + - id: default-df + ext-cpd: + - id: mgmt-ext + k8s-cluster-net: osm-ext + id: oai_knf + k8s-cluster: + nets: + - id: osm-ext + kdu: + - name: mecplatform + helm-chart: helm-plugtest/oai-5gcore + mgmt-cp: mgmt-ext + product-name: oai_knf + provider: OAI + version: '1.0' diff --git a/oai-helm/pdu.yaml b/oai-helm/pdu.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d0448476ac48cac560d4e1cd2a4771dc05ec66ff --- /dev/null +++ b/oai-helm/pdu.yaml @@ -0,0 +1,9 @@ +name: router01 +description: router +type: gateway +vim_accounts: [ 42ee7fda-2996-4de0-877f-61abc792ad92 ] +shared: false +interfaces: + - name: eth0 + ip-address: 172.21.250.200 + mgmt: true diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/.helmignore b/oai-helm/vyos_pnf/helm-charts/eechart/.helmignore new file mode 100644 index 0000000000000000000000000000000000000000..50af0317254197a5a019f4ac2f8ecc223f93f5a7 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/.helmignore @@ -0,0 +1,22 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/Chart.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/Chart.yaml new file mode 100644 index 0000000000000000000000000000000000000000..414c5f1aa1becbd34d69342874b63db8bb1cb77c --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/Chart.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +appVersion: "1.0" +description: OSM EE helm chart +name: eechart +version: 0.1.0 diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz b/oai-helm/vyos_pnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz new file mode 100644 index 0000000000000000000000000000000000000000..2cfb9b29533b6f6837de93a2022eec32c11b0b4b Binary files /dev/null and b/oai-helm/vyos_pnf/helm-charts/eechart/charts.sample/mysql-8.8.26.tgz differ diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/charts/.gitkeep b/oai-helm/vyos_pnf/helm-charts/eechart/charts/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/source/configure-remote.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/source/configure-remote.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bc4d4fb3da54712547560fe291f47b674f7017db --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/source/configure-remote.yaml @@ -0,0 +1,11 @@ +- hosts: all + connection: local + tasks: + - name: add static routes + vyos_config: + lines: + - set protocols static route 12.1.1.0/24 next-hop 192.168.18.179 + - set protocols static route 192.168.68.128/26 next-hop 192.168.1.4 + - set protocols static route 192.168.69.128/26 next-hop 192.168.1.5 + - set protocols static route 192.168.70.128/26 next-hop 192.168.1.6 + diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/source/install.sh b/oai-helm/vyos_pnf/helm-charts/eechart/source/install.sh new file mode 100755 index 0000000000000000000000000000000000000000..db8f0538a1c1e508094f2a19bb1ab1e8acbee55e --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/source/install.sh @@ -0,0 +1,36 @@ +#!/bin/bash +## +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +## + +echo "Updating operating system" +apt-get update + +# Install ansible libraries +echo "Installing ansible" +apt-get install -y software-properties-common +apt-add-repository --yes --update ppa:ansible/ansible +apt install -y ansible + +# Install library to execute command remotely by ssh +echo "Installing asynssh" +python3 -m pip install asyncssh + +# Install ping system command +apt install -y iputils-ping + +# Install HTTP python library +python3 -m pip install requests + +# Install MySQL library +python3 -m pip install mysql-connector-python diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/source/install_nginx.sh b/oai-helm/vyos_pnf/helm-charts/eechart/source/install_nginx.sh new file mode 100755 index 0000000000000000000000000000000000000000..48f8cf767ec0727652fd0ae8c97c932a8dd4146b --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/source/install_nginx.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eux +sudo -s < (int, str): + """ + Execute a remote command via SSH. + """ + + try: + async with asyncssh.connect(host, + username=user, + known_hosts=None) as conn: + logger.debug("Executing command '{}'".format(command)) + result = await conn.run(command) + logger.debug("Result: {}".format(result)) + return result.exit_status, result.stderr + except Exception as e: + logger.error("Error: {}".format(repr(e))) + return -1, str(e) + + +def mysql_query(host: str, user: str, password: str, retries: int, query: str + ) -> (int, str): + """ + Execute a query to a MySQL database. + """ + + text = "" + logger.debug("Host: '{}', user: '{}', password: '{}', query: '{}'".format(host, user, password, query)) + for i in range(0, retries): + try: + with connect( + host=host, + user=user, + password=password, + ) as connection: + with connection.cursor() as cursor: + cursor.execute(query) + for (db) in cursor: + logger.debug(db) + text = text + str(db[0]) + ", " + return 0, text[0:len(text)-2] + except Error as e: + text = str(e) + logger.debug("Error: {}".format(e)) + time.sleep(3) + continue + + return -1, text diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/source/playbook.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/source/playbook.yaml new file mode 100644 index 0000000000000000000000000000000000000000..bc6013d7e5a0557d5a41cd2211d50e85c0d71222 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/source/playbook.yaml @@ -0,0 +1,14 @@ +--- +- hosts: all + become: yes + tasks: + - name: Wait 120 seconds, but only start checking after 10 seconds + wait_for_connection: + delay: 20 + timeout: 120 + - name: Install packages + apt: + name: + - "{{ app }}" + state: latest + cache_valid_time: 3600 diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/source/run_ssh.sh b/oai-helm/vyos_pnf/helm-charts/eechart/source/run_ssh.sh new file mode 100755 index 0000000000000000000000000000000000000000..8b58b3cce67868565722c481427d683a14a84fe4 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/source/run_ssh.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +date "+%H:%M:%S Starting $0..." +IP=$1 +USERNAME=$2 +SCRIPT=$3 +PARAMS=$4 + +DIR=$(dirname $0) + +date "+%H:%M:%S Waiting for $IP to be ready..." +i=5 +while ! ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" 'exit' ; do + date "+%H:%M:%S Error accessing $IP, retrying..." + sleep 5 + i=$(( $i - 1 )) + [ $i -ge 0 ] || exit 1 +done + +date "+%H:%M:%S SSH server is up, sending script '${DIR}/${SCRIPT}'..." +scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${DIR}/${SCRIPT} "$USERNAME"@"$IP": +if [ $? -ne 0 ]; then + date "+%H:%M:%S scp error" + exit 1 +fi +date "+%H:%M:%S OK. Setting file permissions" +ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" "chmod a+x $SCRIPT" +if [ $? -ne 0 ]; then + date "+%H:%M:%S ssh error" + exit 1 +fi + +COMMAND="./$SCRIPT" +[ ${#PARAMS} -ge 0 ] || COMMAND="${COMMAND=} $PARAMS" +date "+%H:%M:%S Running '$COMMAND' on $IP..." +ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o ConnectTimeout=10 -o LogLevel=ERROR "$USERNAME"@"$IP" "$COMMAND" +if [ $? -ne 0 ]; then + date "+%H:%M:%S ssh error" + exit 1 +fi + +date "+%H:%M:%S End" +exit 0 diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/source/vnf_ee.py b/oai-helm/vyos_pnf/helm-charts/eechart/source/vnf_ee.py new file mode 100644 index 0000000000000000000000000000000000000000..c4015c3fadf3f2ae2343b1d58661bef3e6791882 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/source/vnf_ee.py @@ -0,0 +1,74 @@ +## +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +## + +import asyncio +import asyncssh +import requests +import logging +import os + +from osm_ee.exceptions import VnfException + +import osm_ee.util.util_ee as util_ee +import osm_ee.util.util_ansible as util_ansible +import osm_ee.vnf.mylib as mylib + +class VnfEE: + + PLAYBOOK_PATH = "/app/EE/osm_ee/vnf" + SSH_SCRIPT = "/app/EE/osm_ee/vnf/run_ssh.sh" + + def __init__(self, config_params): + self.logger = logging.getLogger('osm_ee.vnf') + self.config_params = config_params + + # config method saves SSH access parameters (host and username) for future use by other methods. + # It is mandatory in any case. + async def config(self, id, params): + self.logger.debug("Execute action config, params: {}".format(params)) + # Config action is special, params are merged with previous config calls + self.config_params.update(params) + required_params = ["ssh-hostname"] + self._check_required_params(self.config_params, required_params) + yield "OK", "Configured" + + # This method implements the "ansible_playbook" primitive. Uncomment and modify it if a primitive requires + # executing an Ansible Playbook. It needs "playbook-name" parameter (playbook file, must be in "source" directory). + async def ansible_playbook(self, id, params): + self.logger.debug("Execute action ansible_playbook, params: '{}'".format(params)) + + try: + self._check_required_params(params, ["playbook-name"]) + params["ansible_user"] = self.config_params["ssh-username"] + params["ansible_password"] = self.config_params["ssh-password"] + inventory = self.config_params["ssh-hostname"] + "," + playbook = self.PLAYBOOK_PATH + "/" + params["playbook-name"] + os.environ["ANSIBLE_HOST_KEY_CHECKING"] = "False" + return_code, stdout, stderr = await util_ansible.execute_playbook(playbook, inventory, params) + status = "OK" if return_code == 0 else "ERROR" + yield status, stdout + stderr + except Exception as e: + self.logger.debug("Error executing ansible playbook: {}".format(repr(e))) + yield "ERROR", str(e) + + # Static method that verifies whether a parameter exists in the map + @staticmethod + def _check_required_params(params, required_params): + for required_param in required_params: + if required_param not in params: + raise VnfException("Missing required param: {}".format(required_param)) + diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/NOTES.txt b/oai-helm/vyos_pnf/helm-charts/eechart/templates/NOTES.txt new file mode 100755 index 0000000000000000000000000000000000000000..c52fc2c419ef6f4cccfb63fd93ca7379bfc04cf7 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/NOTES.txt @@ -0,0 +1,21 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ . }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "eechart.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "eechart.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "eechart.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "eechart.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl port-forward $POD_NAME 8080:80 +{{- end }} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/_helpers.tpl b/oai-helm/vyos_pnf/helm-charts/eechart/templates/_helpers.tpl new file mode 100755 index 0000000000000000000000000000000000000000..d3e28e0260b8bff2fdef09046df0abaea885739c --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* vim: set filetype=mustache: */}} +{{/* +Expand the name of the chart. +*/}} +{{- define "eechart.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "eechart.fullname" -}} +{{- if .Values.fullnameOverride -}} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- $name := default .Chart.Name .Values.nameOverride -}} +{{- if contains $name .Release.Name -}} +{{- .Release.Name | trunc 63 | trimSuffix "-" -}} +{{- else -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} +{{- end -}} +{{- end -}} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "eechart.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Common labels +*/}} +{{- define "eechart.labels" -}} +app.kubernetes.io/name: {{ include "eechart.name" . }} +helm.sh/chart: {{ include "eechart.chart" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end -}} + +{{/* +Create the name of the service account to use +*/}} +{{- define "eechart.serviceAccountName" -}} +{{- if .Values.serviceAccount.create -}} + {{ default (include "eechart.fullname" .) .Values.serviceAccount.name }} +{{- else -}} + {{ default "default" .Values.serviceAccount.name }} +{{- end -}} +{{- end -}} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/configmap.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/configmap.yaml new file mode 100755 index 0000000000000000000000000000000000000000..5b9634c7e1abe64c6f720f708dd5c9664e72e8cf --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/configmap.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "eechart.fullname" . }} +data: +{{ (.Files.Glob "source/*").AsConfig | indent 2 }} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/generator.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/generator.yaml new file mode 100644 index 0000000000000000000000000000000000000000..96f7e237d85cecfba6f7047c169ba09fdcb8865e --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/generator.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "vnf-snmp-generator-{{ .Values.global.osm.vnf_id | lower }}" +data: + generator.yml: |- + {{ .Files.Get "snmp/generator.yml" | nindent 4}} \ No newline at end of file diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/ingress.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/ingress.yaml new file mode 100755 index 0000000000000000000000000000000000000000..264f89091bee2ba8746edc2841c275d28fef1168 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/ingress.yaml @@ -0,0 +1,41 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "eechart.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: +{{ include "eechart.labels" . | indent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: +{{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} +{{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ . }} + backend: + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/mibs.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/mibs.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e7b5eab55038ea9e0d17d7c8d0b9fc7dc15ddfe6 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/mibs.yaml @@ -0,0 +1,6 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "vnf-snmp-mibs-{{ .Values.global.osm.vnf_id | lower}}" +data: +{{ (.Files.Glob "snmp/mibs/**").AsConfig | indent 2 }} \ No newline at end of file diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/secret.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/secret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..62d4b267e8cae8df9dcdee471dcbb6a4151b040b --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "eechart.fullname" . }} +type: Opaque +data: + mysql_host: {{ .Values.mysql.fullnameOverride | b64enc | quote }} + mysql_user: {{ "root" | b64enc | quote }} + mysql_password: {{ .Values.mysql.auth.rootPassword | b64enc | quote }} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/service.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/service.yaml new file mode 100755 index 0000000000000000000000000000000000000000..88d38d66a3997c6e2a96754582736cfb065da6c2 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/service.yaml @@ -0,0 +1,16 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "eechart.fullname" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: grpc + protocol: TCP + name: grpc + selector: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/serviceaccount.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/serviceaccount.yaml new file mode 100755 index 0000000000000000000000000000000000000000..be615a5f08c7b557446fa74e5e3619e47d2ee804 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ template "eechart.serviceAccountName" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +{{- end -}} diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/statefulset.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/statefulset.yaml new file mode 100755 index 0000000000000000000000000000000000000000..a13cfa6e7a767ad96ac697fe2ae406c4b9ec6f53 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/statefulset.yaml @@ -0,0 +1,65 @@ +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "eechart.fullname" . }} + labels: +{{ include "eechart.labels" . | indent 4 }} +spec: + serviceName: {{ include "eechart.fullname" . }} + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + template: + metadata: + labels: + app.kubernetes.io/name: {{ include "eechart.name" . }} + app.kubernetes.io/instance: {{ .Release.Name }} + vnf: {{ .Values.global.osm.vnf_id | lower}} + spec: + imagePullSecrets: + - name: regcred + serviceAccountName: {{ template "eechart.serviceAccountName" . }} + securityContext: + runAsUser: 0 + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + envFrom: + - secretRef: + name: {{ include "eechart.fullname" . }} + ports: + - name: grpc + containerPort: 50051 + protocol: TCP + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: osm-ee + mountPath: /app/storage + - name: osm-ee-source + mountPath: /app/EE/osm_ee/vnf + - name: snmp-config-volume + mountPath: /etc/snmp_exporter + - name: vnf-mibs + mountPath: /root/.snmp/mibs + - name: vnf-generator + mountPath: /app/vnf/generator + volumes: + - name: osm-ee-source + configMap: + name: {{ include "eechart.fullname" . }} + - name: snmp-config-volume + hostPath: + path: "/var/lib/osm/snmp_exporter/{{ .Values.global.osm.vnf_id | lower }}/" + - name: vnf-mibs + configMap: + name: "vnf-snmp-mibs-{{ .Values.global.osm.vnf_id | lower}}" + - name: vnf-generator + configMap: + name: "vnf-snmp-generator-{{ .Values.global.osm.vnf_id | lower}}" + - name: osm-ee + hostPath: + path: /var/lib/osm/osm/osm_osm_packages/_data diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/templates/tests/test-connection.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/templates/tests/test-connection.yaml new file mode 100755 index 0000000000000000000000000000000000000000..e52b7b8b2515729e582b5efbc22dc5a0bdb0f3b2 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "eechart.fullname" . }}-test-connection" + labels: +{{ include "eechart.labels" . | indent 4 }} + annotations: + "helm.sh/hook": test-success +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "eechart.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/oai-helm/vyos_pnf/helm-charts/eechart/values.yaml b/oai-helm/vyos_pnf/helm-charts/eechart/values.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c63644a2497f459647ee3520206e8bc8fc05b544 --- /dev/null +++ b/oai-helm/vyos_pnf/helm-charts/eechart/values.yaml @@ -0,0 +1,77 @@ +global: + osm: + vnf_id: AVNFId + +# Default values for eechart. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: opensourcemano/api-fe + tag: latest + pullPolicy: IfNotPresent + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: false + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: + +podSecurityContext: {} + # fsGroup: 2000 + +securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + +service: + type: ClusterIP + port: 50050 + +ingress: + enabled: false + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + - host: chart-example.local + paths: [] + + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +mysql: + auth: + rootPassword: "123456" + fullnameOverride: "eechart-mysql" diff --git a/oai-helm/vyos_pnf/vyos_pnfd.yaml b/oai-helm/vyos_pnf/vyos_pnfd.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c3edebc403b3b9513035784d9d5e17b1d18eac93 --- /dev/null +++ b/oai-helm/vyos_pnf/vyos_pnfd.yaml @@ -0,0 +1,65 @@ +vnfd: + description: VyOS Router PNF + df: + - id: default-df + instantiation-level: + - id: default-instantiation-level + vdu-level: + - number-of-instances: 1 + vdu-id: gateway_pdu + vdu-profile: + - id: gateway_pdu + min-number-of-instances: 1 + lcm-operations-configuration: + operate-vnf-op-config: + day1-2: + - config-primitive: + # - execution-environment-primitive: ansible_playbook + # execution-environment-ref: vyos-config-ee + # name: ansible_playbook + # parameter: + # - data-type: STRING + # name: playbook-name + config-access: + ssh-access: + default-user: vyos + required: true + execution-environment-list: + - id: vyos-config-ee + helm-chart: eechart + id: vyos_pnf + initial-config-primitive: + - execution-environment-ref: vyos-config-ee + name: config + parameter: + - name: ssh-hostname + value: + - name: ssh-username + value: vyos + - name: ssh-password + value: vyos + seq: 1 + - execution-environment-ref: vyos-config-ee + name: ansible_playbook + parameter: + - name: playbook-name + value: configure-remote.yaml + seq: 2 + ext-cpd: + - id: gateway_public-ext + int-cpd: + cpd: eth0-int + vdu-id: gateway_pdu + id: vyos_pnf + mgmt-cp: gateway_public-ext + product-name: vyos_pnf + vdu: + - description: gateway_pdu + name: gateway_pdu + id: gateway_pdu + int-cpd: + - id: eth0-int + virtual-network-interface-requirement: + - name: eth0 + pdu-type: gateway + version: 1.0