diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data index 3f80dec306..6c7b4c74ca 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/build_srpm.data @@ -1,3 +1,3 @@ SRC_DIR="stx-openstack-helm" -COPY_LIST_TO_TAR="$PKG_BASE/../../../helm-charts/rbd-provisioner" -TIS_PATCH_VER=1 +COPY_LIST_TO_TAR="$PKG_BASE/../../../helm-charts/rbd-provisioner $PKG_BASE/../../../helm-charts/garbd" +TIS_PATCH_VER=2 diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec index c613ebfd66..26d346a057 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/centos/stx-openstack-helm.spec @@ -57,6 +57,7 @@ helm repo add local http://localhost:8879/charts # Make the charts. These produce a tgz file make nova-api-proxy make rbd-provisioner +make garbd # terminate helm server (the last backgrounded task) kill %1 diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml index 016c5b3eae..2fba79139c 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest-no-tests.yaml @@ -166,6 +166,39 @@ data: - helm-toolkit --- schema: armada/Chart/v1 +metadata: + schema: metadata/Document/v1 + name: openstack-garbd +data: + chart_name: garbd + release: openstack-garbd + namespace: openstack + wait: + timeout: 1800 + labels: + release_group: osh-openstack-garbd + install: + no_hooks: false + upgrade: + no_hooks: false + pre: + delete: + - type: job + labels: + release_group: osh-openstack-garbd + values: + labels: + server: + node_selector_key: openstack-compute-node + node_selector_value: enabled + source: + type: tar + location: http://172.17.0.1/helm_charts/garbd-0.1.0.tgz + subpath: garbd + dependencies: + - helm-toolkit +--- +schema: armada/Chart/v1 metadata: schema: metadata/Document/v1 name: openstack-memcached @@ -2309,6 +2342,7 @@ data: sequenced: true chart_group: - openstack-mariadb + - openstack-garbd --- schema: armada/ChartGroup/v1 metadata: diff --git a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml index 3ee305ce87..556316faba 100644 --- a/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml +++ b/kubernetes/applications/stx-openstack/stx-openstack-helm/stx-openstack-helm/manifests/manifest.yaml @@ -166,6 +166,39 @@ data: - helm-toolkit --- schema: armada/Chart/v1 +metadata: + schema: metadata/Document/v1 + name: openstack-garbd +data: + chart_name: garbd + release: openstack-garbd + namespace: openstack + wait: + timeout: 1800 + labels: + release_group: osh-openstack-garbd + install: + no_hooks: false + upgrade: + no_hooks: false + pre: + delete: + - type: job + labels: + release_group: osh-openstack-garbd + values: + labels: + server: + node_selector_key: openstack-compute-node + node_selector_value: enabled + source: + type: tar + location: http://172.17.0.1/helm_charts/garbd-0.1.0.tgz + subpath: garbd + dependencies: + - helm-toolkit +--- +schema: armada/Chart/v1 metadata: schema: metadata/Document/v1 name: openstack-memcached @@ -2309,6 +2342,7 @@ data: sequenced: true chart_group: - openstack-mariadb + - openstack-garbd --- schema: armada/ChartGroup/v1 metadata: diff --git a/kubernetes/helm-charts/garbd/Chart.yaml b/kubernetes/helm-charts/garbd/Chart.yaml new file mode 100644 index 0000000000..3aa9379082 --- /dev/null +++ b/kubernetes/helm-charts/garbd/Chart.yaml @@ -0,0 +1,18 @@ +# Copyright 2017 The Openstack-Helm Authors. +# +# 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 +description: OpenStack-Helm Garbd +name: garbd +version: 0.1.0 diff --git a/kubernetes/helm-charts/garbd/requirements.yaml b/kubernetes/helm-charts/garbd/requirements.yaml new file mode 100644 index 0000000000..53782e69b2 --- /dev/null +++ b/kubernetes/helm-charts/garbd/requirements.yaml @@ -0,0 +1,18 @@ +# Copyright 2017 The Openstack-Helm Authors. +# +# 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. + +dependencies: + - name: helm-toolkit + repository: http://localhost:8879/charts + version: 0.1.0 diff --git a/kubernetes/helm-charts/garbd/templates/bin/_garbd.sh.tpl b/kubernetes/helm-charts/garbd/templates/bin/_garbd.sh.tpl new file mode 100644 index 0000000000..662c583636 --- /dev/null +++ b/kubernetes/helm-charts/garbd/templates/bin/_garbd.sh.tpl @@ -0,0 +1,21 @@ +#!/bin/sh + +{{/* +Copyright 2017 The Openstack-Helm Authors. + +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 -ex + +exec garbd --group=${GROUP_NAME} --address="${GROUP_ADDRESS}" diff --git a/kubernetes/helm-charts/garbd/templates/configmap-bin.yaml b/kubernetes/helm-charts/garbd/templates/configmap-bin.yaml new file mode 100644 index 0000000000..57023aa64d --- /dev/null +++ b/kubernetes/helm-charts/garbd/templates/configmap-bin.yaml @@ -0,0 +1,32 @@ +{{/* +Copyright 2017 The Openstack-Helm Authors. + +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. +*/}} + +{{- if .Values.manifests.configmap_bin }} +{{- $envAll := . }} +{{- $configMapBinName := printf "%s-%s" $envAll.Release.Name "garbd-bin" }} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ $configMapBinName }} +data: +{{- if .Values.images.local_registry.active }} + image-repo-sync.sh: | +{{- include "helm-toolkit.scripts.image_repo_sync" . | indent 4 }} +{{- end }} + garbd.sh: | +{{ tuple "bin/_garbd.sh.tpl" . | include "helm-toolkit.utils.template" | indent 4 }} +{{- end }} diff --git a/kubernetes/helm-charts/garbd/templates/deployment.yaml b/kubernetes/helm-charts/garbd/templates/deployment.yaml new file mode 100644 index 0000000000..a67d58c373 --- /dev/null +++ b/kubernetes/helm-charts/garbd/templates/deployment.yaml @@ -0,0 +1,76 @@ +{{/* +Copyright 2017 The Openstack-Helm Authors. + +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. +*/}} + +{{- if .Values.manifests.deployment }} +{{- $envAll := . }} + +{{- $rcControllerName := printf "%s-%s" $envAll.Release.Name "garbd" }} +{{- $configMapBinName := printf "%s-%s" $envAll.Release.Name "garbd-bin" }} + +{{ tuple $envAll "garbd" $rcControllerName | include "helm-toolkit.snippets.kubernetes_pod_rbac_serviceaccount" }} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ $rcControllerName | quote }} + annotations: + {{ tuple $envAll | include "helm-toolkit.snippets.release_uuid" }} + labels: +{{ tuple $envAll "garbd" "server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 4 }} +spec: + replicas: {{ .Values.pod.replicas.server }} + selector: + matchLabels: +{{ tuple $envAll "garbd" "server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 6 }} +{{ tuple $envAll | include "helm-toolkit.snippets.kubernetes_upgrades_deployment" | indent 2 }} + template: + metadata: + annotations: + configmap-bin-hash: {{ tuple "configmap-bin.yaml" . | include "helm-toolkit.utils.hash" }} + labels: +{{ tuple $envAll "garbd" "server" | include "helm-toolkit.snippets.kubernetes_metadata_labels" | indent 8 }} + spec: + shareProcessNamespace: true + serviceAccountName: {{ $rcControllerName | quote }} + affinity: +{{ tuple $envAll "garbd" "server" | include "helm-toolkit.snippets.kubernetes_pod_anti_affinity" | indent 8 }} + nodeSelector: + {{ .Values.labels.server.node_selector_key }}: {{ .Values.labels.server.node_selector_value | quote }} + terminationGracePeriodSeconds: {{ .Values.pod.lifecycle.termination_grace_period.garbd.timeout | default "30" }} + initContainers: +{{ tuple $envAll "garbd" list | include "helm-toolkit.snippets.kubernetes_entrypoint_init_container" | indent 8 }} + containers: + - name: garbd +{{ tuple $envAll "garbd" | include "helm-toolkit.snippets.image" | indent 10 }} +{{ tuple $envAll $envAll.Values.pod.resources.server | include "helm-toolkit.snippets.kubernetes_resources" | indent 10 }} + env: + - name: GROUP_NAME + value: {{ .Values.conf.garbd.group_name | quote }} + - name: GROUP_ADDRESS + value: {{ .Values.conf.garbd.group_address | quote }} + command: + - /tmp/garbd.sh + volumeMounts: + - name: garbd-bin + mountPath: /tmp/garbd.sh + subPath: garbd.sh + readOnly: true + volumes: + - name: garbd-bin + configMap: + name: {{ $configMapBinName | quote }} + defaultMode: 0555 +{{- end }} diff --git a/kubernetes/helm-charts/garbd/templates/job-image-repo-sync.yaml b/kubernetes/helm-charts/garbd/templates/job-image-repo-sync.yaml new file mode 100644 index 0000000000..78a2572e47 --- /dev/null +++ b/kubernetes/helm-charts/garbd/templates/job-image-repo-sync.yaml @@ -0,0 +1,20 @@ +{{/* +Copyright 2017 The Openstack-Helm Authors. + +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. +*/}} + +{{- if and .Values.manifests.job_image_repo_sync .Values.images.local_registry.active }} +{{- $imageRepoSyncJob := dict "envAll" . "serviceName" "garbd" -}} +{{ $imageRepoSyncJob | include "helm-toolkit.manifests.job_image_repo_sync" }} +{{- end }} diff --git a/kubernetes/helm-charts/garbd/templates/network_policy.yaml b/kubernetes/helm-charts/garbd/templates/network_policy.yaml new file mode 100644 index 0000000000..cf56bb148e --- /dev/null +++ b/kubernetes/helm-charts/garbd/templates/network_policy.yaml @@ -0,0 +1,19 @@ +{{/* +Copyright 2017-2018 The Openstack-Helm Authors. + +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. +*/}} +{{- if .Values.manifests.network_policy -}} +{{- $netpol_opts := dict "envAll" . "name" "application" "label" "garbd" -}} +{{ $netpol_opts | include "helm-toolkit.manifests.kubernetes_network_policy" }} +{{- end -}} diff --git a/kubernetes/helm-charts/garbd/values.yaml b/kubernetes/helm-charts/garbd/values.yaml new file mode 100644 index 0000000000..ddef814153 --- /dev/null +++ b/kubernetes/helm-charts/garbd/values.yaml @@ -0,0 +1,125 @@ +# Copyright 2017 The Openstack-Helm Authors. +# +# 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. + +# Default values for garbd. +# This is a YAML-formatted file. +# Declare name/value pairs to be passed into your templates. +# name: value + +conf: + garbd: + group_name: mariadb-server_openstack + group_address: gcomm://mariadb-server-0.mariadb-discovery.openstack.svc.cluster.local,mariadb-server-1.mariadb-discovery.openstack.svc.cluster.local + +dependencies: + dynamic: + common: + local_image_registry: + jobs: + - garbd-image-repo-sync + services: + - endpoint: node + service: local_image_registry + static: + image_repo_sync: + services: + - endpoint: internal + service: local_image_registry + +endpoints: + cluster_domain_suffix: cluster.local + local_image_registry: + name: docker-registry + namespace: docker-registry + hosts: + default: localhost + internal: docker-registry + node: localhost + host_fqdn_override: + default: null + port: + registry: + node: 5000 + kube_dns: + namespace: kube-system + name: kubernetes-dns + hosts: + default: kube-dns + host_fqdn_override: + default: null + path: + default: null + scheme: http + port: + dns_tcp: + default: 53 + dns: + default: 53 + protocol: UDP + +network_policy: + garbd: + ingress: + - {} + +images: + pull_policy: IfNotPresent + tags: + dep_check: 'quay.io/stackanetes/kubernetes-entrypoint:v0.3.1' + garbd: 'docker.io/starlingx/stx-mariadb:dev-centos-pike-latest' + image_repo_sync: docker.io/docker:17.07.0 + local_registry: + active: false + exclude: + - image_repo_sync + +labels: + server: + node_selector_key: openstack-compute-node + node_selector_value: enabled + +manifests: + configmap_bin: true + deployment: true + network_policy: false + +pod: + affinity: + anti: + topologyKey: + default: kubernetes.io/hostname + type: + default: preferredDuringSchedulingIgnoredDuringExecution + lifecycle: + upgrades: + deployments: + pod_replacement_strategy: RollingUpdate + revision_history: 3 + rolling_update: + max_surge: 3 + max_unavailable: 1 + termination_grace_period: + garbd: + timeout: 10 + replicas: + server: 1 + resources: + enabled: false + garbd: + limits: + cpu: "2000m" + memory: "1024Mi" + requests: + cpu: "500m" + memory: "128Mi" diff --git a/puppet-manifests/src/modules/platform/manifests/kubernetes.pp b/puppet-manifests/src/modules/platform/manifests/kubernetes.pp index f30dbd5da6..319d23b626 100644 --- a/puppet-manifests/src/modules/platform/manifests/kubernetes.pp +++ b/puppet-manifests/src/modules/platform/manifests/kubernetes.pp @@ -39,7 +39,6 @@ class platform::kubernetes::kubeadm { } # Start kubelet. -> service { 'kubelet': - ensure => 'running', enable => true, } # A seperate enable is required since we have modified the service resource @@ -124,6 +123,21 @@ class platform::kubernetes::master::init command => "kubectl --kubeconfig=/etc/kubernetes/admin.conf taint node ${::platform::params::hostname} node-role.kubernetes.io/master-", # lint:ignore:140chars logoutput => true, } + + # Add a dependency to kubelet on config so it doesn't enter a bad state on subsequent boots + -> file { '/etc/systemd/system/kubelet.service.d/kube-stx-override.conf': + ensure => file, + content => template('platform/kube-stx-override.conf.erb'), + owner => 'root', + group => 'root', + mode => '0644', + } + + # Reload systemd + -> exec { 'perform systemctl daemon reload for kubelet override': + command => 'systemctl daemon-reload', + logoutput => true, + } } else { if str2bool($::is_initial_config) { # For subsequent controller installs, install kubernetes using the @@ -206,6 +220,21 @@ class platform::kubernetes::master::init command => "kubectl --kubeconfig=/etc/kubernetes/admin.conf taint node ${::platform::params::hostname} node-role.kubernetes.io/master-", # lint:ignore:140chars logoutput => true, } + + # Add a dependency to kubelet on config so it doesn't enter a bad state on subsequent boots + -> file { '/etc/systemd/system/kubelet.service.d/kube-stx-override.conf': + ensure => file, + content => template('platform/kube-stx-override.conf.erb'), + owner => 'root', + group => 'root', + mode => '0644', + } + + # Reload systemd + -> exec { 'perform systemctl daemon reload for kubelet override': + command => 'systemctl daemon-reload', + logoutput => true, + } } } } @@ -242,6 +271,21 @@ class platform::kubernetes::worker::init logoutput => true, unless => 'test -f /etc/kubernetes/kubelet.conf', } + + # Add a dependency to kubelet on config so it doesn't enter a bad state + -> file { '/etc/systemd/system/kubelet.service.d/kube-stx-override.conf': + ensure => file, + content => template('platform/kube-stx-override.conf.erb'), + owner => 'root', + group => 'root', + mode => '0644', + } + + # Reload systemd + -> exec { 'perform systemctl daemon reload for kubelet override': + command => 'systemctl daemon-reload', + logoutput => true, + } } class platform::kubernetes::worker diff --git a/puppet-manifests/src/modules/platform/templates/kube-stx-override.conf.erb b/puppet-manifests/src/modules/platform/templates/kube-stx-override.conf.erb new file mode 100644 index 0000000000..69f59043f2 --- /dev/null +++ b/puppet-manifests/src/modules/platform/templates/kube-stx-override.conf.erb @@ -0,0 +1,2 @@ +[Unit] +After=config.service \ No newline at end of file diff --git a/sysinv/sysinv/centos/build_srpm.data b/sysinv/sysinv/centos/build_srpm.data index fb9c4ef5cd..27453fdecb 100644 --- a/sysinv/sysinv/centos/build_srpm.data +++ b/sysinv/sysinv/centos/build_srpm.data @@ -1,2 +1,2 @@ SRC_DIR="sysinv" -TIS_PATCH_VER=296 +TIS_PATCH_VER=297 diff --git a/sysinv/sysinv/sysinv/setup.cfg b/sysinv/sysinv/sysinv/setup.cfg index 1cd04bf484..4ce1245844 100644 --- a/sysinv/sysinv/sysinv/setup.cfg +++ b/sysinv/sysinv/sysinv/setup.cfg @@ -78,6 +78,7 @@ systemconfig.helm_plugins = barbican = sysinv.helm.barbican:BarbicanHelm ceilometer = sysinv.helm.ceilometer:CeilometerHelm cinder = sysinv.helm.cinder:CinderHelm + garbd = sysinv.helm.garbd:GarbdHelm glance = sysinv.helm.glance:GlanceHelm gnocchi = sysinv.helm.gnocchi:GnocchiHelm heat = sysinv.helm.heat:HeatHelm diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py index 1ce12f9fa3..300f4dd6f3 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/host.py @@ -2110,6 +2110,11 @@ class HostController(rest.RestController): ihost_obj['uuid'], ibm_msg_dict) + # Trigger a system app reapply if the host has been unlocked + if (utils.is_kubernetes_config() and patched_ihost.get('action') in + [constants.UNLOCK_ACTION, constants.FORCE_UNLOCK_ACTION]): + self._reapply_system_app() + elif mtc_response['status'] is None: raise wsme.exc.ClientSideError( _("Timeout waiting for maintenance response. " @@ -2341,6 +2346,15 @@ class HostController(rest.RestController): # wait for VIM signal return + openstack_worker = False + if utils.is_kubernetes_config(): + labels = objects.label.get_by_host_id(pecan.request.context, ihost.uuid) + for l in labels: + if (constants.COMPUTE_NODE_LABEL == + str(l.label_key) + '=' + str(l.label_value)): + openstack_worker = True + break + idict = {'operation': constants.DELETE_ACTION, 'uuid': ihost.uuid, 'invprovision': ihost.invprovision} @@ -2464,6 +2478,32 @@ class HostController(rest.RestController): pecan.request.dbapi.ihost_destroy(ihost_id) + # If the host being removed was an openstack worker node, trigger + # a reapply + if openstack_worker: + self._reapply_system_app() + + def _reapply_system_app(self): + try: + db_app = objects.kube_app.get_by_name( + pecan.request.context, constants.HELM_APP_OPENSTACK) + + if db_app.status == constants.APP_APPLY_SUCCESS: + LOG.info( + "Reapplying the %s app" % constants.HELM_APP_OPENSTACK) + db_app.status = constants.APP_APPLY_IN_PROGRESS + db_app.progress = None + db_app.save() + pecan.request.rpcapi.perform_app_apply( + pecan.request.context, db_app) + else: + LOG.info("%s system app is present but not applied, " + "skipping re-apply" % constants.HELM_APP_OPENSTACK) + except exception.KubeAppNotFound: + LOG.info( + "%s system app not present, skipping re-apply" % + constants.HELM_APP_OPENSTACK) + def _check_upgrade_provision_order(self, personality, hostname): LOG.info("_check_upgrade_provision_order personality=%s, hostname=%s" % (personality, hostname)) diff --git a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/label.py b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/label.py index abd7f68ec8..3121eddae3 100644 --- a/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/label.py +++ b/sysinv/sysinv/sysinv/sysinv/api/controllers/v1/label.py @@ -288,11 +288,5 @@ class LabelController(rest.RestController): # UTILS ########### def _check_host_locked(host): - - # TODO(ksmith): - # turn this on later - return - - if (utils.is_aio_simplex_host_unlocked(host) or - host.administrative != constants.ADMIN_LOCKED): + if host.administrative != constants.ADMIN_LOCKED: raise wsme.exc.ClientSideError(_("Host must be locked.")) diff --git a/sysinv/sysinv/sysinv/sysinv/common/constants.py b/sysinv/sysinv/sysinv/sysinv/common/constants.py index 6bd76eaafa..b8c87e3652 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/constants.py +++ b/sysinv/sysinv/sysinv/sysinv/common/constants.py @@ -123,6 +123,7 @@ HOST_DELETE = 'host_delete' # for personality sub-type validation # Availability AVAILABILITY_AVAILABLE = 'available' +AVAILABILITY_INTEST = 'intest' AVAILABILITY_OFFLINE = 'offline' AVAILABILITY_ONLINE = 'online' AVAILABILITY_DEGRADED = 'degraded' @@ -1394,6 +1395,7 @@ HELM_CHART_AODH = 'aodh' HELM_CHART_BARBICAN = 'barbican' HELM_CHART_CEILOMETER = 'ceilometer' HELM_CHART_CINDER = 'cinder' +HELM_CHART_GARBD = 'garbd' HELM_CHART_GLANCE = 'glance' HELM_CHART_GNOCCHI = 'gnocchi' HELM_CHART_HEAT = 'heat' @@ -1418,6 +1420,7 @@ SUPPORTED_HELM_CHARTS = [ HELM_CHART_BARBICAN, HELM_CHART_CEILOMETER, HELM_CHART_CINDER, + HELM_CHART_GARBD, HELM_CHART_GLANCE, HELM_CHART_GNOCCHI, HELM_CHART_HEAT, @@ -1450,6 +1453,7 @@ SUPPORTED_HELM_APP_CHARTS = { HELM_CHART_INGRESS, HELM_CHART_RBD_PROVISIONER, HELM_CHART_MARIADB, + HELM_CHART_GARBD, HELM_CHART_RABBITMQ, HELM_CHART_MEMCACHED, HELM_CHART_KEYSTONE, diff --git a/sysinv/sysinv/sysinv/sysinv/common/exception.py b/sysinv/sysinv/sysinv/sysinv/common/exception.py index b675ee862b..30077ae331 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/exception.py +++ b/sysinv/sysinv/sysinv/sysinv/common/exception.py @@ -1170,6 +1170,10 @@ class HostLabelInvalid(Invalid): message = _("Host label is invalid. Reason: %(reason)s") +class K8sNodeNotFound(NotFound): + message = _("Kubernetes Node %(name)s could not be found.") + + class PickleableException(Exception): """ Pickleable Exception diff --git a/sysinv/sysinv/sysinv/sysinv/common/kubernetes.py b/sysinv/sysinv/sysinv/sysinv/common/kubernetes.py index 511f6bff47..7d5abffc54 100644 --- a/sysinv/sysinv/sysinv/sysinv/common/kubernetes.py +++ b/sysinv/sysinv/sysinv/sysinv/common/kubernetes.py @@ -51,6 +51,19 @@ class KubeOperator(object): if e.status == httplib.UNPROCESSABLE_ENTITY: reason = json.loads(e.body).get('message', "") raise exception.HostLabelInvalid(reason=reason) + elif e.status == httplib.NOT_FOUND: + raise exception.K8sNodeNotFound(name=name) + else: + raise except Exception as e: - LOG.error("Kubernetes exception: %s" % e) + LOG.error("Kubernetes exception in kube_patch_node: %s" % e) + raise + + def kube_get_nodes(self): + try: + api_response = self._get_kubernetesclient().list_node() + LOG.debug("Response: %s" % api_response) + return api_response.items + except Exception as e: + LOG.error("Kubernetes exception in kube_get_nodes: %s" % e) raise diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py index eefbfaceb7..35ba29444b 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/kube_app.py @@ -528,10 +528,15 @@ class AppOperator(object): } } body['metadata']['labels'].update(label_dict) - self._kube.kube_patch_node(hostname, body) + try: + self._kube.kube_patch_node(hostname, body) + except exception.K8sNodeNotFound: + pass def _assign_host_labels(self, hosts, labels): for host in hosts: + if host.administrative != constants.ADMIN_LOCKED: + continue for label_str in labels: k, v = label_str.split('=') try: @@ -553,6 +558,8 @@ class AppOperator(object): def _remove_host_labels(self, hosts, labels): for host in hosts: + if host.administrative != constants.ADMIN_LOCKED: + continue null_labels = {} for label_str in labels: lbl_obj = self._find_label(host.uuid, label_str) @@ -679,6 +686,21 @@ class AppOperator(object): missing_overrides.append(overrides_file) else: available_overrides.append(overrides_file) + + # Now handle any meta-overrides files. These can affect + # sections of the chart schema other than "values, and can + # affect the chartgroup or even the manifest. + if self._helm.generate_meta_overrides( + chart.name, chart.namespace): + overrides = chart.namespace + '-' + chart.name + \ + '-meta' + '.yaml' + overrides_file = os.path.join(common.HELM_OVERRIDES_PATH, + overrides) + if not os.path.exists(overrides_file): + missing_overrides.append(overrides_file) + else: + available_overrides.append(overrides_file) + if missing_overrides: LOG.error("Missing the following overrides: %s" % missing_overrides) return None @@ -937,43 +959,60 @@ class AppOperator(object): if self._make_armada_request_with_monitor(app, constants.APP_DELETE_OP): if app.system_app: - try: - # TODO convert these kubectl commands to use the k8s api - p1 = subprocess.Popen( - ['kubectl', '--kubeconfig=/etc/kubernetes/admin.conf', - 'get', 'pvc', '--no-headers', '-n', 'openstack'], - stdout=subprocess.PIPE) - p2 = subprocess.Popen(['awk', '{print $3}'], - stdin=p1.stdout, - stdout=subprocess.PIPE) - p3 = subprocess.Popen( - ['xargs', '-i', 'kubectl', - '--kubeconfig=/etc/kubernetes/admin.conf', 'delete', - 'pv', '{}', '--wait=false'], - stdin=p2.stdout, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) + # TODO convert these kubectl commands to use the k8s api + p1 = subprocess.Popen( + ['kubectl', '--kubeconfig=/etc/kubernetes/admin.conf', + 'get', 'pvc', '--no-headers', '-n', 'openstack'], + stdout=subprocess.PIPE) + p2 = subprocess.Popen(['awk', '{print $3}'], + stdin=p1.stdout, + stdout=subprocess.PIPE) + p3 = subprocess.Popen( + ['xargs', '-i', 'kubectl', + '--kubeconfig=/etc/kubernetes/admin.conf', 'delete', + 'pv', '{}', '--wait=false'], + stdin=p2.stdout, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + timer = threading.Timer(10, p3.kill) + try: + timer.start() p1.stdout.close() p2.stdout.close() out, err = p3.communicate() - if not err: + if out and not err: LOG.info("Persistent Volumes marked for deletion.") + else: + self._abort_operation(app, constants.APP_REMOVE_OP) + LOG.error("Failed to clean up PVs after app removal.") except Exception as e: + self._abort_operation(app, constants.APP_REMOVE_OP) LOG.exception("Failed to clean up PVs after app " "removal: %s" % e) + finally: + timer.cancel() + p4 = subprocess.Popen( + ['kubectl', '--kubeconfig=/etc/kubernetes/admin.conf', + 'delete', 'namespace', 'openstack'], + stdout=subprocess.PIPE) + timer2 = threading.Timer(10, p4.kill) try: - p1 = subprocess.Popen( - ['kubectl', '--kubeconfig=/etc/kubernetes/admin.conf', - 'delete', 'namespace', 'openstack'], - stdout=subprocess.PIPE) - out, err = p1.communicate() - if not err: + timer2.start() + out, err = p4.communicate() + if out and not err: LOG.info("Openstack namespace delete completed.") + else: + self._abort_operation(app, constants.APP_REMOVE_OP) + LOG.error("Failed to clean up openstack namespace" + " after app removal.") except Exception as e: + self._abort_operation(app, constants.APP_REMOVE_OP) LOG.exception("Failed to clean up openstack namespace " "after app removal: %s" % e) + finally: + timer2.cancel() self._update_app_status(app, constants.APP_UPLOAD_SUCCESS) LOG.info("Application (%s) remove completed." % app.name) diff --git a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py index ebd720cfd5..f738bfd8af 100644 --- a/sysinv/sysinv/sysinv/sysinv/conductor/manager.py +++ b/sysinv/sysinv/sysinv/sysinv/conductor/manager.py @@ -4937,12 +4937,45 @@ class ConductorManager(service.PeriodicService): # Audit install states self._audit_install_states(hosts) + # Audit kubernetes node labels + self._audit_kubernetes_labels(hosts) + for host in hosts: # only audit configured hosts if not host.personality: continue self._audit_ihost_action(host) + def _audit_kubernetes_labels(self, hosts): + if not utils.is_kubernetes_config(self.dbapi): + LOG.debug("_audit_kubernetes_labels skip") + return + + LOG.debug("Starting kubernetes label audit") + sysinv_labels = self.dbapi.label_get_all() + nodes = self._kube.kube_get_nodes() + + for host in hosts: + try: + for node in nodes: + if host.hostname == node.metadata.name: + node_labels = node.metadata.labels + host_labels = [l for l in sysinv_labels if l.host_id == host.id] + for host_label in host_labels: + if host_label.label_key not in node_labels.keys(): + LOG.info("Label audit: creating %s=%s on node %s" + % (host_label.label_key, + host_label.label_value, host.hostname)) + body = { + 'metadata': { + 'labels': {host_label.label_key: host_label.label_value} + } + } + self._kube.kube_patch_node(host.hostname, body) + except Exception as e: + LOG.warning("Failed to sync kubernetes label to host %s: %s" % + (host.hostname, e)) + # TODO(CephPoolsDecouple): remove @periodic_task.periodic_task(spacing=60) def _osd_pool_audit(self, context): @@ -10530,7 +10563,11 @@ class ConductorManager(service.PeriodicService): } } body['metadata']['labels'].update(label_dict) - self._kube.kube_patch_node(host.hostname, body) + try: + self._kube.kube_patch_node(host.hostname, body) + except exception.K8sNodeNotFound: + LOG.info("Host %s does not exist in kubernetes yet, label will " + "be added after node's unlock by audit" % host.hostname) def update_host_memory(self, context, host_uuid): try: diff --git a/sysinv/sysinv/sysinv/sysinv/helm/base.py b/sysinv/sysinv/sysinv/sysinv/helm/base.py index 07d194b8c1..fefc65e71a 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/base.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/base.py @@ -188,3 +188,16 @@ class BaseHelm(object): address = self._get_address_by_name( constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_MGMT) return address.address + + def get_meta_overrides(self, namespace): + """ + Return Armada-formatted chart-specific meta-overrides + + This allows a helm chart class to specify overrides (in Armada format) + for things other than the "values" section of a chart. This includes + other sections of a chart, as well as chart groups or even the + overall manifest itself. + + May be left blank to indicate that there are no additional overrides. + """ + return {} diff --git a/sysinv/sysinv/sysinv/sysinv/helm/garbd.py b/sysinv/sysinv/sysinv/sysinv/helm/garbd.py new file mode 100644 index 0000000000..55b77186f6 --- /dev/null +++ b/sysinv/sysinv/sysinv/sysinv/helm/garbd.py @@ -0,0 +1,89 @@ +# +# Copyright (c) 2018 Wind River Systems, Inc. +# +# SPDX-License-Identifier: Apache-2.0 +# + +from sysinv.common import constants +from sysinv.common import exception +from sysinv.openstack.common import log as logging +from sysinv.helm import common +from sysinv.helm import base + +LOG = logging.getLogger(__name__) + + +class GarbdHelm(base.BaseHelm): + """Class to encapsulate helm operations for the galera arbitrator chart""" + + # The service name is used to build the standard docker image location. + # It is intentionally "mariadb" and not "garbd" as they both use the + # same docker image. + SERVICE_NAME = 'mariadb' + + CHART = constants.HELM_CHART_GARBD + SUPPORTED_NAMESPACES = [ + common.HELM_NS_OPENSTACK + ] + + def get_namespaces(self): + return self.SUPPORTED_NAMESPACES + + def get_meta_overrides(self, namespace): + + def _meta_overrides(): + if self._num_controllers() < 2: + # If there are fewer than 2 controllers we'll use a single + # mariadb server and so we don't want to run garbd. This + # will remove "openstack-garbd" from the charts in the + # openstack-mariadb chartgroup. + return { + 'schema': 'armada/ChartGroup/v1', + 'metadata': { + 'schema': 'metadata/Document/v1', + 'name': 'openstack-mariadb', + }, + 'data': { + 'description': 'Mariadb', + 'sequenced': True, + 'chart_group': [ + 'openstack-mariadb', + ] + } + } + else: + return {} + + overrides = { + common.HELM_NS_OPENSTACK: _meta_overrides() + } + if namespace in self.SUPPORTED_NAMESPACES: + return overrides[namespace] + elif namespace: + raise exception.InvalidHelmNamespace(chart=self.CHART, + namespace=namespace) + else: + return overrides + + def get_overrides(self, namespace=None): + overrides = { + common.HELM_NS_OPENSTACK: { + 'images': self._get_images_overrides(), + } + } + + if namespace in self.SUPPORTED_NAMESPACES: + return overrides[namespace] + elif namespace: + raise exception.InvalidHelmNamespace(chart=self.CHART, + namespace=namespace) + else: + return overrides + + def _get_images_overrides(self): + + return { + 'tags': { + 'garbd': self.docker_image + } + } diff --git a/sysinv/sysinv/sysinv/sysinv/helm/helm.py b/sysinv/sysinv/sysinv/sysinv/helm/helm.py index 7eb7301915..e890d4788e 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/helm.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/helm.py @@ -340,6 +340,18 @@ class HelmOperator(object): else: LOG.exception("chart name is required") + @helm_context + def generate_meta_overrides(self, chart_name, chart_namespace): + overrides = {} + if chart_name in self.implemented_charts: + try: + overrides.update( + self.chart_operators[chart_name].get_meta_overrides( + chart_namespace)) + except exception.InvalidHelmNamespace: + raise + return overrides + @helm_context def generate_helm_application_overrides(self, app_name, cnamespace=None, armada_format=False, @@ -404,6 +416,17 @@ class HelmOperator(object): overrides[key] = new_overrides self._write_chart_overrides(chart_name, cnamespace, overrides) + + # Write any meta-overrides for this chart. These will be in + # armada format already. + if armada_format: + overrides = self.generate_meta_overrides(chart_name, + cnamespace) + if overrides: + chart_meta_name = chart_name + '-meta' + self._write_chart_overrides( + chart_meta_name, cnamespace, overrides) + elif app_name: LOG.exception("%s application is not supported" % app_name) else: diff --git a/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py b/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py index 6cff6133c8..265c7f8698 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/mariadb.py @@ -29,7 +29,7 @@ class MariadbHelm(openstack.OpenstackBaseHelm): common.HELM_NS_OPENSTACK: { 'pod': { 'replicas': { - 'server': 1 + 'server': self._num_controllers() } }, 'images': self._get_images_overrides(), diff --git a/sysinv/sysinv/sysinv/sysinv/helm/neutron.py b/sysinv/sysinv/sysinv/sysinv/helm/neutron.py index dbaef7ce1c..8627fe9384 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/neutron.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/neutron.py @@ -158,7 +158,8 @@ class NeutronHelm(openstack.OpenstackBaseHelm): hosts = self.dbapi.ihost_get_list() for host in hosts: - if (host.invprovision == constants.PROVISIONED): + if (host.invprovision in [constants.PROVISIONED, + constants.PROVISIONING]): if constants.WORKER in utils.get_personalities(host): hostname = str(host.hostname) diff --git a/sysinv/sysinv/sysinv/sysinv/helm/nova.py b/sysinv/sysinv/sysinv/sysinv/helm/nova.py index e759606435..7e24879f00 100644 --- a/sysinv/sysinv/sysinv/sysinv/helm/nova.py +++ b/sysinv/sysinv/sysinv/sysinv/helm/nova.py @@ -409,7 +409,8 @@ class NovaHelm(openstack.OpenstackBaseHelm): hosts = self.dbapi.ihost_get_list() for host in hosts: - if (host.invprovision == constants.PROVISIONED): + if (host.invprovision in [constants.PROVISIONED, + constants.PROVISIONING]): if constants.WORKER in utils.get_personalities(host): hostname = str(host.hostname) diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py index 2af759f40b..4423422fac 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/interface.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/interface.py @@ -50,6 +50,9 @@ MELLANOX_DRIVERS = [DRIVER_MLX_CX3, LOOPBACK_IFNAME = 'lo' LOOPBACK_METHOD = 'loopback' +STATIC_METHOD = 'static' +MANUAL_METHOD = 'manual' +DHCP_METHOD = 'dhcp' NETWORK_CONFIG_RESOURCE = 'platform::interfaces::network_config' ROUTE_CONFIG_RESOURCE = 'platform::interfaces::route_config' @@ -593,13 +596,13 @@ def get_interface_primary_address(context, iface, network_id=None): return _set_address_netmask(address) -def get_interface_address_family(context, iface): +def get_interface_address_family(context, iface, network_id=None): """ Determine the IP family/version of the interface primary address. If there is no address then the IPv4 family identifier is returned so that an appropriate default is always present in interface configurations. """ - address = get_interface_primary_address(context, iface) + address = get_interface_primary_address(context, iface, network_id) if not address: return 'inet' # default to ipv4 elif IPAddress(address['address']).version == 4: @@ -615,55 +618,55 @@ def get_interface_gateway_address(context, networktype): return context['gateways'].get(networktype, None) -def get_interface_address_method(context, iface): +def get_interface_address_method(context, iface, network_id=None): """ Determine what type of interface to configure for each network type. """ + networktype = find_networktype_by_network_id(context, network_id) if not iface.ifclass or iface.ifclass == constants.INTERFACE_CLASS_NONE \ - or not iface.networktype: + or not networktype: # Interfaces that are configured purely as a dependency from other # interfaces (i.e., vlan lower interface, bridge member, bond slave) # should be left as manual config - return 'manual' + return MANUAL_METHOD elif iface.ifclass == constants.INTERFACE_CLASS_DATA: # All data interfaces configured in the kernel because they are not # natively supported in vswitch or need to be shared with the kernel # because of a platform VLAN should be left as manual config - return 'manual' + return MANUAL_METHOD elif iface.ifclass in PCI_INTERFACE_CLASSES: - return 'manual' + return MANUAL_METHOD else: if is_controller(context): # All other interface types that exist on a controller are setup # statically since the controller themselves run the DHCP server. - return 'static' - elif iface.networktype == constants.NETWORK_TYPE_CLUSTER_HOST: - return 'static' - elif iface.networktype == constants.NETWORK_TYPE_PXEBOOT: + return STATIC_METHOD + elif networktype == constants.NETWORK_TYPE_CLUSTER_HOST: + return STATIC_METHOD + elif networktype == constants.NETWORK_TYPE_PXEBOOT: # All pxeboot interfaces that exist on non-controller nodes are set # to manual as they are not needed/used once the install is done. # They exist only in support of the vlan mgmt interface above it. - return 'manual' + return MANUAL_METHOD else: # All other types get their addresses from the controller - return 'dhcp' + return DHCP_METHOD def get_interface_traffic_classifier(context, iface, network_id=None): """ Get the interface traffic classifier command line (if any) """ - if (iface.networktype and - iface.networktype in [constants.NETWORK_TYPE_MGMT, - constants.NETWORK_TYPE_INFRA]): + networktype = find_networktype_by_network_id(context, network_id) + if (networktype and + networktype in [constants.NETWORK_TYPE_MGMT, + constants.NETWORK_TYPE_INFRA]): networkspeed = constants.LINK_SPEED_10G ifname = get_interface_os_ifname(context, iface) - if network_id: - ifname = ifname + ':' + str(network_id) return '/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' \ % (ifname, - iface.networktype, + networktype, networkspeed) return None @@ -915,8 +918,8 @@ def get_common_network_config(context, iface, config, network_id=None): if traffic_classifier: config['options']['post_up'] = traffic_classifier - method = get_interface_address_method(context, iface) - if method == 'static': + method = get_interface_address_method(context, iface, network_id) + if method == STATIC_METHOD: address = get_interface_primary_address(context, iface, network_id) if address: config['ipaddress'] = address['address'] @@ -924,12 +927,10 @@ def get_common_network_config(context, iface, config, network_id=None): else: LOG.info("Interface %s has no primary address" % iface['ifname']) - if network_id is None and len(iface.networks) > 0: - networktype = find_networktype_by_network_id( - context, int(iface.networks[0])) - gateway = get_interface_gateway_address(context, networktype) - if gateway: - config['gateway'] = gateway + networktype = find_networktype_by_network_id(context, network_id) + gateway = get_interface_gateway_address(context, networktype) + if gateway: + config['gateway'] = gateway return config @@ -939,15 +940,28 @@ def get_interface_network_config(context, iface, network_id=None): """ # Create a basic network config resource os_ifname = get_interface_os_ifname(context, iface) - method = get_interface_address_method(context, iface) - family = get_interface_address_family(context, iface) + method = get_interface_address_method(context, iface, network_id) + family = get_interface_address_family(context, iface, network_id) + + # setup an alias interface if there are multiple addresses assigned + # NOTE: DHCP will only operate over a non-alias interface + if len(iface.networks) > 1 and network_id and method != DHCP_METHOD: + ifname = "%s:%d" % (os_ifname, network_id) + else: + ifname = os_ifname + mtu = get_interface_mtu(context, iface) config = get_basic_network_config( - os_ifname, method=method, family=family, mtu=mtu) + ifname, method=method, family=family, mtu=mtu) # Add options common to all top level interfaces config = get_common_network_config(context, iface, config, network_id) + # ensure addresses have host scope when configured against the loopback + if os_ifname == LOOPBACK_IFNAME: + options = {'SCOPE': 'scope host'} + config['options'].update(options) + # Add type specific options if iface['iftype'] == constants.INTERFACE_TYPE_VLAN: config = get_vlan_network_config(context, iface, config) @@ -966,38 +980,25 @@ def generate_network_config(context, config, iface): resource, while in other cases it will emit multiple resources to create a bridge, or to add additional route resources. """ - if len(iface.networks) == 1: - # get the network type of the single network - iface.networktype = find_networktype_by_network_id( - context, int(iface.networks[0])) - else: - # Either no network assigned to the interface or multiple networks - iface.networktype = None + ifname = get_interface_os_ifname(context, iface) - # Set up the interface network config or the parent of alias interfaces - network_config = get_interface_network_config(context, iface) + # Setup the default device configuration for the interface. This will be + # overridden if there is a specific network type configuration, otherwise + # it will act as the parent device for the aliases + net_config = get_interface_network_config(context, iface) config[NETWORK_CONFIG_RESOURCE].update({ - network_config['ifname']: format_network_config(network_config) + net_config['ifname']: format_network_config(net_config) }) - if len(iface.networks) > 1: - # Loop over the networks to create network config for each - # alias interface - for net_id in iface.networks: - iface.networktype = find_networktype_by_network_id( - context, int(net_id)) - net_config = get_interface_network_config(context, iface, - int(net_id)) - ifname = net_config['ifname'] + ':' + net_id - if context['system_mode'] == constants.SYSTEM_MODE_SIMPLEX: - options = {'SCOPE': 'scope host'} - net_config['options'].update(options) - config[NETWORK_CONFIG_RESOURCE].update({ - ifname: format_network_config(net_config) - }) + + for net_id in iface.networks: + net_config = get_interface_network_config(context, iface, int(net_id)) + config[NETWORK_CONFIG_RESOURCE].update({ + net_config['ifname']: format_network_config(net_config) + }) # Add complementary puppet resource definitions (if needed) for route in get_interface_routes(context, iface): - route_config = get_route_config(route, network_config['ifname']) + route_config = get_route_config(route, ifname) config[ROUTE_CONFIG_RESOURCE].update({ route_config['name']: route_config }) diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/networking.py b/sysinv/sysinv/sysinv/sysinv/puppet/networking.py index 8bb62932bc..affc871e80 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/networking.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/networking.py @@ -214,7 +214,9 @@ class NetworkingPuppet(base.BasePuppet): networktype = networktype.replace('-', '_') config.update({ 'platform::network::%s::params::interface_name' % networktype: - interface_name + interface_name, + 'platform::network::%s::params::mtu' % networktype: + network_interface.imtu }) interface_address = interface.get_interface_primary_address( diff --git a/sysinv/sysinv/sysinv/sysinv/puppet/platform.py b/sysinv/sysinv/sysinv/sysinv/puppet/platform.py index ea5f30c247..744d9dd3be 100644 --- a/sysinv/sysinv/sysinv/sysinv/puppet/platform.py +++ b/sysinv/sysinv/sysinv/sysinv/puppet/platform.py @@ -48,7 +48,6 @@ class PlatformPuppet(base.BasePuppet): config.update(self._get_sm_config()) config.update(self._get_firewall_config()) config.update(self._get_drbd_sync_config()) - config.update(self._get_nfs_config()) config.update(self._get_remotelogging_config()) config.update(self._get_snmp_config()) return config @@ -61,6 +60,7 @@ class PlatformPuppet(base.BasePuppet): def get_host_config(self, host): config = {} config.update(self._get_hosts_config(host)) + config.update(self._get_nfs_config(host)) config.update(self._get_host_platform_config(host, self.config_uuid)) config.update(self._get_host_ntp_config(host)) config.update(self._get_host_ptp_config(host)) @@ -782,24 +782,26 @@ class PlatformPuppet(base.BasePuppet): return config - def _get_nfs_config(self): + def _get_nfs_config(self, host): # Calculate the optimal NFS r/w size based on the network mtu based # on the configured network(s) mtu = constants.DEFAULT_MTU try: - interfaces = self.dbapi.iinterface_get_by_network( + infra_network = self.dbapi.network_get_by_type( constants.NETWORK_TYPE_INFRA) - for interface in interfaces: - mtu = interface.imtu - except exception.InvalidParameterValue: - try: - interfaces = self.dbapi.iinterface_get_by_network( - constants.NETWORK_TYPE_MGMT) - for interface in interfaces: - mtu = interface.imtu - except exception.InvalidParameterValue: - pass + network_id = infra_network.id + except exception.NetworkTypeNotFound: + mgmt_network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_MGMT) + network_id = mgmt_network.id + interfaces = self.dbapi.iinterface_get_by_ihost(host.uuid) + for interface in interfaces: + if interface['ifclass'] == constants.INTERFACE_CLASS_PLATFORM: + for net_id in interface['networks']: + if int(net_id) == network_id: + mtu = interface.imtu + break if self._get_address_by_name( constants.CONTROLLER_PLATFORM_NFS, diff --git a/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py b/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py index 94be8584d1..732f67b468 100644 --- a/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py +++ b/sysinv/sysinv/sysinv/sysinv/tests/puppet/test_interface.py @@ -31,11 +31,6 @@ NETWORKTYPES_WITH_V4_ROUTES = [constants.NETWORK_TYPE_DATA] NETWORKTYPES_WITH_V6_ROUTES = [constants.NETWORK_TYPE_DATA] -PLATFORM_INTERFACE_CLASSES = [constants.NETWORK_TYPE_PXEBOOT, - constants.NETWORK_TYPE_MGMT, - constants.NETWORK_TYPE_INFRA, - constants.NETWORK_TYPE_OAM] - class BaseTestCase(dbbase.DbTestCase): @@ -49,6 +44,7 @@ class BaseTestCase(dbbase.DbTestCase): self.addresses = [] self.routes = [] self.networks = [] + self.address_pools = [] def assertIn(self, needle, haystack, message=''): """Custom assertIn that handles object comparison""" @@ -111,25 +107,47 @@ class BaseTestCase(dbbase.DbTestCase): 'metric': '1'} self.routes.append(dbutils.create_test_route(**route)) - def _create_ethernet_test(self, ifname=None, ifclass=None, - networktype=None, **kwargs): - if not isinstance(networktype, list): + def _find_network_by_type(self, networktype): + for network in self.networks: + if network['type'] == networktype: + return network + + def _find_address_pool_by_uuid(self, pool_uuid): + for pool in self.address_pools: + if pool['uuid'] == pool_uuid: + return pool + + def _get_network_ids_by_type(self, networktype): + if isinstance(networktype, list): + networktypelist = networktype + elif networktype: networktypelist = [networktype] else: - networktypelist = networktype - networktype = ','.join(networktype) - interface_id = len(self.interfaces) + networktypelist = [] networks = [] + for network_type in networktypelist: + network = self._find_network_by_type(networktype) + networks.append(str(network['id'])) + return networks + + def _update_interface_address_pool(self, iface, networktype): + network = self._find_network_by_type(networktype) + pool = self._find_address_pool_by_uuid(network['pool_uuid']) + addresses = self.context['addresses'].get(iface['ifname'], []) + for address in addresses: + address['pool_uuid'] = pool['uuid'] + + def _create_ethernet_test(self, ifname=None, ifclass=None, + networktype=None, **kwargs): + interface_id = len(self.interfaces) if not ifname: ifname = (networktype or 'eth') + str(interface_id) - if all(network_type in constants.PLATFORM_NETWORK_TYPES - for network_type in networktypelist): - ifclass = constants.INTERFACE_CLASS_PLATFORM - for network_type in networktypelist: - network = self.dbapi.network_get_by_type(network_type) - networks.append(str(network.id)) - if not ifclass and networktype: - ifclass = networktype + if not ifclass: + ifclass = constants.INTERFACE_CLASS_NONE + if ifclass == constants.INTERFACE_CLASS_PLATFORM: + networks = self._get_network_ids_by_type(networktype) + else: + networks = [] interface = {'id': interface_id, 'uuid': str(uuid.uuid4()), 'forihostid': self.host.id, @@ -165,24 +183,16 @@ class BaseTestCase(dbbase.DbTestCase): def _create_vlan_test(self, ifname, ifclass, networktype, vlan_id, lower_iface=None): - if not isinstance(networktype, list): - networktypelist = [networktype] - else: - networktypelist = networktype - networktype = ','.join(networktype) if not lower_iface: lower_port, lower_iface = self._create_ethernet_test() if not ifname: ifname = 'vlan' + str(vlan_id) - networks = [] - if all(network_type in constants.PLATFORM_NETWORK_TYPES - for network_type in networktypelist): - ifclass = constants.INTERFACE_CLASS_PLATFORM - for network_type in networktypelist: - network = self.dbapi.network_get_by_type(network_type) - networks.append(str(network.id)) - if not ifclass and networktype: - ifclass = networktype + if not ifclass: + ifclass = constants.INTERFACE_CLASS_NONE + if ifclass == constants.INTERFACE_CLASS_PLATFORM: + networks = self._get_network_ids_by_type(networktype) + else: + networks = [] interface_id = len(self.interfaces) interface = {'id': interface_id, 'uuid': str(uuid.uuid4()), @@ -204,27 +214,17 @@ class BaseTestCase(dbbase.DbTestCase): return db_interface def _create_bond_test(self, ifname, ifclass=None, networktype=None): - if not isinstance(networktype, list): - networktypelist = [networktype] - else: - networktypelist = networktype - networktype = ','.join(networktype) port1, iface1 = self._create_ethernet_test() port2, iface2 = self._create_ethernet_test() interface_id = len(self.interfaces) if not ifname: ifname = 'bond' + str(interface_id) - - networks = [] - if all(network_type in constants.PLATFORM_NETWORK_TYPES - for network_type in networktypelist): - ifclass = constants.INTERFACE_CLASS_PLATFORM - for network_type in networktypelist: - network = self.dbapi.network_get_by_type(network_type) - networks.append(str(network.id)) - if not ifclass and networktype: - ifclass = networktype - + if not ifclass: + ifclass = constants.INTERFACE_CLASS_NONE + if ifclass == constants.INTERFACE_CLASS_PLATFORM: + networks = self._get_network_ids_by_type(networktype) + else: + networks = [] interface = {'id': interface_id, 'uuid': str(uuid.uuid4()), 'forihostid': self.host.id, @@ -259,24 +259,28 @@ class BaseTestCase(dbbase.DbTestCase): name='management', ranges=[['192.168.204.2', '192.168.204.254']], prefix=24) + self.address_pools.append(mgmt_pool) pxeboot_pool = dbutils.create_test_address_pool( network='192.168.202.0', name='pxeboot', ranges=[['192.168.202.2', '192.168.202.254']], prefix=24) + self.address_pools.append(pxeboot_pool) infra_pool = dbutils.create_test_address_pool( network='192.168.205.0', name='infrastructure', ranges=[['192.168.205.2', '192.168.205.254']], prefix=24) + self.address_pools.append(infra_pool) oam_pool = dbutils.create_test_address_pool( network='10.10.10.0', name='oam', ranges=[['10.10.10.2', '10.10.10.254']], prefix=24) + self.address_pools.append(oam_pool) self.networks.append(dbutils.create_test_network( type=constants.NETWORK_TYPE_MGMT, @@ -434,7 +438,8 @@ class InterfaceTestCase(BaseTestCase): self._create_test_common() self._create_test_host(constants.CONTROLLER) self.port, self.iface = self._create_ethernet_test( - "mgmt0", None, constants.NETWORK_TYPE_MGMT) + "mgmt0", constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) def _update_context(self): # ensure DB entries are updated prior to updating the context which @@ -451,6 +456,8 @@ class InterfaceTestCase(BaseTestCase): def test_is_platform_network_type_true(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) result = interface.is_platform_network_type(self.iface) self.assertTrue(result) @@ -622,6 +629,8 @@ class InterfaceTestCase(BaseTestCase): def test_get_interface_gateway_address_oam(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_OAM + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_OAM) gateway = interface.get_interface_gateway_address( self.context, constants.NETWORK_TYPE_OAM) expected = str(self.oam_gateway_address.ip) @@ -630,6 +639,8 @@ class InterfaceTestCase(BaseTestCase): def test_get_interface_gateway_address_mgmt(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) gateway = interface.get_interface_gateway_address( self.context, constants.NETWORK_TYPE_MGMT) expected = str(self.mgmt_gateway_address.ip) @@ -644,7 +655,6 @@ class InterfaceTestCase(BaseTestCase): def test_get_interface_address_method_for_none(self): self.iface['ifclass'] = None - self.iface['networktype'] = None method = interface.get_interface_address_method( self.context, self.iface) self.assertEqual(method, 'manual') @@ -673,102 +683,154 @@ class InterfaceTestCase(BaseTestCase): def test_get_interface_address_method_for_pxeboot_worker(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_PXEBOOT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_PXEBOOT) self.host['personality'] = constants.WORKER self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_PXEBOOT) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_PXEBOOT) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'manual') def test_get_interface_address_method_for_pxeboot_storage(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_PXEBOOT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_PXEBOOT) self.host['personality'] = constants.STORAGE self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_PXEBOOT) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_PXEBOOT) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'manual') def test_get_interface_address_method_for_pxeboot_controller(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_PXEBOOT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_PXEBOOT) self.host['personality'] = constants.CONTROLLER self._update_context() + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_PXEBOOT) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'static') def test_get_interface_address_method_for_mgmt_worker(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) self.host['personality'] = constants.WORKER self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_MGMT) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_MGMT) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'dhcp') def test_get_interface_address_method_for_mgmt_storage(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) self.host['personality'] = constants.STORAGE self._update_context() + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_MGMT) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'dhcp') def test_get_interface_address_method_for_mgmt_controller(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) self.host['personality'] = constants.CONTROLLER self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_MGMT) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_MGMT) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'static') def test_get_interface_address_method_for_infra_worker(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) self.host['personality'] = constants.WORKER self._update_context() + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_INFRA) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'dhcp') def test_get_interface_address_method_for_infra_storage(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) self.host['personality'] = constants.STORAGE self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_INFRA) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_INFRA) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'dhcp') def test_get_interface_address_method_for_infra_controller(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) self.host['personality'] = constants.CONTROLLER self._update_context() + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_INFRA) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'static') def test_get_interface_address_method_for_oam_controller(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_OAM + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_OAM) self.host['personality'] = constants.CONTROLLER self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_OAM) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_OAM) method = interface.get_interface_address_method( - self.context, self.iface) + self.context, self.iface, network.id) self.assertEqual(method, 'static') def test_get_interface_traffic_classifier_for_mgmt(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_MGMT: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_MGMT) classifier = interface.get_interface_traffic_classifier( - self.context, self.iface) + self.context, self.iface, network.id) print(self.context) expected = ('/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' % (self.port['name'], constants.NETWORK_TYPE_MGMT, @@ -779,12 +841,12 @@ class InterfaceTestCase(BaseTestCase): self.iface['ifname'] = 'infra0' self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_INFRA: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_INFRA) classifier = interface.get_interface_traffic_classifier( - self.context, self.iface) + self.context, self.iface, network.id) expected = ('/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' % (self.port['name'], constants.NETWORK_TYPE_INFRA, constants.LINK_SPEED_10G)) @@ -793,16 +855,15 @@ class InterfaceTestCase(BaseTestCase): def test_get_interface_traffic_classifier_for_oam(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_OAM - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_OAM: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_OAM) + network = self.dbapi.network_get_by_type( + constants.NETWORK_TYPE_OAM) classifier = interface.get_interface_traffic_classifier( - self.context, self.iface) + self.context, self.iface, network.id) self.assertIsNone(classifier) def test_get_interface_traffic_classifier_for_none(self): - self.iface['networktype'] = None classifier = interface.get_interface_traffic_classifier( self.context, self.iface) self.assertIsNone(classifier) @@ -818,6 +879,8 @@ class InterfaceTestCase(BaseTestCase): def test_get_bridge_interface_name_none_not_data(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) ifname = interface.get_bridge_interface_name(self.context, self.iface) self.assertIsNone(ifname) @@ -832,6 +895,8 @@ class InterfaceTestCase(BaseTestCase): def test_needs_interface_config_kernel_mgmt(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) self.host['personality'] = constants.CONTROLLER self._update_context() needed = interface.needs_interface_config(self.context, self.iface) @@ -840,6 +905,8 @@ class InterfaceTestCase(BaseTestCase): def test_needs_interface_config_kernel_infra(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) self.host['personality'] = constants.CONTROLLER self._update_context() needed = interface.needs_interface_config(self.context, self.iface) @@ -848,6 +915,8 @@ class InterfaceTestCase(BaseTestCase): def test_needs_interface_config_kernel_oam(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_OAM + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_OAM) self.host['personality'] = constants.CONTROLLER self._update_context() needed = interface.needs_interface_config(self.context, self.iface) @@ -1055,13 +1124,14 @@ class InterfaceTestCase(BaseTestCase): def test_get_controller_ethernet_config_oam(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_OAM - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_OAM: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_OAM) self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_OAM) + network = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_OAM) config = interface.get_interface_network_config( - self.context, self.iface) + self.context, self.iface, network.id) options = {'LINKDELAY': '20'} expected = self._get_static_network_config( ifname=self.port['name'], mtu=1500, gateway='10.10.10.1', @@ -1072,13 +1142,14 @@ class InterfaceTestCase(BaseTestCase): def test_get_controller_ethernet_config_mgmt(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_MGMT: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_MGMT) + network = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_MGMT) config = interface.get_interface_network_config( - self.context, self.iface) + self.context, self.iface, network.id) options = {'LINKDELAY': '20', 'post_up': '/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' % @@ -1093,13 +1164,14 @@ class InterfaceTestCase(BaseTestCase): def test_get_controller_ethernet_config_infra(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_INFRA: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_INFRA) + network = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_INFRA) config = interface.get_interface_network_config( - self.context, self.iface) + self.context, self.iface, network.id) options = {'LINKDELAY': '20', 'post_up': '/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' % @@ -1195,14 +1267,15 @@ class InterfaceTestCase(BaseTestCase): def test_get_worker_ethernet_config_mgmt(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_MGMT + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_MGMT) self.host['personality'] = constants.WORKER - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_MGMT: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_MGMT) + network = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_MGMT) config = interface.get_interface_network_config( - self.context, self.iface) + self.context, self.iface, network.id) options = {'LINKDELAY': '20', 'post_up': '/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' % @@ -1216,14 +1289,15 @@ class InterfaceTestCase(BaseTestCase): def test_get_worker_ethernet_config_infra(self): self.iface['ifclass'] = constants.INTERFACE_CLASS_PLATFORM self.iface['networktype'] = constants.NETWORK_TYPE_INFRA + self.iface['networks'] = self._get_network_ids_by_type( + constants.NETWORK_TYPE_INFRA) self.host['personality'] = constants.WORKER - for network in self.networks: - if network['type'] == constants.NETWORK_TYPE_INFRA: - net_id = network['id'] - self.iface['networks'] = [str(net_id)] self._update_context() + self._update_interface_address_pool( + self.iface, constants.NETWORK_TYPE_INFRA) + network = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_INFRA) config = interface.get_interface_network_config( - self.context, self.iface) + self.context, self.iface, network.id) options = {'LINKDELAY': '20', 'post_up': '/usr/local/bin/cgcs_tc_setup.sh %s %s %s > /dev/null' % @@ -1531,9 +1605,12 @@ class InterfaceControllerEthernet(InterfaceHostTestCase): # ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER) - self._create_ethernet_test('oam', None, constants.NETWORK_TYPE_OAM) - self._create_ethernet_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_ethernet_test('infra', None, constants.NETWORK_TYPE_INFRA) + self._create_ethernet_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM) + self._create_ethernet_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_ethernet_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) self._create_ethernet_test('none') def setUp(self): @@ -1548,9 +1625,12 @@ class InterfaceControllerBond(InterfaceHostTestCase): # aggregated ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER) - self._create_bond_test('oam', None, constants.NETWORK_TYPE_OAM) - self._create_bond_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_bond_test('infra', None, constants.NETWORK_TYPE_INFRA) + self._create_bond_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM) + self._create_bond_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_bond_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) def setUp(self): super(InterfaceControllerBond, self).setUp() @@ -1569,11 +1649,15 @@ class InterfaceControllerVlanOverBond(InterfaceHostTestCase): # vlan interfaces over aggregated ethernet interfaces self._create_test_common() self._create_test_host(constants.CONTROLLER) - bond = self._create_bond_test('pxeboot', None, + bond = self._create_bond_test('pxeboot', + constants.INTERFACE_CLASS_PLATFORM, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, bond) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, bond) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3, + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, bond) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, bond) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3, bond) self._create_ethernet_test('none') @@ -1592,12 +1676,14 @@ class InterfaceControllerVlanOverEthernet(InterfaceHostTestCase): self._create_test_common() self._create_test_host(constants.CONTROLLER) port, iface = self._create_ethernet_test( - 'pxeboot', None, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, iface) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, - iface) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3, - iface) + 'pxeboot', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_PXEBOOT) + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, iface) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, iface) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3, iface) self._create_ethernet_test('none') def setUp(self): @@ -1613,10 +1699,11 @@ class InterfaceComputeEthernet(InterfaceHostTestCase): # worker and all interfaces are ethernet interfaces. self._create_test_common() self._create_test_host(constants.WORKER) - self._create_ethernet_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_ethernet_test('infra', None, constants.NETWORK_TYPE_INFRA) - self._create_ethernet_test('data', constants.INTERFACE_CLASS_DATA, - constants.NETWORK_TYPE_DATA) + self._create_ethernet_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_ethernet_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) + self._create_ethernet_test('data', constants.INTERFACE_CLASS_DATA) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, constants.NETWORK_TYPE_PCI_SRIOV) self._create_ethernet_test('pthru', constants.INTERFACE_CLASS_PCI_PASSTHROUGH, @@ -1655,10 +1742,12 @@ class InterfaceComputeVlanOverEthernet(InterfaceHostTestCase): self._create_test_common() self._create_test_host(constants.WORKER) port, iface = self._create_ethernet_test( - 'pxeboot', None, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, - iface) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3) + 'pxeboot', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_PXEBOOT) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, iface) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3) self._create_vlan_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA, 5) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, @@ -1681,8 +1770,10 @@ class InterfaceComputeBond(InterfaceHostTestCase): self._create_test_common() # worker and all interfaces are aggregated ethernet interfaces. self._create_test_host(constants.WORKER) - self._create_bond_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_bond_test('infra', None, constants.NETWORK_TYPE_INFRA) + self._create_bond_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_bond_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) self._create_bond_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA) self._create_ethernet_test('sriov', @@ -1712,16 +1803,18 @@ class InterfaceComputeVlanOverBond(InterfaceHostTestCase): # interfaces. self._create_test_common() self._create_test_host(constants.WORKER) - bond = self._create_bond_test('pxeboot', None, + bond = self._create_bond_test('pxeboot', + constants.INTERFACE_CLASS_PLATFORM, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, bond) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, bond) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3, - bond) + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, bond) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, bond) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3, bond) bond2 = self._create_bond_test('bond2') self._create_vlan_test('data', constants.INTERFACE_CLASS_DATA, - constants.NETWORK_TYPE_DATA, 5, - bond2) + constants.NETWORK_TYPE_DATA, 5, bond2) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, constants.NETWORK_TYPE_PCI_SRIOV) @@ -1748,9 +1841,12 @@ class InterfaceCpeEthernet(InterfaceHostTestCase): # ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER) - self._create_ethernet_test('oam', None, constants.NETWORK_TYPE_OAM) - self._create_ethernet_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_ethernet_test('infra', None, constants.NETWORK_TYPE_INFRA) + self._create_ethernet_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM) + self._create_ethernet_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_ethernet_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) self._create_ethernet_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, @@ -1791,11 +1887,14 @@ class InterfaceCpeVlanOverEthernet(InterfaceHostTestCase): self._create_test_common() self._create_test_host(constants.CONTROLLER) port, iface = self._create_ethernet_test( - 'pxeboot', None, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, iface) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, - iface) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3) + 'pxeboot', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_PXEBOOT) + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, iface) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, iface) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3) self._create_vlan_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA, 5) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, @@ -1819,9 +1918,12 @@ class InterfaceCpeBond(InterfaceHostTestCase): # aggregated ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER) - self._create_bond_test('oam', None, constants.NETWORK_TYPE_OAM) - self._create_bond_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_bond_test('infra', None, constants.NETWORK_TYPE_INFRA) + self._create_bond_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM) + self._create_bond_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_bond_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) self._create_bond_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, @@ -1849,12 +1951,14 @@ class InterfaceCpeVlanOverBond(InterfaceHostTestCase): # vlan interfaces over aggregated ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER) - bond = self._create_bond_test('pxeboot', None, + bond = self._create_bond_test('pxeboot', constants.INTERFACE_CLASS_PLATFORM, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, bond) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, bond) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3, - bond) + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, bond) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, bond) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3, bond) bond2 = self._create_bond_test('bond4') self._create_vlan_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA, 5, @@ -1881,15 +1985,18 @@ class InterfaceCpeComputeEthernet(InterfaceHostTestCase): # ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER, constants.WORKER) - self._create_ethernet_test('oam', None, constants.NETWORK_TYPE_OAM) - self._create_ethernet_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_ethernet_test('infra', None, constants.NETWORK_TYPE_INFRA) self._create_ethernet_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, constants.NETWORK_TYPE_PCI_SRIOV) self._create_ethernet_test('pthru', constants.INTERFACE_CLASS_PCI_PASSTHROUGH, constants.NETWORK_TYPE_PCI_PASSTHROUGH) + self._create_ethernet_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM) + self._create_ethernet_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_ethernet_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) port, iface = ( self._create_ethernet_test('slow', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA, @@ -1924,11 +2031,14 @@ class InterfaceCpeComputeVlanOverEthernet(InterfaceHostTestCase): self._create_test_common() self._create_test_host(constants.CONTROLLER, constants.WORKER) port, iface = self._create_ethernet_test( - 'pxeboot', None, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, iface) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, - iface) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3) + 'pxeboot', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_PXEBOOT) + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, iface) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, iface) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3) self._create_vlan_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA, 5) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, @@ -1952,9 +2062,12 @@ class InterfaceCpeComputeBond(InterfaceHostTestCase): # aggregated ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER, constants.WORKER) - self._create_bond_test('oam', None, constants.NETWORK_TYPE_OAM) - self._create_bond_test('mgmt', None, constants.NETWORK_TYPE_MGMT) - self._create_bond_test('infra', None, constants.NETWORK_TYPE_INFRA) + self._create_bond_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM) + self._create_bond_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT) + self._create_bond_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA) self._create_bond_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA) self._create_ethernet_test('sriov', constants.INTERFACE_CLASS_PCI_SRIOV, @@ -1982,12 +2095,15 @@ class InterfaceCpeComputeVlanOverBond(InterfaceHostTestCase): # vlan interfaces over aggregated ethernet interfaces. self._create_test_common() self._create_test_host(constants.CONTROLLER, constants.WORKER) - bond = self._create_bond_test('pxeboot', None, + bond = self._create_bond_test('pxeboot', + constants.INTERFACE_CLASS_PLATFORM, constants.NETWORK_TYPE_PXEBOOT) - self._create_vlan_test('oam', None, constants.NETWORK_TYPE_OAM, 1, bond) - self._create_vlan_test('mgmt', None, constants.NETWORK_TYPE_MGMT, 2, bond) - self._create_vlan_test('infra', None, constants.NETWORK_TYPE_INFRA, 3, - bond) + self._create_vlan_test('oam', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_OAM, 1, bond) + self._create_vlan_test('mgmt', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_MGMT, 2, bond) + self._create_vlan_test('infra', constants.INTERFACE_CLASS_PLATFORM, + constants.NETWORK_TYPE_INFRA, 3, bond) bond2 = self._create_bond_test('bond2') self._create_vlan_test('data', constants.INTERFACE_CLASS_DATA, constants.NETWORK_TYPE_DATA, 5,