From c74696366fb1ab3f3400b6a98a384e8c2f1207ba Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 07:11:22 -0400 Subject: [PATCH 01/10] [sdn_tests]: Adding Build support for pins_ondatra --- sdn_tests/pins_ondatra/.gitignore | 4 + sdn_tests/pins_ondatra/BUILD | 4 + sdn_tests/pins_ondatra/README.md | 29 ++ sdn_tests/pins_ondatra/WORKSPACE.bazel | 135 ++++++ .../bazel/patches/ghodss_yaml.patch | 12 + .../gnmi-001-fix_virtual_proto_import.patch | 37 ++ .../pins_ondatra/bazel/patches/gnmi.patch | 392 ++++++++++++++++++ .../pins_ondatra/bazel/patches/gnoi.patch | 45 ++ .../pins_ondatra/bazel/patches/gnoigo.patch | 32 ++ .../pins_ondatra/bazel/patches/gnsi.patch | 59 +++ .../pins_ondatra/bazel/patches/gribi.patch | 48 +++ ...-001-fix_file_watcher_race_condition.patch | 12 + ...03-fix_go_gazelle_register_toolchain.patch | 12 + .../pins_ondatra/bazel/patches/ondatra.patch | 51 +++ .../pins_ondatra/bazel/patches/p4lang.patch | 24 ++ .../bazel/patches/rules_proto_grpc.patch | 39 ++ .../pins_ondatra/bazel/patches/snappi.patch | 53 +++ .../pins_ondatra/bazel/patches/ygnmi.patch | 13 + .../pins_ondatra/bazel/patches/ygot.patch | 85 ++++ sdn_tests/pins_ondatra/infra_deps.bzl | 324 +++++++++++++++ sdn_tests/pins_ondatra/pins_deps.bzl | 203 +++++++++ 21 files changed, 1613 insertions(+) create mode 100644 sdn_tests/pins_ondatra/.gitignore create mode 100644 sdn_tests/pins_ondatra/BUILD create mode 100644 sdn_tests/pins_ondatra/README.md create mode 100644 sdn_tests/pins_ondatra/WORKSPACE.bazel create mode 100644 sdn_tests/pins_ondatra/bazel/patches/ghodss_yaml.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/gnmi-001-fix_virtual_proto_import.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/gnmi.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/gnoi.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/gnoigo.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/gnsi.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/gribi.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/grpc-001-fix_file_watcher_race_condition.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/grpc-003-fix_go_gazelle_register_toolchain.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/ondatra.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/p4lang.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/rules_proto_grpc.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/snappi.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/ygnmi.patch create mode 100644 sdn_tests/pins_ondatra/bazel/patches/ygot.patch create mode 100644 sdn_tests/pins_ondatra/infra_deps.bzl create mode 100644 sdn_tests/pins_ondatra/pins_deps.bzl diff --git a/sdn_tests/pins_ondatra/.gitignore b/sdn_tests/pins_ondatra/.gitignore new file mode 100644 index 00000000000..e923bbc11ab --- /dev/null +++ b/sdn_tests/pins_ondatra/.gitignore @@ -0,0 +1,4 @@ +bazel-* +*.pem +*.cnf +*.orig diff --git a/sdn_tests/pins_ondatra/BUILD b/sdn_tests/pins_ondatra/BUILD new file mode 100644 index 00000000000..565db34f194 --- /dev/null +++ b/sdn_tests/pins_ondatra/BUILD @@ -0,0 +1,4 @@ +load("@bazel_gazelle//:def.bzl", "gazelle") + +# gazelle:prefix github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra +gazelle(name = "gazelle") diff --git a/sdn_tests/pins_ondatra/README.md b/sdn_tests/pins_ondatra/README.md new file mode 100644 index 00000000000..b9f3a5b5cca --- /dev/null +++ b/sdn_tests/pins_ondatra/README.md @@ -0,0 +1,29 @@ +# Dependencies: +- Linux (tested on ubuntu) +- Go (https://go.dev/doc/install) +- Bazel-5.4.0+ (https://bazel.build/install) +- Rest of the dependencies should be auto-installed on bazel run. + +# Compilation: +``` +bazel build ... +``` + +# Compile and Run Test: +``` +bazel run //tests:test_name --test_strategy=exclusive --test_timeout=3600 +``` + + +# Debug code: +- Install Delve (https://github.com/go-delve/delve/tree/master/Documentation/installation) +- Compile repo in debug mode: +``` +bazel build ... --strip=never --compilation_mode=dbg +``` +- Run the test with dlv debugger: +``` +dlv --wd=$PWD/tests/ exec bazel-bin/tests/test_name_/test_name -- --testbed=$PWD/testbeds/testbed.textproto +// inside dlv; map path for debugging: +config substitute-path external bazel-pins_ondatra/external +``` diff --git a/sdn_tests/pins_ondatra/WORKSPACE.bazel b/sdn_tests/pins_ondatra/WORKSPACE.bazel new file mode 100644 index 00000000000..6b582fc6a3e --- /dev/null +++ b/sdn_tests/pins_ondatra/WORKSPACE.bazel @@ -0,0 +1,135 @@ +# Copyright 2024 Google LLC +# +# 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. + +workspace(name = "com_github_sonic_net_sonic_mgmt_sdn_tests_pins_ondatra") + +# -- Load buildifier ----------------------------------------------------------- +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +# Bazel toolchain to build go-lang. +http_archive( + name = "io_bazel_rules_go", + sha256 = "91585017debb61982f7054c9688857a2ad1fd823fc3f9cb05048b0025c47d023", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip", + "https://github.com/bazelbuild/rules_go/releases/download/v0.42.0/rules_go-v0.42.0.zip", + ], +) + +# Gazelle to auto generate go-lang BUILD rules. +http_archive( + name = "bazel_gazelle", + sha256 = "b7387f72efb59f876e4daae42f1d3912d0d45563eac7cb23d1de0b094ab588cf", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz", + "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.34.0/bazel-gazelle-v0.34.0.tar.gz", + ], +) + +load("pins_deps.bzl", "pins_deps") + +pins_deps() + +# -- Load Rules Foreign CC ----------------------------------------------------- + +load("@rules_foreign_cc//foreign_cc:repositories.bzl", "rules_foreign_cc_dependencies") + +rules_foreign_cc_dependencies() + +# -- Load GoLang Rules ----------------------------------------------------- + +load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies") +load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") +load("//:infra_deps.bzl", "binding_deps") + +binding_deps() + +go_rules_dependencies() + +go_register_toolchains(version = "1.21.1") + +gazelle_dependencies(go_repository_default_config = "@//:WORKSPACE.bazel") + +# -- Load GRPC ------------------------------------------------------------- + +load("@com_google_googleapis//:repository_rules.bzl", "switched_rules_by_language") + +switched_rules_by_language( + name = "com_google_googleapis_imports", + cc = True, + go = True, + grpc = True, +) + +load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") + +grpc_deps() + +load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") + +grpc_extra_deps() + +# -- Load Protobuf ------------------------------------------------------------- + +load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps") + +protobuf_deps() + +load("@rules_proto//proto:repositories.bzl", "rules_proto_dependencies", "rules_proto_toolchains") + +rules_proto_dependencies() + +rules_proto_toolchains() + +### Bazel rules for many languages to compile PROTO into gRPC libraries +http_archive( + name = "rules_proto_grpc", + sha256 = "f87d885ebfd6a1bdf02b4c4ba5bf6fb333f90d54561e4d520a8413c8d1fb7beb", + strip_prefix = "rules_proto_grpc-4.5.0", + urls = ["https://github.com/rules-proto-grpc/rules_proto_grpc/archive/4.5.0.tar.gz"], + patch_args = ["-p1"], + patches = [ + "//:bazel/patches/rules_proto_grpc.patch", + ], +) + +load("@rules_proto_grpc//:repositories.bzl", "rules_proto_grpc_repos", "rules_proto_grpc_toolchains") + +rules_proto_grpc_toolchains() + +rules_proto_grpc_repos() + +# -- Load P4Runtime ------------------------------------------------------------ + +load("@com_github_p4lang_p4runtime//:p4runtime_deps.bzl", "p4runtime_deps") + +p4runtime_deps() + +# -- Load packaging rules ------------------------------------------------------ + +load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies") + +rules_pkg_dependencies() + +# == Dependencies needed for testing and formatting only ======================= + +# -- Load p4c ------------------------------------------------------------------ + +load("@com_github_p4lang_p4c//:bazel/p4c_deps.bzl", "p4c_deps") + +p4c_deps() + +load("@com_github_nelhage_rules_boost//:boost/boost.bzl", "boost_deps") + +boost_deps() diff --git a/sdn_tests/pins_ondatra/bazel/patches/ghodss_yaml.patch b/sdn_tests/pins_ondatra/bazel/patches/ghodss_yaml.patch new file mode 100644 index 00000000000..011d484f3e8 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/ghodss_yaml.patch @@ -0,0 +1,12 @@ +diff --git a/BUILD.bazel b/BUILD.bazel +index 4f4ecec..ee196e8 100644 +--- a/BUILD.bazel ++++ b/BUILD.bazel +@@ -6,6 +6,7 @@ go_library( + "fields.go", + "yaml.go", + ], ++ deps = ["@in_gopkg_yaml_v2//:yaml_v2"], + importpath = "github.com/ghodss/yaml", + visibility = ["//visibility:public"], + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/gnmi-001-fix_virtual_proto_import.patch b/sdn_tests/pins_ondatra/bazel/patches/gnmi-001-fix_virtual_proto_import.patch new file mode 100644 index 00000000000..ca3deff5d2f --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/gnmi-001-fix_virtual_proto_import.patch @@ -0,0 +1,37 @@ +diff --git a/proto/gnmi/BUILD.bazel b/proto/gnmi/BUILD.bazel +index f471488..14a242b 100755 +--- a/proto/gnmi/BUILD.bazel ++++ b/proto/gnmi/BUILD.bazel +@@ -22,6 +22,17 @@ package( + licenses = ["notice"], + ) + ++proto_library( ++ name = "gnmi_internal_proto", ++ srcs = ["gnmi.proto"], ++ deps = [ ++ "//proto/gnmi_ext:gnmi_ext_proto", ++ "@com_google_protobuf//:any_proto", ++ "@com_google_protobuf//:descriptor_proto", ++ ], ++ visibility = ["//visibility:private"], ++) ++ + proto_library( + name = "gnmi_proto", + srcs = ["gnmi.proto"], +@@ -35,12 +46,12 @@ proto_library( + + cc_proto_library( + name = "gnmi_cc_proto", +- deps = [":gnmi_proto"], ++ deps = [":gnmi_internal_proto"], + ) + + cc_grpc_library( + name = "gnmi_cc_grpc_proto", +- srcs = [":gnmi_proto"], ++ srcs = [":gnmi_internal_proto"], + generate_mocks = True, + grpc_only = True, + deps = [":gnmi_cc_proto"], diff --git a/sdn_tests/pins_ondatra/bazel/patches/gnmi.patch b/sdn_tests/pins_ondatra/bazel/patches/gnmi.patch new file mode 100644 index 00000000000..a07686d3ab9 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/gnmi.patch @@ -0,0 +1,392 @@ +diff --git a/BUILD.bazel b/BUILD.bazel +index ca5484e..238dde9 100644 +--- a/BUILD.bazel ++++ b/BUILD.bazel +@@ -13,6 +13,7 @@ + # limitations under the License. + # + # Supporting infrastructure for implementing and testing PINS. ++load("@bazel_gazelle//:def.bzl", "gazelle") + + package( + default_visibility = ["//visibility:public"], +@@ -20,3 +21,6 @@ package( + ) + + exports_files(["LICENSE"]) ++ ++# gazelle:prefix github.com/openconfig/gnmi ++gazelle(name = "gazelle") +diff --git a/WORKSPACE.bazel b/WORKSPACE.bazel +deleted file mode 100644 +index 2f385f7..0000000 +--- a/WORKSPACE.bazel ++++ /dev/null +@@ -1,45 +0,0 @@ +-# Copyright 2021 Google LLC +-# +-# 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 +-# +-# https://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. +- +-workspace(name = "gnmi") +- +-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") +- +-http_archive( +- name = "io_bazel_rules_go", +- sha256 = "d6b2513456fe2229811da7eb67a444be7785f5323c6708b38d851d2b51e54d83", +- urls = [ +- "https://github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", +- "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.30.0/rules_go-v0.30.0.zip", +- ], +-) +- +-load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies") +- +-go_rules_dependencies() +- +-go_register_toolchains(version = "1.17") +- +-# -- Load Dependencies --------------------------------------------------------- +-load("gnmi_deps.bzl", "gnmi_deps") +- +-gnmi_deps() +- +-load("@com_github_grpc_grpc//bazel:grpc_deps.bzl", "grpc_deps") +- +-grpc_deps() +- +-load("@com_github_grpc_grpc//bazel:grpc_extra_deps.bzl", "grpc_extra_deps") +- +-grpc_extra_deps() +diff --git a/proto/gnmi/BUILD.bazel b/proto/gnmi/BUILD.bazel +index f471488..f6bd3bd 100644 +--- a/proto/gnmi/BUILD.bazel ++++ b/proto/gnmi/BUILD.bazel +@@ -16,6 +16,9 @@ + # + + load("@com_github_grpc_grpc//bazel:cc_grpc_library.bzl", "cc_grpc_library") ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") ++load("@rules_proto//proto:defs.bzl", "proto_library") + + package( + default_visibility = ["//visibility:public"], +@@ -45,3 +48,13 @@ cc_grpc_library( + grpc_only = True, + deps = [":gnmi_cc_proto"], + ) ++ ++go_proto_library( ++ name = "gnmi_go_proto", ++ compilers = ["@io_bazel_rules_go//proto:go_grpc"], ++ importpath = "github.com/openconfig/gnmi/proto/gnmi", ++ proto = ":gnmi_proto", ++ deps = [ ++ "//proto/gnmi_ext:gnmi_ext_go_proto", ++ ], ++) +diff --git a/proto/gnmi_ext/BUILD.bazel b/proto/gnmi_ext/BUILD.bazel +index 2e0e9b4..5dcf6fb 100644 +--- a/proto/gnmi_ext/BUILD.bazel ++++ b/proto/gnmi_ext/BUILD.bazel +@@ -14,6 +14,7 @@ + # + # Supporting infrastructure for implementing and testing PINS. + # ++load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +@@ -29,3 +30,10 @@ cc_proto_library( + name = "gnmi_ext_cc_proto", + deps = [":gnmi_ext_proto"], + ) ++ ++go_proto_library( ++ name = "gnmi_ext_go_proto", ++ compilers = ["@io_bazel_rules_go//proto:go_grpc"], ++ importpath = "github.com/openconfig/gnmi/proto/gnmi_ext", ++ proto = ":gnmi_ext_proto", ++) +\ No newline at end of file +diff --git a/errlist/BUILD.bazel b/errlist/BUILD.bazel +new file mode 100644 +index 0000000..2b112a8 +--- /dev/null ++++ b/errlist/BUILD.bazel +@@ -0,0 +1,16 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "errlist", ++ srcs = [ ++ "errlist.go", ++ ], ++ importpath = "github.com/openconfig/gnmi/errlist", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":errlist", ++ visibility = ["//visibility:public"], ++) + +diff --git a/value/BUILD.bazel b/value/BUILD.bazel +new file mode 100644 +index 0000000..1b5e851 +--- /dev/null ++++ b/value/BUILD.bazel +@@ -0,0 +1,19 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "value", ++ srcs = [ ++ "value.go", ++ ], ++ importpath = "github.com/openconfig/gnmi/value", ++ visibility = ["//visibility:public"], ++ deps = [ ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", ++ ] ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":value", ++ visibility = ["//visibility:public"], ++) + +diff --git a/cache/BUILD.bazel b/cache/BUILD.bazel +new file mode 100644 +index 0000000..07971dd +--- /dev/null ++++ b/cache/BUILD.bazel +@@ -0,0 +1,33 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "cache", ++ srcs = [ ++ "cache.go", ++ ], ++ deps = [ ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", ++ "@com_github_openconfig_gnmi//path", ++ "@com_github_openconfig_gnmi//ctree", ++ "@com_github_openconfig_gnmi//errlist", ++ "@com_github_openconfig_gnmi//value", ++ "@com_github_openconfig_gnmi//latency", ++ "@com_github_openconfig_gnmi//metadata", ++ "@org_golang_google_grpc//:go_default_library", ++ "@org_golang_google_grpc//codes:go_default_library", ++ "@org_golang_google_grpc//peer:go_default_library", ++ "@org_golang_google_grpc//status:go_default_library", ++ "@org_golang_x_net//context", ++ "@com_github_golang_glog//:glog", ++ "@org_golang_google_protobuf//encoding/prototext", ++ "@org_golang_google_protobuf//proto", ++ ], ++ importpath = "github.com/openconfig/gnmi/cache", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":cache", ++ visibility = ["//visibility:public"], ++) + +diff --git a/subscribe/BUILD.bazel b/subscribe/BUILD.bazel +new file mode 100644 +index 0000000..05b9be3 +--- /dev/null ++++ b/subscribe/BUILD.bazel +@@ -0,0 +1,35 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "subscribe", ++ srcs = [ ++ "subscribe.go", ++ "stats.go" ++ ], ++ importpath = "github.com/openconfig/gnmi/subscribe", ++ deps = [ ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", ++ "@com_github_openconfig_gnmi//path", ++ "@com_github_openconfig_gnmi//ctree", ++ "@com_github_openconfig_gnmi//errlist", ++ "@com_github_openconfig_gnmi//value", ++ "@com_github_openconfig_gnmi//latency", ++ "@com_github_openconfig_gnmi//cache", ++ "@com_github_openconfig_gnmi//coalesce", ++ "@com_github_openconfig_gnmi//match", ++ "@org_golang_google_grpc//:go_default_library", ++ "@org_golang_google_grpc//codes:go_default_library", ++ "@org_golang_google_grpc//peer:go_default_library", ++ "@org_golang_google_grpc//status:go_default_library", ++ "@org_golang_x_net//context", ++ "@org_golang_google_protobuf//proto", ++ "@com_github_golang_glog//:glog", ++ ], ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":subscribe", ++ visibility = ["//visibility:public"], ++) + +diff --git a/ctree/BUILD.bazel b/ctree/BUILD.bazel +new file mode 100644 +index 0000000..510cc34 +--- /dev/null ++++ b/ctree/BUILD.bazel +@@ -0,0 +1,16 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "ctree", ++ srcs = [ ++ "tree.go", ++ ], ++ importpath = "github.com/openconfig/gnmi/ctree", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":ctree", ++ visibility = ["//visibility:public"], ++) +diff --git a/latency/BUILD.bazel b/latency/BUILD.bazel +new file mode 100644 +index 0000000..d110090 +--- /dev/null ++++ b/latency/BUILD.bazel +@@ -0,0 +1,16 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "latency", ++ srcs = [ ++ "latency.go", ++ ], ++ importpath = "github.com/openconfig/gnmi/latency", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":latency", ++ visibility = ["//visibility:public"], ++) +diff --git a/metadata/BUILD.bazel b/metadata/BUILD.bazel +new file mode 100644 +index 0000000..aa715a9 +--- /dev/null ++++ b/metadata/BUILD.bazel +@@ -0,0 +1,19 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "metadata", ++ srcs = [ ++ "metadata.go", ++ ], ++ deps = [ ++ "@com_github_openconfig_gnmi//latency", ++ ], ++ importpath = "github.com/openconfig/gnmi/metadata", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":metadata", ++ visibility = ["//visibility:public"], ++) +diff --git a/path/BUILD.bazel b/path/BUILD.bazel +new file mode 100644 +index 0000000..65a7efd +--- /dev/null ++++ b/path/BUILD.bazel +@@ -0,0 +1,19 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "path", ++ srcs = [ ++ "path.go", ++ ], ++ deps = [ ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", ++ ], ++ importpath = "github.com/openconfig/gnmi/path", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":path", ++ visibility = ["//visibility:public"], ++) + +diff --git a/coalesce/BUILD.bazel b/coalesce/BUILD.bazel +new file mode 100644 +index 0000000..887440e +--- /dev/null ++++ b/coalesce/BUILD.bazel +@@ -0,0 +1,16 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "coalesce", ++ srcs = [ ++ "coalesce.go", ++ ], ++ importpath = "github.com/openconfig/gnmi/coalesce", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":coalesce", ++ visibility = ["//visibility:public"], ++) +diff --git a/match/BUILD.bazel b/match/BUILD.bazel +new file mode 100644 +index 0000000..b09b9f3 +--- /dev/null ++++ b/match/BUILD.bazel +@@ -0,0 +1,16 @@ ++load("@io_bazel_rules_go//go:def.bzl", "go_library") ++ ++go_library( ++ name = "match", ++ srcs = [ ++ "match.go", ++ ], ++ importpath = "github.com/openconfig/gnmi/match", ++ visibility = ["//visibility:public"], ++) ++ ++alias( ++ name = "go_default_library", ++ actual = ":match", ++ visibility = ["//visibility:public"], ++) diff --git a/sdn_tests/pins_ondatra/bazel/patches/gnoi.patch b/sdn_tests/pins_ondatra/bazel/patches/gnoi.patch new file mode 100644 index 00000000000..4520fe9fc63 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/gnoi.patch @@ -0,0 +1,45 @@ +diff --git a/healthz/BUILD.bazel b/healthz/BUILD.bazel +index 039f3b5..7c9940b 100644 +--- a/healthz/BUILD.bazel ++++ b/healthz/BUILD.bazel +@@ -34,7 +34,7 @@ proto_library( + ], + ) + +-go_proto_library( ++go_grpc_library( + name = "healthz_go_proto", + compilers = ["@io_bazel_rules_go//proto:go_grpc"], + importpath = "github.com/openconfig/gnoi/healthz", + +diff --git a/types/BUILD.bazel b/types/BUILD.bazel +index 921d7c1..995dd1e 100644 +--- a/types/BUILD.bazel ++++ b/types/BUILD.bazel +@@ -32,6 +32,13 @@ proto_library( + deps = ["@com_google_protobuf//:descriptor_proto"], + ) + ++proto_library( ++ name = "gnoi_types_proto", ++ srcs = ["types.proto"], ++ import_prefix = "github.com/openconfig/gnoi", ++ deps = ["@com_google_protobuf//:descriptor_proto"], ++) ++ + cc_proto_library( + name = "types_cc_proto", + deps = [":types_proto"], + +diff --git a/packet_link_qualification/BUILD.bazel b/packet_link_qualification/BUILD.bazel +index 249bc3a..d215296 100644 +--- a/packet_link_qualification/BUILD.bazel ++++ b/packet_link_qualification/BUILD.bazel +@@ -22,6 +22,6 @@ go_proto_library( + visibility = ["//visibility:public"], + deps = [ + "//types:types_go_proto", +- "@go_googleapis//google/rpc:status_go_proto", ++ "@org_golang_google_genproto//googleapis/rpc/status", + ], + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/gnoigo.patch b/sdn_tests/pins_ondatra/bazel/patches/gnoigo.patch new file mode 100644 index 00000000000..7693d6416fa --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/gnoigo.patch @@ -0,0 +1,32 @@ +diff --git a/gnoigo.go b/gnoigo.go +index cc1a3ec..f656e0e 100644 +--- a/gnoigo.go ++++ b/gnoigo.go +@@ -27,10 +27,10 @@ import ( + fpb "github.com/openconfig/gnoi/file" + hpb "github.com/openconfig/gnoi/healthz" + lpb "github.com/openconfig/gnoi/layer2" ++ plqpb "github.com/openconfig/gnoi/linkqual" + mpb "github.com/openconfig/gnoi/mpls" + ospb "github.com/openconfig/gnoi/os" + otpb "github.com/openconfig/gnoi/otdr" +- plqpb "github.com/openconfig/gnoi/packet_link_qualification" + spb "github.com/openconfig/gnoi/system" + wrpb "github.com/openconfig/gnoi/wavelength_router" + "github.com/openconfig/gnoigo/internal" +diff --git a/internal/clients.go b/internal/clients.go +index f49e470..b634ab3 100644 +--- a/internal/clients.go ++++ b/internal/clients.go +@@ -23,10 +23,10 @@ import ( + fpb "github.com/openconfig/gnoi/file" + hpb "github.com/openconfig/gnoi/healthz" + lpb "github.com/openconfig/gnoi/layer2" ++ plqpb "github.com/openconfig/gnoi/linkqual" + mpb "github.com/openconfig/gnoi/mpls" + ospb "github.com/openconfig/gnoi/os" + otpb "github.com/openconfig/gnoi/otdr" +- plqpb "github.com/openconfig/gnoi/packet_link_qualification" + spb "github.com/openconfig/gnoi/system" + wrpb "github.com/openconfig/gnoi/wavelength_router" + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/gnsi.patch b/sdn_tests/pins_ondatra/bazel/patches/gnsi.patch new file mode 100644 index 00000000000..c295d55a993 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/gnsi.patch @@ -0,0 +1,59 @@ +diff --git a/authz/authz.proto b/authz/authz.proto +index ecb3f3f..c6216b8 100644 +--- a/authz/authz.proto ++++ b/authz/authz.proto +@@ -132,6 +132,9 @@ service Authz { + // together with its version and created-on information. + // If no policy has been set, Get() returns FAILED_PRECONDITION. + rpc Get(GetRequest) returns (GetResponse); ++ ++ rpc Install(stream InstallAuthzRequest) ++ returns (stream InstallAuthzResponse); + } + + // Request messages to rotate existing gRPC-level Authorization Policy on +@@ -152,6 +155,16 @@ message RotateAuthzRequest { + bool force_overwrite = 3; + } + ++// Request messages to install a new Authz Policy on ++// the target. ++message InstallAuthzRequest { ++ // Request Messages. ++ oneof install_request { ++ UploadRequest upload_request = 1; ++ FinalizeRequest finalize_installation = 2; ++ } ++} ++ + // Response messages from the target. + message RotateAuthzResponse { + // Response messages. +@@ -160,6 +173,14 @@ message RotateAuthzResponse { + } + } + ++// Response messages from the target. ++message InstallAuthzResponse { ++ // Response messages. ++ oneof install_response { ++ UploadResponse upload_response = 1; ++ } ++} ++ + // A Finalize message is sent to the target to confirm the rotation of + // the gRPC-level Authorization Policy, indicating that it should not be + // rolled back when the stream concludes. +diff --git a/version/BUILD.bazel b/version/BUILD.bazel +index e047013..5dbb1c6 100644 +--- a/version/BUILD.bazel ++++ b/version/BUILD.bazel +@@ -11,7 +11,7 @@ proto_library( + srcs = [ + "version.proto", + ], +- deps = ["@com_github_openconfig_gnoi//types:types_proto"], ++ deps = ["@com_github_openconfig_gnoi//types:gnoi_types_proto"], + import_prefix = "github.com/openconfig/gnsi", + visibility = ["//visibility:public"], + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/gribi.patch b/sdn_tests/pins_ondatra/bazel/patches/gribi.patch new file mode 100644 index 00000000000..fc6cac07526 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/gribi.patch @@ -0,0 +1,48 @@ +diff --git a/v1/proto/gribi_aft/BUILD.bazel b/v1/proto/gribi_aft/BUILD.bazel +index fdb39a2..3ddfc19 100644 +--- a/v1/proto/gribi_aft/BUILD.bazel ++++ b/v1/proto/gribi_aft/BUILD.bazel +@@ -7,8 +7,8 @@ proto_library( + srcs = ["gribi_aft.proto"], + visibility = ["//visibility:public"], + deps = [ +- "//github.com/openconfig/ygot/proto/yext:yext_proto", +- "//github.com/openconfig/ygot/proto/ywrapper:ywrapper_proto", ++ "@com_github_openconfig_ygot//proto/yext:yext_proto", ++ "@com_github_openconfig_ygot//proto/ywrapper:ywrapper_proto", + "//v1/proto/gribi_aft/enums:enums_proto", + ], + ) +@@ -19,8 +19,8 @@ go_proto_library( + proto = ":gribi_aft_proto", + visibility = ["//visibility:public"], + deps = [ +- "//github.com/openconfig/ygot/proto/yext:yext_proto", +- "//github.com/openconfig/ygot/proto/ywrapper:ywrapper_proto", ++ "@com_github_openconfig_ygot//proto/yext:go_default_library", ++ "@com_github_openconfig_ygot//proto/ywrapper:go_default_library", + "//v1/proto/gribi_aft/enums", + ], + ) +diff --git a/v1/proto/gribi_aft/enums/BUILD.bazel b/v1/proto/gribi_aft/enums/BUILD.bazel +index 7ef4d9d..18f7324 100644 +--- a/v1/proto/gribi_aft/enums/BUILD.bazel ++++ b/v1/proto/gribi_aft/enums/BUILD.bazel +@@ -6,7 +6,7 @@ proto_library( + name = "enums_proto", + srcs = ["enums.proto"], + visibility = ["//visibility:public"], +- deps = ["//github.com/openconfig/ygot/proto/yext:yext_proto"], ++ deps = ["@com_github_openconfig_ygot//proto/yext:yext_proto"], + ) + + go_proto_library( +@@ -14,7 +14,7 @@ go_proto_library( + importpath = "github.com/openconfig/gribi/v1/proto/gribi_aft/enums", + proto = ":enums_proto", + visibility = ["//visibility:public"], +- deps = ["//github.com/openconfig/ygot/proto/yext:yext_proto"], ++ deps = ["@com_github_openconfig_ygot//proto/yext:go_default_library"], + ) + + go_library( diff --git a/sdn_tests/pins_ondatra/bazel/patches/grpc-001-fix_file_watcher_race_condition.patch b/sdn_tests/pins_ondatra/bazel/patches/grpc-001-fix_file_watcher_race_condition.patch new file mode 100644 index 00000000000..af5d1510f80 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/grpc-001-fix_file_watcher_race_condition.patch @@ -0,0 +1,12 @@ +diff --git a/src/core/lib/iomgr/load_file.cc b/src/core/lib/iomgr/load_file.cc +index 9068670118..a4d9bc95b2 100644 +--- a/src/core/lib/iomgr/load_file.cc ++++ b/src/core/lib/iomgr/load_file.cc +@@ -55,7 +55,6 @@ grpc_error_handle grpc_load_file(const char* filename, int add_null_terminator, + if (bytes_read < contents_size) { + gpr_free(contents); + error = GRPC_OS_ERROR(errno, "fread"); +- GPR_ASSERT(ferror(file)); + goto end; + } + if (add_null_terminator) { diff --git a/sdn_tests/pins_ondatra/bazel/patches/grpc-003-fix_go_gazelle_register_toolchain.patch b/sdn_tests/pins_ondatra/bazel/patches/grpc-003-fix_go_gazelle_register_toolchain.patch new file mode 100644 index 00000000000..bfed9023aca --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/grpc-003-fix_go_gazelle_register_toolchain.patch @@ -0,0 +1,12 @@ +diff --git a/bazel/grpc_extra_deps.bzl b/bazel/grpc_extra_deps.bzl +index 4d8afa3..b090036 100755 +--- a/bazel/grpc_extra_deps.bzl ++++ b/bazel/grpc_extra_deps.bzl +@@ -53,7 +53,6 @@ def grpc_extra_deps(ignore_version_differences = False): + api_dependencies() + + go_rules_dependencies() +- go_register_toolchains(version = "1.18") + gazelle_dependencies() + + # Pull-in the go 3rd party dependencies for protoc_gen_validate, which is diff --git a/sdn_tests/pins_ondatra/bazel/patches/ondatra.patch b/sdn_tests/pins_ondatra/bazel/patches/ondatra.patch new file mode 100644 index 00000000000..9f3b83b6402 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/ondatra.patch @@ -0,0 +1,51 @@ +diff --git a/binding/abstract.go b/binding/abstract.go +index 4d431d1..0ff43a4 100644 +--- a/binding/abstract.go ++++ b/binding/abstract.go +@@ -33,7 +33,7 @@ import ( + credzpb "github.com/openconfig/gnsi/credentialz" + pathzpb "github.com/openconfig/gnsi/pathz" + +- grpb "github.com/openconfig/gribi/v1/proto/service" ++ grpb "github.com/openconfig/gribi/proto/service" + opb "github.com/openconfig/ondatra/proto" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" + ) +diff --git a/binding/binding.go b/binding/binding.go +index 2a4d7ae..96229b5 100644 +--- a/binding/binding.go ++++ b/binding/binding.go +@@ -33,7 +33,7 @@ import ( + certzpb "github.com/openconfig/gnsi/certz" + credzpb "github.com/openconfig/gnsi/credentialz" + pathzpb "github.com/openconfig/gnsi/pathz" +- grpb "github.com/openconfig/gribi/v1/proto/service" ++ grpb "github.com/openconfig/gribi/proto/service" + opb "github.com/openconfig/ondatra/proto" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" + ) +diff --git a/internal/rawapis/rawapis.go b/internal/rawapis/rawapis.go +index bef545c..98df921 100644 +--- a/internal/rawapis/rawapis.go ++++ b/internal/rawapis/rawapis.go +@@ -34,7 +34,7 @@ import ( + "google.golang.org/grpc" + + gpb "github.com/openconfig/gnmi/proto/gnmi" +- grpb "github.com/openconfig/gribi/v1/proto/service" ++ grpb "github.com/openconfig/gribi/proto/service" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" + ) + +diff --git a/raw/raw.go b/raw/raw.go +index 780e978..1821141 100644 +--- a/raw/raw.go ++++ b/raw/raw.go +@@ -89,7 +89,7 @@ import ( + "github.com/openconfig/ondatra/internal/rawapis" + + gpb "github.com/openconfig/gnmi/proto/gnmi" +- grpb "github.com/openconfig/gribi/v1/proto/service" ++ grpb "github.com/openconfig/gribi/proto/service" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/p4lang.patch b/sdn_tests/pins_ondatra/bazel/patches/p4lang.patch new file mode 100644 index 00000000000..ee9f8dd17f0 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/p4lang.patch @@ -0,0 +1,24 @@ +diff --git a/proto/p4/config/v1/p4info.proto b/proto/p4/config/v1/p4info.proto +index badddd9..079f258 100644 +--- a/proto/p4/config/v1/p4info.proto ++++ b/proto/p4/config/v1/p4info.proto +@@ -15,7 +15,7 @@ + syntax = "proto3"; + + import "google/protobuf/any.proto"; +-import "p4/config/v1/p4types.proto"; ++import "proto/p4/config/v1/p4types.proto"; + + // This package and its contents are a work-in-progress. + +diff --git a/go/p4/v1/BUILD.bazel b/go/p4/v1/BUILD.bazel +index 6445fff..17a350c 100644 +--- a/go/p4/v1/BUILD.bazel ++++ b/go/p4/v1/BUILD.bazel +@@ -17,6 +17,7 @@ go_library( + "@org_golang_google_protobuf//reflect/protoreflect:go_default_library", + "@org_golang_google_protobuf//runtime/protoimpl:go_default_library", + "@org_golang_google_protobuf//types/known/anypb:go_default_library", ++ "@com_github_p4lang_p4runtime//go/p4/config/v1:go_default_library" + ], + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/rules_proto_grpc.patch b/sdn_tests/pins_ondatra/bazel/patches/rules_proto_grpc.patch new file mode 100644 index 00000000000..7d78ff80277 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/rules_proto_grpc.patch @@ -0,0 +1,39 @@ +diff --git a/c/c_proto_library.bzl b/c/c_proto_library.bzl +index ee33ebd..a35a8a5 100644 +--- a/c/c_proto_library.bzl ++++ b/c/c_proto_library.bzl +@@ -44,7 +44,7 @@ def c_proto_library(name, **kwargs): # buildifier: disable=function-docstring + linkopts = kwargs.get("linkopts"), + linkstatic = kwargs.get("linkstatic"), + local_defines = kwargs.get("local_defines"), +- nocopts = kwargs.get("nocopts"), ++ #nocopts = kwargs.get("nocopts"), + strip_include_prefix = kwargs.get("strip_include_prefix"), + **{ + k: v +diff --git a/cpp/cpp_grpc_library.bzl b/cpp/cpp_grpc_library.bzl +index 7064aa7..009a931 100644 +--- a/cpp/cpp_grpc_library.bzl ++++ b/cpp/cpp_grpc_library.bzl +@@ -44,7 +44,7 @@ def cpp_grpc_library(name, **kwargs): # buildifier: disable=function-docstring + linkopts = kwargs.get("linkopts"), + linkstatic = kwargs.get("linkstatic"), + local_defines = kwargs.get("local_defines"), +- nocopts = kwargs.get("nocopts"), ++ #nocopts = kwargs.get("nocopts"), + strip_include_prefix = kwargs.get("strip_include_prefix"), + **{ + k: v +diff --git a/cpp/cpp_proto_library.bzl b/cpp/cpp_proto_library.bzl +index 38e3999..556e8b1 100644 +--- a/cpp/cpp_proto_library.bzl ++++ b/cpp/cpp_proto_library.bzl +@@ -44,7 +44,7 @@ def cpp_proto_library(name, **kwargs): # buildifier: disable=function-docstring + linkopts = kwargs.get("linkopts"), + linkstatic = kwargs.get("linkstatic"), + local_defines = kwargs.get("local_defines"), +- nocopts = kwargs.get("nocopts"), ++ #nocopts = kwargs.get("nocopts"), + strip_include_prefix = kwargs.get("strip_include_prefix"), + **{ + k: v diff --git a/sdn_tests/pins_ondatra/bazel/patches/snappi.patch b/sdn_tests/pins_ondatra/bazel/patches/snappi.patch new file mode 100644 index 00000000000..fcae40d9004 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/snappi.patch @@ -0,0 +1,53 @@ +diff --git a/gosnappi/BUILD.bazel b/gosnappi/BUILD.bazel +index d72ce05..91b14e9 100644 +--- a/gosnappi/BUILD.bazel ++++ b/gosnappi/BUILD.bazel +@@ -10,7 +10,17 @@ go_library( + ], + importpath = "github.com/open-traffic-generator/snappi/gosnappi", + visibility = ["//visibility:public"], +- deps = ["@org_golang_google_grpc//:go_default_library"], ++ deps = [ ++ "@com_github_ghodss_yaml//:yaml", ++ "@com_github_masterminds_semver_v3//:semver", ++ "@com_github_open_traffic_generator_snappi//gosnappi/otg:go_default_library", ++ "@org_golang_google_grpc//:go_default_library", ++ "@org_golang_google_grpc//credentials/insecure", ++ "@org_golang_google_grpc//status", ++ "@org_golang_google_protobuf//encoding/protojson", ++ "@org_golang_google_protobuf//proto", ++ "@org_golang_google_protobuf//types/known/emptypb", ++ ], + ) + + alias( + +diff --git a/gosnappi/otg/BUILD.bazel b/gosnappi/otg/BUILD.bazel +index c0c81d6..5c4fc59 100644 +--- a/gosnappi/otg/BUILD.bazel ++++ b/gosnappi/otg/BUILD.bazel +@@ -5,6 +5,7 @@ load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library") + proto_library( + name = "otg_proto", + srcs = ["otg.proto"], ++ import_prefix = "github.com/open-traffic-generator/snappi", + visibility = ["//visibility:public"], + deps = [ + "@com_google_protobuf//:descriptor_proto", +@@ -15,7 +16,7 @@ proto_library( + go_proto_library( + name = "otg_go_proto", + compilers = ["@io_bazel_rules_go//proto:go_grpc"], +- importpath = "./otg", ++ importpath = "github.com/open-traffic-generator/snappi/gosnappi/otg_go_proto", + proto = ":otg_proto", + visibility = ["//visibility:public"], + ) +@@ -23,7 +24,7 @@ go_proto_library( + go_library( + name = "otg", + embed = [":otg_go_proto"], +- importpath = "./otg", ++ importpath = "github.com/open-traffic-generator/snappi/gosnappi/otg", + visibility = ["//visibility:public"], + ) diff --git a/sdn_tests/pins_ondatra/bazel/patches/ygnmi.patch b/sdn_tests/pins_ondatra/bazel/patches/ygnmi.patch new file mode 100644 index 00000000000..38252ca93c5 --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/ygnmi.patch @@ -0,0 +1,13 @@ +diff --git a/ygnmi/BUILD.bazel b/ygnmi/BUILD.bazel +index a152057..3a2ee21 100644 +--- a/ygnmi/BUILD.bazel ++++ b/ygnmi/BUILD.bazel +@@ -15,7 +15,7 @@ go_library( + "//internal/logutil", + "@com_github_golang_glog//:go_default_library", + "@com_github_openconfig_gnmi//errlist:go_default_library", +- "@com_github_openconfig_gnmi//proto/gnmi:go_default_library", ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_gocloser//:go_default_library", + "@com_github_openconfig_goyang//pkg/yang:go_default_library", + "@com_github_openconfig_ygot//util:go_default_library", diff --git a/sdn_tests/pins_ondatra/bazel/patches/ygot.patch b/sdn_tests/pins_ondatra/bazel/patches/ygot.patch new file mode 100644 index 00000000000..d90ae26c56c --- /dev/null +++ b/sdn_tests/pins_ondatra/bazel/patches/ygot.patch @@ -0,0 +1,85 @@ +diff --git a/proto/yext/BUILD.bazel b/proto/yext/BUILD.bazel +index 4ebd593..cd1f209 100644 +--- a/proto/yext/BUILD.bazel ++++ b/proto/yext/BUILD.bazel +@@ -1,5 +1,13 @@ + load("@io_bazel_rules_go//go:def.bzl", "go_library") + ++proto_library( ++ name = "yext_proto", ++ srcs = ["yext.proto"], ++ visibility = ["//visibility:public"], ++ import_prefix = "github.com/openconfig/ygot", ++ deps = ["@com_google_protobuf//:descriptor_proto"], ++) ++ + go_library( + name = "yext", + srcs = [ +@@ -20,3 +28,4 @@ alias( + actual = ":yext", + visibility = ["//visibility:public"], + ) ++ +diff --git a/proto/ywrapper/BUILD.bazel b/proto/ywrapper/BUILD.bazel +index 4537c63..51fb410 100644 +--- a/proto/ywrapper/BUILD.bazel ++++ b/proto/ywrapper/BUILD.bazel +@@ -1,5 +1,12 @@ + load("@io_bazel_rules_go//go:def.bzl", "go_library") + ++proto_library( ++ name = "ywrapper_proto", ++ srcs = ["ywrapper.proto"], ++ visibility = ["//visibility:public"], ++ import_prefix = "github.com/openconfig/ygot", ++) ++ + go_library( + name = "ywrapper", + srcs = [ +@@ -19,3 +26,4 @@ alias( + actual = ":ywrapper", + visibility = ["//visibility:public"], + ) ++ + +diff --git a/util/BUILD.bazel b/util/BUILD.bazel +index af907f2..8b45361 100644 +--- a/util/BUILD.bazel ++++ b/util/BUILD.bazel +@@ -18,7 +18,7 @@ go_library( + "//internal/yreflect", + "@com_github_golang_glog//:go_default_library", + "@com_github_kylelemons_godebug//pretty:go_default_library", +- "@com_github_openconfig_gnmi//proto/gnmi:go_default_library", ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_goyang//pkg/yang:go_default_library", + "@org_golang_google_protobuf//proto:go_default_library", + ], +diff --git a/ygot/BUILD.bazel b/ygot/BUILD.bazel +index 96d93c2..7023807 100644 +--- a/ygot/BUILD.bazel ++++ b/ygot/BUILD.bazel +@@ -20,7 +20,7 @@ go_library( + "//util", + "@com_github_kylelemons_godebug//pretty:go_default_library", + "@com_github_openconfig_gnmi//errlist:go_default_library", +- "@com_github_openconfig_gnmi//proto/gnmi:go_default_library", ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_gnmi//value:go_default_library", + "@com_github_openconfig_goyang//pkg/yang:go_default_library", + "@org_golang_google_protobuf//encoding/prototext:go_default_library", +diff --git a/ytypes/BUILD.bazel b/ytypes/BUILD.bazel +index d468783..99d604c 100644 +--- a/ytypes/BUILD.bazel ++++ b/ytypes/BUILD.bazel +@@ -35,7 +35,7 @@ go_library( + "//ygot", + "@com_github_golang_glog//:go_default_library", + "@com_github_kylelemons_godebug//pretty:go_default_library", +- "@com_github_openconfig_gnmi//proto/gnmi:go_default_library", ++ "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_goyang//pkg/yang:go_default_library", + "@org_golang_google_grpc//codes:go_default_library", + "@org_golang_google_grpc//status:go_default_library", diff --git a/sdn_tests/pins_ondatra/infra_deps.bzl b/sdn_tests/pins_ondatra/infra_deps.bzl new file mode 100644 index 00000000000..0d5c1557ee3 --- /dev/null +++ b/sdn_tests/pins_ondatra/infra_deps.bzl @@ -0,0 +1,324 @@ +load("@bazel_gazelle//:deps.bzl", "go_repository") +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") + +def binding_deps(): + """Sets up 3rd party workspaces needed to build ondatra infrastructure.""" + + # repo_map maps repo to alternate repo names. Add mapping to resolve gazelle repo name conflicts. + repo_map = { + "@com_github_p4lang_p4runtime": "@com_github_p4lang_golang_p4runtime", + "@go_googleapis": "@com_google_googleapis", + } + + build_directives = [ + "gazelle:resolve go github.com/openconfig/gnmi/proto/gnmi @com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/bgp @com_github_openconfig_gnoi//bgp:bgp_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/cert @com_github_openconfig_gnoi//cert:cert_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/diag @com_github_openconfig_gnoi//diag:diag_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/factory_reset @com_github_openconfig_gnoi//factory_reset:factory_reset_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/healthz @com_github_openconfig_gnoi//healthz:healthz_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/layer2 @com_github_openconfig_gnoi//layer2:layer2_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/os @com_github_openconfig_gnoi//os:os_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/file @com_github_openconfig_gnoi//file:file_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/mpls @com_github_openconfig_gnoi//mpls:mpls_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/otdr @com_github_openconfig_gnoi//otdr:otdr_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/system @com_github_openconfig_gnoi//system:system_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/wavelength_router @com_github_openconfig_gnoi//wavelength_router:wavelength_router_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/packet_link_qualification @com_github_openconfig_gnoi//packet_link_qualification:linkqual_go_proto", + "gazelle:resolve go github.com/openconfig/gnoi/linkqual @com_github_openconfig_gnoi//packet_link_qualification:linkqual_go_proto", + "gazelle:resolve go github.com/openconfig/gnsi/acctz @com_github_openconfig_gnsi//acctz:acctz_go_proto", + "gazelle:resolve go github.com/openconfig/gnsi/pathz @com_github_openconfig_gnsi//pathz:pathz_go_proto", + "gazelle:resolve go github.com/openconfig/gnsi/credentialz @com_github_openconfig_gnsi//credentialz:credentialz", + "gazelle:resolve go github.com/openconfig/gribi/v1/proto/service @com_github_openconfig_gribi//v1/proto/service:go_default_library", + "gazelle:resolve go github.com/p4lang/p4runtime/go/p4/v1 @com_github_p4lang_p4runtime//go/p4/v1:go_default_library", + "gazelle:resolve go github.com/openconfig/gnsi/authz @com_github_openconfig_gnsi//authz", + "gazelle:resolve go github.com/openconfig/gnsi/certz @com_github_openconfig_gnsi//certz", + "gazelle:resolve go github.com/open-traffic-generator/snappi/gosnappi @com_github_open_traffic_generator_snappi//gosnappi:go_default_library", + "gazelle:resolve go github.com/openconfig/gnoi/types @com_github_openconfig_gnoi//types:types_go_proto", + "gazelle:resolve go google.golang.org/genproto/googleapis/rpc/status @org_golang_google_genproto//googleapis/rpc/status:status", + ] + + go_repository( + name = "com_github_ghodss_yaml", + importpath = "github.com/ghodss/yaml", + repo_mapping = repo_map, + sum = "h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=", + version = "v1.0.0", + patches = ["//:bazel/patches/ghodss_yaml.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_golang_glog", + importpath = "github.com/golang/glog", + repo_mapping = repo_map, + sum = "h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=", + version = "v1.0.0", + ) + + go_repository( + name = "com_github_golang_groupcache", + importpath = "github.com/golang/groupcache", + repo_mapping = repo_map, + sum = "h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=", + version = "v0.0.0-20210331224755-41bb18bfe9da", + ) + + go_repository( + name = "com_github_golang_protobuf", + importpath = "github.com/golang/protobuf", + repo_mapping = repo_map, + sum = "h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=", + version = "v1.5.3", + ) + + go_repository( + name = "com_github_google_go_cmp", + importpath = "github.com/google/go-cmp", + repo_mapping = repo_map, + sum = "h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=", + version = "v0.5.9", + ) + + go_repository( + name = "com_github_google_gopacket", + importpath = "github.com/google/gopacket", + sum = "h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8=", + version = "v1.1.19", + ) + + go_repository( + name = "com_github_kylelemons_godebug", + importpath = "github.com/kylelemons/godebug", + repo_mapping = repo_map, + sum = "h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=", + version = "v1.1.0", + ) + + go_repository( + name = "com_github_masterminds_semver_v3", + importpath = "github.com/Masterminds/semver/v3", + repo_mapping = repo_map, + sum = "h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0=", + version = "v3.2.1", + ) + + go_repository( + name = "com_github_openconfig_ondatra", + importpath = "github.com/openconfig/ondatra", + repo_mapping = repo_map, + build_file_proto_mode = "disable", + build_directives = build_directives, + patches = ["//:bazel/patches/ondatra.patch"], + patch_args = ["-p1"], + commit = "c22622bbf6da04c44fe4bdc77c31c0001b8a5593", #main as of 12/18/2023 + ) + + go_repository( + name = "com_github_open_traffic_generator_snappi", + importpath = "github.com/open-traffic-generator/snappi", + repo_mapping = repo_map, + commit = "c39ebe4b4cc4a0f63f2ed14b27e14ac51ec32b5d", # v0.13.3 + patches = ["//:bazel/patches/snappi.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_gnmi", + build_file_proto_mode = "disable", + importpath = "github.com/openconfig/gnmi", + repo_mapping = repo_map, + commit = "5473f2ef722ee45c3f26eee3f4a44a7d827e3575", #v0.10.0 + patches = ["//:bazel/patches/gnmi.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_ygnmi", + importpath = "github.com/openconfig/ygnmi", + build_file_proto_mode = "disable", + commit = "c4957ab3f1a1c9ff0a6baacf94a1e25a595a9f79", # v0.11.0 + patches = ["//:bazel/patches/ygnmi.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_gnoi", + build_file_proto_mode = "disable", + importpath = "github.com/openconfig/gnoi", + repo_mapping = repo_map, + commit = "97f56280571337f6122b8c30c6bdd93368c57b54", # v0.3.0 + patches = ["//:bazel/patches/gnoi.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_gnoigo", + build_file_proto_mode = "disable", + importpath = "github.com/openconfig/gnoigo", + repo_mapping = repo_map, + build_directives = build_directives, + commit = "87413fdb22e732d9935c0b2de0567e3e09d5318b", #main as of 12/18/2023 + patches = ["//:bazel/patches/gnoigo.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_gnsi", + build_file_proto_mode = "disable", + importpath = "github.com/openconfig/gnsi", + repo_mapping = repo_map, + commit = "d5abc2e8fa51d7b57b49511655b71422638ce8cf", + patches = ["//:bazel/patches/gnsi.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_gocloser", + importpath = "github.com/openconfig/gocloser", + repo_mapping = repo_map, + sum = "h1:NSYuxdlOWLldNpid1dThR6Dci96juXioUguMho6aliI=", + version = "v0.0.0-20220310182203-c6c950ed3b0b", + ) + + go_repository( + name = "com_github_openconfig_goyang", + importpath = "github.com/openconfig/goyang", + repo_mapping = repo_map, + commit = "5ad0d2feb9ce655fb39e414bd4e3696356780cdb" # v1.4.4 + ) + + go_repository( + name = "com_github_openconfig_gribi", + importpath = "github.com/openconfig/gribi", + repo_mapping = repo_map, + commit = "635d8ce0fd7673c29ddba927c32b834e313d575c", # v1.0.0 + patches = ["//:bazel/patches/gribi.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_ygot", + importpath = "github.com/openconfig/ygot", + repo_mapping = repo_map, + build_file_proto_mode = "disable", + commit = "8efc81471e0fe679c453aa0e8c03d752721733bc", # v0.29.17 + patches = ["//:bazel/patches/ygot.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_p4lang_golang_p4runtime", + importpath = "github.com/p4lang/p4runtime", + repo_mapping = repo_map, + build_file_proto_mode = "disable", + commit = "a6f035f8ddea4fb22b2244afb59e3223dc5c1f69", + patches = ["//:bazel/patches/p4lang.patch"], + patch_args = ["-p1"], + ) + + go_repository( + name = "com_github_openconfig_testt", + importpath = "github.com/openconfig/testt", + commit = "efbb1a32ec07fa7f0b6cf7cda977fa1c584154d6", + ) + + go_repository( + name = "in_gopkg_yaml_v2", + importpath = "gopkg.in/yaml.v2", + repo_mapping = repo_map, + sum = "h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=", + version = "v2.4.0", + ) + + go_repository( + name = "io_opencensus_go", + importpath = "go.opencensus.io", + repo_mapping = repo_map, + sum = "h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=", + version = "v0.24.0", + ) + + go_repository( + name = "org_golang_google_grpc", + importpath = "google.golang.org/grpc", + repo_mapping = repo_map, + sum = "h1:EhTqbhiYeixwWQtAEZAxmV9MGqcjEU2mFx52xCzNyag=", + version = "v1.54.0", + ) + + go_repository( + name = "org_golang_google_grpc_cmd_protoc_gen_go_grpc", + importpath = "google.golang.org/grpc/cmd/protoc-gen-go-grpc", + repo_mapping = repo_map, + sum = "h1:M1YKkFIboKNieVO5DLUEVzQfGwJD30Nv2jfUgzb5UcE=", + version = "v1.1.0", + ) + + go_repository( + name = "org_golang_google_protobuf", + importpath = "google.golang.org/protobuf", + repo_mapping = repo_map, + sum = "h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=", + version = "v1.30.0", + ) + + go_repository( + name = "org_golang_x_exp", + importpath = "golang.org/x/exp", + commit = "aacd6d4b4611949ff7dcca7a0118e9312168a5f8", + ) + + go_repository( + name = "org_golang_x_net", + importpath = "golang.org/x/net", + repo_mapping = repo_map, + sum = "h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=", + version = "v0.9.0", + ) + + go_repository( + name = "org_golang_x_sync", + importpath = "golang.org/x/sync", + repo_mapping = repo_map, + tag = "v0.3.0", + ) + + go_repository( + name = "org_golang_x_sys", + importpath = "golang.org/x/sys", + repo_mapping = repo_map, + sum = "h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=", + version = "v0.7.0", + ) + + go_repository( + name = "org_golang_x_text", + importpath = "golang.org/x/text", + repo_mapping = repo_map, + sum = "h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=", + version = "v0.9.0", + ) + + + git_repository( + name = "com_google_googleapis", + remote = "https://github.com/googleapis/googleapis", + commit = "c4915db59896a1da45b55507ece2ebc1d53ef6f5", + shallow_since = "1642638275 -0800", + ) + + + go_repository( + name = "com_github_pkg_errors", + importpath = "github.com/pkg/errors", + sum = "h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=", + version = "v0.9.1", + ) + + go_repository( + name = "com_github_pkg_sftp", + importpath = "github.com/pkg/sftp", + sum = "h1:I2qBYMChEhIjOgazfJmV3/mZM256btk6wkCDRmW7JYs=", + version = "v1.13.1", + ) diff --git a/sdn_tests/pins_ondatra/pins_deps.bzl b/sdn_tests/pins_ondatra/pins_deps.bzl new file mode 100644 index 00000000000..b80cb2e1a73 --- /dev/null +++ b/sdn_tests/pins_ondatra/pins_deps.bzl @@ -0,0 +1,203 @@ +load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository") +load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +def pins_deps(): + if not native.existing_rule("com_github_grpc_grpc"): + http_archive( + name = "com_github_grpc_grpc", + url = "https://github.com/grpc/grpc/archive/v1.58.0.zip", + strip_prefix = "grpc-1.58.0", + sha256 = "aa329c7de707a03511c88206ef4483e9346ab6336b6be4378d294060aa7400b3", + patch_args = ["-p1"], + patches = [ + "//:bazel/patches/grpc-001-fix_file_watcher_race_condition.patch", + "//:bazel/patches/grpc-003-fix_go_gazelle_register_toolchain.patch", + ], + ) + if not native.existing_rule("com_google_absl"): + http_archive( + name = "com_google_absl", + url = "https://github.com/abseil/abseil-cpp/archive/20230802.0.tar.gz", + strip_prefix = "abseil-cpp-20230802.0", + sha256 = "59d2976af9d6ecf001a81a35749a6e551a335b949d34918cfade07737b9d93c5", + ) + if not native.existing_rule("com_google_googletest"): + http_archive( + name = "com_google_googletest", + urls = ["https://github.com/google/googletest/archive/release-1.11.0.tar.gz"], + strip_prefix = "googletest-release-1.11.0", + sha256 = "b4870bf121ff7795ba20d20bcdd8627b8e088f2d1dab299a031c1034eddc93d5", + ) + if not native.existing_rule("com_google_benchmark"): + http_archive( + name = "com_google_benchmark", + urls = ["https://github.com/google/benchmark/archive/v1.5.4.tar.gz"], + strip_prefix = "benchmark-1.5.4", + sha256 = "e3adf8c98bb38a198822725c0fc6c0ae4711f16fbbf6aeb311d5ad11e5a081b5", + ) + if not native.existing_rule("com_google_protobuf"): + http_archive( + name = "com_google_protobuf", + url = "https://github.com/protocolbuffers/protobuf/archive/refs/tags/v25.1.zip", + strip_prefix = "protobuf-25.1", + sha256 = "eaafa4e19a6619c15df4c30d7213efbfd0f33ad16021cc5f72bbc5d0877346b5", + ) + if not native.existing_rule("com_googlesource_code_re2"): + http_archive( + name = "com_googlesource_code_re2", + url = "https://github.com/google/re2/archive/refs/tags/2023-06-01.tar.gz", + strip_prefix = "re2-2023-06-01", + sha256 = "8b4a8175da7205df2ad02e405a950a02eaa3e3e0840947cd598e92dca453199b", + ) + if not native.existing_rule("com_google_googleapis"): + http_archive( + name = "com_google_googleapis", + url = "https://github.com/googleapis/googleapis/archive/f405c718d60484124808adb7fb5963974d654bb4.zip", + strip_prefix = "googleapis-f405c718d60484124808adb7fb5963974d654bb4", + sha256 = "406b64643eede84ce3e0821a1d01f66eaf6254e79cb9c4f53be9054551935e79", + ) + if not native.existing_rule("com_github_google_glog"): + http_archive( + name = "com_github_google_glog", + url = "https://github.com/google/glog/archive/v0.6.0.tar.gz", + strip_prefix = "glog-0.6.0", + sha256 = "8a83bf982f37bb70825df71a9709fa90ea9f4447fb3c099e1d720a439d88bad6", + ) + if not native.existing_rule("com_github_otg_models"): + http_archive( + name = "com_github_otg_models", + url = "https://github.com/open-traffic-generator/models/archive/refs/tags/v0.12.5.zip", + strip_prefix = "models-0.12.5", + build_file = "@//:bazel/BUILD.otg-models.bazel", + sha256 = "1a63e769f1d7f42c79bc1115babf54acbc44761849a77ac28f47a74567f10090", + ) + + # Needed to make glog happy. + if not native.existing_rule("com_github_gflags_gflags"): + http_archive( + name = "com_github_gflags_gflags", + url = "https://github.com/gflags/gflags/archive/v2.2.2.tar.gz", + strip_prefix = "gflags-2.2.2", + sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf", + ) + if not native.existing_rule("com_github_gnmi"): + http_archive( + name = "com_github_gnmi", + # v0.10.0 release; commit-hash:5473f2ef722ee45c3f26eee3f4a44a7d827e3575. + url = "https://github.com/openconfig/gnmi/archive/refs/tags/v0.10.0.zip", + strip_prefix = "gnmi-0.10.0", + patch_args = ["-p1"], + patches = [ + "//:bazel/patches/gnmi-001-fix_virtual_proto_import.patch", + ], + sha256 = "2231e1cc398a523fa840810fa6fdb8960639f7b91b57bb8f12ed8681e0142a67", + ) + if not native.existing_rule("com_github_gnoi"): + http_archive( + name = "com_github_gnoi", + # Newest commit on main on 2021-11-08. + url = "https://github.com/openconfig/gnoi/archive/1ece8ed91a0d5d283219a99eb4dc6c7eadb8f287.zip", + strip_prefix = "gnoi-1ece8ed91a0d5d283219a99eb4dc6c7eadb8f287", + sha256 = "991ff13a0b28f2cdc2ccb123261e7554d9bcd95c00a127411939a3a8c8a9cc62", + ) + if not native.existing_rule("com_github_p4lang_p4c"): + http_archive( + name = "com_github_p4lang_p4c", + # Newest commit on main on 2023-10-09. + url = "https://github.com/p4lang/p4c/archive/d79e2e8bfa07c7797891d44b7d084910947bf0a7.zip", + strip_prefix = "p4c-d79e2e8bfa07c7797891d44b7d084910947bf0a7", + sha256 = "1fad9b8e96988da76e3ad01c90e99d70fe7db90b3acb7bddf78b603117e857f9", + ) + if not native.existing_rule("com_github_p4lang_p4runtime"): + # We frequently need bleeding-edge, unreleased version of P4Runtime, so we use a commit + # rather than a release. + http_archive( + name = "com_github_p4lang_p4runtime", + # 90553b9 is the newest commit on main as of 2023-10-09. + urls = ["https://github.com/p4lang/p4runtime/archive/f0e9f33818b74f0009daa44160926e568f1eaa4d.zip"], + strip_prefix = "p4runtime-f0e9f33818b74f0009daa44160926e568f1eaa4d/proto", + sha256 = "97b43996ada83484bfa3f9be205d6b6fd75b9ed6985839414ee72110d369cd53", + ) + if not native.existing_rule("com_github_p4lang_p4_constraints"): + http_archive( + name = "com_github_p4lang_p4_constraints", + urls = ["https://github.com/p4lang/p4-constraints/archive/3d5196a793f375ccbe1bf38ae6c49e2e65604f4b.zip"], + strip_prefix = "p4-constraints-3d5196a793f375ccbe1bf38ae6c49e2e65604f4b", + sha256 = "f87d885ebfd6a1bdf02b4c4ba5bf6fb333f90d54561e4d520a8413c8d1fb7beb", + ) + if not native.existing_rule("com_github_nlohmann_json"): + http_archive( + name = "com_github_nlohmann_json", + # JSON for Modern C++ + url = "https://github.com/nlohmann/json/archive/v3.7.3.zip", + strip_prefix = "json-3.7.3", + sha256 = "e109cd4a9d1d463a62f0a81d7c6719ecd780a52fb80a22b901ed5b6fe43fb45b", + build_file_content = """cc_library(name = "nlohmann_json", + visibility = ["//visibility:public"], + hdrs = glob([ + "include/nlohmann/*.hpp", + "include/nlohmann/**/*.hpp", + ]), + includes = ["include"], + )""", + ) + if not native.existing_rule("com_jsoncpp"): + http_archive( + name = "com_jsoncpp", + url = "https://github.com/open-source-parsers/jsoncpp/archive/1.9.4.zip", + strip_prefix = "jsoncpp-1.9.4", + build_file = "@//:bazel/BUILD.jsoncpp.bazel", + sha256 = "6da6cdc026fe042599d9fce7b06ff2c128e8dd6b8b751fca91eb022bce310880", + ) + if not native.existing_rule("com_github_ivmai_cudd"): + http_archive( + name = "com_github_ivmai_cudd", + build_file = "@//:bazel/BUILD.cudd.bazel", + strip_prefix = "cudd-cudd-3.0.0", + sha256 = "5fe145041c594689e6e7cf4cd623d5f2b7c36261708be8c9a72aed72cf67acce", + urls = ["https://github.com/ivmai/cudd/archive/cudd-3.0.0.tar.gz"], + ) + if not native.existing_rule("com_gnu_gmp"): + http_archive( + name = "com_gnu_gmp", + urls = [ + "https://gmplib.org/download/gmp/gmp-6.2.1.tar.xz", + "https://ftp.gnu.org/gnu/gmp/gmp-6.2.1.tar.xz", + ], + strip_prefix = "gmp-6.2.1", + sha256 = "fd4829912cddd12f84181c3451cc752be224643e87fac497b69edddadc49b4f2", + build_file = "@//:bazel/BUILD.gmp.bazel", + ) + if not native.existing_rule("com_github_z3prover_z3"): + http_archive( + name = "com_github_z3prover_z3", + url = "https://github.com/Z3Prover/z3/archive/z3-4.8.12.tar.gz", + strip_prefix = "z3-z3-4.8.12", + sha256 = "e3aaefde68b839299cbc988178529535e66048398f7d083b40c69fe0da55f8b7", + build_file = "@//:bazel/BUILD.z3.bazel", + ) + if not native.existing_rule("rules_foreign_cc"): + http_archive( + name = "rules_foreign_cc", + sha256 = "d54742ffbdc6924f222d2179f0e10e911c5c659c4ae74158e9fe827aad862ac6", + strip_prefix = "rules_foreign_cc-0.2.0", + url = "https://github.com/bazelbuild/rules_foreign_cc/archive/0.2.0.tar.gz", + ) + if not native.existing_rule("rules_proto"): + http_archive( + name = "rules_proto", + urls = [ + "https://github.com/bazelbuild/rules_proto/archive/3f1ab99b718e3e7dd86ebdc49c580aa6a126b1cd.tar.gz", + ], + strip_prefix = "rules_proto-3f1ab99b718e3e7dd86ebdc49c580aa6a126b1cd", + sha256 = "c9cc7f7be05e50ecd64f2b0dc2b9fd6eeb182c9cc55daf87014d605c31548818", + ) + if not native.existing_rule("rules_pkg"): + http_archive( + name = "rules_pkg", + urls = [ + "https://mirror.bazel.build/github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz", + "https://github.com/bazelbuild/rules_pkg/releases/download/0.5.1/rules_pkg-0.5.1.tar.gz", + ], + sha256 = "a89e203d3cf264e564fcb96b6e06dd70bc0557356eb48400ce4b5d97c2c3720d", + ) From 3bb29519818c5787e0418c52917ca7cdf3f43162 Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 08:18:07 -0400 Subject: [PATCH 02/10] [sdn_tests]: Adding binding infra to pins_ondatra. --- .../infrastructure/binding/BUILD.bazel | 56 +++ .../infrastructure/binding/binding_backend.go | 84 ++++ .../infrastructure/binding/pins_backend.go | 206 ++++++++ .../infrastructure/binding/pins_binding.go | 449 ++++++++++++++++++ 4 files changed, 795 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/binding/BUILD.bazel create mode 100644 sdn_tests/pins_ondatra/infrastructure/binding/binding_backend.go create mode 100644 sdn_tests/pins_ondatra/infrastructure/binding/pins_backend.go create mode 100644 sdn_tests/pins_ondatra/infrastructure/binding/pins_binding.go diff --git a/sdn_tests/pins_ondatra/infrastructure/binding/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/binding/BUILD.bazel new file mode 100644 index 00000000000..83ed441df16 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/binding/BUILD.bazel @@ -0,0 +1,56 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +go_library( + name = "pinsbind", + testonly = True, + srcs = ["pins_binding.go"], + importpath = "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbind", + deps = [ + "//infrastructure/binding:bindingbackend", + "//infrastructure/binding:pinsbackend", + "@com_github_golang_glog//:glog", + "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_gnoigo//:gnoigo", + "@com_github_openconfig_ondatra//binding", + "@com_github_openconfig_ondatra//binding/grpcutil", + "@com_github_openconfig_ondatra//proto:go_default_library", + "@com_github_openconfig_ondatra//proxy", + "@com_github_openconfig_ondatra//proxy/proto/reservation:go_default_library", + "@com_github_p4lang_golang_p4runtime//go/p4/v1:p4", + "@org_golang_google_grpc//:go_default_library", + ], +) + +go_library( + name = "bindingbackend", + testonly = True, + srcs = ["binding_backend.go"], + importpath = "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/bindingbackend", + deps = [ + "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_ondatra//binding", + "@com_github_openconfig_ondatra//proto:go_default_library", + "@org_golang_google_grpc//:go_default_library", + ], +) + +go_library( + name = "pinsbackend", + testonly = True, + srcs = ["pins_backend.go"], + importpath = "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbackend", + deps = [ + "//infrastructure/binding:bindingbackend", + "@com_github_golang_glog//:glog", + "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_ondatra//binding", + "@com_github_openconfig_ondatra//proto:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//credentials", + ], +) diff --git a/sdn_tests/pins_ondatra/infrastructure/binding/binding_backend.go b/sdn_tests/pins_ondatra/infrastructure/binding/binding_backend.go new file mode 100644 index 00000000000..69bd7b2a951 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/binding/binding_backend.go @@ -0,0 +1,84 @@ +// Package bindingbackend describes the interface to interact with the reservations and devices. +package bindingbackend + +import ( + "context" + "time" + + gpb "github.com/openconfig/gnmi/proto/gnmi" + "github.com/openconfig/ondatra/binding" + opb "github.com/openconfig/ondatra/proto" + "google.golang.org/grpc" +) + +// ReservedTestbed contains information about reserved testbed. +type ReservedTestbed struct { + id string // Reservation id + name string +} + +// Device contains data of reserved switch. +type Device struct { + Name string + ID string + PortMap map[string]*binding.Port +} + +// GRPCService represents supported grpc service. +type GRPCService string + +const ( + // GNMI represents gnmi grpc service. + GNMI GRPCService = "gnmi" + // GNOI represents gnoi grpc service. + GNOI GRPCService = "gnoi" + // GNSI represents gnsi grpc service. + GNSI GRPCService = "gnsi" + // P4RT represents p4rt grpc service. + P4RT GRPCService = "p4rt" +) + +// GRPCServices contains addresses for services using grpc protocol. +type GRPCServices struct { + Addr map[GRPCService]string +} + +// HTTPService contains addresses for services using HTTP protocol. +type HTTPService struct { + Addr string +} + +// DUTDevice contains device and service addresses for DUT device. +type DUTDevice struct { + *Device + GRPC GRPCServices +} + +// ATEDevice contains device and service addresses for ATE device. +type ATEDevice struct { + *Device + HTTP HTTPService +} + +// ReservedTopology represents the reserved DUT and ATE devices. +type ReservedTopology struct { + ID string + DUTs []*DUTDevice + ATEs []*ATEDevice +} + +// Backend exposes functions to interact with reservations and reserved devices. +type Backend interface { + // ReserveTopology returns topology of reserved DUT and ATE devices. + ReserveTopology(ctx context.Context, tb *opb.Testbed, runtime, waittime time.Duration) (*ReservedTopology, error) + // Release releases the reserved devices, called during teardown. + Release(ctx context.Context) error + // DialGRPC connects to grpc service and returns the opened grpc client for use. + DialGRPC(ctx context.Context, addr string, opts ...grpc.DialOption) (*grpc.ClientConn, error) + DialConsole(ctx context.Context, dut *binding.AbstractDUT) (binding.ConsoleClient, error) + // GNMIClient wraps the grpc connection under gnmi client. + GNMIClient(ctx context.Context, dut *binding.AbstractDUT, conn *grpc.ClientConn) (gpb.GNMIClient, error) + + // Close closes backend's internal objects. + Close() error +} diff --git a/sdn_tests/pins_ondatra/infrastructure/binding/pins_backend.go b/sdn_tests/pins_ondatra/infrastructure/binding/pins_backend.go new file mode 100644 index 00000000000..d1598bb4fb8 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/binding/pins_backend.go @@ -0,0 +1,206 @@ +// Package pinsbackend can reserve Ondatra DUTs and provide clients to interact with the DUTs. +package pinsbackend + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "os" + "time" + + log "github.com/golang/glog" + gpb "github.com/openconfig/gnmi/proto/gnmi" + "github.com/openconfig/ondatra/binding" + opb "github.com/openconfig/ondatra/proto" + "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/bindingbackend" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" +) + +// Backend can reserve Ondatra DUTs and provide clients to interact with the DUTs. +type Backend struct { + configs map[string]*tls.Config +} + +// New creates a backend object. +func New() *Backend { + return &Backend{configs: map[string]*tls.Config{}} +} + +// registerGRPCTLS caches grpc TLS certificates for the given serverName. +func (b *Backend) registerGRPCTLS(grpc *bindingbackend.GRPCServices, serverName string) error { + if serverName == "" { + return fmt.Errorf("serverName is empty") + } + + // Load certificate of the CA who signed server's certificate. + pemServerCA, err := os.ReadFile("ondatra/certs/ca_crt.pem") + if err != nil { + return err + } + + certPool := x509.NewCertPool() + if !certPool.AppendCertsFromPEM(pemServerCA) { + return fmt.Errorf("failed to add server CA's certificate") + } + // Load client's certificate and private key + clientCert, err := tls.LoadX509KeyPair("ondatra/certs/client_crt.pem", "ondatra/certs/client_key.pem") + if err != nil { + return err + } + + for _, service := range grpc.Addr { + b.configs[service] = &tls.Config{ + Certificates: []tls.Certificate{clientCert}, + RootCAs: certPool, + ServerName: serverName, + MinVersion: tls.VersionTLS13, + } + } + + return nil +} + + + +// ReserveTopology returns topology containing reserved DUT and ATE devices. +func (b *Backend) ReserveTopology(ctx context.Context, tb *opb.Testbed, runtime, waitTime time.Duration) (*bindingbackend.ReservedTopology, error) { + // Fill in the Dut and Control device details. + dut := "192.168.0.1" // sample dut address. + control := "192.168.0.2" // sample control address. + log.Infof("testbed Dut:%s Control switch:%s", dut, control) + + grpcPort := "9339" + p4rtPort := "9559" + dutGRPCAddr := fmt.Sprintf("%v:%v", dut, grpcPort) + dutP4RTAddr := fmt.Sprintf("%v:%v", dut, p4rtPort) + controlGRPCAddr := fmt.Sprintf("%v:%v", control, grpcPort) + controlP4RTAddr := fmt.Sprintf("%v:%v", control, p4rtPort) + + // Modify the reservation based on your topology. + r := &bindingbackend.ReservedTopology{ + ID: "PINS Reservation", + DUTs: []*bindingbackend.DUTDevice{{ + Device: &bindingbackend.Device{ + ID: "DUT", + Name: dut, + PortMap: map[string]*binding.Port{ + "port1": {Name: "Ethernet1/1/1"}, + "port2": {Name: "Ethernet1/1/5"}, + "port3": {Name: "Ethernet1/2/1"}, + "port4": {Name: "Ethernet1/2/5"}, + "port5": {Name: "Ethernet1/3/1"}, + "port6": {Name: "Ethernet1/3/5"}, + "port7": {Name: "Ethernet1/4/1"}, + "port8": {Name: "Ethernet1/4/5"}, + "port9": {Name: "Ethernet1/5/1"}, + "port10": {Name: "Ethernet1/5/5"}, + "port11": {Name: "Ethernet1/6/1"}, + "port12": {Name: "Ethernet1/6/5"}, + "port13": {Name: "Ethernet1/7/1"}, + "port14": {Name: "Ethernet1/7/5"}, + "port15": {Name: "Ethernet1/8/1"}, + "port16": {Name: "Ethernet1/8/5"}, + "port17": {Name: "Ethernet1/9/1"}, + "port18": {Name: "Ethernet1/9/5"}, + "port19": {Name: "Ethernet1/10/1"}, + "port20": {Name: "Ethernet1/10/5"}, + }, + }, + GRPC: bindingbackend.GRPCServices{ + Addr: map[bindingbackend.GRPCService]string{ + bindingbackend.GNMI: dutGRPCAddr, + bindingbackend.GNOI: dutGRPCAddr, + bindingbackend.GNSI: dutGRPCAddr, + bindingbackend.P4RT: dutP4RTAddr, + }, + }}, + { + Device: &bindingbackend.Device{ + ID: "CONTROL", + Name: control, + PortMap: map[string]*binding.Port{ + "port1": {Name: "Ethernet1/1/1"}, + "port2": {Name: "Ethernet1/1/5"}, + "port3": {Name: "Ethernet1/2/1"}, + "port4": {Name: "Ethernet1/2/5"}, + "port5": {Name: "Ethernet1/3/1"}, + "port6": {Name: "Ethernet1/3/5"}, + "port7": {Name: "Ethernet1/4/1"}, + "port8": {Name: "Ethernet1/4/5"}, + "port9": {Name: "Ethernet1/5/1"}, + "port10": {Name: "Ethernet1/5/5"}, + "port11": {Name: "Ethernet1/6/1"}, + "port12": {Name: "Ethernet1/6/5"}, + "port13": {Name: "Ethernet1/7/1"}, + "port14": {Name: "Ethernet1/7/5"}, + "port15": {Name: "Ethernet1/8/1"}, + "port16": {Name: "Ethernet1/8/5"}, + "port17": {Name: "Ethernet1/9/1"}, + "port18": {Name: "Ethernet1/9/5"}, + "port19": {Name: "Ethernet1/10/1"}, + "port20": {Name: "Ethernet1/10/5"}, + }, + }, + GRPC: bindingbackend.GRPCServices{ + Addr: map[bindingbackend.GRPCService]string{ + bindingbackend.GNMI: controlGRPCAddr, + bindingbackend.GNOI: controlGRPCAddr, + bindingbackend.GNSI: controlGRPCAddr, + bindingbackend.P4RT: controlP4RTAddr, + }, + }}, + }} + + for _, dut := range r.DUTs { + if err := b.registerGRPCTLS(&dut.GRPC, dut.Name); err != nil { + return nil, err + } + } + + return r, nil +} + +// Release releases the reserved devices, called during teardown. +func (b *Backend) Release(ctx context.Context) error { + return nil +} + +// DialGRPC connects to grpc service and returns the opened grpc client for use. +func (b *Backend) DialGRPC(ctx context.Context, addr string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { + tlsConfig, ok := b.configs[addr] + if !ok { + return nil, fmt.Errorf("failed to find TLS config for %s", addr) + } + + opts = append(opts, grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))) + conn, err := grpc.DialContext(ctx, addr, opts...) + if err != nil { + return nil, fmt.Errorf("DialContext(%s, %v) : %v", addr, opts, err) + } + + return conn, nil +} + +// DialConsole returns a StreamClient for the DUT. +func (b *Backend) DialConsole(ctx context.Context, dut *binding.AbstractDUT) (binding.ConsoleClient, error) { + return nil, fmt.Errorf("unimplemented function") +} + +// GNMIClient wraps the grpc connection under gnmi client. +func (b *Backend) GNMIClient(ctx context.Context, dut *binding.AbstractDUT, conn *grpc.ClientConn) (gpb.GNMIClient, error) { + if conn == nil { + return nil, fmt.Errorf("conn is nil") + } + if dut == nil { + return nil, fmt.Errorf("dut is nil") + } + return gpb.NewGNMIClient(conn), nil +} + +// Close closes backend's internal objects. +func (b *Backend) Close() error { + b.configs = nil + return nil +} diff --git a/sdn_tests/pins_ondatra/infrastructure/binding/pins_binding.go b/sdn_tests/pins_ondatra/infrastructure/binding/pins_binding.go new file mode 100644 index 00000000000..ed8250e3c3f --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/binding/pins_binding.go @@ -0,0 +1,449 @@ +// Package pinsbind contains all the code related to the PINS project's binding to Ondatra. +package pinsbind + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + log "github.com/golang/glog" + + "github.com/openconfig/gnoigo" + "github.com/openconfig/ondatra/binding" + "github.com/openconfig/ondatra/binding/grpcutil" + pinsbackend "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/pinsbackend" + "google.golang.org/grpc" + + opb "github.com/openconfig/ondatra/proto" + "github.com/openconfig/ondatra/proxy" + "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/binding/bindingbackend" + + gpb "github.com/openconfig/gnmi/proto/gnmi" + + rpb "github.com/openconfig/ondatra/proxy/proto/reservation" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" +) + +var ( + // validate that the Binding fulfills both binding.Binding and proxy.Dialer + // interfaces. + _ binding.Binding = &Binding{} + _ proxy.Dialer = &Binding{} +) + +var backend bindingbackend.Backend + +// Binding is a binding for PINS switches. +type Binding struct { + resv *binding.Reservation + httpDialer func(target string) (proxy.HTTPDoCloser, error) +} + +// Option are configurable inputs to the binding. +type Option func(b *Binding) + +// WithHTTPDialer provides a custom http dialer that is capable of dialing specific targets. +func WithHTTPDialer(f func(target string) (proxy.HTTPDoCloser, error)) Option { + return func(b *Binding) { + b.httpDialer = f + } +} + +// New returns a new instance of a PINS Binding. +func New() (binding.Binding, error) { + return NewWithOpts() +} + +type httpClient struct { + *http.Client +} + +func (h *httpClient) Close() error { + return nil +} + +func defaultHTTPDialer(target string) (proxy.HTTPDoCloser, error) { + return &httpClient{http.DefaultClient}, nil +} + +// NewWithOpts returns a new instance of a PINS Binding. +func NewWithOpts(opts ...Option) (*Binding, error) { + b := &Binding{ + httpDialer: defaultHTTPDialer, + } + + for _, opt := range opts { + opt(b) + } + + if backend == nil { + backend = pinsbackend.New() + } + + return b, nil +} + +// SetBackend sets the backend for binding. +func SetBackend(b bindingbackend.Backend) { + backend = b +} + +// CloseBackend closes the backend. +func CloseBackend() { + if backend != nil { + backend.Close() + } + backend = nil +} + +// Reserve returns a testbed meeting requirements of testbed proto. +func (b *Binding) Reserve(ctx context.Context, tb *opb.Testbed, runtime, waitTime time.Duration, partial map[string]string) (*binding.Reservation, error) { + if backend == nil { + return nil, fmt.Errorf("backend is not set") + } + + if len(partial) > 0 { + return nil, fmt.Errorf("PINSBind Reserve does not yet support partial mappings") + } + + reservedtopology, err := backend.ReserveTopology(ctx, tb, runtime, waitTime) + if err != nil { + return nil, fmt.Errorf("failed to reserve topology: %v", err) + } + + resv := &binding.Reservation{ID: reservedtopology.ID, DUTs: map[string]binding.DUT{}} + for _, dut := range reservedtopology.DUTs { + resv.DUTs[dut.ID] = &pinsDUT{ + AbstractDUT: &binding.AbstractDUT{&binding.Dims{ + Name: dut.Name, + Ports: dut.PortMap, + }}, + bind: b, + grpc: dut.GRPC, + } + } + + if len(reservedtopology.ATEs) != 0 { + resv.ATEs = map[string]binding.ATE{} + } + for _, ate := range reservedtopology.ATEs { + resv.ATEs[ate.ID] = &pinsATE{ + AbstractATE: &binding.AbstractATE{&binding.Dims{ + Name: ate.Name, + Ports: ate.PortMap, + }}, + http: ate.HTTP, + } + } + + b.resv = resv + return resv, nil +} + +// Release returns the testbed to a pool of resources. +func (b *Binding) Release(ctx context.Context) error { + return backend.Release(ctx) +} + +type pinsDUT struct { + *binding.AbstractDUT + bind *Binding + grpc bindingbackend.GRPCServices +} + +type pinsATE struct { + *binding.AbstractATE + bind *Binding + http bindingbackend.HTTPService +} + +// DialGRPC will return a gRPC client conn for the target. This method should +// be used by any new service definitions which create underlying gRPC +// connections. +func (b *Binding) DialGRPC(ctx context.Context, addr string, opts ...grpc.DialOption) (*grpc.ClientConn, error) { + if backend == nil { + return nil, fmt.Errorf("backend is not set") + } + + return backend.DialGRPC(ctx, addr, opts...) +} + +// HTTPClient returns a http client that is capable of dialing the provided target. +func (b *Binding) HTTPClient(target string) (proxy.HTTPDoCloser, error) { + return b.httpDialer(target) +} + +// DialGNMI connects directly to the switch's proxy. +func (d *pinsDUT) DialGNMI(ctx context.Context, opts ...grpc.DialOption) (gpb.GNMIClient, error) { + addr := d.grpc.Addr[bindingbackend.GNMI] + if addr == "" { + return nil, fmt.Errorf("service gnmi not registered on DUT %q", d.Name()) + } + + const defaultTimeout = time.Minute + ctx, cancel := grpcutil.WithDefaultTimeout(ctx, defaultTimeout) + defer cancel() + opts = append(opts, + grpcutil.WithUnaryDefaultTimeout(defaultTimeout), + grpcutil.WithStreamDefaultTimeout(defaultTimeout), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024*1024*20))) + + conn, err := d.bind.DialGRPC(ctx, addr, opts...) + if err != nil { + return nil, err + } + + cli, err := backend.GNMIClient(ctx, d.AbstractDUT, conn) + if err != nil { + return nil, err + } + return &clientWrap{GNMIClient: cli}, nil +} + +type clientWrap struct { + gpb.GNMIClient +} + +// wrapValueInUpdate wraps the typed value in the provided update into a +// serialized JSON node., e.g. +// - 123 -> {"foo": 123} +// - [{"str": "one"}] -> {"foo": [{"str": "one"}]} +// - {"str": "test-string"} -> {"foo": {"str": "test-string"}} +func wrapValueInUpdate(up *gpb.Update) error { + elems := up.GetPath().GetElem() + if len(elems) == 0 { + // root path case + return nil + } + name := elems[len(elems)-1].GetName() + var i any + if err := json.Unmarshal(up.GetVal().GetJsonIetfVal(), &i); err != nil { + return fmt.Errorf("unable to unmarshal config: %v", err) + } + + // For list paths such as /interfaces/interface[name=], JSON IETF value + // needs to be an array instead of an object. Ondatra returns value for such paths + // as an object, which need to be translated into a JSON array. E.g. + // - {"str": "test-string"} -> [{"str": "test-string"}] + if len(elems[len(elems)-1].GetKey()) > 0 { + // The path is a list node. Perform translation to JSON array. + var arr []any + arr = append(arr, i) + arrVal, err := json.Marshal(arr) + if err != nil { + return fmt.Errorf("unable to marshal value %v as a JSON array: %v", arr, err) + } + if err := json.Unmarshal(arrVal, &i); err != nil { + return fmt.Errorf("unable to unmarshal JSON array config: %v", err) + } + } + js, err := json.MarshalIndent(map[string]any{name: i}, "", " ") + if err != nil { + return fmt.Errorf("unable to marshal config with wrapping container: %v", err) + } + up.GetVal().Value = &gpb.TypedValue_JsonIetfVal{js} + return nil +} + +func (c *clientWrap) Set(ctx context.Context, in *gpb.SetRequest, opts ...grpc.CallOption) (*gpb.SetResponse, error) { + for _, up := range in.GetReplace() { + if err := wrapValueInUpdate(up); err != nil { + return nil, err + } + } + for _, up := range in.GetUpdate() { + if err := wrapValueInUpdate(up); err != nil { + return nil, err + } + } + + return c.GNMIClient.Set(ctx, in, opts...) +} + +func (c *clientWrap) Get(ctx context.Context, in *gpb.GetRequest, opts ...grpc.CallOption) (*gpb.GetResponse, error) { + return c.GNMIClient.Get(ctx, in, opts...) +} + +type subscribeClientWrap struct { + gpb.GNMI_SubscribeClient + client *clientWrap +} + +// CloseSend signals that the client has done sending messages to the server. +// Calling the CloseSend will cause PINs to close the Subscribe stream and return an +// error. Hence we overwrite this method to be no-op here. +func (sc *subscribeClientWrap) CloseSend() error { + return nil +} + +func (c *clientWrap) Subscribe(ctx context.Context, opts ...grpc.CallOption) (gpb.GNMI_SubscribeClient, error) { + sub, err := c.GNMIClient.Subscribe(ctx, opts...) + if err != nil { + return nil, err + } + return &subscribeClientWrap{GNMI_SubscribeClient: sub, client: c}, nil +} + +func (c *clientWrap) Capabilities(ctx context.Context, in *gpb.CapabilityRequest, opts ...grpc.CallOption) (*gpb.CapabilityResponse, error) { + return c.GNMIClient.Capabilities(ctx, in, opts...) +} + +// DialGNOI connects directly to the switch's proxy. +func (d *pinsDUT) DialGNOI(ctx context.Context, opts ...grpc.DialOption) (gnoigo.Clients, error) { + addr := d.grpc.Addr[bindingbackend.GNOI] + if addr == "" { + return nil, fmt.Errorf("service gnoi not registered on DUT %q", d.Name()) + } + + ctx, cancel := grpcutil.WithDefaultTimeout(ctx, 2*time.Minute) + defer cancel() + opts = append(opts, + grpcutil.WithUnaryDefaultTimeout(30*time.Second), + grpcutil.WithStreamDefaultTimeout(2*time.Minute), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024*1024*20))) + + conn, err := d.bind.DialGRPC(ctx, addr, opts...) + if err != nil { + return nil, err + } + + log.Infof("GNOI dial success Address:%s, Switch:%s", conn.Target(), d.Name()) + return &GNOIClients{ + Clients: gnoigo.NewClients(conn), + }, nil +} + +// GNOIClients consist of the GNOI clients supported by PINs. +type GNOIClients struct { + gnoigo.Clients +} + +// DialP4RT connects directly to the switch's proxy. +func (d *pinsDUT) DialP4RT(ctx context.Context, opts ...grpc.DialOption) (p4pb.P4RuntimeClient, error) { + addr := d.grpc.Addr[bindingbackend.P4RT] + if addr == "" { + return nil, fmt.Errorf("service gnsi not registered on DUT %q", d.Name()) + } + + ctx, cancel := grpcutil.WithDefaultTimeout(ctx, 2*time.Minute) + defer cancel() + opts = append(opts, + grpcutil.WithUnaryDefaultTimeout(30*time.Second), + grpcutil.WithStreamDefaultTimeout(2*time.Minute), + grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(1024*1024*20))) + + conn, err := d.bind.DialGRPC(ctx, addr, opts...) + if err != nil { + return nil, err + } + + log.Infof("P4RT dial success Address:%s, Switch:%s", conn.Target(), d.Name()) + return p4pb.NewP4RuntimeClient(conn), nil +} + +// DialConsole returns a StreamClient for the DUT. +func (d *pinsDUT) DialConsole(ctx context.Context) (binding.ConsoleClient, error) { + return backend.DialConsole(ctx, d.AbstractDUT) +} + +// FetchReservation unimplemented for experimental purposes. +func (*Binding) FetchReservation(context.Context, string) (*binding.Reservation, error) { + return nil, nil +} + +// Resolve will return a concrete reservation with services defined. +func (b *Binding) Resolve() (*rpb.Reservation, error) { + devices := map[string]*rpb.ResolvedDevice{} + for k, d := range b.resv.DUTs { + rD, err := b.resolveDUT(k, d.(*pinsDUT)) + if err != nil { + return nil, err + } + devices[k] = rD + } + ates := map[string]*rpb.ResolvedDevice{} + for k, a := range b.resv.ATEs { + rD, err := b.resolveATE(k, a.(*pinsATE)) + if err != nil { + return nil, err + } + ates[k] = rD + } + return &rpb.Reservation{ + Id: b.resv.ID, + Ates: ates, + Devices: devices, + }, nil +} + +func resolvePort(k string, p *binding.Port) *rpb.ResolvedPort { + return &rpb.ResolvedPort{ + Id: k, + Speed: p.Speed, + Name: p.Name, + } +} + +func (b *Binding) resolveDUT(key string, d *pinsDUT) (*rpb.ResolvedDevice, error) { + ports := map[string]*rpb.ResolvedPort{} + for k, p := range d.Ports() { + ports[k] = resolvePort(k, p) + } + services := map[string]*rpb.Service{ + "gnmi.gNMI": { + Id: "gnmi.gNMI", + Endpoint: &rpb.Service_ProxiedGrpc{ + ProxiedGrpc: &rpb.ProxiedGRPCEndpoint{ + Address: d.grpc.Addr[bindingbackend.GNMI], + Proxy: nil, + }, + }, + }, + "p4.v1.P4Runtime": { + Id: "p4.v1.P4Runtime", + Endpoint: &rpb.Service_ProxiedGrpc{ + ProxiedGrpc: &rpb.ProxiedGRPCEndpoint{ + Address: d.grpc.Addr[bindingbackend.P4RT], + Proxy: nil, + }, + }, + }, + } + return &rpb.ResolvedDevice{ + Id: key, + HardwareModel: d.HardwareModel(), + Vendor: d.Vendor(), + SoftwareVersion: d.SoftwareVersion(), + Name: d.Name(), + Ports: ports, + Services: services, + }, nil +} + +func (b *Binding) resolveATE(key string, d *pinsATE) (*rpb.ResolvedDevice, error) { + ports := map[string]*rpb.ResolvedPort{} + for k, p := range d.Ports() { + ports[k] = resolvePort(k, p) + } + services := map[string]*rpb.Service{ + "http": { + Id: "http", + Endpoint: &rpb.Service_HttpOverGrpc{ + HttpOverGrpc: &rpb.HTTPOverGRPCEndpoint{ + Address: d.http.Addr, + }, + }, + }, + } + return &rpb.ResolvedDevice{ + Id: key, + HardwareModel: d.HardwareModel(), + Vendor: d.Vendor(), + SoftwareVersion: d.SoftwareVersion(), + Name: d.Name(), + Ports: ports, + Services: services, + }, nil +} From f55f9901421c044fd6cacd398bea62378698681e Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 08:49:57 -0400 Subject: [PATCH 03/10] [sdn_tests]: Adding cert generation script and certs folder to pins_ondatra. --- .../infrastructure/certs/BUILD.bazel | 9 +++++++++ .../infrastructure/certs/crt_gen.sh | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/certs/BUILD.bazel create mode 100755 sdn_tests/pins_ondatra/infrastructure/certs/crt_gen.sh diff --git a/sdn_tests/pins_ondatra/infrastructure/certs/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/certs/BUILD.bazel new file mode 100644 index 00000000000..97f471eecbb --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/certs/BUILD.bazel @@ -0,0 +1,9 @@ +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +filegroup( + name = "certs", + srcs = glob(["*.pem"]), +) diff --git a/sdn_tests/pins_ondatra/infrastructure/certs/crt_gen.sh b/sdn_tests/pins_ondatra/infrastructure/certs/crt_gen.sh new file mode 100755 index 00000000000..73133a5e91c --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/certs/crt_gen.sh @@ -0,0 +1,18 @@ +rm ca_key.pem ca_crt.pem server_key.pem server_req.pem server_crt.pem server_ext.cnf client_key.pem client_req.pem client_crt.pem client_ext.cnf + +echo subjectAltName = IP:"$1" > server_ext.cnf +# 1. Generate CA's private key and self-signed certificate +openssl req -x509 -newkey rsa:4096 -days 365 -nodes -keyout ca_key.pem -out ca_crt.pem -subj "/C=US" + +# 2. Generate web server's private key and certificate signing request (CSR) +openssl req -newkey rsa:4096 -nodes -keyout server_key.pem -out server_req.pem -subj "/CN='$1'" + +# 3. Use CA's private key to sign web server's CSR and get back the signed certificate +openssl x509 -req -in server_req.pem -days 100 -CA ca_crt.pem -CAkey ca_key.pem -CAcreateserial -out server_crt.pem -extfile server_ext.cnf + +echo subjectAltName = IP:"$1" > client_ext.cnf +# 4. Generate client's private key and certificate signing request (CSR) +openssl req -newkey rsa:4096 -nodes -keyout client_key.pem -out client_req.pem -subj "/CN=*" + +# 5. Use CA's private key to sign client's CSR and get back the signed certificate +openssl x509 -req -in client_req.pem -days 100 -CA ca_crt.pem -CAkey ca_key.pem -CAcreateserial -out client_crt.pem -extfile client_ext.cnf From fedf8b77f529d8db197bec5d93e84b61c5cd896f Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 10:54:24 -0400 Subject: [PATCH 04/10] [sdn_tests]: Adding Data Infra to pins_ondatra. --- .../infrastructure/data/BUILD.bazel | 9 + .../infrastructure/data/config.json | 3 + .../infrastructure/data/p4rtconfig.prototext | 3 + .../infrastructure/data/testbeds.textproto | 216 ++++++++++++++++++ 4 files changed, 231 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/data/BUILD.bazel create mode 100644 sdn_tests/pins_ondatra/infrastructure/data/config.json create mode 100644 sdn_tests/pins_ondatra/infrastructure/data/p4rtconfig.prototext create mode 100644 sdn_tests/pins_ondatra/infrastructure/data/testbeds.textproto diff --git a/sdn_tests/pins_ondatra/infrastructure/data/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/data/BUILD.bazel new file mode 100644 index 00000000000..40105d7c303 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/data/BUILD.bazel @@ -0,0 +1,9 @@ +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +filegroup( + name = "data", + srcs = glob(["**"]), +) diff --git a/sdn_tests/pins_ondatra/infrastructure/data/config.json b/sdn_tests/pins_ondatra/infrastructure/data/config.json new file mode 100644 index 00000000000..491247e3dcf --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/data/config.json @@ -0,0 +1,3 @@ +{ + "openconfig-interfaces:interfaces" : {} +} diff --git a/sdn_tests/pins_ondatra/infrastructure/data/p4rtconfig.prototext b/sdn_tests/pins_ondatra/infrastructure/data/p4rtconfig.prototext new file mode 100644 index 00000000000..0b9f05ffd0d --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/data/p4rtconfig.prototext @@ -0,0 +1,3 @@ +pkg_info{ + name : "sampleP4" version : "1.0" arch : "arch" organization : "org" +} tables {} diff --git a/sdn_tests/pins_ondatra/infrastructure/data/testbeds.textproto b/sdn_tests/pins_ondatra/infrastructure/data/testbeds.textproto new file mode 100644 index 00000000000..9765c114211 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/data/testbeds.textproto @@ -0,0 +1,216 @@ +# proto-message: ondatra.Testbed + +# DUT device with 20 ports. +duts { + id: "DUT" + ports { + id: "port1" + } + ports { + id: "port2" + } + ports { + id: "port3" + } + ports { + id: "port4" + } + ports { + id: "port5" + } + ports { + id: "port6" + } + ports { + id: "port7" + } + ports { + id: "port8" + } + ports { + id: "port9" + } + ports { + id: "port10" + } + ports { + id: "port11" + } + ports { + id: "port12" + } + ports { + id: "port13" + } + ports { + id: "port14" + } + ports { + id: "port15" + } + ports { + id: "port16" + } + ports { + id: "port17" + } + ports { + id: "port18" + } + ports { + id: "port19" + } + ports { + id: "port20" + } +} + +# CONTROL device with 20 ports. +duts { + id: "CONTROL" + ports { + id: "port1" + } + ports { + id: "port2" + } + ports { + id: "port3" + } + ports { + id: "port4" + } + ports { + id: "port5" + } + ports { + id: "port6" + } + ports { + id: "port7" + } + ports { + id: "port8" + } + ports { + id: "port9" + } + ports { + id: "port10" + } + ports { + id: "port11" + } + ports { + id: "port12" + } + ports { + id: "port13" + } + ports { + id: "port14" + } + ports { + id: "port15" + } + ports { + id: "port16" + } + ports { + id: "port17" + } + ports { + id: "port18" + } + ports { + id: "port19" + } + ports { + id: "port20" + } +} + +# Specify the links between DUT and CONTROL. + +# Below link represents DUT:port1 mapped to CONTROL:port1 +links { + a: "DUT:port1" + b: "CONTROL:port1" +} +# Below link represents DUT:port2 mapped to CONTROL:port2 +links { + a: "DUT:port2" + b: "CONTROL:port2" +} +links { + a: "DUT:port3" + b: "CONTROL:port3" +} +links { + a: "DUT:port4" + b: "CONTROL:port4" +} +links { + a: "DUT:port5" + b: "CONTROL:port5" +} +links { + a: "DUT:port6" + b: "CONTROL:port6" +} +links { + a: "DUT:port7" + b: "CONTROL:port7" +} +links { + a: "DUT:port8" + b: "CONTROL:port8" +} +links { + a: "DUT:port9" + b: "CONTROL:port9" +} +links { + a: "DUT:port10" + b: "CONTROL:port10" +} +links { + a: "DUT:port11" + b: "CONTROL:port11" +} +links { + a: "DUT:port12" + b: "CONTROL:port12" +} +links { + a: "DUT:port13" + b: "CONTROL:port13" +} +links { + a: "DUT:port14" + b: "CONTROL:port14" +} +links { + a: "DUT:port15" + b: "CONTROL:port15" +} +links { + a: "DUT:port16" + b: "CONTROL:port16" +} +links { + a: "DUT:port17" + b: "CONTROL:port17" +} +links { + a: "DUT:port18" + b: "CONTROL:port18" +} +links { + a: "DUT:port19" + b: "CONTROL:port19" +} +links { + a: "DUT:port20" + b: "CONTROL:port20" +} From 27f0a40166736e0aaa01a2b0d9af15af8ebd67d7 Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 14:24:00 -0400 Subject: [PATCH 05/10] [sdn_tests]: Adding gnmi testhelper to pins_ondatra. --- .../infrastructure/testhelper/BUILD.bazel | 46 ++++++++++ .../infrastructure/testhelper/gnmi.go | 90 +++++++++++++++++++ 2 files changed, 136 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel new file mode 100644 index 00000000000..081fbae5b04 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel @@ -0,0 +1,46 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") + +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +go_library( + name = "testhelper", + testonly = 1, + srcs = [ + "gnmi.go", + ], + data = [ + "//infrastructure/data", + ], + importpath = "github.com/sonic-net/sonic-mgmt/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper", + deps = [ + "@com_github_golang_glog//:glog", + "@com_github_openconfig_goyang//pkg/yang:go_default_library", + "@com_github_openconfig_gnmi//proto/gnmi:gnmi_go_proto", + "@com_github_openconfig_gnoi//healthz:healthz_go_proto", + "@com_github_openconfig_gnoi//system:system_go_proto", + "@com_github_openconfig_gnoi//types:types_go_proto", + "@com_github_openconfig_gocloser//:gocloser", + "@com_github_openconfig_ondatra//:go_default_library", + "@com_github_openconfig_ondatra//gnmi", + "@com_github_openconfig_ondatra//gnmi/oc", + "@com_github_openconfig_ondatra//gnmi/oc/interfaces", + "@com_github_openconfig_ondatra//gnmi/oc/platform", + "@com_github_openconfig_ondatra//gnmi/oc/system", + "@com_github_openconfig_ygnmi//ygnmi", + "@com_github_openconfig_ygot//ygot", + "@com_github_openconfig_ygot//ytypes", + "@com_github_p4lang_golang_p4runtime//go/p4/config/v1:go_default_library", + "@com_github_p4lang_golang_p4runtime//go/p4/v1:p4", + "@com_github_pkg_errors//:errors", + "@com_github_pkg_sftp//:go_default_library", + "@org_golang_google_grpc//:go_default_library", + "@org_golang_google_grpc//codes", + "@org_golang_google_grpc//status", + "@org_golang_google_protobuf//encoding/prototext", + "@org_golang_google_protobuf//proto", + "@org_golang_x_crypto//ssh", + ], +) diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go new file mode 100644 index 00000000000..be185ced8d9 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnmi.go @@ -0,0 +1,90 @@ +package testhelper + +import ( + "context" + "testing" + + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc/system" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/pkg/errors" + "google.golang.org/grpc" + + gpb "github.com/openconfig/gnmi/proto/gnmi" +) + +// Function pointers that interact with the switch. They enable unit testing +// of methods that interact with the switch. +var ( + gnmiSystemBootTimePath = func() *system.System_BootTimePath { + return gnmi.OC().System().BootTime() + } + gnmiSubscribeClientGet = func(t *testing.T, d *ondatra.DUTDevice, ctx context.Context, opts ...grpc.CallOption) (gpb.GNMI_SubscribeClient, error) { + c, err := d.RawAPIs().BindingDUT().DialGNMI(ctx) + if err != nil { + return nil, err + } + return c.Subscribe(ctx, opts...) + } + gnmiSet = func(t *testing.T, d *ondatra.DUTDevice, req *gpb.SetRequest) (*gpb.SetResponse, error) { + ctx := context.Background() + c, err := d.RawAPIs().BindingDUT().DialGNMI(ctx) + if err != nil { + return nil, err + } + return c.Set(ctx, req) + } +) + +// GNMIConfig provides an interface to implement config get. +type GNMIConfig interface { + ConfigGet() ([]byte, error) +} + +// GNMIConfigDUT contains the DUT for which the config get is being requested for. +type GNMIConfigDUT struct { + DUT *ondatra.DUTDevice +} + +// SubscribeRequestParams specifies the parameters that are used to create the +// SubscribeRequest. +// Target: The target to be specified in the prefix. +// Paths: List of paths to be added in the request. +// Mode: Subscription mode. +type SubscribeRequestParams struct { + Target string + Paths []ygnmi.PathStruct + Mode gpb.SubscriptionList_Mode +} + +// CreateSubscribeRequest creates SubscribeRequest message using the specified +// parameters that include the list of paths to be added in the request. +func CreateSubscribeRequest(params SubscribeRequestParams) (*gpb.SubscribeRequest, error) { + prefix := &gpb.Path{Origin: "openconfig"} + prefix.Target = params.Target + + var subscriptions []*gpb.Subscription + for _, path := range params.Paths { + resolvedPath, _, errs := ygnmi.ResolvePath(path) + if errs != nil { + return nil, errors.New("failed to resolve Openconfig path") + } + + subscription := &gpb.Subscription{ + Path: &gpb.Path{Elem: resolvedPath.Elem}, + } + subscriptions = append(subscriptions, subscription) + } + + return &gpb.SubscribeRequest{ + Request: &gpb.SubscribeRequest_Subscribe{ + Subscribe: &gpb.SubscriptionList{ + Prefix: prefix, + Subscription: subscriptions, + Mode: params.Mode, + Encoding: gpb.Encoding_PROTO, + }, + }, + }, nil +} From 0859c6e561503cdebde3de26df42393d6b18f92b Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 15:02:48 -0400 Subject: [PATCH 06/10] [sdn_tests]: Adding GNOI testhelper to pins_ondatra. --- .../infrastructure/testhelper/BUILD.bazel | 1 + .../infrastructure/testhelper/gnoi.go | 97 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel index 081fbae5b04..a25c18bb040 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel @@ -10,6 +10,7 @@ go_library( testonly = 1, srcs = [ "gnmi.go", + "gnoi.go", ], data = [ "//infrastructure/data", diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go new file mode 100644 index 00000000000..de06454f072 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/gnoi.go @@ -0,0 +1,97 @@ +package testhelper + +// This file contains helper method for gNOI services such as +// Reboot, Install etc. +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + + healthzpb "github.com/openconfig/gnoi/healthz" + syspb "github.com/openconfig/gnoi/system" +) + +// Function pointers that interact with the switch. They enable unit testing +// of methods that interact with the switch. +var ( + gnoiSystemClientGet = func(t *testing.T, d *ondatra.DUTDevice) syspb.SystemClient { + return d.RawAPIs().GNOI(t).System() + } + + gnoiHealthzClientGet = func(t *testing.T, d *ondatra.DUTDevice) healthzpb.HealthzClient { + return d.RawAPIs().GNOI(t).Healthz() + } + + gnmiSystemBootTimeGet = func(t *testing.T, d *ondatra.DUTDevice) uint64 { + return gnmi.Get(t, d, gnmi.OC().System().BootTime().State()) + } +) + +// RebootParams specify the reboot parameters used by the Reboot API. +type RebootParams struct { + request any + waitTime time.Duration + checkInterval time.Duration + lmTTkrID string // latency measurement testtracker UUID + lmTitle string // latency measurement title +} + +// NewRebootParams returns RebootParams structure with default values. +func NewRebootParams() *RebootParams { + return &RebootParams{ + waitTime: 4 * time.Minute, + checkInterval: 20 * time.Second, + } +} + +// WithWaitTime adds the period of time to wait for the reboot operation to be +// successful. +func (p *RebootParams) WithWaitTime(t time.Duration) *RebootParams { + p.waitTime = t + return p +} + +// WithCheckInterval adds the time interval to check whether the reboot +// operation has been successful. +func (p *RebootParams) WithCheckInterval(t time.Duration) *RebootParams { + p.checkInterval = t + return p +} + +// WithRequest adds the reboot request in RebootParams. The reboot request can +// be one of the following: +// 1) RebootMethod such as syspb.RebootMethod_COLD. +// 2) RebootRequest protobuf. +func (p *RebootParams) WithRequest(r any) *RebootParams { + p.request = r + return p +} + +// WithLatencyMeasurement adds testtracker uuid and title for latency measurement. +func (p *RebootParams) WithLatencyMeasurement(testTrackerID, title string) *RebootParams { + p.lmTTkrID = testTrackerID + p.lmTitle = title + return p +} + +// measureLatency returns true if latency measurement parameters are set and valid. +func (p *RebootParams) measureLatency() bool { + return p.waitTime > 0 && p.lmTitle != "" +} + +// GNOIAble returns whether the gNOI server on the specified device is reachable +// or not. +func GNOIAble(t *testing.T, d *ondatra.DUTDevice) error { + // Time() gNOI request is used to verify the gNOI server reachability. + _, err := gnoiSystemClientGet(t, d).Time(context.Background(), &syspb.TimeRequest{}) + return err +} + +// HealthzGetPortDebugData returns port debug data given an interface. +func HealthzGetPortDebugData(t *testing.T, d *ondatra.DUTDevice, intfName string) error { + return fmt.Errorf("unimplemented method HealthzGetPortDebugData") +} From 366a5a3b44206ed0ff296deaffcac95633f6ad43 Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 15:55:47 -0400 Subject: [PATCH 07/10] [sdn_tests]: Adding LACP testhelper to pins_ondatra. --- .../infrastructure/testhelper/BUILD.bazel | 1 + .../infrastructure/testhelper/lacp.go | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel index a25c18bb040..b98a6d1726a 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel @@ -11,6 +11,7 @@ go_library( srcs = [ "gnmi.go", "gnoi.go", + "lacp.go", ], data = [ "//infrastructure/data", diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go new file mode 100644 index 00000000000..18d50eecd24 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/lacp.go @@ -0,0 +1,42 @@ +package testhelper + +import ( + "github.com/openconfig/ondatra/gnmi/oc" +) + +// PeerPorts holds the name of 2 Ethernet interfaces. These interfaces will be on separate machines, +// but connected to each other by a cable. +type PeerPorts struct { + Host string + Peer string +} + +// GeneratePortChannelInterface will return a minimal PortChannel interface that tests can extend as needed. +func GeneratePortChannelInterface(portChannelName string) oc.Interface { + enabled := true + + description := "PortChannel: " + portChannelName + " used for testing gNMI configuration." + minLinks := uint16(1) + + // Unsupported fields: Id, Aggregation/LagType + return oc.Interface{ + Name: &portChannelName, + Enabled: &enabled, + Type: oc.IETFInterfaces_InterfaceType_ieee8023adLag, + Description: &description, + Aggregation: &oc.Interface_Aggregation{ + LagType: oc.IfAggregate_AggregationType_LACP, + MinLinks: &minLinks, + }, + } +} + +// GenerateLACPInterface creates a minimal LACP interface that tests can then extend as needed. +func GenerateLACPInterface(pcName string) oc.Lacp_Interface { + + return oc.Lacp_Interface{ + Name: &pcName, + Interval: oc.Lacp_LacpPeriodType_FAST, + LacpMode: oc.Lacp_LacpActivityType_ACTIVE, + } +} From b66a3ec233bc53569f30667c87e6540fdde81eb1 Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Tue, 30 Apr 2024 16:19:31 -0400 Subject: [PATCH 08/10] [sdn_tests]: Adding P4RT testhelper to pins_ondatra. --- .../infrastructure/testhelper/BUILD.bazel | 1 + .../infrastructure/testhelper/p4rt.go | 305 ++++++++++++++++++ 2 files changed, 306 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel index b98a6d1726a..1c8d5d386be 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel @@ -12,6 +12,7 @@ go_library( "gnmi.go", "gnoi.go", "lacp.go", + "p4rt.go", ], data = [ "//infrastructure/data", diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go new file mode 100644 index 00000000000..e9f5092008c --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/p4rt.go @@ -0,0 +1,305 @@ +package testhelper + +// This file provides helper APIs to perform P4RT related operations. + +import ( + "context" + "encoding/hex" + "fmt" + "os" + "strconv" + "testing" + "time" + + log "github.com/golang/glog" + + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/pkg/errors" + "google.golang.org/grpc/codes" + "google.golang.org/protobuf/encoding/prototext" + + p4infopb "github.com/p4lang/p4runtime/go/p4/config/v1" + p4pb "github.com/p4lang/p4runtime/go/p4/v1" +) + +var ( + icName = "integrated_circuit0" + defaultDeviceID uint64 = 183934027 + + testhelperPortIDGet = func(t *testing.T, d *ondatra.DUTDevice, port string) (int, error) { + idInfo, present := gnmi.Lookup(t, d, gnmi.OC().Interface(port).Id().State()).Val() + if present { + return int(idInfo), nil + } + return 0, errors.Errorf("failed to get port ID for port %v from switch", port) + } + testhelperDeviceIDGet = func(t *testing.T, d *ondatra.DUTDevice) (uint64, error) { + deviceInfo, present := gnmi.Lookup(t, d, gnmi.OC().Component(icName).IntegratedCircuit().State()).Val() + if present && deviceInfo.NodeId != nil { + return *deviceInfo.NodeId, nil + } + // Configure default device ID on the switch. + gnmi.Replace(t, d, gnmi.OC().Component(icName).IntegratedCircuit().NodeId().Config(), defaultDeviceID) + // Verify that default device ID has been configured and return that. + if got, want := gnmi.Get(t, d, gnmi.OC().Component(icName).IntegratedCircuit().NodeId().State()), defaultDeviceID; got != want { + return 0, errors.Errorf("failed to configure default device ID") + } + return defaultDeviceID, nil + } +) + +// PacketOut structure enables the user to specify the following information for +// performing packet-out operation on the switch: +// EgressPort: Front panel port from which the packet needs to be sent out. +// Count: Number of packets to be egressed. +// Interval: Time interval between successive packet-out operations. +// Packet: Raw packet to be sent out. +type PacketOut struct { + SubmitToIngress bool + EgressPort string + Count uint + Interval time.Duration + Packet []byte +} + +// P4RTClient wraps P4RuntimeClient and implements methods for performing P4RT +// operations. +type P4RTClient struct { + client p4pb.P4RuntimeClient + stream p4pb.P4Runtime_StreamChannelClient + deviceID uint64 + electionID *p4pb.Uint128 + isMaster bool + dut *ondatra.DUTDevice + p4Info *p4infopb.P4Info +} + +// P4RTClientOptions contains the fields for creation of P4RTClient. +type P4RTClientOptions struct { + p4info *p4infopb.P4Info +} + +func generateElectionID() *p4pb.Uint128 { + // Get time in milliseconds. + t := uint64(time.Now().UnixNano() / 1000000) + return &p4pb.Uint128{ + Low: t % 1000, + High: t / 1000, + } +} + +// SetMastership tries to configure P4RT client as master by sending master +// arbitration request to the switch. +func (p *P4RTClient) SetMastership() error { + // Don't take any action if the client is already the master. + if p.isMaster { + return nil + } + + mastershipReq := &p4pb.StreamMessageRequest{ + Update: &p4pb.StreamMessageRequest_Arbitration{ + Arbitration: &p4pb.MasterArbitrationUpdate{ + DeviceId: p.deviceID, + ElectionId: p.electionID, + }, + }, + } + + log.Infof("Sending master arbitration request with DeviceId:%v, ElectionId:%v", p.deviceID, p.electionID) + if err := p.stream.Send(mastershipReq); err != nil { + return errors.Wrapf(err, "master arbitration send request failed") + } + + res, err := p.stream.Recv() + if err != nil { + return errors.Wrapf(err, "stream Recv() error") + } + + arb := res.GetArbitration() + if arb == nil { + return errors.Errorf("unexpected response received from switch: %v", res.String()) + } + if codes.Code(arb.Status.Code) != codes.OK { + return errors.Errorf("master arbitration failed (response status: %v)", arb.Status) + } + + log.Infof("Master arbitration successful: client is master") + p.isMaster = true + return nil +} + +// P4InfoDetails is an interface to get P4Info of a chassis. +type P4InfoDetails interface { + P4Info() (*p4infopb.P4Info, error) +} + +// P4Info gets P4Info of the switch. +func (p *P4RTClient) P4Info() (*p4infopb.P4Info, error) { + var p4Info *p4infopb.P4Info + err := fmt.Errorf("P4Info is not implemented") + + // Read P4Info from file. + p4Info = &p4infopb.P4Info{} + data, err := os.ReadFile("infrastructure/data/p4rtconfig.prototext") + if err != nil { + return nil, err + } + err = prototext.Unmarshal(data, p4Info) + + return p4Info, err +} + +// FetchP4Info fetches P4Info from the switch. +func (p *P4RTClient) FetchP4Info() (*p4infopb.P4Info, error) { + req := &p4pb.GetForwardingPipelineConfigRequest{DeviceId: p.deviceID} + resp, err := p.client.GetForwardingPipelineConfig(context.Background(), req) + if err != nil { + return nil, errors.Wrap(err, "GetForwardingPipelineConfig() failed") + } + if resp == nil { + return nil, errors.New("received nil GetForwardingPipelineConfigResponse") + } + config := resp.GetConfig() + if config == nil { + return nil, nil + } + return config.GetP4Info(), nil +} + +// PushP4Info pushes P4Info into the switch. +func (p *P4RTClient) PushP4Info() error { + var err error + if p.p4Info == nil { + p.p4Info, err = p.P4Info() + if err != nil { + return errors.Wrapf(err, "failed to fetch P4Info") + } + } + config := &p4pb.ForwardingPipelineConfig{ + P4Info: p.p4Info, + } + req := &p4pb.SetForwardingPipelineConfigRequest{ + DeviceId: p.deviceID, + ElectionId: p.electionID, + Action: p4pb.SetForwardingPipelineConfigRequest_RECONCILE_AND_COMMIT, + Config: config, + } + + _, err = p.client.SetForwardingPipelineConfig(context.Background(), req) + if err != nil { + return errors.Wrapf(err, "SetForwardingPipelineConfig operation failed") + } + + log.Infof("P4Info push successful") + return nil +} + +// FetchP4RTClient method fetches P4RTClient associated with a device. If the +// client does not exist, then it creates one and caches it for future use. +// During client creation, it performs master arbitration and P4Info push. +func FetchP4RTClient(t *testing.T, d *ondatra.DUTDevice, p p4pb.P4RuntimeClient, options *P4RTClientOptions) (*P4RTClient, error) { + p4Client := &P4RTClient{ + client: p, + dut: d, + } + if options != nil { + p4Client.p4Info = options.p4info + } + var err error + p4Client.deviceID, err = testhelperDeviceIDGet(t, d) + if err != nil { + return nil, err + } + // Create stream for master arbitration and packet I/O. + var streamErr error + p4Client.stream, streamErr = p4Client.client.StreamChannel(context.Background()) + if streamErr != nil { + return nil, errors.Wrap(streamErr, "failed to create stream for master arbitration") + } + + // Configure P4RT client as master. + p4Client.electionID = generateElectionID() + if err := p4Client.SetMastership(); err != nil { + return nil, errors.Wrap(err, "failed to configure P4RT client as master") + } + + // Push P4Info only if it isn't present in the switch. + p4Info, err := p4Client.FetchP4Info() + if err != nil { + return nil, errors.Wrap(err, "FetchP4Info() failed") + } + if p4Info == nil { + if err := p4Client.PushP4Info(); err != nil { + return nil, errors.Wrap(err, "P4Info push failed") + } + } + + return p4Client, nil +} + +// SendPacketOut instructs the P4RT server on the switch to perform packet-out +// operation. +func (p *P4RTClient) SendPacketOut(t *testing.T, packetOut *PacketOut) error { + // Validate user input parameters. + if packetOut.SubmitToIngress && packetOut.EgressPort != "" { + return errors.Errorf("cannot have both SubmitToIngress and EgressPort set in the packet-out request: %+v", packetOut) + } + + // Metadata value cannot be empty, so dummy value is set and ignored when SubmitToIngress is true. + portID := "Unused" + submitToIngress := []byte{0} + if packetOut.SubmitToIngress { + submitToIngress = []byte{1} + } else { + egressPortID, err := testhelperPortIDGet(t, p.dut, packetOut.EgressPort) + if err != nil { + return errors.Errorf("failed to get ID for port %v: %v", packetOut.EgressPort, err) + } + portID = strconv.Itoa(egressPortID) + } + + if packetOut.Count == 0 { + return errors.Errorf("packet-out count should be > 0 in packet-out request: %+v", packetOut) + } + count := packetOut.Count + interval := packetOut.Interval + + // Prepare packet I/O request. + pktOut := &p4pb.PacketOut{ + Payload: packetOut.Packet, + } + // Add egress_port metadata. + pktOut.Metadata = append(pktOut.Metadata, &p4pb.PacketMetadata{ + MetadataId: 1, + Value: []byte(portID), + }) + // Add submit_to_ingress metadata. + pktOut.Metadata = append(pktOut.Metadata, &p4pb.PacketMetadata{ + MetadataId: 2, + Value: submitToIngress, + }) + // Add unused_pad metadata. + pktOut.Metadata = append(pktOut.Metadata, &p4pb.PacketMetadata{ + MetadataId: 3, + Value: []byte{0}, + }) + packetOutReq := &p4pb.StreamMessageRequest{ + Update: &p4pb.StreamMessageRequest_Packet{Packet: pktOut}, + } + + log.Infof("Sending %v packets to the switch at %v interval. Packet:\n%v", count, interval, hex.Dump(packetOut.Packet)) + for c := uint(1); c <= count; c++ { + // Send packet-out request to the switch. + if err := p.stream.Send(packetOutReq); err != nil { + return errors.Errorf("Packet-out request failed for packet number: %v (%v)", c, err) + } + // Sleep only if user has specified time interval and more packets need to be sent. + if interval > 0 && c < count { + time.Sleep(interval) + } + } + + log.Infof("Packet-out operation completed") + return nil +} From 4f850ec8e22ec3a30f1c93817e2f5478dce5c723 Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Wed, 1 May 2024 03:52:31 -0400 Subject: [PATCH 09/10] [sdn_tests]: Adding Platform and port_management testhelper to pins_ondatra. --- .../infrastructure/testhelper/BUILD.bazel | 4 + .../testhelper/platform_components.go | 319 ++++++++++++++++++ .../testhelper/platform_info.go | 1 + .../testhelper/platform_info/BUILD.bazel | 10 + .../testhelper/platform_info/default.go | 48 +++ .../testhelper/platform_info/platform_info.go | 294 ++++++++++++++++ .../testhelper/port_management.go | 142 ++++++++ 7 files changed, 818 insertions(+) create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/platform_components.go create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info.go create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/BUILD.bazel create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/default.go create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/platform_info.go create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/port_management.go diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel index 1c8d5d386be..d3c2c2560e3 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel @@ -13,6 +13,10 @@ go_library( "gnoi.go", "lacp.go", "p4rt.go", + "platform_info.go", + "platform_components.go", + "port_management.go", + "//infrastructure/testhelper/platform_info:platform_info", ], data = [ "//infrastructure/data", diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_components.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_components.go new file mode 100644 index 00000000000..3cc537f7022 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_components.go @@ -0,0 +1,319 @@ +package testhelper + +import ( + "fmt" + "strings" +) + +// Software Component APIs. + +// SwitchNameRegex returns the regex for switch name. +func SwitchNameRegex() string { + return "" +} + +// ImageVersionRegex returns the regular expressions for the image version of the switch. +func ImageVersionRegex() []string { + return []string{ + "^pins_daily_(20\\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])_([0-1]?[0-9]|2[0-3])_RC(\\d{2})$", + "^pins_release_(20\\d{2})(0[1-9]|1[0-2])(0[1-9]|[12]\\d|3[01])_([0-1]?[0-9]|2[0-3])_(prod|dev)_RC(\\d{2})$", + } +} + +// System APIs. + +// GetIndex returns the CPU index. +func (c CPUInfo) GetIndex() uint32 { + return c.Index +} + +// GetMaxAverageUsage returns the maximum CPU average usage. +func (c CPUInfo) GetMaxAverageUsage() uint8 { + return c.MaxAverageUsage +} + + + + +// GetPhysical returns the expected physical memory. +func (m MemoryInfo) GetPhysical() uint64 { + return m.Physical +} + +// GetFreeThreshold returns the free memory threshold. +func (m MemoryInfo) GetFreeThreshold() uint64 { + return m.FreeThreshold +} + +// GetUsedThreshold returns the used memory threshold. +func (m MemoryInfo) GetUsedThreshold() uint64 { + return m.UsedThreshold +} + +// GetCorrectableEccErrorThreshold returns the correctable ECC error threshold. +func (m MemoryInfo) GetCorrectableEccErrorThreshold() uint64 { + return m.CorrectableEccErrorThreshold +} + + +// GetName returns the name of the mount point. +func (m MountPointInfo) GetName() string { + return m.Name +} + + +// GetIPv4Address returns NTP server's IPv4 addresses. +func (n NTPServerInfo) GetIPv4Address() []string { + return n.IPv4Address +} + +// GetIPv6Address returns NTP server's IPv6 addresses. +func (n NTPServerInfo) GetIPv6Address() []string { + return n.IPv6Address +} + +// GetStratumThreshold returns the stratum threshold for the NTP server. +func (n NTPServerInfo) GetStratumThreshold() uint8 { + return n.StratumThreshold +} + + +// Integrated Circuit APIs. + +// GetName returns the integrated-circuit name. +func (i IntegratedCircuitInfo) GetName() string { + return i.Name +} + +// GetCorrectedParityErrorsThreshold returns the corrected-parity-error +// threshold for the integrated-circuit. +func (i IntegratedCircuitInfo) GetCorrectedParityErrorsThreshold() uint64 { + return i.CorrectedParityErrorsThreshold +} + +// FPGA APIs. + +// GetName returns the FPGA name. +func (f FPGAInfo) GetName() string { + return f.Name +} + +// GetMfgName returns the FPGA manufacturer. +func (f FPGAInfo) GetMfgName() string { + return f.Manufacturer +} + +// GetDescription returns the FPGA description. +func (f FPGAInfo) GetDescription() string { + return f.Description +} + +// GetFirmwareVersionRegex returns the FPGA firmware version regex. +func (f FPGAInfo) GetFirmwareVersionRegex() string { + return f.FirmwareVersionRegex +} + +// GetResetCauseNum returns the number of reset causes reported by the FPGA. +func (f FPGAInfo) GetResetCauseNum() int { + return f.ResetCauseNum +} + + +// GetMin returns the minimum threshold for the power information. +func (p Threshold32) GetMin() float32 { + return p.Min +} + +// GetMax returns the maximum threshold for the power information. +func (p Threshold32) GetMax() float32 { + return p.Max +} + +// GetMin returns the minimum threshold for the power information. +func (p Threshold64) GetMin() float64 { + return p.Min +} + +// GetMax returns the maximum threshold for the power information. +func (p Threshold64) GetMax() float64 { + return p.Max +} + +// TemperatureSensorType defines the type of temperature sensors. +type TemperatureSensorType int + +// Type of temperature sensors. +const ( + CPUTempSensor TemperatureSensorType = iota + HeatsinkTempSensor + ExhaustTempSensor + InletTempSensor + DimmTempSensor +) + +// GetName returns the temperature sensor name. +func (t TemperatureSensorInfo) GetName() string { + return t.Name +} + +// GetLocation returns the temperature sensor location. +func (t TemperatureSensorInfo) GetLocation() string { + return t.Location +} + +// GetMaxTemperature returns the temperature threshold for the temperature sensor. +func (t TemperatureSensorInfo) GetMaxTemperature() float64 { + return t.MaxTemperature +} + + +// GetName returns the security component name. +func (s SecurityComponentInfo) GetName() string { + return s.Name +} + + +// IsValid checks if a value is in the thresholds. +func (t Thresholds[T]) IsValid(v T) bool { + if t.HasLo && v < t.Lo { + return false + } + if t.HasHi && v > t.Hi { + return false + } + return true +} + +// ThresholdsToString is a helper method to convert a set of thresholds to a readable string. +func (t Thresholds[T]) String() string { + var sb strings.Builder + if t.HasLo { + sb.WriteString("lo:>=") + sb.WriteString(fmt.Sprintf("%v", t.Lo)) + } else { + sb.WriteString("(no lo)") + } + sb.WriteString(" ") + + if t.HasHi { + sb.WriteString("hi:<=") + sb.WriteString(fmt.Sprintf("%v", t.Hi)) + } else { + sb.WriteString("(no hi)") + } + + return sb.String() +} + +// GetWriteAmplificationFactorThresholds returns the write amplification factor thresholds. +func (s SmartDataInfo) GetWriteAmplificationFactorThresholds() Thresholds[float64] { + return s.WriteAmplificationFactorThresholds +} + +// GetRawReadErrorRateThresholds returns the raw read error rate thresholds. +func (s SmartDataInfo) GetRawReadErrorRateThresholds() Thresholds[float64] { + return s.RawReadErrorRateThresholds +} + +// GetThroughputPerformanceThresholds returns the throughput performance thresholds. +func (s SmartDataInfo) GetThroughputPerformanceThresholds() Thresholds[float64] { + return s.ThroughputPerformanceThresholds +} + +// GetReallocatedSectorCountThresholds returns the throughput performance thresholds. +func (s SmartDataInfo) GetReallocatedSectorCountThresholds() Thresholds[uint64] { + return s.ReallocatedSectorCountThresholds +} + +// GetPowerOnSecondsThresholds returns the throughput performance thresholds. +func (s SmartDataInfo) GetPowerOnSecondsThresholds() Thresholds[uint64] { + return s.PowerOnSecondsThresholds +} + +// GetSsdLifeLeftThresholds returns the SSD life left thresholds. +func (s SmartDataInfo) GetSsdLifeLeftThresholds() Thresholds[uint64] { + return s.SSDLifeLeftThresholds +} + +// GetAvgEraseCountThresholds returns the average erase count thresholds. +func (s SmartDataInfo) GetAvgEraseCountThresholds() Thresholds[uint32] { + return s.AvgEraseCountThresholds +} + +// GetMaxEraseCountThresholds returns the average erase count thresholds. +func (s SmartDataInfo) GetMaxEraseCountThresholds() Thresholds[uint32] { + return s.MaxEraseCountThresholds +} + +// GetName returns the storage device name. +func (s StorageDeviceInfo) GetName() string { + return s.Name +} + +// GetIsRemovable returns whether the storage device is removable or not. +func (s StorageDeviceInfo) GetIsRemovable() bool { + return s.IsRemovable +} + +// GetIoErrorsThreshold returns the threshold for storage device I/O errors. +func (s StorageDeviceInfo) GetIoErrorsThreshold() uint64 { + return s.IOErrorsThreshold +} + +// GetSmartDataInfo returns the SMART data info. +func (s StorageDeviceInfo) GetSmartDataInfo() SmartDataInfo { + return s.SmartDataInfo +} + + +// GetName returns the fan name. +func (f FanInfo) GetName() string { + return f.Name +} + +// GetIsRemovable returns whether the fan is removable or not. +func (f FanInfo) GetIsRemovable() bool { + return f.IsRemovable +} + +// GetLocation returns the location of the fan. +func (f FanInfo) GetLocation() string { + return f.Location +} + +// GetMaxSpeed returns the maximum speed of the fan. +func (f FanInfo) GetMaxSpeed() uint32 { + return f.MaxSpeed +} + +// GetParent returns the parent component of the fan. +func (f FanInfo) GetParent() string { + return f.Parent +} + +// GetName returns the fan tray name. +func (f FanTrayInfo) GetName() string { + return f.Name +} + +// GetIsRemovable returns whether the fan tray is removable or not. +func (f FanTrayInfo) GetIsRemovable() bool { + return f.IsRemovable +} + +// GetParent returns the parent component of the fan tray. +func (f FanTrayInfo) GetParent() string { + return f.Parent +} + +// GetLocation returns the location of the fan tray. +func (f FanTrayInfo) GetLocation() string { + return f.Location +} + + + +// GetName returns the PCIe device name. +func (p PCIeInfo) GetName() string { + return p.Name +} diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info.go new file mode 100644 index 00000000000..9110d4311e0 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info.go @@ -0,0 +1 @@ +package testhelper diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/BUILD.bazel new file mode 100644 index 00000000000..c33a96e7f52 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/BUILD.bazel @@ -0,0 +1,10 @@ +package( + default_visibility = ["//visibility:public"], + licenses = ["notice"], +) + +filegroup( + name = "platform_info", + srcs = glob(["*.go"]), + visibility = ["//visibility:public"], +) diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/default.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/default.go new file mode 100644 index 00000000000..8b6c09bdf2c --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/default.go @@ -0,0 +1,48 @@ +package testhelper + +import ( + "testing" + + "github.com/openconfig/ondatra" +) + +type defaultPlatform struct { + infoBuilder + platformInfo PlatformInfo + portInfo PortInfo +} + +var platform = defaultPlatform{ + platformInfo: PlatformInfo{ + SystemInfo: SystemInfo{ + RebootTime: 360000000000, + }, + HardwareInfo: HardwareInfo{}, + }, + portInfo: PortInfo{ + MaxLanes: 8, + PMD: map[PMDType]bool{ + "ETH_200GBASE_BSM8": true, + "ETH_2X200GBASE_BGR4": true, + "ETH_2X400GBASE_CDGR4_PLUS": true, + "ETH_2X400GBASE_CR4": true, + "ETH_2X400GBASE_DR4": true, + "ETH_2X400GBASE_PSM4": true, + }, + PortProperties: map[string]*PortProperty{}, + }, +} + +func (d *defaultPlatform) newPlatformInfo(t *testing.T, dut *ondatra.DUTDevice) (*PlatformInfo, error) { + ret := d.platformInfo + return &ret, nil +} + +func (d *defaultPlatform) newPortInfo(t *testing.T, dut *ondatra.DUTDevice) (*PortInfo, error) { + ret := d.portInfo + return &ret, nil +} + +func init() { + registerPlatform("default", &platform) +} diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/platform_info.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/platform_info.go new file mode 100644 index 00000000000..eb727a6cdab --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/platform_info/platform_info.go @@ -0,0 +1,294 @@ +package testhelper + +import ( + "fmt" + "log" + "testing" + "time" + + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi/oc" +) + +// LoggingInfo contains a remote server addresses to be used for logging. +type LoggingInfo struct { + IPv4RemoteAddresses []string + IPv6RemoteAddresses []string +} + +// CPUInfo contains CPU-related information. +type CPUInfo struct { + Index uint32 + MaxAverageUsage uint8 +} + +// MemoryInfo contains memory related information. +type MemoryInfo struct { + Physical uint64 + FreeThreshold uint64 + UsedThreshold uint64 + CorrectableEccErrorThreshold uint64 +} + +// NTPServerInfo returns NTP server related information. +type NTPServerInfo struct { + IPv4Address []string + IPv6Address []string + StratumThreshold uint8 +} + +// FPGAInfo consists of FPGA related information. +type FPGAInfo struct { + Name string + Manufacturer string + Description string + FirmwareVersionRegex string + ResetCauseNum int +} + +// IntegratedCircuitInfo consists of integrated-circuit related information. +type IntegratedCircuitInfo struct { + Name string + CorrectedParityErrorsThreshold uint64 +} + +// Threshold32 consists of the minimum and maximum thresholds as a float32. +type Threshold32 struct { + Min float32 + Max float32 +} + +// Threshold64 consists of the minimum and maximum thresholds as a float64. +type Threshold64 struct { + Min float64 + Max float64 +} + +// TemperatureSensorInfo consists of temperature sensor related information. +type TemperatureSensorInfo struct { + Name string + Location string + MaxTemperature float64 +} + +// SecurityComponentInfo consists of security component related information. +type SecurityComponentInfo struct { + Name string +} + +// Threshold is any numeric type that is used as a lower or upper threshold. +type Threshold interface { + float64 | uint64 | uint32 +} + +// Thresholds encapsulates a set of inclusive lower and upper thresholds. +type Thresholds[T Threshold] struct { + HasLo bool + Lo T + HasHi bool + Hi T +} + +// SmartDataInfo consists of storage device SMART data related information. +type SmartDataInfo struct { + WriteAmplificationFactorThresholds Thresholds[float64] + RawReadErrorRateThresholds Thresholds[float64] + ThroughputPerformanceThresholds Thresholds[float64] + ReallocatedSectorCountThresholds Thresholds[uint64] + PowerOnSecondsThresholds Thresholds[uint64] + SSDLifeLeftThresholds Thresholds[uint64] + AvgEraseCountThresholds Thresholds[uint32] + MaxEraseCountThresholds Thresholds[uint32] +} + +// StorageDeviceInfo consists of storage device related information. +type StorageDeviceInfo struct { + Name string + IsRemovable bool + IOErrorsThreshold uint64 + SmartDataInfo SmartDataInfo +} + +// FanInfo consists of fan related information. +type FanInfo struct { + Name string + IsRemovable bool + Parent string + Location string + MaxSpeed uint32 +} + +// PcieInfo consists of PCIe device related information. +type PCIeInfo struct { + Name string +} + +// FanTrayInfo consists of fan tray related information. +type FanTrayInfo struct { + Name string + IsRemovable bool + Parent string + Location string +} + +// MountPointInfo returns mount points related information. +type MountPointInfo struct { + Name string +} + +// HardwareInfo contains hardware components related information. +type HardwareInfo struct { + Fans []FanInfo + Fantrays []FanTrayInfo + FPGAs []FPGAInfo + ICs []IntegratedCircuitInfo + PCIe []PCIeInfo + Security []SecurityComponentInfo + Storage []StorageDeviceInfo + CPU []TemperatureSensorInfo + Heatsink []TemperatureSensorInfo + Exhaust []TemperatureSensorInfo + Inlet []TemperatureSensorInfo + Dimm []TemperatureSensorInfo +} + +// SystemInfo consists of system related information. +type SystemInfo struct { + RebootTime time.Duration + CPUInfo []CPUInfo + LoggingInfo LoggingInfo + MemInfo MemoryInfo + MountPointInfo []MountPointInfo + NTPServerInfo []NTPServerInfo +} + +// PlatformInfo contains platform specific information. +type PlatformInfo struct { + SystemInfo SystemInfo + HardwareInfo HardwareInfo + build func(t *testing.T, dut *ondatra.DUTDevice, p *PlatformInfo) error +} + +// Lanes represents number of lanes. +type Lanes int + +// PMDProperty contain PMD information. +type PMDProperty struct { + SupportedSpeeds map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED + SupportedBreakoutModes []string + CollateralFlap bool +} + +type PMDType string + +var pmdProperties = map[PMDType]*PMDProperty{ + "ETH_2X400GBASE_PSM4": &PMDProperty{ + CollateralFlap: false, + SupportedSpeeds: map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED{ + 4: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB}, + 2: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB}, + }, + SupportedBreakoutModes: []string{"2x400G", "4x200G", "1x400G(4)+2x200G(4)", "2x200G(4),+1x400G(4)"}, + }, + "ETH_2X400GBASE_DR4": &PMDProperty{ + CollateralFlap: false, + SupportedSpeeds: map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED{ + 4: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB}, + 2: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB}, + 1: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB}, + }, + SupportedBreakoutModes: []string{"8x100G", "2x400G", "4x200G", "1x400G(4)+2x200G(4)", "2x200G(4)+1x400G(4)"}, + }, + "ETH_2X200GBASE_BGR4": &PMDProperty{ + CollateralFlap: false, + SupportedSpeeds: map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED{ + 4: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB}, + 2: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_50GB}, + }, + SupportedBreakoutModes: []string{"1x200G(4)+2x50G(4)", "2x50G(4)+1x200G(4)"}, + }, + + "ETH_200GBASE_BSM8": &PMDProperty{ + CollateralFlap: false, + SupportedSpeeds: map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED{ + 2: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_50GB}, + }, + SupportedBreakoutModes: []string{"1x200G(4)+2x50G(4)", "2x50G(4)+1x200G(4)"}, + }, + "ETH_2X400GBASE_CDGR4_PLUS": &PMDProperty{ + CollateralFlap: true, + SupportedSpeeds: map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED{ + 4: []oc.E_IfEthernet_ETHERNET_SPEED{ + oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB, + oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB, + oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB, + }, + }, + SupportedBreakoutModes: []string{"2x400G", "2x200G", "2x100G", "1x400G(4)+1x200G(4)", "1x400G(4)+1x100G(4)", "1x200G(4)+1x400G(4)", "1x200G(4)+1x100G(4)", "1x100G(4)+1x400G(4)", "1x100G(4)+1x200G(4)"}, + }, + "ETH_2X400GBASE_CR4": &PMDProperty{ + CollateralFlap: false, + SupportedSpeeds: map[Lanes][]oc.E_IfEthernet_ETHERNET_SPEED{ + 4: []oc.E_IfEthernet_ETHERNET_SPEED{oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB}, + }, + SupportedBreakoutModes: []string{"2x400G"}, + }, +} + +// PortProperties contains front panel port information. +type PortProperty struct { + Index int + DefaultBreakoutMode string + MediaType string +} + +func (p *PortInfo) PMDProperty(pmdType PMDType) (*PMDProperty, error) { + if _, ok := p.PMD[pmdType]; !ok { + return nil, fmt.Errorf("PMDType : %v not supported by the PortInfo", pmdType) + } + if v, ok := pmdProperties[pmdType]; ok { + ret := *v + return &ret, nil + } + return nil, fmt.Errorf("PMDType : %v not defined in pmdProperties", pmdType) +} + +// PortInfo contains port related information. +type PortInfo struct { + MaxLanes int + PortProperties map[string]*PortProperty + PMD map[PMDType]bool + build func(t *testing.T, dut *ondatra.DUTDevice, p *PortInfo) error +} + +type infoBuilder interface { + newPlatformInfo(t *testing.T, dut *ondatra.DUTDevice) (*PlatformInfo, error) + newPortInfo(t *testing.T, dut *ondatra.DUTDevice) (*PortInfo, error) +} + +var platforms = map[string]infoBuilder{} + +func registerPlatform(platformName string, val infoBuilder) { + if _, ok := platforms[platformName]; ok { + log.Fatalf("platform : %v already registered.", platformName) + } + platforms[platformName] = val +} + +// NewPortInfo creates a new PortInfo. +func NewPortInfo(t *testing.T, dut *ondatra.DUTDevice, platformName string) (*PortInfo, error) { + val, ok := platforms[platformName] + if !ok { + return nil, fmt.Errorf("PortInfo struct not found for : %v", platformName) + } + return val.newPortInfo(t, dut) +} + +// NewPlatformInfo creates a new PlatformInfo. +func NewPlatformInfo(t *testing.T, dut *ondatra.DUTDevice, platformName string) (*PlatformInfo, error) { + val, ok := platforms[platformName] + if !ok { + return nil, fmt.Errorf("PlatformInfo struct not found for : %v", platformName) + } + return val.newPlatformInfo(t, dut) +} diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/port_management.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/port_management.go new file mode 100644 index 00000000000..18be71a8308 --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/port_management.go @@ -0,0 +1,142 @@ +package testhelper + +// This file provides helper APIs to perform ports related operations. + +import ( + "strconv" + "strings" + + "github.com/openconfig/ondatra/gnmi/oc" +) + +type speedEnumInfo struct { + // Speed value in string format in bits/second. + speedStr string + // Speed value in integer format in bits/second. + speedInt uint64 +} + +var stringToEnumSpeedMap = map[string]oc.E_IfEthernet_ETHERNET_SPEED{ + "10M": oc.IfEthernet_ETHERNET_SPEED_SPEED_10MB, + "100M": oc.IfEthernet_ETHERNET_SPEED_SPEED_100MB, + "1G": oc.IfEthernet_ETHERNET_SPEED_SPEED_1GB, + "2500M": oc.IfEthernet_ETHERNET_SPEED_SPEED_2500MB, + "5G": oc.IfEthernet_ETHERNET_SPEED_SPEED_5GB, + "10G": oc.IfEthernet_ETHERNET_SPEED_SPEED_10GB, + "25G": oc.IfEthernet_ETHERNET_SPEED_SPEED_25GB, + "40G": oc.IfEthernet_ETHERNET_SPEED_SPEED_40GB, + "50G": oc.IfEthernet_ETHERNET_SPEED_SPEED_50GB, + "100G": oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB, + "200G": oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB, + "400G": oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB, + "600G": oc.IfEthernet_ETHERNET_SPEED_SPEED_600GB, + "800G": oc.IfEthernet_ETHERNET_SPEED_SPEED_800GB, +} + +var enumToSpeedInfoMap = map[oc.E_IfEthernet_ETHERNET_SPEED]speedEnumInfo{ + oc.IfEthernet_ETHERNET_SPEED_SPEED_10MB: {"10M", 10_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_100MB: {"100M", 100_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_1GB: {"1G", 1_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_2500MB: {"2500M", 2500_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_5GB: {"5G", 5_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_10GB: {"10G", 10_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_25GB: {"25G", 25_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_40GB: {"40G", 40_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_50GB: {"50G", 50_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB: {"100G", 100_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB: {"200G", 200_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB: {"400G", 400_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_600GB: {"600G", 600_000_000_000}, + oc.IfEthernet_ETHERNET_SPEED_SPEED_800GB: {"800G", 800_000_000_000}, +} + +// Indices for slot, port and lane number in Ethernet port naming format. +const ( + slotIndex int = iota + portIndex + laneIndex +) + +// PortProperties contains front panel port information. +type PortProperties struct { + index int + supportedSpeeds map[string]map[int][]oc.E_IfEthernet_ETHERNET_SPEED + defaultBreakoutMode string + supportedBreakoutModes map[string][]string + mediaType string +} + +// RandomPortBreakoutInfo contains information about a randomly picked port on the switch. +type RandomPortBreakoutInfo struct { + PortName string // Randomly selected port on switch. + CurrBreakoutMode string // Currently configured breakout mode on the port. + SupportedBreakoutMode string // Supported breakout mode on port different from current breakout mode. +} + +// BreakoutType describes the possible types of breakout modes +type BreakoutType int + +const ( + // Unset indicates a not set breakout mode to be used where breakout is not applicable. + Unset BreakoutType = iota + // Any indicates any breakout modes (mixed as well as non-mixed) + Any + // Mixed indicates mixed breakout modes only + Mixed + // NonMixed indicates non mixed breakout only + NonMixed + // Channelized indicates breakout mode with at least one more port other than parent port. + // This mode is used to test breakout with subinterface config on child port. + Channelized + // SpeedChangeOnly indicates breakout mode that results in a speed change only (no lane change) on requested number of ports. + SpeedChangeOnly +) + +// PortBreakoutInfo contains list of resultant ports for a given breakout mode and physical channels and operational status for each interface. +type PortBreakoutInfo struct { + PhysicalChannels []uint16 + OperStatus oc.E_Interface_OperStatus + PortSpeed oc.E_IfEthernet_ETHERNET_SPEED +} + +// RandomPortWithSupportedBreakoutModesParams contains list of additional parameters for RandomPortWithSupportedBreakoutModes +type RandomPortWithSupportedBreakoutModesParams struct { + CurrBreakoutType BreakoutType // mixed/non-mixed/any/channelized + NewBreakoutType BreakoutType // mixed/non-mixed/any/channelized + SpeedChangeOnlyPortCount int // number of ports that are required to change in speed only on breakout + PortList []string // List of ports from which a random port can be selected +} + +// Uint16ListToString returns comma separate string representation of list of uint16. +func Uint16ListToString(a []uint16) string { + s := make([]string, len(a)) + for index, value := range a { + s[index] = strconv.Itoa(int(value)) + } + return strings.Join(s, ",") +} + +func fecMode(portSpeed oc.E_IfEthernet_ETHERNET_SPEED, lanes uint8) oc.E_IfEthernet_INTERFACE_FEC { + switch portSpeed { + case oc.IfEthernet_ETHERNET_SPEED_SPEED_400GB: + return oc.IfEthernet_INTERFACE_FEC_FEC_RS544_2X_INTERLEAVE + case oc.IfEthernet_ETHERNET_SPEED_SPEED_200GB: + return oc.IfEthernet_INTERFACE_FEC_FEC_RS544_2X_INTERLEAVE + case oc.IfEthernet_ETHERNET_SPEED_SPEED_100GB: + switch lanes { + case 1, 2: + return oc.IfEthernet_INTERFACE_FEC_FEC_RS544 + case 4: + return oc.IfEthernet_INTERFACE_FEC_FEC_RS528 + } + case oc.IfEthernet_ETHERNET_SPEED_SPEED_50GB: + switch lanes { + case 1: + return oc.IfEthernet_INTERFACE_FEC_FEC_RS544 + case 2: + return oc.IfEthernet_INTERFACE_FEC_FEC_DISABLED + } + } + + return oc.IfEthernet_INTERFACE_FEC_FEC_DISABLED +} From 06aa285ece7379e16782e6a4beca0611d74dd646 Mon Sep 17 00:00:00 2001 From: vsuryaprasad-hcl Date: Wed, 1 May 2024 04:54:04 -0400 Subject: [PATCH 10/10] [sdn_tests]: Adding testhelper to pins_ondatra. --- .../infrastructure/testhelper/BUILD.bazel | 3 +- .../infrastructure/testhelper/testhelper.go | 383 ++++++++++++++++++ 2 files changed, 385 insertions(+), 1 deletion(-) create mode 100644 sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper.go diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel index d3c2c2560e3..a6535a3ae05 100644 --- a/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/BUILD.bazel @@ -13,8 +13,9 @@ go_library( "gnoi.go", "lacp.go", "p4rt.go", - "platform_info.go", + "testhelper.go", "platform_components.go", + "platform_info.go", "port_management.go", "//infrastructure/testhelper/platform_info:platform_info", ], diff --git a/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper.go b/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper.go new file mode 100644 index 00000000000..9b2006a979e --- /dev/null +++ b/sdn_tests/pins_ondatra/infrastructure/testhelper/testhelper.go @@ -0,0 +1,383 @@ +// Package testhelper contains APIs that help in writing GPINs Ondatra tests. +package testhelper + +import ( + "crypto/rand" + "strings" + "testing" + "time" + + log "github.com/golang/glog" + healthzpb "github.com/openconfig/gnoi/healthz" + "github.com/openconfig/ondatra" + "github.com/openconfig/ondatra/gnmi" + "github.com/openconfig/ondatra/gnmi/oc" + "github.com/openconfig/ygnmi/ygnmi" + "github.com/pkg/errors" +) + +var pph portPmdHandler + +// Function pointers that interact with the switch. They enable unit testing +// of methods that interact with the switch. +var ( + testhelperIntfOperStatusGet = func(t *testing.T, d *ondatra.DUTDevice, port string) oc.E_Interface_OperStatus { + return gnmi.Get(t, d, gnmi.OC().Interface(port).OperStatus().State()) + } + + testhelperAllIntfNameGet = func(t *testing.T, d *ondatra.DUTDevice) []string { + return gnmi.GetAll(t, d, gnmi.OC().InterfaceAny().Name().State()) + } + + testhelperDUTNameGet = func(d *ondatra.DUTDevice) string { + return d.Name() + } + + testhelperDUTPortGet = func(t *testing.T, d *ondatra.DUTDevice, id string) *ondatra.Port { + return d.Port(t, id) + } + + testhelperDUTPortsGet = func(d *ondatra.DUTDevice) []*ondatra.Port { + return d.Ports() + } + + testhelperConfigIntfAggregateIDGet = func(t *testing.T, d *ondatra.DUTDevice, port string) string { + return gnmi.Get(t, d, gnmi.OC().Interface(port).Ethernet().AggregateId().Config()) + } + + testhelperIntfAggregateIDReplace = func(t *testing.T, d *ondatra.DUTDevice, port string, ID string) { + gnmi.Replace(t, d, gnmi.OC().Interface(port).Ethernet().AggregateId().Config(), ID) + } + + testhelperIntfPhysicalChannelsGet = func(t *testing.T, d *ondatra.DUTDevice, port string) []uint16 { + return gnmi.Get(t, d, gnmi.OC().Interface(port).PhysicalChannel().State()) + } + + testhelperIntfOperStatusAwait = func(t *testing.T, d *ondatra.DUTDevice, port string, expectedOperSatus oc.E_Interface_OperStatus, timeout time.Duration) (oc.E_Interface_OperStatus, bool) { + predicate := func(val *ygnmi.Value[oc.E_Interface_OperStatus]) bool { + status, present := val.Val() + return present && status == expectedOperSatus + } + lastVal, match := gnmi.Watch(t, d, gnmi.OC().Interface(port).OperStatus().State(), timeout, predicate).Await(t) + lastStatus, _ := lastVal.Val() + return lastStatus, match + } + + testhelperIntfDelete = func(t *testing.T, d *ondatra.DUTDevice, port string) { + gnmi.Delete(t, d, gnmi.OC().Interface(port).Config()) + } + + testhelperIntfLookup = func(t *testing.T, d *ondatra.DUTDevice, port string) *ygnmi.Value[*oc.Interface] { + return gnmi.Lookup(t, d, gnmi.OC().Interface(port).State()) + } + + testhelperIntfHardwarePortGet = func(t *testing.T, d *ondatra.DUTDevice, port string) string { + return gnmi.Get(t, d, gnmi.OC().Interface(port).HardwarePort().State()) + } + + testhelperConfigPortSpeedGet = func(t *testing.T, d *ondatra.DUTDevice, portName string) oc.E_IfEthernet_ETHERNET_SPEED { + return gnmi.Get(t, d, gnmi.OC().Interface(portName).Ethernet().PortSpeed().Config()) + } + + testhelperStatePortSpeedGet = func(t *testing.T, d *ondatra.DUTDevice, portName string) oc.E_IfEthernet_ETHERNET_SPEED { + return gnmi.Get(t, d, gnmi.OC().Interface(portName).Ethernet().PortSpeed().State()) + } + + testhelperOndatraPortNameGet = func(p *ondatra.Port) string { + return p.Name() + } + + testhelperOndatraPortIDGet = func(p *ondatra.Port) string { + return p.ID() + } + + teardownDUTNameGet = func(t *testing.T) string { + return ondatra.DUT(t, "DUT").Name() + } + + teardownDUTDeviceInfoGet = func(t *testing.T) DUTInfo { + dut := ondatra.DUT(t, "DUT") + return DUTInfo{ + name: dut.Name(), + vendor: dut.Vendor(), + } + } + + teardownDUTPeerDeviceInfoGet = func(t *testing.T) DUTInfo { + duts := ondatra.DUTs(t) + if len(duts) <= 1 { + return DUTInfo{} + } + + if peer, ok := duts["CONTROL"]; ok { + return DUTInfo{ + name: peer.Name(), + vendor: peer.Vendor(), + } + } + return DUTInfo{} + } + + teardownDUTHealthzGet = func(t *testing.T) healthzpb.HealthzClient { + return ondatra.DUT(t, "DUT").RawAPIs().GNOI(t).Healthz() + } + + teardownDUTPeerHealthzGet = func(t *testing.T) healthzpb.HealthzClient { + return ondatra.DUT(t, "CONTROL").RawAPIs().GNOI(t).Healthz() + } + + testhelperBreakoutModeGet = func(t *testing.T, d *ondatra.DUTDevice, physicalPort string) *oc.Component_Port_BreakoutMode { + return gnmi.Get(t, d, gnmi.OC().Component(physicalPort).Port().BreakoutMode().State()) + } + + testhelperTransceiverEmpty = func(t *testing.T, d *ondatra.DUTDevice, port string) bool { + return gnmi.Get(t, d, gnmi.OC().Component(port).Empty().State()) + } +) + +// FrontPanelPortPrefix defines prefix string for front panel ports. +const ( + FrontPanelPortPrefix = "Ethernet" +) + +// RandomInterfaceParams contains optional list of parameters than can be passed to RandomInterface(): +// PortList: If passed, only ports in this list must be considered when picking a random interface. +// IsParent: If set, only parent ports must be considered. +// OperDownOk: If set, then operationally down ports can also be picked. +type RandomInterfaceParams struct { + PortList []string + IsParent bool + OperDownOk bool +} + +// OperStatusInfo returns the list of interfaces with the following oper-status: +// 1) UP +// 2) DOWN +// 3) TESTING +// 4) Any other value +type OperStatusInfo struct { + Up []string + Down []string + Testing []string + Invalid []string +} + +// DUTInfo contains dut related info. +type DUTInfo struct { + name string + vendor ondatra.Vendor +} + +// NewDUTInfo creates the DUTInfo structure for a given DUTDevice +func NewDUTInfo(t *testing.T, dut *ondatra.DUTDevice) DUTInfo { + return DUTInfo{ + name: dut.Name(), + vendor: dut.Vendor(), + } +} + +// TearDownOptions consist of the options to be taken into account by the teardown method. +type TearDownOptions struct { + StartTime time.Time + DUTName string + IDs []string + DUTDeviceInfo DUTInfo + DUTPeerDeviceInfo DUTInfo + SaveLogs func(t *testing.T, savePrefix string, dut, peer DUTInfo) +} + +// NewTearDownOptions creates the TearDownOptions structure with default values. +func NewTearDownOptions(t *testing.T) TearDownOptions { + return TearDownOptions{ + StartTime: time.Now(), + DUTName: teardownDUTNameGet(t), + DUTDeviceInfo: teardownDUTDeviceInfoGet(t), + DUTPeerDeviceInfo: teardownDUTPeerDeviceInfoGet(t), + } +} + +// WithID attaches an ID to the test. +func (o TearDownOptions) WithID(id string) TearDownOptions { + o.IDs = append(o.IDs, id) + return o +} + +// WithIDs attaches a list of IDs to the test. +func (o TearDownOptions) WithIDs(ids []string) TearDownOptions { + for _, id := range ids { + o.IDs = append(o.IDs, id) + } + return o +} + +// TearDown provides an interface to implement the teardown routine. +type TearDown interface { + Teardown(t *testing.T) +} + +// infoHandler is a holder for populateInfoHandlers interface. +type infoHandler struct{} + +// RandomInterface picks a random front panel port which is operationally UP. +// Many tests typically need a link that is up, so we'll return +// a randomly selected interface if it is Operationally UP. Options can be passed +// to this method using RandomInterfaceParams struct. +func RandomInterface(t *testing.T, dut *ondatra.DUTDevice, params *RandomInterfaceParams) (string, error) { + // Parse additional parameters + var portList []string + isOperDownOk := false + if params != nil { + portList = params.PortList + isOperDownOk = params.OperDownOk + } + + info, err := FetchPortsOperStatus(t, dut, portList...) + if err != nil || info == nil { + return "", errors.Wrap(err, "failed to fetch ports oper-status") + } + + // By default this API considers only operationally UP ports. + interfaces := info.Up + if isOperDownOk { + interfaces = append(interfaces, info.Down...) + } + + if len(interfaces) == 0 { + if params == nil { + return "", errors.Errorf("no operationally UP interfaces found in %v", testhelperDUTNameGet(dut)) + } + return "", errors.Errorf("no interface found in %v with params: %+v", testhelperDUTNameGet(dut), *params) + } + s := interfaces[rand.Intn(len(interfaces))] + + log.Infof("Using interface %v (%d considered)", s, len(interfaces)) + return s, nil +} + +// FetchPortsOperStatus fetches the oper-status of the specified front +// panel ports. If front panel ports are not specified, then it fetches the +// oper-status for all ports on the device. It returns the list of ports with +// oper-status values present in OperStatusInfo struct. +func FetchPortsOperStatus(t *testing.T, d *ondatra.DUTDevice, ports ...string) (*OperStatusInfo, error) { + if len(ports) == 0 { + var err error + ports, err = FrontPanelPortListForDevice(t, d) + if err != nil { + return nil, errors.Wrap(err, "failed to fetch front panel ports") + } + } + + operStatusInfo := &OperStatusInfo{} + for _, port := range ports { + switch operStatus := testhelperIntfOperStatusGet(t, d, port); operStatus { + case oc.Interface_OperStatus_UP: + operStatusInfo.Up = append(operStatusInfo.Up, port) + case oc.Interface_OperStatus_DOWN: + operStatusInfo.Down = append(operStatusInfo.Down, port) + case oc.Interface_OperStatus_TESTING: + operStatusInfo.Testing = append(operStatusInfo.Testing, port) + default: + operStatusInfo.Invalid = append(operStatusInfo.Invalid, port) + } + } + + return operStatusInfo, nil +} + +// VerifyPortsOperStatus verifies that the oper-status of the specified front +// panel ports is up. If front panel ports are not specified, then it verifies +// the oper-status for all ports on the device. +func VerifyPortsOperStatus(t *testing.T, d *ondatra.DUTDevice, ports ...string) error { + i, err := FetchPortsOperStatus(t, d, ports...) + if err != nil { + return errors.Wrap(err, "failed to fetch ports oper-status") + } + if len(i.Down) > 0 || len(i.Testing) > 0 || len(i.Invalid) > 0 { + return errors.Errorf("some interfaces are not operationally up: %+v", *i) + } + return nil +} + +// IsFrontPanelPort returns true if the specified port is a front panel port. +func IsFrontPanelPort(port string) bool { + return strings.HasPrefix(port, FrontPanelPortPrefix) +} + +// FrontPanelPortListForDevice returns the list of front panel ports on the switch. +func FrontPanelPortListForDevice(t *testing.T, dut *ondatra.DUTDevice) ([]string, error) { + var frontPanelPortList []string + // Filter-out non-front panel ports. + for _, port := range testhelperAllIntfNameGet(t, dut) { + if IsFrontPanelPort(port) { + frontPanelPortList = append(frontPanelPortList, port) + } + } + if len(frontPanelPortList) == 0 { + return nil, errors.New("no front panel port found") + } + + return frontPanelPortList, nil +} + +// Returns platform-specific information. +func platformInfoForDevice(t *testing.T, dut *ondatra.DUTDevice) (*PlatformInfo, error) { + return NewPlatformInfo(t, dut, "default") +} + +// Returns port-specific information. +func portInfoForDevice(t *testing.T, dut *ondatra.DUTDevice) (*PortInfo, error) { + // Populate port properties statically for front panel ports. + return NewPortInfo(t, dut, "default") +} + +// WrapError wraps a new error with new line or creates a new error if +// err == nil. It has been created because errors.Wrapf() returns nil +// if err == nil. +func WrapError(err error, format string, args ...any) error { + format = format + "\n" + if err == nil { + return errors.Errorf(format, args...) + } + return errors.Wrapf(err, format, args...) +} + +// DUTPortNames returns the port names of the DUT. +func DUTPortNames(dut *ondatra.DUTDevice) []string { + var portNames []string + for _, port := range testhelperDUTPortsGet(dut) { + portNames = append(portNames, testhelperOndatraPortNameGet(port)) + } + return portNames +} + +// populatePortPMDInfo provides api to return list of ports with given pmd type from a set of ports. +type populatePortPMDInfo interface { + portsOfPmdType(dutName string, portNames []string, pmdType oc.E_TransportTypes_ETHERNET_PMD_TYPE) ([]string, error) +} + +// portPmdHandler holds the mapping from port names to transceiver. +type portPmdHandler struct { + PortToTransceiver map[string]string +} + +func (p portPmdHandler) portPmdType(dutName string, port string) (oc.E_TransportTypes_ETHERNET_PMD_TYPE, error) { + return oc.TransportTypes_ETHERNET_PMD_TYPE_ETH_UNDEFINED, nil +} + +func (p portPmdHandler) portsOfPmdType(dutName string, portNames []string, pmdType oc.E_TransportTypes_ETHERNET_PMD_TYPE) ([]string, error) { + var ports []string + return ports, nil +} + +// AvailablePortsOfPMDType returns ports with matching PMD type. +func AvailablePortsOfPMDType(t *testing.T, d *ondatra.DUTDevice, pmdType oc.E_TransportTypes_ETHERNET_PMD_TYPE) ([]string, error) { + if pph.PortToTransceiver == nil { + pph.PortToTransceiver = make(map[string]string) + } + for _, port := range DUTPortNames(d) { + if pph.PortToTransceiver[port] == "" { + pph.PortToTransceiver[port] = gnmi.Get(t, d, gnmi.OC().Interface(port).Transceiver().State()) + } + } + return pph.portsOfPmdType(d.Name(), DUTPortNames(d), pmdType) +}