aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xkud/tests/_common.sh12
-rwxr-xr-xkud/tests/plugin_collection_v2.sh392
-rw-r--r--kud/tests/vnfs/comp-app/collection/.helmignore22
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/.helmignore21
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/Chart.yaml19
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/resources/collectd.conf44
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/NOTES.txt34
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/_helpers.tpl25
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/configmap.yaml26
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/daemonset.yaml84
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/service.yaml32
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/helm/collectd/values.yaml78
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/profile/manifest.yaml4
-rw-r--r--kud/tests/vnfs/comp-app/collection/app1/profile/override_values.yaml9
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/.helmignore22
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/Chart.yaml5
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/NOTES.txt15
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/_helpers.tpl57
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/prometheus.yaml19
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/role.yaml21
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/rolebinding.yaml17
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/service.yaml38
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/serviceaccount.yaml11
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/servicemonitor.yaml30
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/values.yaml69
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/profile/manifest.yaml4
-rw-r--r--kud/tests/vnfs/comp-app/collection/app2/profile/override_values.yaml6
-rw-r--r--src/k8splugin/internal/app/instance.go2
-rw-r--r--src/orchestrator/api/api.go1
-rw-r--r--src/orchestrator/api/app_profilehandler.go4
-rw-r--r--src/orchestrator/api/apphandler.go28
-rw-r--r--src/orchestrator/pkg/infra/validation/validation.go264
-rw-r--r--src/orchestrator/pkg/infra/validation/validation_test.go466
-rw-r--r--src/orchestrator/pkg/module/app.go29
-rw-r--r--src/orchestrator/utils/utils.go66
-rw-r--r--src/orchestrator/utils/utils_test.go74
36 files changed, 1905 insertions, 145 deletions
diff --git a/kud/tests/_common.sh b/kud/tests/_common.sh
index 92c09b0d..cd704c53 100755
--- a/kud/tests/_common.sh
+++ b/kud/tests/_common.sh
@@ -1158,3 +1158,15 @@ function populate_CSAR_fw_rbdefinition {
popd
}
+function populate_CSAR_composite_app_helm {
+ _checks_args "$1"
+ pushd "${CSAR_DIR}/$1"
+ print_msg "Create Helm Chart Archives for compositeApp"
+ rm -f *.tar.gz
+ tar -czf collectd.tar.gz -C $test_folder/vnfs/comp-app/collection/app1/helm .
+ tar -czf prometheus.tar.gz -C $test_folder/vnfs/comp-app/collection/app2/helm .
+ tar -czf collectd_profile.tar.gz -C $test_folder/vnfs/comp-app/collection/app1/profile .
+ tar -czf prometheus_profile.tar.gz -C $test_folder/vnfs/comp-app/collection/app2/profile .
+ popd
+}
+
diff --git a/kud/tests/plugin_collection_v2.sh b/kud/tests/plugin_collection_v2.sh
new file mode 100755
index 00000000..068864d7
--- /dev/null
+++ b/kud/tests/plugin_collection_v2.sh
@@ -0,0 +1,392 @@
+# /*
+# * Copyright 2020 Intel Corporation, Inc
+# *
+# * 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.
+# */
+
+set -o errexit
+set -o nounset
+set -o pipefail
+#set -o xtrace
+
+source _common_test.sh
+source _functions.sh
+source _common.sh
+
+if [ ${1:+1} ]; then
+ if [ "$1" == "--external" ]; then
+ master_ip=$(kubectl cluster-info | grep "Kubernetes master" | \
+ awk -F ":" '{print $2}' | awk -F "//" '{print $2}')
+ onap_svc_node_port=30498
+ base_url="http://$master_ip:$onap_svc_node_port/v1"
+ fi
+fi
+
+base_url=${base_url:-"http://localhost:9015/v2"}
+kubeconfig_path="$HOME/.kube/config"
+csar_id=cb009bfe-bbee-11e8-9766-525400435678
+
+
+project_name="test_project"
+project_description="test_project_description"
+userData1="user1"
+userData2="user2"
+
+composite_app_name="test_composite_app"
+composite_app_description="test_project_description"
+composite_app_version="test_composite_app_version"
+app1_helm_path="$CSAR_DIR/$csar_id/collectd.tar.gz"
+app2_helm_path="$CSAR_DIR/$csar_id/prometheus.tar.gz"
+app1_profile_path="$CSAR_DIR/$csar_id/collectd_profile.tar.gz"
+app2_profile_path="$CSAR_DIR/$csar_id/prometheus_profile.tar.gz"
+
+app1_name="collectd"
+app2_name="prometheus"
+app1_desc="collectd_desc"
+app2_desc="prometheus_desc"
+
+main_composite_profile_name="main_composite_profile"
+sub_composite_profile_name1="test_composite_profile1"
+sub_composite_profile_name2="test_composite_profile2"
+composite_profile_description="test_composite_profile_description"
+
+genericPlacementIntentName1="test_gen_placement_intent1"
+genericPlacementIntentName2="test_gen_placement_intent2"
+genericPlacementIntentDesc="test_gen_placement_intent_desc"
+logicalCloud="logical_cloud_name"
+clusterName1="edge1"
+clusterName2="edge2"
+clusterLabelName1="east-us1"
+clusterLabelName2="east-us2"
+
+deploymentIntentGroupName="test_deployment_intent_group"
+deploymentIntentGroupNameDesc="test_deployment_intent_group_desc"
+
+chart_name="edgex"
+profile_name="test_profile"
+release_name="test-release"
+namespace="plugin-tests-namespace"
+cloud_region_id="kud"
+cloud_region_owner="localhost"
+
+# Setup
+install_deps
+populate_CSAR_composite_app_helm "$csar_id"
+
+# BEGIN: Register project API
+print_msg "Registering project"
+payload="$(cat <<EOF
+{
+ "metadata": {
+ "name": "${project_name}",
+ "description": "${project_description}",
+ "userData1": "${userData1}",
+ "userData2": "${userData2}"
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects"
+# END: Register project API
+
+# BEGIN: Register composite-app API
+print_msg "Registering composite-app"
+payload="$(cat <<EOF
+{
+ "metadata": {
+ "name": "${composite_app_name}",
+ "description": "${composite_app_description}",
+ "userData1": "${userData1}",
+ "userData2": "${userData2}"
+ },
+ "spec":{
+ "version":"${composite_app_version}"
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps"
+# END: Register composite-app API
+
+
+
+
+# BEGIN: Create entries for app1&app2 in the database
+print_msg "Making app entry in the database"
+payload="$(cat <<EOF
+{
+ "metadata": {
+ "name": "${app1_name}",
+ "description": "${app1_desc}",
+ "userData1": "${userData1}",
+ "userData2": "${userData2}"
+ }
+}
+EOF
+)"
+
+call_api -F "metadata=$payload" \
+ -F "file=@$app1_helm_path" \
+ "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/apps"
+
+
+# BEGIN: Create an entry for app2 in the database
+print_msg "Making app entry in the database"
+payload="$(cat <<EOF
+{
+ "metadata": {
+ "name": "${app2_name}",
+ "description": "${app2_desc}",
+ "userData1": "${userData1}",
+ "userData2": "${userData2}"
+ }
+}
+EOF
+)"
+
+call_api -F "metadata=$payload" \
+ -F "file=@$app2_helm_path" \
+ "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/apps"
+# END: Create entries for app1&app2 in the database
+
+
+# BEGIN: Register the main composite-profile
+print_msg "Registering the main composite-profile"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${main_composite_profile_name}",
+ "description":"${composite_profile_description}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/composite-profiles"
+# BEGIN: Register the main composite-profile
+
+
+# BEGIN : Adding profile to each of the two apps - app1(collectd) and app2(prometheus)
+print_msg "Registering profile with app1(collectd)"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${sub_composite_profile_name1}",
+ "description":"${composite_profile_description}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "app-name": "${app1_name}"
+ }
+}
+EOF
+)"
+
+call_api -F "metadata=$payload" \
+ -F "file=@$app1_profile_path" \
+ "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/composite-profiles/${main_composite_profile_name}/profiles"
+
+print_msg "Registering profile with app2(prometheus)"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${sub_composite_profile_name2}",
+ "description":"${composite_profile_description}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "app-name": "${app2_name}"
+ }
+}
+EOF
+)"
+
+call_api -F "metadata=$payload" \
+ -F "file=@$app2_profile_path" \
+ "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/composite-profiles/${main_composite_profile_name}/profiles"
+# END : Adding profile to each of the two apps - app1(collectd) and app2(prometheus)
+
+# BEGIN: Register GenericPlacementIntents with the database
+print_msg "Registering GenericPlacementIntent for app1"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${genericPlacementIntentName1}",
+ "description":"${genericPlacementIntentDesc}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "logical-cloud":"${logicalCloud}"
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents"
+
+
+print_msg "Registering GenericPlacementIntent for app2"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${genericPlacementIntentName2}",
+ "description":"${genericPlacementIntentDesc}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "logical-cloud":"${logicalCloud}"
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents"
+# END: Register GenericPlacementIntents with the database
+
+# BEGIN: Adding placement intent for each app in the composite app.
+print_msg "Adding placement intent for app1(collectd)"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${genericPlacementIntentName1}",
+ "description":"${genericPlacementIntentDesc}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "app-name":"${app1_name}",
+ "intent":{
+ "allOf":[
+ {
+ "cluster-name":"${clusterName1}"
+ },
+ {
+ "cluster-name":"${clusterName2}"
+ },
+ {
+ "anyOf":[
+ {
+ "cluster-label-name":"${clusterLabelName1}"
+ },
+ {
+ "cluster-label-name":"${clusterLabelName2}"
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents/${genericPlacementIntentName1}/app-intents"
+
+print_msg "Adding placement intent for app2(prometheus)"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${genericPlacementIntentName2}",
+ "description":"${genericPlacementIntentDesc}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "app-name":"${app2_name}",
+ "intent":{
+ "allOf":[
+ {
+ "cluster-name":"${clusterName1}"
+ },
+ {
+ "cluster-name":"${clusterName2}"
+ },
+ {
+ "anyOf":[
+ {
+ "cluster-label-name":"${clusterLabelName1}"
+ },
+ {
+ "cluster-label-name":"${clusterLabelName2}"
+ }
+ ]
+ }
+ ]
+ }
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/generic-placement-intents/${genericPlacementIntentName2}/app-intents"
+# END: Adding placement intent for each app in the composite app.
+
+# BEGIN: Registering DeploymentIntentGroup in the database
+print_msg "Registering DeploymentIntentGroup"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${deploymentIntentGroupName}",
+ "description":"${deploymentIntentGroupNameDesc}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "profile":"${main_composite_profile_name}",
+ "version":"${composite_app_version}",
+ "override-values":[
+ {
+ "app-name":"${app1_name}",
+ "values":
+ {
+ "imageRepository":"registry.hub.docker.com"
+ }
+ },
+ {
+ "app-name":"${app2_name}",
+ "values":
+ {
+ "imageRepository":"registry.hub.docker.com"
+ }
+ }
+ ]
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/deployment-intent-groups"
+# END: Registering DeploymentIntentGroup in the database
+
+# BEGIN: Adding intents to an intent group
+print_msg "Adding two intents to the intent group"
+payload="$(cat <<EOF
+{
+ "metadata":{
+ "name":"${deploymentIntentGroupName}",
+ "description":"${deploymentIntentGroupNameDesc}",
+ "userData1":"${userData1}",
+ "userData2":"${userData2}"
+ },
+ "spec":{
+ "intent":{
+ "generic-placement-intent":"${genericPlacementIntentName1}",
+ "generic-placement-intent":"${genericPlacementIntentName2}"
+ }
+ }
+}
+EOF
+)"
+call_api -d "${payload}" "${base_url}/projects/${project_name}/composite-apps/${composite_app_name}/${composite_app_version}/deployment-intent-groups/${deploymentIntentGroupName}/intents"
+# END: Adding intents to an intent group
+
diff --git a/kud/tests/vnfs/comp-app/collection/.helmignore b/kud/tests/vnfs/comp-app/collection/.helmignore
new file mode 100644
index 00000000..50af0317
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/.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/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/.helmignore b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/.helmignore
new file mode 100644
index 00000000..f0c13194
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/.helmignore
@@ -0,0 +1,21 @@
+# 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
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/Chart.yaml b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/Chart.yaml
new file mode 100644
index 00000000..fcdcfde9
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/Chart.yaml
@@ -0,0 +1,19 @@
+# Copyright 2019 Intel Corporation, Inc
+#
+# 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.
+
+apiVersion: v1
+appVersion: "7.1.0"
+description: Collectd Helm Chart
+name: collectd
+version: 0.2.0
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/resources/collectd.conf b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/resources/collectd.conf
new file mode 100644
index 00000000..b023b320
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/resources/collectd.conf
@@ -0,0 +1,44 @@
+FQDNLookup false
+LoadPlugin cpu
+LoadPlugin memory
+LoadPlugin cpufreq
+LoadPlugin disk
+LoadPlugin ethstat
+LoadPlugin ipc
+LoadPlugin ipmi
+LoadPlugin load
+LoadPlugin numa
+LoadPlugin processes
+LoadPlugin df
+LoadPlugin turbostat
+LoadPlugin uptime
+LoadPlugin contextswitch
+LoadPlugin irq
+LoadPlugin df
+LoadPlugin swap
+LoadPlugin write_prometheus
+
+LoadPlugin logfile
+<Plugin logfile>
+ LogLevel info
+ File "/var/log/collectd.log"
+ Timestamp true
+ PrintSeverity false
+</Plugin>
+<Plugin "cpu">
+ Interval 5
+ ReportByState false
+ ReportByCpu false
+</Plugin>
+
+<Plugin "memory">
+ Interval 30
+ ValuesAbsolute false
+ ValuesPercentage true
+</Plugin>
+
+<Plugin "write_prometheus">
+ Port "{{ .Values.collectd_prometheus.service.targetPort }}"
+</Plugin>
+
+#Last line (collectd requires ā€˜\nā€™ at the last line)
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/NOTES.txt b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/NOTES.txt
new file mode 100644
index 00000000..06ca128b
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/NOTES.txt
@@ -0,0 +1,34 @@
+# Copyright (c) 2019 Intel Corporation.
+#
+# 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.
+
+
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range .Values.ingress.hosts }}
+ http://{{ . }}
+{{- end }}
+{{- else if contains "NodePort" .Values.collectd_prometheus.service.type }}
+ NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "name" . }})
+ NODE_IPS=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[*].status.addresses[0].address}")
+ visit http://NODE_IP:NODE_PORT
+{{- else if contains "LoadBalancer" .Values.collectd_prometheus.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 svc -w {{ include "name" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "name" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+ echo http://$SERVICE_IP:{{ .Values.service.externalPort }}
+{{- else if contains "ClusterIP" .Values.collectd_prometheus.service.type }}
+ CLUSTER_NODE_IPS=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[*].status.addresses[0].address}")
+ CLUSTER_NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].port}" services {{ include "name" . }})
+ visit http://CLUSTER_NODE_IP:CLUSTER_NODE_PORT
+{{- end }}
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/_helpers.tpl b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/_helpers.tpl
new file mode 100644
index 00000000..b5e98086
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/_helpers.tpl
@@ -0,0 +1,25 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "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).
+*/}}
+{{- define "fullname" -}}
+{{- $name := default .Chart.Name .Values.nameOverride -}}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/* Workaround for https://github.com/helm/helm/issues/3117 */}}
+{{- define "rangeskipempty" -}}
+{{- range $key, $value := . }}
+{{- if $value }}
+{{ $key }}: {{ $value }}
+{{- end }}
+{{- end }}
+{{- end }} \ No newline at end of file
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/configmap.yaml b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/configmap.yaml
new file mode 100644
index 00000000..26d0fb5d
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/configmap.yaml
@@ -0,0 +1,26 @@
+{{/*
+# Copyright 2019 Intel Corporation, Inc
+#
+# 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.
+*/}}
+
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ template "fullname" . }}-config
+ labels:
+ app: {{ template "name" . }}
+ chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
+ release: {{ .Release.Name }}
+data:
+ {{- tpl (.Files.Glob "resources/*").AsConfig . | nindent 2 }}
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/daemonset.yaml b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/daemonset.yaml
new file mode 100644
index 00000000..bc686381
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/daemonset.yaml
@@ -0,0 +1,84 @@
+{{/*
+# Copyright 2019 Intel Corporation, Inc
+#
+# 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.
+*/}}
+
+apiVersion: extensions/v1beta1
+kind: DaemonSet
+metadata:
+ name: {{ template "fullname" . }}
+ annotations:
+ checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
+ labels:
+ app: {{ template "name" . }}
+ chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
+ release: {{ .Release.Name }}
+spec:
+ replicas: {{ .Values.replicaCount }}
+ updateStrategy:
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app: {{ template "name" . }}
+ collector: collectd
+ release: {{ .Release.Name }}
+ spec:
+ hostNetwork: true
+ {{- if .Values.serviceAccountName }}
+ serviceAccountName: {{ .Values.serviceAccountName }}
+ {{- end }}
+{{- if .Values.tolerations }}
+ tolerations:
+{{ toYaml .Values.tolerations | trim | indent 8 }}
+{{- end }}
+{{- if .Values.nodeSelector }}
+ nodeSelector:
+{{ toYaml .Values.nodeSelector | trim | indent 8 }}
+{{- end }}
+ containers:
+ - name: {{ .Chart.Name }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ securityContext:
+ allowPrivilegeEscalation: true
+ privileged: true
+{{- if .Values.env }}
+ env:
+{{ toYaml .Values.env | trim | indent 10 }}
+{{- end }}
+{{- if .Values.command }}
+ command:
+{{ toYaml .Values.command | trim | indent 10 }}
+{{- end }}
+{{- if .Values.args }}
+ args:
+{{ toYaml .Values.args | trim | indent 10 }}
+{{- end }}
+ volumeMounts:
+ - name: {{ template "fullname" . }}-config
+ mountPath: {{ .Values.configMountPath }}
+{{- if .Values.volumeMounts }}
+{{ toYaml .Values.volumeMounts | trim | indent 10 }}
+{{- end }}
+ resources:
+{{- toYaml .Values.resources | trim | indent 12}}
+ volumes:
+ - name: {{ template "fullname" . }}-config
+ configMap:
+ name: {{ template "fullname" . }}-config
+ defaultMode: 0744
+{{- if .Values.volumeMounts }}
+{{ toYaml .Values.volumes | indent 6 }}
+{{- end }}
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/service.yaml b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/service.yaml
new file mode 100644
index 00000000..7571715d
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/templates/service.yaml
@@ -0,0 +1,32 @@
+{{/*
+# Copyright 2019 Intel Corporation, Inc
+#
+# 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.
+*/}}
+
+apiVersion: v1
+kind: Service
+metadata:
+ name: collectd
+ labels:
+ app: collectd
+ release: {{ .Release.Name }}
+spec:
+ ports:
+ - name: collectd-prometheus
+ port: {{ .Values.collectd_prometheus.service.port }}
+ protocol: TCP
+ targetPort: {{ .Values.collectd_prometheus.service.targetPort }}
+ selector:
+{{ include "rangeskipempty" .Values.collectd_prometheus.service.selector | indent 4 }}
+ type: ClusterIP
diff --git a/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/values.yaml b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/values.yaml
new file mode 100644
index 00000000..41d63cbf
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/helm/collectd/values.yaml
@@ -0,0 +1,78 @@
+# Default values for collectd.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+ingress:
+ enabled: false
+image:
+ repository: opnfv/barometer-collectd
+ tag: latest
+ pullPolicy: IfNotPresent
+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
+
+
+#serviceAccountName: cmk-serviceaccount
+
+# Uncomment the following tolerations and/or nodeSelector to select the node collectd to be deployed
+#tolerations:
+# - operator: "Exists"
+#nodeSelector:
+# vcmts: "true"
+
+# Uncomment the following to set environment, command and args for the collectd container
+#env:
+#- name: CMK_PROC_FS
+# value: "/host/proc"
+#command:
+#- "/bin/bash"
+#- "-c"
+#args: [ "/opt/bin/cmk isolate --conf-dir=/etc/cmk --pool=infra /script/collectd.sh" ]
+
+# all the files under the directory resource will be mount into the directory specified by 'configMountPath' inside the container.
+# Besides that, users can specify any mount by using the 'volumeMounts' and 'volumes'.
+configMountPath: /opt/collectd/etc
+volumeMounts:
+- name: proc
+ mountPath: /mnt/proc
+ readOnly: true
+- name: root
+ mountPath: /hostfs
+ readOnly: true
+- name: etc
+ mountPath: /mnt/etc
+ readOnly: true
+- name: run
+ mountPath: /var/run/docker.sock
+
+volumes:
+- name: proc
+ hostPath:
+ path: /proc
+- name: root
+ hostPath:
+ path: /
+- name: etc
+ hostPath:
+ path: /etc
+- name: run
+ hostPath:
+ path: /var/run/docker.sock
+
+collectd_prometheus:
+ service:
+ type: ClusterIP
+ name: collectd
+ port: 9103
+ targetPort: 9103
+ selector:
+ app: collectd
+ collector: collectd
diff --git a/kud/tests/vnfs/comp-app/collection/app1/profile/manifest.yaml b/kud/tests/vnfs/comp-app/collection/app1/profile/manifest.yaml
new file mode 100644
index 00000000..4d381d02
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/profile/manifest.yaml
@@ -0,0 +1,4 @@
+---
+version: v1
+type:
+ values: "override_values.yaml"
diff --git a/kud/tests/vnfs/comp-app/collection/app1/profile/override_values.yaml b/kud/tests/vnfs/comp-app/collection/app1/profile/override_values.yaml
new file mode 100644
index 00000000..304ae5de
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app1/profile/override_values.yaml
@@ -0,0 +1,9 @@
+collectd_prometheus:
+ service:
+ type: ClusterIP
+ name: collectd-override
+ port: 9103
+ targetPort: 9103
+ selector:
+ app: collectd
+ collector: collectd \ No newline at end of file
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/.helmignore b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/.helmignore
new file mode 100644
index 00000000..50af0317
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/.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/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/Chart.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/Chart.yaml
new file mode 100644
index 00000000..6e7ddfbc
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/Chart.yaml
@@ -0,0 +1,5 @@
+apiVersion: v1
+appVersion: "1.0"
+description: Prometheus instance with remote storage integrations.
+name: prometheus
+version: 0.1.0
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/NOTES.txt b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/NOTES.txt
new file mode 100644
index 00000000..f8882883
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/NOTES.txt
@@ -0,0 +1,15 @@
+1. Get the application URL by running these commands:
+{{ if contains "NodePort" .Values.prometheus.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "prometheus.fullname" . }}-prometheus)
+ 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.prometheus.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 svc -w {{ include "prometheus.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "prometheus.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
+ echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.prometheus.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "prometheus.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ echo "Visit http://127.0.0.1:9090 to use your application"
+ kubectl port-forward $POD_NAME 9090:80
+{{- end }}
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/_helpers.tpl b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/_helpers.tpl
new file mode 100644
index 00000000..17b7e7bd
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/_helpers.tpl
@@ -0,0 +1,57 @@
+{{/* vim: set filetype=mustache: */}}
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "prometheus.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 "prometheus.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 "prometheus.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
+{{- end -}}
+
+{{/* Create chart name and version as used by the chart label. */}}
+{{- define "prometheus.chartref" -}}
+{{- replace "+" "_" .Chart.Version | printf "%s-%s" .Chart.Name -}}
+{{- end }}
+
+{{/* Generate basic labels */}}
+{{- define "prometheus.labels" }}
+chart: {{ template "prometheus.chartref" . }}
+release: {{ .Release.Name | quote }}
+heritage: {{ .Release.Service | quote }}
+{{- if .Values.commonLabels}}
+{{ toYaml .Values.commonLabels }}
+{{- end }}
+{{- end }}
+
+
+{{/* Create the name of prometheus service account to use */}}
+{{- define "prometheus.serviceAccountName" -}}
+{{- if .Values.prometheus.serviceAccount.create -}}
+ {{ default (include "prometheus.fullname" .) .Values.prometheus.serviceAccount.name }}
+{{- else -}}
+ {{ default "default" .Values.prometheus.serviceAccount.name }}
+{{- end -}}
+{{- end -}} \ No newline at end of file
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/prometheus.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/prometheus.yaml
new file mode 100644
index 00000000..53494920
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/prometheus.yaml
@@ -0,0 +1,19 @@
+apiVersion: monitoring.coreos.com/v1
+kind: Prometheus
+metadata:
+ name: {{ template "prometheus.fullname" . }}-prometheus
+ labels:
+ app: {{ template "prometheus.name" . }}-prometheus
+ "helm.sh/hook": post-install
+ "helm.sh/hook-weight": "2"
+spec:
+ serviceAccountName: {{ template "prometheus.serviceAccountName" . }}
+ serviceMonitorSelector:
+ matchLabels:
+ app: {{ template "prometheus.name" . }}-prometheus
+ release: {{ .Release.Name }}
+ serviceMonitorNamespaceSelector:
+ matchNames:
+ - {{ .Release.Namespace | quote }}
+ resources:
+{{ toYaml .Values.prometheus.resources | indent 4 }}
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/role.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/role.yaml
new file mode 100644
index 00000000..dfb932d8
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/role.yaml
@@ -0,0 +1,21 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+kind: Role
+metadata:
+ name: {{ template "prometheus.fullname" . }}-prometheus
+ labels:
+ app: {{ template "prometheus.name" . }}-prometheus
+{{ include "prometheus.labels" . | indent 4 }}
+rules:
+- apiGroups:
+ - ""
+ resources:
+ - nodes
+ - services
+ - endpoints
+ - pods
+ verbs:
+ - get
+ - list
+ - watch \ No newline at end of file
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/rolebinding.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/rolebinding.yaml
new file mode 100644
index 00000000..04932ee1
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/rolebinding.yaml
@@ -0,0 +1,17 @@
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+ name: {{ template "prometheus.fullname" . }}-prometheus
+ labels:
+ app: {{ template "prometheus.name" . }}-prometheus
+{{ include "prometheus.labels" . | indent 4 }}
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: Role
+ name: {{ template "prometheus.fullname" . }}-prometheus
+subjects:
+- kind: ServiceAccount
+ name: {{ template "prometheus.serviceAccountName" . }}
+ namespace: {{ .Release.Namespace }} \ No newline at end of file
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/service.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/service.yaml
new file mode 100644
index 00000000..0114ed2e
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/service.yaml
@@ -0,0 +1,38 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ template "prometheus.fullname" . }}-prometheus
+ labels:
+ app: {{ template "prometheus.name" . }}-prometheus
+{{- if .Values.prometheus.service.annotations }}
+ annotations:
+{{ toYaml .Values.prometheus.service.annotations | indent 4 }}
+{{- end }}
+spec:
+{{- if .Values.prometheus.service.clusterIP }}
+ clusterIP: {{ .Values.prometheus.service.clusterIP }}
+{{- end }}
+{{- if .Values.prometheus.service.externalIPs }}
+ externalIPs:
+{{ toYaml .Values.prometheus.service.externalIPs | indent 4 }}
+{{- end }}
+{{- if .Values.prometheus.service.loadBalancerIP }}
+ loadBalancerIP: {{ .Values.prometheus.service.loadBalancerIP }}
+{{- end }}
+{{- if .Values.prometheus.service.loadBalancerSourceRanges }}
+ loadBalancerSourceRanges:
+ {{- range $cidr := .Values.prometheus.service.loadBalancerSourceRanges }}
+ - {{ $cidr }}
+ {{- end }}
+{{- end }}
+ ports:
+ - name: web
+ {{- if eq .Values.prometheus.service.type "NodePort" }}
+ nodePort: {{ .Values.global.nodePortPrefix }}{{ .Values.prometheus.service.nodePort }}
+ {{- end }}
+ port: 9090
+ targetPort: web
+ selector:
+ app: prometheus
+ prometheus: {{ template "prometheus.fullname" . }}-prometheus
+ type: "{{ .Values.prometheus.service.type }}"
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/serviceaccount.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/serviceaccount.yaml
new file mode 100644
index 00000000..82437523
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/serviceaccount.yaml
@@ -0,0 +1,11 @@
+{{- if .Values.prometheus.serviceAccount.create }}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ template "prometheus.serviceAccountName" . }}
+ labels:
+ app: {{ template "prometheus.name" . }}-prometheus
+{{ include "prometheus.labels" . | indent 4 }}
+imagePullSecrets:
+{{ toYaml .Values.global.imagePullSecrets | indent 2 }}
+{{- end }}
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/servicemonitor.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/servicemonitor.yaml
new file mode 100644
index 00000000..ea2b81b6
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/templates/servicemonitor.yaml
@@ -0,0 +1,30 @@
+{{- if .Values.prometheus.additionalServiceMonitors }}
+apiVersion: v1
+kind: List
+items:
+{{- range .Values.prometheus.additionalServiceMonitors }}
+ - apiVersion: "monitoring.coreos.com/v1"
+ kind: ServiceMonitor
+ metadata:
+ name: {{ .name }}
+ "helm.sh/hook": post-install
+ "helm.sh/hook-weight": "1"
+ labels:
+ app: {{ template "prometheus.name" $ }}-prometheus
+{{ include "prometheus.labels" $ | indent 8 }}
+ {{- if .additionalLabels }}
+{{ toYaml .additionalLabels | indent 8 }}
+ {{- end }}
+ spec:
+ endpoints:
+{{ toYaml .endpoints | indent 8 }}
+ {{- if .jobLabel }}
+ jobLabel: {{ .jobLabel }}
+ {{- end }}
+ namespaceSelector:
+ matchNames:
+ - {{ $.Release.Namespace | quote }}
+ selector:
+{{ toYaml .selector | indent 8 }} release: {{ $.Release.Name | quote }}
+{{- end }}
+{{- end }}
diff --git a/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/values.yaml b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/values.yaml
new file mode 100644
index 00000000..e35c6735
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/helm/prometheus/values.yaml
@@ -0,0 +1,69 @@
+## Deploy a Prometheus instance
+##
+prometheus:
+ serviceAccount:
+ create: true
+ name: ""
+ additionalServiceMonitors:
+ - name: service-monitor-collectd
+ additionalLabels:
+ collector: collectd
+ jobLabel: collectd
+ selector:
+ matchLabels:
+ app: collectd
+ endpoints:
+ - port: collectd-prometheus
+ interval: 10s
+ path: /metrics
+ - name: service-monitor-node-exporter
+ additionalLabels:
+ collector: prometheus-node-exporter
+ jobLabel: node-exporter
+ selector:
+ matchLabels:
+ app: prometheus-node-exporter
+ endpoints:
+ - port: metrics
+ interval: 30s
+ - name: service-monitor-cadvisor
+ additionalLabels:
+ collector: cadvisor
+ jobLabel: cadvisor
+ selector:
+ matchLabels:
+ app: cadvisor
+ endpoints:
+ - port: cadvisor-prometheus
+ interval: 10s
+ path: /metrics
+
+ resources: {}
+ service:
+ type: ClusterIP
+ annotations: {}
+ labels: {}
+ clusterIP: ""
+
+ ## To be used with a proxy extraContainer port
+ targetPort: 9090
+
+ ## List of IP addresses at which the Prometheus server service is available
+ ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
+ ##
+ externalIPs: []
+
+ ## Port to expose on each node
+ ## Only used if service.type is 'NodePort'
+ ##
+ # nodePort: 90
+
+ ## Loadbalancer IP
+ ## Only use if service.type is "loadbalancer"
+ loadBalancerIP: ""
+ loadBalancerSourceRanges: []
+ ## Service type
+ ##
+ #type: NodePort
+
+ sessionAffinity: ""
diff --git a/kud/tests/vnfs/comp-app/collection/app2/profile/manifest.yaml b/kud/tests/vnfs/comp-app/collection/app2/profile/manifest.yaml
new file mode 100644
index 00000000..4d381d02
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/profile/manifest.yaml
@@ -0,0 +1,4 @@
+---
+version: v1
+type:
+ values: "override_values.yaml"
diff --git a/kud/tests/vnfs/comp-app/collection/app2/profile/override_values.yaml b/kud/tests/vnfs/comp-app/collection/app2/profile/override_values.yaml
new file mode 100644
index 00000000..6743ac5b
--- /dev/null
+++ b/kud/tests/vnfs/comp-app/collection/app2/profile/override_values.yaml
@@ -0,0 +1,6 @@
+service:
+ type: ClusterIP
+ name: Prometheus
+ annotations: {}
+ labels: {}
+ clusterIP: "" \ No newline at end of file
diff --git a/src/k8splugin/internal/app/instance.go b/src/k8splugin/internal/app/instance.go
index 5d8b2100..d6eb91b4 100644
--- a/src/k8splugin/internal/app/instance.go
+++ b/src/k8splugin/internal/app/instance.go
@@ -120,7 +120,7 @@ func NewInstanceClient() *InstanceClient {
}
}
-// Create an entry for the resource bundle profile in the database
+// Create an instance of rb on the cluster in the database
func (v *InstanceClient) Create(i InstanceRequest) (InstanceResponse, error) {
// Name is required
diff --git a/src/orchestrator/api/api.go b/src/orchestrator/api/api.go
index 70b40d96..a261319c 100644
--- a/src/orchestrator/api/api.go
+++ b/src/orchestrator/api/api.go
@@ -84,6 +84,7 @@ func NewRouter(projectClient moduleLib.ProjectManager,
router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{version}/apps", appHandler.createAppHandler).Methods("POST")
router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{version}/apps/{app-name}", appHandler.getAppHandler).Methods("GET")
+ router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{version}/apps", appHandler.getAppHandler).Methods("GET")
router.HandleFunc("/projects/{project-name}/composite-apps/{composite-app-name}/{version}/apps/{app-name}", appHandler.deleteAppHandler).Methods("DELETE")
if compositeProfileClient == nil {
diff --git a/src/orchestrator/api/app_profilehandler.go b/src/orchestrator/api/app_profilehandler.go
index 16423483..ef7833de 100644
--- a/src/orchestrator/api/app_profilehandler.go
+++ b/src/orchestrator/api/app_profilehandler.go
@@ -27,8 +27,8 @@ import (
"net/http"
"net/textproto"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation"
moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module"
- "github.com/onap/multicloud-k8s/src/orchestrator/utils"
"github.com/gorilla/mux"
pkgerrors "github.com/pkg/errors"
@@ -89,7 +89,7 @@ func (h appProfileHandler) createAppProfileHandler(w http.ResponseWriter, r *htt
return
}
- err = utils.IsTarGz(bytes.NewBuffer(content))
+ err = validation.IsTarGz(bytes.NewBuffer(content))
if err != nil {
http.Error(w, "Error in file format", http.StatusUnprocessableEntity)
return
diff --git a/src/orchestrator/api/apphandler.go b/src/orchestrator/api/apphandler.go
index 3cd2dbc8..2c81431c 100644
--- a/src/orchestrator/api/apphandler.go
+++ b/src/orchestrator/api/apphandler.go
@@ -27,8 +27,8 @@ import (
"net/http"
"net/textproto"
+ "github.com/onap/multicloud-k8s/src/orchestrator/pkg/infra/validation"
moduleLib "github.com/onap/multicloud-k8s/src/orchestrator/pkg/module"
- "github.com/onap/multicloud-k8s/src/orchestrator/utils"
"github.com/gorilla/mux"
)
@@ -92,7 +92,7 @@ func (h appHandler) createAppHandler(w http.ResponseWriter, r *http.Request) {
return
}
- err = utils.IsTarGz(bytes.NewBuffer(content))
+ err = validation.IsTarGz(bytes.NewBuffer(content))
if err != nil {
http.Error(w, "Error in file format", http.StatusUnprocessableEntity)
return
@@ -129,6 +129,30 @@ func (h appHandler) getAppHandler(w http.ResponseWriter, r *http.Request) {
compositeAppVersion := vars["version"]
name := vars["app-name"]
+ // handle the get all apps case - return a list of only the json parts
+ if len(name) == 0 {
+ var retList []moduleLib.App
+
+ ret, err := h.client.GetApps(projectName, compositeAppName, compositeAppVersion)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+
+ for _, app := range ret {
+ retList = append(retList, moduleLib.App{Metadata: app.Metadata})
+ }
+
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ err = json.NewEncoder(w).Encode(retList)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ return
+ }
+
accepted, _, err := mime.ParseMediaType(r.Header.Get("Accept"))
if err != nil {
http.Error(w, err.Error(), http.StatusNotAcceptable)
diff --git a/src/orchestrator/pkg/infra/validation/validation.go b/src/orchestrator/pkg/infra/validation/validation.go
new file mode 100644
index 00000000..d744dc3d
--- /dev/null
+++ b/src/orchestrator/pkg/infra/validation/validation.go
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2020 Intel Corporation, Inc
+ *
+ * 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.
+ */
+
+package validation
+
+import (
+ "archive/tar"
+ "compress/gzip"
+ "io"
+ "net"
+ "regexp"
+ "strings"
+
+ pkgerrors "github.com/pkg/errors"
+ "k8s.io/apimachinery/pkg/util/validation"
+)
+
+func IsTarGz(r io.Reader) error {
+ //Check if it is a valid gz
+ gzf, err := gzip.NewReader(r)
+ if err != nil {
+ return pkgerrors.Wrap(err, "Invalid gzip format")
+ }
+
+ //Check if it is a valid tar file
+ //Unfortunately this can only be done by inspecting all the tar contents
+ tarR := tar.NewReader(gzf)
+ first := true
+
+ for true {
+ header, err := tarR.Next()
+
+ if err == io.EOF {
+ //Check if we have just a gzip file without a tar archive inside
+ if first {
+ return pkgerrors.New("Empty or non-existant Tar file found")
+ }
+ //End of archive
+ break
+ }
+
+ if err != nil {
+ return pkgerrors.Errorf("Error reading tar file %s", err.Error())
+ }
+
+ //Check if files are of type directory and regular file
+ if header.Typeflag != tar.TypeDir &&
+ header.Typeflag != tar.TypeReg {
+ return pkgerrors.Errorf("Unknown header in tar %s, %s",
+ header.Name, string(header.Typeflag))
+ }
+
+ first = false
+ }
+
+ return nil
+}
+
+func IsIpv4Cidr(cidr string) error {
+ _, _, err := net.ParseCIDR(cidr)
+ if err != nil {
+ return pkgerrors.Wrapf(err, "could not parse subnet %v", cidr)
+ }
+ return nil
+}
+
+func IsIpv4(ip string) error {
+ addr := net.ParseIP(ip)
+ if addr == nil {
+ return pkgerrors.Errorf("invalid ipv4 address %v", ip)
+ }
+ return nil
+}
+
+// default name check - matches valid label value with addtion that length > 0
+func IsValidName(name string) []string {
+ var errs []string
+
+ errs = validation.IsValidLabelValue(name)
+ if len(name) == 0 {
+ errs = append(errs, "name must have non-zero length")
+ }
+ return errs
+}
+
+const VALID_NAME_STR string = "NAME"
+
+var validNameRegEx = regexp.MustCompile("^([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9]$")
+
+const VALID_ALPHA_STR string = "ALPHA"
+
+var validAlphaStrRegEx = regexp.MustCompile("^[A-Za-z]*$")
+
+const VALID_ALPHANUM_STR string = "ALPHANUM"
+
+var validAlphaNumStrRegEx = regexp.MustCompile("^[A-Za-z0-9]*$")
+
+// doesn't verify valid base64 length - just checks for proper base64 characters
+const VALID_BASE64_STR string = "BASE64"
+
+var validBase64StrRegEx = regexp.MustCompile("^[A-Za-z0-9+/]+={0,2}$")
+
+const VALID_ANY_STR string = "ANY"
+
+var validAnyStrRegEx = regexp.MustCompile("(?s)^.*$")
+
+// string check - validates for conformance to provided lengths and specified content
+// min and max - the string
+// if format string provided - check against matching predefined
+func IsValidString(str string, min, max int, format string) []string {
+ var errs []string
+
+ if min > max {
+ errs = append(errs, "Invalid string length constraints - min is greater than max")
+ return errs
+ }
+
+ if len(str) < min {
+ errs = append(errs, "string length is less than the minimum constraint")
+ return errs
+ }
+ if len(str) > max {
+ errs = append(errs, "string length is greater than the maximum constraint")
+ return errs
+ }
+
+ switch format {
+ case VALID_ALPHA_STR:
+ if !validAlphaStrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the alpha only constraint")
+ }
+ case VALID_ALPHANUM_STR:
+ if !validAlphaNumStrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the alphanumeric only constraint")
+ }
+ case VALID_NAME_STR:
+ if !validNameRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the valid k8s name constraint")
+ }
+ case VALID_BASE64_STR:
+ if !validBase64StrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the valid base64 characters constraint")
+ }
+ if len(str)%4 != 0 {
+ errs = append(errs, "base64 string length should be a multiple of 4")
+ }
+ case VALID_ANY_STR:
+ if !validAnyStrRegEx.MatchString(str) {
+ errs = append(errs, "string does not match the any characters constraint")
+ }
+ default:
+ // invalid string format supplied
+ errs = append(errs, "an invalid string constraint was supplied")
+ }
+
+ return errs
+}
+
+// validate that label conforms to kubernetes label conventions
+// general label format expected is:
+// "<labelprefix>/<labelname>=<Labelvalue>"
+// where labelprefix matches DNS1123Subdomain format
+// labelname matches DNS1123Label format
+//
+// Input labels are allowed to match following formats:
+// "<DNS1123Subdomain>/<DNS1123Label>=<Labelvalue>"
+// "<DNS1123Label>=<LabelValue>"
+// "<LabelValue>"
+func IsValidLabel(label string) []string {
+ var labelerrs []string
+
+ expectLabelName := false
+ expectLabelPrefix := false
+
+ // split label up into prefix, name and value
+ // format: prefix/name=value
+ var labelprefix, labelname, labelvalue string
+
+ kv := strings.SplitN(label, "=", 2)
+ if len(kv) == 1 {
+ labelprefix = ""
+ labelname = ""
+ labelvalue = kv[0]
+ } else {
+ pn := strings.SplitN(kv[0], "/", 2)
+ if len(pn) == 1 {
+ labelprefix = ""
+ labelname = pn[0]
+ } else {
+ labelprefix = pn[0]
+ labelname = pn[1]
+ expectLabelPrefix = true
+ }
+ labelvalue = kv[1]
+ // if "=" was in the label input, then expect a non-zero length name
+ expectLabelName = true
+ }
+
+ // check label prefix validity - prefix is optional
+ if len(labelprefix) > 0 {
+ errs := validation.IsDNS1123Subdomain(labelprefix)
+ if len(errs) > 0 {
+ labelerrs = append(labelerrs, "Invalid label prefix - label=["+label+"%], labelprefix=["+labelprefix+"], errors: ")
+ for _, err := range errs {
+ labelerrs = append(labelerrs, err)
+ }
+ }
+ } else if expectLabelPrefix {
+ labelerrs = append(labelerrs, "Invalid label prefix - label=["+label+"%], labelprefix=["+labelprefix+"]")
+ }
+ if expectLabelName {
+ errs := validation.IsDNS1123Label(labelname)
+ if len(errs) > 0 {
+ labelerrs = append(labelerrs, "Invalid label name - label=["+label+"%], labelname=["+labelname+"], errors: ")
+ for _, err := range errs {
+ labelerrs = append(labelerrs, err)
+ }
+ }
+ }
+ if len(labelvalue) > 0 {
+ errs := validation.IsValidLabelValue(labelvalue)
+ if len(errs) > 0 {
+ labelerrs = append(labelerrs, "Invalid label value - label=["+label+"%], labelvalue=["+labelvalue+"], errors: ")
+ for _, err := range errs {
+ labelerrs = append(labelerrs, err)
+ }
+ }
+ } else {
+ // expect a non-zero value
+ labelerrs = append(labelerrs, "Invalid label value - label=["+label+"%], labelvalue=["+labelvalue+"]")
+ }
+
+ return labelerrs
+}
+
+func IsValidNumber(value, min, max int) []string {
+ var errs []string
+
+ if min > max {
+ errs = append(errs, "invalid constraints")
+ return errs
+ }
+
+ if value < min {
+ errs = append(errs, "value less than minimum")
+ }
+ if value > max {
+ errs = append(errs, "value greater than maximum")
+ }
+ return errs
+}
diff --git a/src/orchestrator/pkg/infra/validation/validation_test.go b/src/orchestrator/pkg/infra/validation/validation_test.go
new file mode 100644
index 00000000..5109b6c7
--- /dev/null
+++ b/src/orchestrator/pkg/infra/validation/validation_test.go
@@ -0,0 +1,466 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * 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.
+ */
+
+package validation
+
+import (
+ "bytes"
+ "testing"
+)
+
+func TestIsTarGz(t *testing.T) {
+
+ t.Run("Valid tar.gz", func(t *testing.T) {
+ content := []byte{
+ 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b,
+ 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
+ 0x61, 0x72, 0x00, 0xed, 0xce, 0x41, 0x0a, 0xc2,
+ 0x30, 0x10, 0x85, 0xe1, 0xac, 0x3d, 0x45, 0x4e,
+ 0x50, 0x12, 0xd2, 0xc4, 0xe3, 0x48, 0xa0, 0x01,
+ 0x4b, 0x52, 0x0b, 0xed, 0x88, 0x1e, 0xdf, 0x48,
+ 0x11, 0x5c, 0x08, 0xa5, 0x8b, 0x52, 0x84, 0xff,
+ 0xdb, 0xbc, 0x61, 0x66, 0x16, 0x4f, 0xd2, 0x2c,
+ 0x8d, 0x3c, 0x45, 0xed, 0xc8, 0x54, 0x21, 0xb4,
+ 0xef, 0xb4, 0x67, 0x6f, 0xbe, 0x73, 0x61, 0x9d,
+ 0xb2, 0xce, 0xd5, 0x55, 0xf0, 0xde, 0xd7, 0x3f,
+ 0xdb, 0xd6, 0x49, 0x69, 0xb3, 0x67, 0xa9, 0x8f,
+ 0xfb, 0x2c, 0x71, 0xd2, 0x5a, 0xc5, 0xee, 0x92,
+ 0x73, 0x8e, 0x43, 0x7f, 0x4b, 0x3f, 0xff, 0xd6,
+ 0xee, 0x7f, 0xea, 0x9a, 0x4a, 0x19, 0x1f, 0xe3,
+ 0x54, 0xba, 0xd3, 0xd1, 0x55, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x1b, 0xbc, 0x00, 0xb5, 0xe8,
+ 0x4a, 0xf9, 0x00, 0x28, 0x00, 0x00,
+ }
+
+ err := IsTarGz(bytes.NewBuffer(content))
+ if err != nil {
+ t.Errorf("Error reading valid tar.gz file %s", err.Error())
+ }
+ })
+
+ t.Run("Invalid tar.gz", func(t *testing.T) {
+ content := []byte{
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0xff, 0xf2, 0x48, 0xcd,
+ }
+
+ err := IsTarGz(bytes.NewBuffer(content))
+ if err == nil {
+ t.Errorf("Error should NOT be nil")
+ }
+ })
+
+ t.Run("Empty tar.gz", func(t *testing.T) {
+ content := []byte{}
+ err := IsTarGz(bytes.NewBuffer(content))
+ if err == nil {
+ t.Errorf("Error should NOT be nil")
+ }
+ })
+}
+
+func TestIsValidName(t *testing.T) {
+ t.Run("Valid Names", func(t *testing.T) {
+ validnames := []string{
+ "abc123",
+ "1_abc123.ONE",
+ "0abcABC_-.5",
+ "123456789012345678901234567890123456789012345678901234567890123", // max of 63 characters
+ }
+ for _, name := range validnames {
+ errs := IsValidName(name)
+ if len(errs) > 0 {
+ t.Errorf("Valid name failed to pass: %v", name)
+ }
+ }
+ })
+
+ t.Run("Invalid Names", func(t *testing.T) {
+ invalidnames := []string{
+ "", // empty
+ "_abc123", // starts with non-alphanum
+ "-abc123", // starts with non-alphanum
+ ".abc123", // starts with non-alphanum
+ "abc123-", // ends with non-alphanum
+ "abc123_", // ends with non-alphanum
+ "abc123.", // ends with non-alphanum
+ "1_abc-123.O=NE", // contains not allowed character
+ "1_a/bc-123.ONE", // contains not allowed character
+ "1234567890123456789012345678901234567890123456789012345678901234", // longer than 63 characters
+ }
+ for _, name := range invalidnames {
+ errs := IsValidName(name)
+ if len(errs) == 0 {
+ t.Errorf("Invalid name passed: %v", name)
+ }
+ }
+ })
+}
+
+func TestIsIpv4Cidr(t *testing.T) {
+ t.Run("Valid IPv4 Cidr", func(t *testing.T) {
+ validipv4cidr := []string{
+ "1.2.3.4/32",
+ "10.11.12.0/24",
+ "192.168.1.2/8",
+ "255.0.0.0/16",
+ }
+ for _, ip := range validipv4cidr {
+ err := IsIpv4Cidr(ip)
+ if err != nil {
+ t.Errorf("Valid IPv4 CIDR string failed to pass: %v", ip)
+ }
+ }
+ })
+
+ t.Run("Invalid IPv4 Cidr", func(t *testing.T) {
+ invalidipv4cidr := []string{
+ "",
+ "1.2.3.4.5/32",
+ "1.2.3.415/16",
+ "1.2.3.4/33",
+ "2.3.4/24",
+ "1.2.3.4",
+ "1.2.3.4/",
+ }
+ for _, ip := range invalidipv4cidr {
+ err := IsIpv4Cidr(ip)
+ if err == nil {
+ t.Errorf("Invalid IPv4 Cidr passed: %v", ip)
+ }
+ }
+ })
+}
+
+func TestIsIpv4(t *testing.T) {
+ t.Run("Valid IPv4", func(t *testing.T) {
+ validipv4 := []string{
+ "1.2.3.42",
+ "10.11.12.0",
+ "192.168.1.2",
+ "255.0.0.0",
+ "255.255.255.255",
+ "0.0.0.0",
+ }
+ for _, ip := range validipv4 {
+ err := IsIpv4(ip)
+ if err != nil {
+ t.Errorf("Valid IPv4 string failed to pass: %v", ip)
+ }
+ }
+ })
+
+ t.Run("Invalid IPv4", func(t *testing.T) {
+ invalidipv4 := []string{
+ "",
+ "1.2.3.4.5",
+ "1.2.3.45/32",
+ "1.2.3.4a",
+ "2.3.4",
+ "1.2.3.400",
+ "256.255.255.255",
+ "10,11,12,13",
+ "1.2.3.4/",
+ }
+ for _, ip := range invalidipv4 {
+ err := IsIpv4(ip)
+ if err == nil {
+ t.Errorf("Invalid IPv4 passed: %v", ip)
+ }
+ }
+ })
+}
+
+func TestIsValidString(t *testing.T) {
+ t.Run("Valid Strings", func(t *testing.T) {
+ validStrings := []struct {
+ str string
+ min int
+ max int
+ format string
+ }{
+ {
+ str: "abc123",
+ min: 0,
+ max: 16,
+ format: VALID_NAME_STR,
+ },
+ {
+ str: "ab-c1_2.3",
+ min: 0,
+ max: 16,
+ format: VALID_NAME_STR,
+ },
+ {
+ str: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ min: 0,
+ max: 62,
+ format: VALID_ALPHANUM_STR,
+ },
+ {
+ str: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ min: 0,
+ max: 52,
+ format: VALID_ALPHA_STR,
+ },
+ {
+ str: "",
+ min: 0,
+ max: 52,
+ format: VALID_ALPHA_STR,
+ },
+ {
+ str: "",
+ min: 0,
+ max: 52,
+ format: VALID_ALPHANUM_STR,
+ },
+ {
+ str: "dGhpcyBpcyBhCnRlc3Qgc3RyaW5nCg==",
+ min: 0,
+ max: 52,
+ format: VALID_BASE64_STR,
+ },
+ {
+ str: "\t\n \n0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-=,.<>/?'\"\\[]{}\n",
+ min: 0,
+ max: 256,
+ format: VALID_ANY_STR,
+ },
+ }
+ for _, test := range validStrings {
+ errs := IsValidString(test.str, test.min, test.max, test.format)
+ if len(errs) > 0 {
+ t.Errorf("Valid string failed to pass: str:%v, min:%v, max:%v, format:%v", test.str, test.min, test.max, test.format)
+ }
+ }
+ })
+
+ t.Run("Invalid Strings", func(t *testing.T) {
+ inValidStrings := []struct {
+ str string
+ min int
+ max int
+ format string
+ }{
+ {
+ str: "abc123",
+ min: 0,
+ max: 5,
+ format: VALID_NAME_STR,
+ },
+ {
+ str: "",
+ min: 0,
+ max: 5,
+ format: VALID_NAME_STR,
+ },
+ {
+ str: "-ab-c1_2.3",
+ min: 0,
+ max: 16,
+ format: VALID_NAME_STR,
+ },
+ {
+ str: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ=",
+ min: 0,
+ max: 100,
+ format: VALID_ALPHANUM_STR,
+ },
+ {
+ str: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ123456",
+ min: 0,
+ max: 62,
+ format: VALID_ALPHA_STR,
+ },
+ {
+ str: "",
+ min: 1,
+ max: 52,
+ format: VALID_ALPHA_STR,
+ },
+ {
+ str: "abc123",
+ min: 1,
+ max: 3,
+ format: VALID_ALPHA_STR,
+ },
+ {
+ str: "",
+ min: 1,
+ max: 52,
+ format: VALID_ALPHANUM_STR,
+ },
+ {
+ str: "dGhpcyBpcyBhCnRlc3Qgc3RyaW5nCg===",
+ min: 0,
+ max: 52,
+ format: VALID_BASE64_STR,
+ },
+ {
+ str: "dGhpcyBpcyBhCnRlc3=Qgc3RyaW5nCg==",
+ min: 0,
+ max: 52,
+ format: VALID_BASE64_STR,
+ },
+ {
+ str: "dGhpcyBpcyBhCnRlc3#Qgc3RyaW5nCg==",
+ min: 0,
+ max: 52,
+ format: VALID_BASE64_STR,
+ },
+ {
+ str: "\t\n \n0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^&*()_+-=,.<>/?'\"\\[]{}\n",
+ min: 0,
+ max: 10,
+ format: VALID_ANY_STR,
+ },
+ {
+ str: "abc123",
+ min: 0,
+ max: 10,
+ format: "unknownformat",
+ },
+ }
+ for _, test := range inValidStrings {
+ errs := IsValidString(test.str, test.min, test.max, test.format)
+ if len(errs) == 0 {
+ t.Errorf("Invalid string passed: str:%v, min:%v, max:%v, format:%v", test.str, test.min, test.max, test.format)
+ }
+ }
+ })
+}
+
+func TestIsValidLabel(t *testing.T) {
+ t.Run("Valid Labels", func(t *testing.T) {
+ validlabels := []string{
+ "kubernetes.io/hostname=localhost",
+ "hostname=localhost",
+ "localhost",
+ }
+ for _, label := range validlabels {
+ errs := IsValidLabel(label)
+ if len(errs) > 0 {
+ t.Errorf("Valid label failed to pass: %v %v", label, errs)
+ }
+ }
+ })
+
+ t.Run("Invalid Labels", func(t *testing.T) {
+ invalidlabels := []string{
+ "",
+ "kubernetes$.io/hostname=localhost",
+ "hostname==localhost",
+ "=localhost",
+ "/hostname=localhost",
+ ".a.b/hostname=localhost",
+ "kubernetes.io/hostname",
+ "kubernetes.io/hostname=",
+ "kubernetes.io/1234567890123456789012345678901234567890123456789012345678901234=localhost", // too long name
+ "kubernetes.io/hostname=localhost1234567890123456789012345678901234567890123456789012345678901234", // too long value
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234/hostname=localhost", // too long prefix
+ }
+ for _, label := range invalidlabels {
+ errs := IsValidLabel(label)
+ if len(errs) == 0 {
+ t.Errorf("Invalid label passed: %v", label)
+ }
+ }
+ })
+}
+
+func TestIsValidNumber(t *testing.T) {
+ t.Run("Valid Number", func(t *testing.T) {
+ validNumbers := []struct {
+ value int
+ min int
+ max int
+ }{
+ {
+ value: 0,
+ min: 0,
+ max: 5,
+ },
+ {
+ value: 1000,
+ min: 0,
+ max: 4095,
+ },
+ {
+ value: 0,
+ min: 0,
+ max: 0,
+ },
+ {
+ value: -100,
+ min: -200,
+ max: -99,
+ },
+ {
+ value: 123,
+ min: 123,
+ max: 123,
+ },
+ }
+ for _, test := range validNumbers {
+ err := IsValidNumber(test.value, test.min, test.max)
+ if len(err) > 0 {
+ t.Errorf("Valid number failed to pass - value:%v, min:%v, max:%v", test.value, test.min, test.max)
+ }
+ }
+ })
+
+ t.Run("Invalid Number", func(t *testing.T) {
+ inValidNumbers := []struct {
+ value int
+ min int
+ max int
+ }{
+ {
+ value: 6,
+ min: 0,
+ max: 5,
+ },
+ {
+ value: 4096,
+ min: 0,
+ max: 4095,
+ },
+ {
+ value: 11,
+ min: 10,
+ max: 10,
+ },
+ {
+ value: -100,
+ min: -99,
+ max: -200,
+ },
+ {
+ value: 123,
+ min: 223,
+ max: 123,
+ },
+ }
+ for _, test := range inValidNumbers {
+ err := IsValidNumber(test.value, test.min, test.max)
+ if len(err) == 0 {
+ t.Errorf("Invalid number passed - value:%v, min:%v, max:%v", test.value, test.min, test.max)
+ }
+ }
+ })
+}
diff --git a/src/orchestrator/pkg/module/app.go b/src/orchestrator/pkg/module/app.go
index c25a1b51..1e1a5974 100644
--- a/src/orchestrator/pkg/module/app.go
+++ b/src/orchestrator/pkg/module/app.go
@@ -65,6 +65,7 @@ type AppManager interface {
CreateApp(a App, ac AppContent, p string, cN string, cV string) (App, error)
GetApp(name string, p string, cN string, cV string) (App, error)
GetAppContent(name string, p string, cN string, cV string) (AppContent, error)
+ GetApps(p string, cN string, cV string) ([]App, error)
DeleteApp(name string, p string, cN string, cV string) error
}
@@ -183,6 +184,34 @@ func (v *AppClient) GetAppContent(name string, p string, cN string, cV string) (
return AppContent{}, pkgerrors.New("Error getting app content")
}
+// GetApps returns all Apps for given composite App
+func (v *AppClient) GetApps(project, compositeApp, compositeAppVersion string) ([]App, error) {
+
+ key := AppKey{
+ App: "",
+ Project: project,
+ CompositeApp: compositeApp,
+ CompositeAppVersion: compositeAppVersion,
+ }
+
+ var resp []App
+ values, err := db.DBconn.Find(v.storeName, key, v.tagMeta)
+ if err != nil {
+ return []App{}, pkgerrors.Wrap(err, "Get Apps")
+ }
+
+ for _, value := range values {
+ a := App{}
+ err = db.DBconn.Unmarshal(value, &a)
+ if err != nil {
+ return []App{}, pkgerrors.Wrap(err, "Unmarshaling Value")
+ }
+ resp = append(resp, a)
+ }
+
+ return resp, nil
+}
+
// DeleteApp deletes the App from database
func (v *AppClient) DeleteApp(name string, p string, cN string, cV string) error {
diff --git a/src/orchestrator/utils/utils.go b/src/orchestrator/utils/utils.go
deleted file mode 100644
index 44cf5120..00000000
--- a/src/orchestrator/utils/utils.go
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2020 Intel Corporation, Inc
- *
- * 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.
- */
-
-package utils
-
-import (
- "archive/tar"
- "compress/gzip"
- "io"
-
- pkgerrors "github.com/pkg/errors"
-)
-
-func IsTarGz(r io.Reader) error {
- //Check if it is a valid gz
- gzf, err := gzip.NewReader(r)
- if err != nil {
- return pkgerrors.Wrap(err, "Invalid gzip format")
- }
-
- //Check if it is a valid tar file
- //Unfortunately this can only be done by inspecting all the tar contents
- tarR := tar.NewReader(gzf)
- first := true
-
- for true {
- header, err := tarR.Next()
-
- if err == io.EOF {
- //Check if we have just a gzip file without a tar archive inside
- if first {
- return pkgerrors.New("Empty or non-existant Tar file found")
- }
- //End of archive
- break
- }
-
- if err != nil {
- return pkgerrors.Errorf("Error reading tar file %s", err.Error())
- }
-
- //Check if files are of type directory and regular file
- if header.Typeflag != tar.TypeDir &&
- header.Typeflag != tar.TypeReg {
- return pkgerrors.Errorf("Unknown header in tar %s, %s",
- header.Name, string(header.Typeflag))
- }
-
- first = false
- }
-
- return nil
-}
diff --git a/src/orchestrator/utils/utils_test.go b/src/orchestrator/utils/utils_test.go
deleted file mode 100644
index 63230e49..00000000
--- a/src/orchestrator/utils/utils_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2018 Intel Corporation, Inc
- *
- * 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.
- */
-
-package utils
-
-import (
- "bytes"
- "testing"
-)
-
-func TestIsTarGz(t *testing.T) {
-
- t.Run("Valid tar.gz", func(t *testing.T) {
- content := []byte{
- 0x1f, 0x8b, 0x08, 0x08, 0xb0, 0x6b, 0xf4, 0x5b,
- 0x00, 0x03, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x74,
- 0x61, 0x72, 0x00, 0xed, 0xce, 0x41, 0x0a, 0xc2,
- 0x30, 0x10, 0x85, 0xe1, 0xac, 0x3d, 0x45, 0x4e,
- 0x50, 0x12, 0xd2, 0xc4, 0xe3, 0x48, 0xa0, 0x01,
- 0x4b, 0x52, 0x0b, 0xed, 0x88, 0x1e, 0xdf, 0x48,
- 0x11, 0x5c, 0x08, 0xa5, 0x8b, 0x52, 0x84, 0xff,
- 0xdb, 0xbc, 0x61, 0x66, 0x16, 0x4f, 0xd2, 0x2c,
- 0x8d, 0x3c, 0x45, 0xed, 0xc8, 0x54, 0x21, 0xb4,
- 0xef, 0xb4, 0x67, 0x6f, 0xbe, 0x73, 0x61, 0x9d,
- 0xb2, 0xce, 0xd5, 0x55, 0xf0, 0xde, 0xd7, 0x3f,
- 0xdb, 0xd6, 0x49, 0x69, 0xb3, 0x67, 0xa9, 0x8f,
- 0xfb, 0x2c, 0x71, 0xd2, 0x5a, 0xc5, 0xee, 0x92,
- 0x73, 0x8e, 0x43, 0x7f, 0x4b, 0x3f, 0xff, 0xd6,
- 0xee, 0x7f, 0xea, 0x9a, 0x4a, 0x19, 0x1f, 0xe3,
- 0x54, 0xba, 0xd3, 0xd1, 0x55, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x1b, 0xbc, 0x00, 0xb5, 0xe8,
- 0x4a, 0xf9, 0x00, 0x28, 0x00, 0x00,
- }
-
- err := IsTarGz(bytes.NewBuffer(content))
- if err != nil {
- t.Errorf("Error reading valid tar.gz file %s", err.Error())
- }
- })
-
- t.Run("Invalid tar.gz", func(t *testing.T) {
- content := []byte{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0xff, 0xf2, 0x48, 0xcd,
- }
-
- err := IsTarGz(bytes.NewBuffer(content))
- if err == nil {
- t.Errorf("Error should NOT be nil")
- }
- })
-
- t.Run("Empty tar.gz", func(t *testing.T) {
- content := []byte{}
- err := IsTarGz(bytes.NewBuffer(content))
- if err == nil {
- t.Errorf("Error should NOT be nil")
- }
- })
-}