VOL-4840 - Makefile edits

VOL-4874, VOL-4877, VOL-4840

howto/edit_voltha_docs.rst
--------------------------
   * Also need to run "make docs" to generate html content.

Makefile
--------
   * (local use) fixed non-functional makefile targets.
   * Begin splitting monolithic makefile into reusable libs.
   * Extended help to document all targets (make help VERBOSE=1)
   * Extended lint to support more targets.
   * Replace wildcard target (%) with a list of sphinx-build named targets:
     + Amusing behavior but "make clean" should not initiate "gendocs".
     + Likewise "make lint" should not attempt to generate documentation.
   * Introduced simple patching logic for virtualenv.  Local users are
     now able to use make clean, lint, etc with a newer interpreter.
     Baby steps toward VOL-4874.
   * Conditional make vars added:
     + NO_PATCH=1
     + NO_OTHER_REPO_DOCS=1 (venv patching not yet supported by foreign repos).

makefiles/consts.mk
-------------------
   * basic values: space, dot, null, HIDE.

makefiles/help/include.mk
-------------------------
   * makefile target help with context.

makefiles/lint/*.mk
-------------------
   * lib makefiles capturing syntax checking logic.

makefiles/patches/include.mk
----------------------------
   * Targets for creation and applying python virtualenv patches.

patches/*/patch
patches/python_310_migration.sh
-------------------------------
   * Logic used to support dynamic python module pathching in a virtual env directory.
   * Module edits are trivial -- attempt to import new modules and fallback to existing import syntax.

Change-Id: I437289a751423217b4193b75b62c4a295db18ffd
diff --git a/Makefile b/Makefile
index e8a029e..ed53983 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,35 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
 # Makefile for Sphinx documentation
 
-# use bash for pushd/popd, and to fail quickly
-SHELL = bash -e -o pipefail
+.DEFAULT_GOAL := help
+
+TOP         ?= .
+MAKEDIR     ?= $(TOP)/makefiles
+
+$(if $(VERBOSE),$(eval export VERBOSE=$(VERBOSE))) # visible to include(s)
+
+##--------------------##
+##---]  INCLUDES  [---##
+##--------------------##
+include $(MAKEDIR)/consts.mk
+include $(MAKEDIR)/help/include.mk
+include $(MAKEDIR)/patches/include.mk
+include $(MAKEDIR)/help/variables.mk
 
 # You can set these variables from the command line.
 SPHINXOPTS   ?=
@@ -13,6 +41,12 @@
 # edit the `git_refs` file with the commit/tag/branch that you want to use
 OTHER_REPO_DOCS ?= bbsim cord-tester ofagent-go openolt voltctl voltha-openolt-adapter voltha-openonu-adapter-go voltha-protos voltha-system-tests device-management-interface voltha-helm-charts
 
+ifdef NO_OTHER_REPO_DOCS
+  # Inhibit pulling in external repos.
+  # python 3.10+ patching not supported by all repos yet.
+  OTHER_REPO_DOCS := $(null)
+endif
+
 # Static docs, built by other means (usually robot framework)
 STATIC_DOCS    := _static/voltha-system-tests _static/cord-tester
 
@@ -22,15 +56,29 @@
 .PHONY: help test lint reload Makefile prep
 
 # Put it first so that "make" without argument is like "make help".
-help: $(VENV_NAME)
-	source $</bin/activate ; set -u ;\
+help :: $(VENV_NAME)
+	@ echo
+	@ source $</bin/activate ; set -u ;\
 	$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
 
+# -----------------------------------------------------------------------
 # Create the virtualenv with all the tools installed
+# -----------------------------------------------------------------------
 $(VENV_NAME):
-	virtualenv -p python3 $(VENV_NAME) ;\
-	source $@/bin/activate ;\
-	pip install -r requirements.txt
+	@echo
+	@echo "============================="
+	@echo "Installing python virtual env"
+	@echo "============================="
+	virtualenv -p python3 $@ ;\
+	source ./$@/bin/activate ;\
+	python -m pip install -r requirements.txt
+ifndef NO_PATCH
+	@echo
+	@echo "========================================"
+	@echo "Applying python 3.10.x migration patches"
+	@echo "========================================"
+	./patches/python_310_migration.sh '--venv' "$@" 'apply' 
+endif
 
 # automatically reload changes in browser as they're made
 reload: $(VENV_NAME)
@@ -39,7 +87,9 @@
 
 # lint and link verification. linkcheck is part of sphinx
 test: lint linkcheck
-
+# doctest
+# coverage
+# linkcheck
 lint: doc8
 
 doc8: $(VENV_NAME) | $(OTHER_REPO_DOCS)
@@ -60,10 +110,10 @@
 
 # clean up
 clean:
-	rm -rf $(BUILDDIR) $(OTHER_REPO_DOCS) $(STATIC_DOCS)
+	$(RM) -r $(BUILDDIR) $(OTHER_REPO_DOCS) $(STATIC_DOCS)
 
-clean-all: clean
-	rm -rf $(VENV_NAME) repos
+clean-all sterile: clean
+	$(RM) -r $(VENV_NAME) repos
 
 # checkout the repos inside repos/ dir
 repos:
@@ -128,6 +178,14 @@
 
 # Catch-all target: route all unknown targets to Sphinx using the new
 # "make mode" option.  $(O) is meant as a shortcut for $(SPHINXOPTS).
-%: $(VENV_NAME) Makefile | $(OTHER_REPO_DOCS) $(STATIC_DOCS)
+# %: $(VENV_NAME) Makefile | $(OTHER_REPO_DOCS) $(STATIC_DOCS)
+
+include $(MAKEDIR)/voltha/docs-catchall-targets.mk 
+$(voltha-docs-catchall): $(VENV_NAME) Makefile | $(OTHER_REPO_DOCS) $(STATIC_DOCS)
+	@echo " ** CATCHALL: $@"
 	source $</bin/activate ; set -u ;\
 	$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+include $(MAKEDIR)/help/trailer.mk
+
+# [EOF]
diff --git a/VERSION b/VERSION
old mode 100755
new mode 100644
index c63c9a7..41fe9f3
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.10.8
+2.10.9
diff --git a/conf.py b/conf.py
index a0a0a96..3523c3c 100644
--- a/conf.py
+++ b/conf.py
@@ -283,12 +283,16 @@
 
 # -- Options for linkcheck ---------------------------------------------------
 # The link checker strips off .md from links and then complains
-linkcheck_ignore = [r'https://github.com/opencord/voltctl/blob/master/LICENSE',
-                    r'https://github.com/ciena/kind-voltha#voltha-up-configuration-options',
-                    r'https://www.sphinx-doc.org',
-                    r'https://github.com/opencord/bbsim/blob/master/docs/source/DMI_Server_README',
-                    r'https://github.com/opencord/voltha-helm-charts/blob/master/README'
-                    ]
+linkcheck_ignore=\
+    [
+        r'https://github.com/opencord/voltctl/blob/master/LICENSE',
+        r'https://github.com/ciena/kind-voltha#voltha-up-configuration-options',
+        r'https://www.sphinx-doc.org',
+        r'https://github.com/opencord/bbsim/blob/master/docs/source/DMI_Server_README',
+        r'https://github.com/opencord/voltha-helm-charts/blob/master/README',
+        r'https://github.com/atomix/atomix/releases/tag/atomix-3.1.9',
+        r'https://github.com/atomix/atomix/releases/tag/atomix-3.1.8',
+    ]
 
 # -- Configure recommonmark to use AutoStructify -----------------------------
 # Docs: https://recommonmark.readthedocs.io/en/latest/auto_structify.html
diff --git a/howto/code/pull_request.rst b/howto/code/pull_request.rst
new file mode 100644
index 0000000..677e4e2
--- /dev/null
+++ b/howto/code/pull_request.rst
@@ -0,0 +1,23 @@
+VOLTHA project repositories
+===========================
+
+Development and code reviews:
+-----------------------------
+
+Commit decorations:
++++++++++++++++++++
+
+`Tokens
+<https://docs.voltha.org/master/testing/voltha_test_automation.html#per-patchset-verification-jobs>`_ can be embedded within a commit message to enable running additional test suites as part of jenkins validation.
+
+NOTE:
++++++
+There have been a few reports of testing not being triggered by a commit.
+If you encounter this behavior visit the VOLTHA jira site and open a ticket.
+Commit hooks can be repository specific and may need to be deployed/enabled to support functionality.
+
+- :vol-jira:``
+- Include gerrit URL for your changeset.
+- Target repository name/url.
+- What tests or suites were expected that were not exercised.
+
diff --git a/howto/edit_voltha_docs.rst b/howto/edit_voltha_docs.rst
index b63c44f..6a3ba66 100644
--- a/howto/edit_voltha_docs.rst
+++ b/howto/edit_voltha_docs.rst
@@ -27,6 +27,7 @@
    $ make html           # doc generation
    $ make lint           # syntax checking
    $ make test           # syntax check *.rst files
+   $ make docs           # generate website pages
 
    $ "$BROWSER" _build/html/index.html  # BROWSER='firefox'
 
diff --git a/makefiles/consts.mk b/makefiles/consts.mk
new file mode 100644
index 0000000..c34d119
--- /dev/null
+++ b/makefiles/consts.mk
@@ -0,0 +1,28 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+null         :=#
+space        :=$(null) $(null)
+dot          :=.
+HIDE         ?=@
+
+# use bash for pusdh/popd and quick failures.
+# virtual env(s) activate has undefined vars so no -u
+#   ^---+ verify this is still true
+export SHELL := bash -e -o pipefail
+
+# [EOF]
diff --git a/makefiles/help/include.mk b/makefiles/help/include.mk
new file mode 100644
index 0000000..ccba3f4
--- /dev/null
+++ b/makefiles/help/include.mk
@@ -0,0 +1,31 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+# Parent makefile should include this early so help
+# message will be prefixed by a usage statement.
+help ::
+	@echo "Usage: $(MAKE) [options] [target] ..."
+	@echo
+	@echo '[CLEAN]'
+	@echo '  clean          Remove generated targets'
+	@echo '  sterile        clean + remove virtual env interpreter install'
+	@echo
+	@echo '[HELP]'
+	@echo '  help           Display program help'
+	@echo '  help-verbose   Display additional targets and help'
+
+# [EOF]
diff --git a/makefiles/help/trailer.mk b/makefiles/help/trailer.mk
new file mode 100644
index 0000000..bf548db
--- /dev/null
+++ b/makefiles/help/trailer.mk
@@ -0,0 +1,27 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+# include this makefile late so text will be displayed at the end6
+
+help ::
+	@echo
+	@echo '[NOTE: python 3.10+]'
+	@echo '  The interpreter is not yet fully supported across foreign repositories.'
+	@echo '  While working locally, if make fails to build a target try:'
+	@echo '      $(MAKE) $${target} NO_OTHER_REPO_DOCS=1'
+
+# [EOF]
diff --git a/makefiles/help/variables.mk b/makefiles/help/variables.mk
new file mode 100644
index 0000000..a50b233
--- /dev/null
+++ b/makefiles/help/variables.mk
@@ -0,0 +1,36 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+# Include variables.mk after library makefiles have been included
+
+ifdef VERBOSE
+  help :: help-variables
+else
+  help ::
+	@echo
+	@echo '[VARIABLES] - Conditional makefile behavior'
+	@echo '  see also: help-variables'
+endif
+
+help-variables:
+	@echo
+	@echo '[VARIABLES] - Conditional makefile behavior'
+	@echo '  NO_PATCHES=           Do not apply patches to the python virtualenv'
+	@echo '  NO_OTHER_REPO_DOCS=   No foreign repos, only apply target to local sources.'
+	@echo '  VERBOSE=              Display extended help'
+
+# [EOF]
diff --git a/makefiles/lint.mk b/makefiles/lint.mk
new file mode 100644
index 0000000..cb4b0a7
--- /dev/null
+++ b/makefiles/lint.mk
@@ -0,0 +1,27 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+help::
+	@echo
+	@echo "[LINT]"
+
+include $(MAKEDIR)/lint/json.mk
+include $(MAKEDIR)/lint/python.mk
+include $(MAKEDIR)/lint/robot.mk
+include $(MAKEDIR)/lint/yaml.mk
+
+# [EOF]
diff --git a/makefiles/lint/json.mk b/makefiles/lint/json.mk
new file mode 100644
index 0000000..0a11c71
--- /dev/null
+++ b/makefiles/lint/json.mk
@@ -0,0 +1,35 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+JSON_FILES ?= $(error JSON_FILES= is rqeuired)
+
+.PHONY: lint-json
+
+lint : lint-json
+
+lint-json: vst_venv
+	source ./$</bin/activate \
+	    ; set -u \
+	    ; for jsonfile in $(JSON_FILES); do \
+		echo "Validating json file: $$jsonfile" ;\
+		python -m json.tool $$jsonfile > /dev/null ;\
+	done
+
+help::
+	@echo "  lint-json            Syntax check json sources"
+
+# [EOF]
diff --git a/makefiles/lint/python.mk b/makefiles/lint/python.mk
new file mode 100644
index 0000000..5aecd58
--- /dev/null
+++ b/makefiles/lint/python.mk
@@ -0,0 +1,34 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+PYTHON_FILES ?= $(error PYTHON_FILES= is required)
+
+.PHONY: lint-python
+
+lint : lint-python
+
+# check deps for format and python3 cleanliness
+lint-python: vst_venv
+	source ./$</bin/activate \
+	    ; set -u \
+	    ; pylint --py3k $(PYTHON_FILES) \
+	    ; flake8 --max-line-length=99 --count $(PYTHON_FILES)
+
+help::
+	@echo "  lint-python          Syntax check using pylint and flake8"
+
+# [EOF]
diff --git a/makefiles/lint/robot.mk b/makefiles/lint/robot.mk
new file mode 100644
index 0000000..ec5579e
--- /dev/null
+++ b/makefiles/lint/robot.mk
@@ -0,0 +1,41 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+ROBOT_FILES ?= $(error ROBOT_FILES= is required)
+
+LINT_ARGS ?= --verbose --configure LineTooLong:130 -e LineTooLong \
+             --configure TooManyTestSteps:65 -e TooManyTestSteps \
+             --configure TooManyTestCases:50 -e TooManyTestCases \
+             --configure TooFewTestSteps:1 \
+             --configure TooFewKeywordSteps:1 \
+             --configure FileTooLong:2000 -e FileTooLong \
+             -e TrailingWhitespace
+
+
+.PHONY: lint-robot
+
+lint : lint-robot
+
+lint-robot: vst_venv
+	source ./$</bin/activate \
+	    ; set -u \
+	    ; rflint $(LINT_ARGS) $(ROBOT_FILES)
+
+help::
+	@echo "  lint-robot           Syntax check robot sources using rflint"
+
+# [EOF]
diff --git a/makefiles/lint/yaml.mk b/makefiles/lint/yaml.mk
new file mode 100644
index 0000000..c9cb392
--- /dev/null
+++ b/makefiles/lint/yaml.mk
@@ -0,0 +1,32 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+YAML_FILES ?= $(error YAML_FILES= is required)
+
+.PHONY: lint-yaml
+
+lint : lint-yaml
+
+lint-yaml: vst_venv
+	source ./$</bin/activate \
+	    ; set -u \
+	    ; yamllint -s $(YAML_FILES)
+
+help::
+	@echo "  lint-yaml            Syntax check yaml source using yamllint"
+
+# [EOF]
diff --git a/makefiles/patches/help.mk b/makefiles/patches/help.mk
new file mode 100644
index 0000000..ce459fd
--- /dev/null
+++ b/makefiles/patches/help.mk
@@ -0,0 +1,44 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+ifdef VERBOSE
+  help :: help-patches
+else
+  help ::
+	@echo
+	@echo "[PATCHES] - helper on the road to python 3.10+ based testing"
+	@echo '  see also: help-patches'
+endif
+
+help-patches:
+	@echo
+	@echo "[PATCHES] - helper on the road to python 3.10+ based testing"
+	@echo "  patch-apply          Apply patches to the virtualenv directory"
+	@echo "  patch-create"
+	@echo "  patch-gather         Gather a list of potential patch sources"
+	@echo "  patch-init           Clone the virtualenv directory for patch creation."
+
+
+
+
+help-trailer ::
+	@echo "[SEE ALSO] patches-help"
+
+help-verbose:
+	$(HIDE)$(MAKE) --no-print-directory help VERBOSE=1
+
+# [EOF]
diff --git a/makefiles/patches/include.mk b/makefiles/patches/include.mk
new file mode 100644
index 0000000..1c0c869
--- /dev/null
+++ b/makefiles/patches/include.mk
@@ -0,0 +1,65 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+include $(MAKEDIR)/patches/help.mk
+
+patch-gather-args += --exclude=Makefile
+patch-gather-args += --exclude-dir=vault
+patch-gather-args += --exclude-dir=makefiles
+patch-gather-args += --exclude-dir=staging
+patch-gather-args += --exclude-dir=patches
+
+# patch-gather-args += -e 'from collections import'
+patch-gather-args += '-e' 'from collections import Mapping'
+patch-gather-args += '-e' 'from collections import MutableMapping'
+
+VENV_NAME   ?= $(error $(MAKE) VENV_NAME= is required)
+PATCH_PATH  ?= $(error $(MAKE) PATCH_PATH= is required)
+
+## -----------------------------------------------------------------------
+## -----------------------------------------------------------------------
+patch-gather:
+	grep -r $(patch-gather-args)
+
+## -----------------------------------------------------------------------
+## -----------------------------------------------------------------------
+patch-diff:
+	$(HIDE)diff -qr staging $(VENV_NAME) \
+	    | awk '{print "# diff -Naur "$$2" "$$4}' \
+	    | tee $@.log
+
+## -----------------------------------------------------------------------
+## -----------------------------------------------------------------------
+patch-create:
+	mkdir -p patches/$(PATCH_PATH)
+	diff -Naur staging/$(PATCH_PATH) $(VENV_NAME)/$(PATCH_PATH) | tee patches/$(PATCH_PATH)/patch
+	exit 1
+
+## -----------------------------------------------------------------------
+## -----------------------------------------------------------------------
+patch-init:
+	find "$(VENV_NAME)" -name '__pycache__' -type d -print0 \
+	    | xargs -I'{}' --null --no-run-if-empty $(RM) -r {}
+	mkdir -p staging
+	rsync -rv --checksum "$(VENV_NAME)/." "staging/."
+	@echo "Modify files beneath staging/ to create a patch source"
+
+# [SEE ALSO]
+# ---------------------------------------------------------------------------
+# https://bobbyhadz.com/blog/python-importerror-cannot-import-name-mapping-from-collections
+# ---------------------------------------------------------------------------
+# [EOF]
diff --git a/makefiles/virtualenv.mk b/makefiles/virtualenv.mk
new file mode 100644
index 0000000..faa7c60
--- /dev/null
+++ b/makefiles/virtualenv.mk
@@ -0,0 +1,32 @@
+# -*- makefile -*-
+## -----------------------------------------------------------------------
+# Copyright 2017-2022 Open Networking Foundation
+#
+# 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.
+## -----------------------------------------------------------------------
+
+# virtualenv for the robot tools
+# VOL-2724 Invoke pip via python3 to avoid pathname too long on QA jobs
+
+vst_venv-2 : vst_venv/bin/activate requirements.txt
+
+vst_venv/bin/activate:
+	virtualenv -p python3 $@ ;\
+	source ./$@/bin/activate ;\
+	python -m pip install -r requirements.txt
+
+zzz: xyz
+xyz: vst_venv/bin/activate
+	source vst_venv/bin/activate
+
+# [EOF]
diff --git a/makefiles/voltha/docs-catchall-targets.mk b/makefiles/voltha/docs-catchall-targets.mk
new file mode 100644
index 0000000..72ed700
--- /dev/null
+++ b/makefiles/voltha/docs-catchall-targets.mk
@@ -0,0 +1,44 @@
+# -*- makefile -*-
+# -----------------------------------------------------------------------
+# Copyright 2022 Open Networking Foundation
+#
+# 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.
+# -----------------------------------------------------------------------
+
+voltha-docs-catchall += docs
+voltha-docs-catchall += html
+voltha-docs-catchall += dirhtml
+voltha-docs-catchall += singlehtml
+voltha-docs-catchall += pickle
+voltha-docs-catchall += json
+voltha-docs-catchall += htmlhelp
+voltha-docs-catchall += qthelp
+voltha-docs-catchall += devhelp
+voltha-docs-catchall += epub
+voltha-docs-catchall += latex
+voltha-docs-catchall += latexpdf
+voltha-docs-catchall += latexpdfja
+voltha-docs-catchall += text
+voltha-docs-catchall += man
+voltha-docs-catchall += texinfo
+voltha-docs-catchall += info
+voltha-docs-catchall += gettext
+voltha-docs-catchall += changes
+voltha-docs-catchall += xml
+voltha-docs-catchall += pseudoxml
+voltha-docs-catchall += linkcheck
+voltha-docs-catchall += doctest
+voltha-docs-catchall += coverage
+# voltha-docs-catchall += clean
+
+# [EOF]
diff --git a/patches/README.md b/patches/README.md
new file mode 100644
index 0000000..6019c05
--- /dev/null
+++ b/patches/README.md
@@ -0,0 +1,64 @@
+# Migration support for python 3.10+
+
+## Intent
+
+Applications of patches will enable local use of newer python versions
+available with a recent OS install or package manager installation.
+Makefile targets will fail out of the box w/o modifying collection imports.
+
+Create new patches as needed to help testing along.
+Eventually this hierarchy can be dismantled once the latest interpreter
+is generally in use.
+
+## patches/
+
+This directory contains patch files that can be directly applied to sources
+in the python virtualenv directory.  Patches are created to support use of
+three python version variants for the robot ramework:
+    python 2x       (deprecated)
+    python >= 3.10  (collections.abc required)
+    python < 3.10   (collections.abc optional)
+
+
+# vst_venv/
+
+Makefile will first create a python virtualenv directory to selectively
+use packages.  After setup patches are applied to venv (as a transition)
+to fully enable support for local interpreter use for newer OS installs.
+
+
+# staging/
+
+The staging directory is used for comparison with the vst_venv directory
+to generate patches.  Populate the directory with a copy of a cleanly
+patched virtual interpreter then modify files benath/ staging to generate
+a patch from.
+
+% make sterile
+% make vst_venv
+% mkdir staging
+% rsync -rv --checksum vst_venv/. staging/.
+[NOTE] Make python 3.10+ migration edits beneath staging as needed
+% make patch-gather
+% make sterile
+% make lint
+
+
+# makefile targets
+
+make patch-gather:
+   * gather a list of potential sources to edit.
+
+make patch-apply:
+   * Gather a list of patch files.
+   * Apply each in turn to sources in the virtualenv directory.
+
+make patch-create:
+   * make patch-create VENV_NAME="venv_docs" PATCH_PATH="lib/python3.10/site-packages/sphinx/util/typing.py"
+   * make sterile
+   * make help     # reinstall virtualenv and verify help target
+
+# Verify installation
+   * make lint -or- make test
+
+# [EOF]
\ No newline at end of file
diff --git a/patches/lib/python3.10/site-packages/robot/utils/normalizing.py/patch b/patches/lib/python3.10/site-packages/robot/utils/normalizing.py/patch
new file mode 100644
index 0000000..fc9ddd4
--- /dev/null
+++ b/patches/lib/python3.10/site-packages/robot/utils/normalizing.py/patch
@@ -0,0 +1,14 @@
+--- vault/lib/python3.10/site-packages/robot/utils/normalizing.py	2022-11-26 06:59:47.438751606 -0500
++++ vst_venv/lib/python3.10/site-packages/robot/utils/normalizing.py	2022-11-26 06:57:29.960476182 -0500
+@@ -13,10 +13,7 @@
+ #  See the License for the specific language governing permissions and
+ #  limitations under the License.
+ 
+-try: # python >= 3.10
+-    from collections.abc import MutableMapping
+-except ImportError: # python 2x
+-    from collections import MutableMapping
++from collections import MutableMapping
+ 
+ from .platform import IRONPYTHON, PY_VERSION, PY3
+ from .robottypes import is_dict_like, is_unicode
diff --git a/patches/lib/python3.10/site-packages/robot/utils/robottypes3.py/patch b/patches/lib/python3.10/site-packages/robot/utils/robottypes3.py/patch
new file mode 100644
index 0000000..399a769
--- /dev/null
+++ b/patches/lib/python3.10/site-packages/robot/utils/robottypes3.py/patch
@@ -0,0 +1,16 @@
+--- vault/lib/python3.10/site-packages/robot/utils/robottypes3.py	2022-11-26 07:00:17.126386733 -0500
++++ vst_venv/lib/python3.10/site-packages/robot/utils/robottypes3.py	2022-11-26 06:57:29.956476232 -0500
+@@ -13,12 +13,7 @@
+ #  See the License for the specific language governing permissions and
+ #  limitations under the License.
+ 
+-try: # python >= 3.10
+-    from collections.abc import Mapping
+-    from collections     import UserString
+-except ImportError: # python 2x
+-    from collections import Mapping, UserString
+-
++from collections import Mapping, UserString
+ from io import IOBase
+ 
+ from .platform import RERAISED_EXCEPTIONS
diff --git a/patches/lib/python3.10/site-packages/sphinx/util/typing.py/patch b/patches/lib/python3.10/site-packages/sphinx/util/typing.py/patch
new file mode 100644
index 0000000..d049e3b
--- /dev/null
+++ b/patches/lib/python3.10/site-packages/sphinx/util/typing.py/patch
@@ -0,0 +1,19 @@
+--- staging/lib/python3.10/site-packages/sphinx/util/typing.py	2022-11-28 06:22:14.637278053 -0500
++++ venv_docs/lib/python3.10/site-packages/sphinx/util/typing.py	2022-11-28 06:34:36.246702890 -0500
+@@ -34,15 +34,7 @@
+             return ref._eval_type(globalns, localns)
+ 
+ if sys.version_info > (3, 10):
+-
+-    try: # ver >= 3.10.6
+-        from types import UnionType as types_Union
+-    except ImportError:
+-        try: # ver < 3.10.6
+-            from types import Union as types_Union
+-        except ImportError:
+-            types_Union = None
+-
++    from types import Union as types_Union
+ else:
+     types_Union = None
+ 
diff --git a/patches/python_310_migration.sh b/patches/python_310_migration.sh
new file mode 100755
index 0000000..e02a75c
--- /dev/null
+++ b/patches/python_310_migration.sh
@@ -0,0 +1,93 @@
+#!/bin/bash
+# -----------------------------------------------------------------------
+# Copyright 2022 Open Networking Foundation
+#
+# 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 -euo pipefail
+
+dst="vst_venv"
+src="staging"
+pat="patches"
+
+## Update logic to: find . -name 'patch')
+declare -a fyls=()
+fyls+=('lib/python3.10/site-packages/robot/utils/normalizing.py')
+fyls+=('lib/python3.10/site-packages/robot/utils/robottypes3.py')
+fyls+=('lib/python3.10/site-packages/sphinx/util/typing.py')
+
+echo
+echo "==========================================================================="
+echo "CMD: $0"
+echo "PWD: $(/bin/pwd)"
+echo "ARGV: $*"
+echo "==========================================================================="
+
+if [ $# -eq 0 ]; then set -- apply; fi
+
+while [ $# -gt 0 ]; do
+    opt="$1"; shift
+    case "$opt" in
+
+	-*venv) dst="$1"; shift ;;
+
+	help)
+	    cat <<EOH
+apply  - generate patches from vault source.
+backup - Archive patch directory
+gather - collect potential python files to edit.
+EOH
+	    ;;
+
+	apply)
+	    pushd "$dst" >/dev/null || { echo "pushd $dst failed"; exit 1; }
+	    for fyl in "${fyls[@]}";
+	    do
+		# Conditional install, jenkins may not support interpreter yet.
+		if [ ! -e "$fyl" ]; then
+		    echo "[SKIP] $fyl"
+		    continue
+		fi
+		
+		echo "[APPLY] $fyl"
+		patch -R -p1 < "../$pat/$fyl/patch"
+	    done
+	    popd >/dev/null || { echo "popd $dst failed"; exit 1; }
+	    ;;
+
+	backup)
+	    mkdir ~/backups
+	    pushd "$src" || { echo "pushd $dst failed"; exit 1; }
+	    tar czvf ~/backups/vault."$(date '+%Y%m%d%H%M%S')" "${fyls[@]}"
+	    popd || { echo "popd $dst failed"; exit 1; }
+	    ;;
+
+	gather)
+	    for fyl in "${fyls[@]}";
+	    do
+		patchDir="$pat/$fyl"
+		mkdir -p "$patchDir"
+		diff -Naur "$src/$fyl" "$dst/$fyl" | tee "$pat/$fyl/patch"
+	    done
+	    find "$pat" -print
+	    ;;
+	
+	*)
+	    echo "ERROR: Unknown action [$opt]"
+	    exit 1
+	    ;;
+    esac
+done
+
+# [EOF]