├── img └── readme │ ├── slack-128.png │ ├── slack-dark-128.png │ ├── community.svg │ ├── layer5-light-no-trim.svg │ ├── layer5-no-trim.svg │ └── meshery-logo-light-text.svg ├── smi-conformance ├── test-gen │ ├── test-yamls │ │ ├── traffic-spec │ │ │ ├── 04-trafficPath.yaml │ │ │ ├── 06-trafficMethod.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 03-assert.yaml │ │ │ ├── 03-install.yaml │ │ │ ├── 05-assert.yaml │ │ │ ├── 05-install.yaml │ │ │ ├── Tests.md │ │ │ ├── 02-assert.yaml │ │ │ └── 02-install.yaml │ │ ├── traffic-split │ │ │ ├── 05-trafficOnlyB.yaml │ │ │ ├── 07-trafficOnlyC.yaml │ │ │ ├── 09-trafficBGrtC.yaml │ │ │ ├── 11-trafficCGrtB.yaml │ │ │ ├── 03-trafficDefault.yaml │ │ │ ├── 04-assert.yaml │ │ │ ├── 04-install.yaml │ │ │ ├── 06-assert.yaml │ │ │ ├── 06-install.yaml │ │ │ ├── 08-assert.yaml │ │ │ ├── 10-assert.yaml │ │ │ ├── 08-install.yaml │ │ │ ├── 10-install.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── Tests.md │ │ │ ├── 02-assert.yaml │ │ │ └── 02-install.yaml │ │ └── traffic-access │ │ │ ├── 03-trafficDefault.yaml │ │ │ ├── 05-trafficAllowed.yaml │ │ │ ├── 07-trafficBlocked.yaml │ │ │ ├── 06-install.yaml │ │ │ ├── 01-assert.yaml │ │ │ ├── 04-assert.yaml │ │ │ ├── 04-install.yaml │ │ │ ├── 06-errors.yaml │ │ │ ├── Tests.md │ │ │ ├── 02-assert.yaml │ │ │ └── 02-install.yaml │ ├── utils.go │ ├── test_gen.go │ ├── service-mesh.go │ ├── traffic-access.go │ ├── traffic-spec.go │ └── traffic-split.go ├── Makefile ├── main.go ├── .golangci.yml ├── Dockerfile ├── conformance │ ├── client.go │ ├── conformance.proto │ └── conformance.pb.go ├── go.mod ├── manifest.yml └── grpc │ ├── grpc.go │ └── handlers.go ├── charts ├── smi-conformance-0.1.0.tgz └── smi-conformance │ ├── Chart.yaml │ ├── templates │ ├── serviceaccount.yaml │ ├── rolebinding.yaml │ ├── service.yaml │ ├── deployment.yaml │ ├── NOTES.txt │ └── _helpers.tpl │ ├── values.yaml │ └── .helmignore ├── service ├── go.mod ├── Dockerfile ├── go.sum └── main.go ├── .github ├── welcome │ └── Layer5-celebration.png ├── workflows │ ├── release-drafter.yml │ ├── slack.yml │ ├── ci.yml │ └── label-commenter-config.yml ├── ISSUE_TEMPLATE │ ├── question.md │ ├── documentation.md │ ├── feature_request.md │ └── bug_report.md ├── PULL_REQUEST_TEMPLATE.md ├── releasedrafter.yml ├── stale.yml ├── config.yml └── label-commenter-config.yml ├── deploy ├── linkerd │ ├── traffic.yaml │ └── app.yaml ├── traffic-crd.yaml ├── k8s-maesh.yaml ├── k8s-consul.yaml └── maesh.yaml ├── .gitignore ├── Makefile ├── CONTRIBUTING.md ├── README.md └── LICENSE /img/readme/slack-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/layer5io/learn-layer5/HEAD/img/readme/slack-128.png -------------------------------------------------------------------------------- /img/readme/slack-dark-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/layer5io/learn-layer5/HEAD/img/readme/slack-dark-128.png -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/04-trafficPath.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/06-trafficMethod.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/05-trafficOnlyB.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/07-trafficOnlyC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/09-trafficBGrtC.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/11-trafficCGrtB.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /charts/smi-conformance-0.1.0.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/layer5io/learn-layer5/HEAD/charts/smi-conformance-0.1.0.tgz -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/03-trafficDefault.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/05-trafficAllowed.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/07-trafficBlocked.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/03-trafficDefault.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep -------------------------------------------------------------------------------- /service/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/layer5io/sample-app 2 | 3 | go 1.14 4 | 5 | require github.com/sirupsen/logrus v1.6.0 6 | -------------------------------------------------------------------------------- /.github/welcome/Layer5-celebration.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/layer5io/learn-layer5/HEAD/.github/welcome/Layer5-celebration.png -------------------------------------------------------------------------------- /smi-conformance/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: go-lint 2 | go-lint: 3 | go run github.com/golangci/golangci-lint/cmd/golangci-lint run --config .golangci.yml -------------------------------------------------------------------------------- /charts/smi-conformance/Chart.yaml: -------------------------------------------------------------------------------- 1 | Name: smi-conformance 2 | description: A Helm chart to install the SMI conformance tool on Kubernetes 3 | version: 0.1.0 -------------------------------------------------------------------------------- /charts/smi-conformance/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: {{ include "smi-conformance.serviceAccount" . }} 5 | namespace: {{ include "smi-conformance.namespace" . }} -------------------------------------------------------------------------------- /deploy/linkerd/traffic.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha1 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-v1 10 | weight: 1 11 | - service: app-v2 12 | weight: 0 -------------------------------------------------------------------------------- /service/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.13.7 as bd 2 | WORKDIR /github.com/layer5io/sample-app-service 3 | ADD . . 4 | RUN go build -a -o ./main . 5 | 6 | FROM golang:1.13.7 7 | COPY --from=bd /github.com/layer5io/sample-app-service/main /home/main 8 | WORKDIR /home/ 9 | EXPOSE 9091 10 | CMD ["./main"] -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/04-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 1 11 | - service: app-c 12 | weight: 0 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/04-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 1 11 | - service: app-c 12 | weight: 0 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/06-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 0 11 | - service: app-c 12 | weight: 1 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/06-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 0 11 | - service: app-c 12 | weight: 1 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/08-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 75 11 | - service: app-c 12 | weight: 25 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/10-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 25 11 | - service: app-c 12 | weight: 75 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/08-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 75 11 | - service: app-c 12 | weight: 25 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/10-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: split.smi-spec.io/v1alpha4 2 | kind: TrafficSplit 3 | metadata: 4 | name: server-split 5 | namespace: 6 | spec: 7 | service: app-svc 8 | backends: 9 | - service: app-b 10 | weight: 25 11 | - service: app-c 12 | weight: 75 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | service/main 2 | # Binaries for programs and plugins 3 | *.exe 4 | *.exe~ 5 | *.dll 6 | *.so 7 | *.dylib 8 | 9 | # Test binary, built with `go test -c` 10 | *.test 11 | 12 | # Output of the go coverage tool, specifically when used with LiteIDE 13 | *.out 14 | 15 | # Dependency directories (remove the comment below to include it) 16 | # vendor/ 17 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/06-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kudo.dev/v1alpha1 2 | kind: TestStep 3 | delete: 4 | - apiVersion: specs.smi-spec.io/v1alpha4 5 | kind: TCPRoute 6 | namespace: 7 | name: service-tcp-route 8 | - apiVersion: access.smi-spec.io/v1alpha3 9 | kind: TrafficTarget 10 | namespace: 11 | name: service-targets -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: traffictargets.access.smi-spec.io 5 | spec: 6 | group: access.smi-spec.io 7 | status: 8 | acceptedNames: 9 | kind: TrafficTarget 10 | shortNames: 11 | - tt 12 | plural: traffictargets 13 | singular: traffictarget -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: httproutegroups.specs.smi-spec.io 5 | spec: 6 | group: specs.smi-spec.io 7 | status: 8 | acceptedNames: 9 | kind: HTTPRouteGroup 10 | shortNames: 11 | - htr 12 | plural: httproutegroups 13 | singular: httproutegroup -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/01-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apiextensions.k8s.io/v1beta1 2 | kind: CustomResourceDefinition 3 | metadata: 4 | name: trafficsplits.split.smi-spec.io 5 | spec: 6 | group: split.smi-spec.io 7 | status: 8 | acceptedNames: 9 | kind: TrafficSplit 10 | shortNames: 11 | - ts 12 | plural: trafficsplits 13 | singular: trafficsplit 14 | -------------------------------------------------------------------------------- /charts/smi-conformance/values.yaml: -------------------------------------------------------------------------------- 1 | namespace: meshery 2 | serviceAccount: meshery 3 | labels: 4 | app: smi-conformance 5 | release: smi-conformance 6 | image: 7 | repository: layer5/learn-layer5 8 | tag: smi 9 | pullPolicy: Always 10 | port: 10011 11 | resources: 12 | limits: 13 | cpu: "500m" 14 | memory: 1000Mi 15 | requests: 16 | cpu: "200m" 17 | memory: 500Mi 18 | service: 19 | type: NodePort 20 | port: 10011 -------------------------------------------------------------------------------- /charts/smi-conformance/templates/rolebinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: rbac.authorization.k8s.io/v1 3 | kind: ClusterRoleBinding 4 | metadata: 5 | name: {{ include "smi-conformance.name" . }} 6 | namespace: meshery 7 | subjects: 8 | - kind: ServiceAccount 9 | name: {{ include "smi-conformance.serviceAccount" . }} 10 | namespace: {{ include "smi-conformance.namespace" . }} 11 | roleRef: 12 | kind: ClusterRole 13 | name: cluster-admin 14 | apiGroup: rbac.authorization.k8s.io -------------------------------------------------------------------------------- /charts/smi-conformance/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | VER=$(shell git rev-parse --short HEAD) 2 | 3 | build-service: 4 | cd service && go build -a -o ./main . 5 | 6 | run-service-a: 7 | SERVICE_NAME="service-a" \ 8 | PORT=9091 \ 9 | ./service/main 10 | 11 | run-service-b: 12 | SERVICE_NAME="service-b" \ 13 | PORT=9092 \ 14 | ./service/main 15 | 16 | build-img-service: 17 | cd service && docker build -t layer5/learn-layer5:latest -t layer5/learn-layer5:$(VER) . 18 | 19 | image-push: 20 | docker push layer5/learn-layer5 21 | -------------------------------------------------------------------------------- /.github/workflows/release-drafter.yml: -------------------------------------------------------------------------------- 1 | name: Release Drafter 2 | 3 | on: 4 | push: 5 | # our release branch 6 | branches: 7 | - master 8 | 9 | jobs: 10 | update_release_draft: 11 | runs-on: ubuntu-latest 12 | steps: 13 | # Drafts your next Release notes as Pull Requests are merged into "master" 14 | - uses: release-drafter/release-drafter@v5 15 | with: 16 | config-name: releasedrafter.yml 17 | env: 18 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 19 | -------------------------------------------------------------------------------- /charts/smi-conformance/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "smi-conformance.name" . }} 5 | namespace: {{ include "smi-conformance.namespace" . }} 6 | labels: 7 | {{- include "smi-conformance.labels" . | nindent 4 }} 8 | spec: 9 | type: {{ .Values.service.type }} 10 | ports: 11 | - port: {{ .Values.service.port }} 12 | targetPort: grpc 13 | protocol: TCP 14 | name: {{ include "smi-conformance.name" . }} 15 | selector: 16 | {{- include "smi-conformance.labels" . | nindent 4 }} 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General question 3 | about: Request information about the project; clarify behavior of the software 4 | title: '[Question]' 5 | labels: 'question' 6 | assignees: '' 7 | --- 8 | 9 | **How can we help?** 10 | 11 | 12 | **Contributor Resources** 13 | - 🎨 Wireframes and [designs for Layer5 site](https://www.figma.com/file/5ZwEkSJwUPitURD59YHMEN/Layer5-Designs) in Figma [(open invite)](https://www.figma.com/team_invite/redeem/qJy1c95qirjgWQODApilR9) -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Description** 2 | 3 | This PR fixes # 4 | 5 | **Notes for Reviewers** 6 | 7 | 8 | **[Signed commits](../CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)** 9 | - [ ] Yes, I signed my commits. 10 | 11 | 12 | -------------------------------------------------------------------------------- /smi-conformance/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "os" 5 | "time" 6 | 7 | "github.com/layer5io/learn-layer5/smi-conformance/grpc" 8 | "sigs.k8s.io/controller-runtime/pkg/log" 9 | ) 10 | 11 | func main() { 12 | service := &grpc.Service{ 13 | Name: "smi-conformance", 14 | Port: "10011", 15 | Version: "v1.0.0", 16 | StartedAt: time.Now(), 17 | } 18 | // Initialize Logger instance 19 | logger := log.Log.WithName(service.Name) 20 | logger.Info("Conformance tool Started") 21 | // Server Initialization 22 | err := grpc.Start(service) 23 | if err != nil { 24 | logger.Error(err, "Conformance tool crashed!!") 25 | os.Exit(1) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/04-assert.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: specs.smi-spec.io/v1alpha4 3 | kind: TCPRoute 4 | metadata: 5 | name: service-tcp-route 6 | namespace: 7 | spec: 8 | matches: 9 | ports: [] 10 | --- 11 | apiVersion: access.smi-spec.io/v1alpha3 12 | kind: TrafficTarget 13 | metadata: 14 | name: service-targets 15 | namespace: 16 | spec: 17 | destination: 18 | kind: ServiceAccount 19 | name: service-b 20 | namespace: 21 | sources: 22 | - kind: ServiceAccount 23 | name: service-a 24 | namespace: 25 | rules: 26 | - kind: TCPRoute 27 | name: service-tcp-route 28 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/04-install.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: specs.smi-spec.io/v1alpha4 3 | kind: TCPRoute 4 | metadata: 5 | name: service-tcp-route 6 | namespace: 7 | spec: 8 | matches: 9 | ports: [] 10 | --- 11 | apiVersion: access.smi-spec.io/v1alpha3 12 | kind: TrafficTarget 13 | metadata: 14 | name: service-targets 15 | namespace: 16 | spec: 17 | destination: 18 | kind: ServiceAccount 19 | name: service-b 20 | namespace: 21 | sources: 22 | - kind: ServiceAccount 23 | name: service-a 24 | namespace: 25 | rules: 26 | - kind: TCPRoute 27 | name: service-tcp-route 28 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/06-errors.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: specs.smi-spec.io/v1alpha4 3 | kind: TCPRoute 4 | metadata: 5 | name: service-tcp-route 6 | namespace: 7 | spec: 8 | matches: 9 | ports: [] 10 | --- 11 | apiVersion: access.smi-spec.io/v1alpha3 12 | kind: TrafficTarget 13 | metadata: 14 | name: service-targets 15 | namespace: 16 | spec: 17 | destination: 18 | kind: ServiceAccount 19 | name: service-b 20 | namespace: 21 | sources: 22 | - kind: ServiceAccount 23 | name: service-a 24 | namespace: 25 | rules: 26 | - kind: TCPRoute 27 | name: service-tcp-route 28 | -------------------------------------------------------------------------------- /.github/releasedrafter.yml: -------------------------------------------------------------------------------- 1 | name-template: 'v$NEXT_PATCH_VERSION' 2 | tag-template: 'v$NEXT_PATCH_VERSION' 3 | categories: 4 | - title: '🚀 Features' 5 | labels: 6 | - 'kind/feature' 7 | - 'kind/enhancement' 8 | - title: '🐛 Bug Fixes' 9 | labels: 10 | - 'kind/fix' 11 | - 'kind/bugfix' 12 | - 'kind/bug' 13 | - title: '🧰 Maintenance' 14 | labels: 15 | - 'kind/chore' 16 | - 'area/ci' 17 | - 'area/tests' 18 | - title: 📖 Documentation 19 | label: area/docs 20 | change-template: '- $TITLE @$AUTHOR (#$NUMBER)' 21 | template: | 22 | ## What's New 23 | $CHANGES 24 | 25 | ## Contributors 26 | 27 | Thank you to our contributors for making this release possible: 28 | $CONTRIBUTORS 29 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/03-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: specs.smi-spec.io/v1alpha4 2 | kind: HTTPRouteGroup 3 | metadata: 4 | name: http-rg 5 | namespace: 6 | matches: 7 | - name: testMatch 8 | pathRegex: /metrics 9 | methods: ["*"] 10 | --- 11 | apiVersion: access.smi-spec.io/v1alpha3 12 | kind: TrafficTarget 13 | metadata: 14 | name: service-targets 15 | namespace: 16 | spec: 17 | destination: 18 | kind: ServiceAccount 19 | name: service-b 20 | namespace: 21 | port: "9091" 22 | sources: 23 | - kind: ServiceAccount 24 | name: service-a 25 | namespace: 26 | rules: 27 | - kind: HTTPRouteGroup 28 | name: http-rg 29 | matches: 30 | - testMatch -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/03-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: specs.smi-spec.io/v1alpha4 2 | kind: HTTPRouteGroup 3 | metadata: 4 | name: http-rg 5 | namespace: 6 | matches: 7 | - name: testMatch 8 | pathRegex: /metrics 9 | methods: ["*"] 10 | --- 11 | apiVersion: access.smi-spec.io/v1alpha3 12 | kind: TrafficTarget 13 | metadata: 14 | name: service-targets 15 | namespace: 16 | spec: 17 | destination: 18 | kind: ServiceAccount 19 | name: service-b 20 | namespace: 21 | port: "9091" 22 | sources: 23 | - kind: ServiceAccount 24 | name: service-a 25 | namespace: 26 | rules: 27 | - kind: HTTPRouteGroup 28 | name: http-rg 29 | matches: 30 | - testMatch -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/Tests.md: -------------------------------------------------------------------------------- 1 | # Traffic Access 2 | 3 | Note that the following tests are executed sequentially in an temporarily spawned namespace. 4 | 5 | * *01* : Asserts if the TrafficTarget CRD exists. 6 | * *02* : Deploys the app and asserts if the app has been deployed 7 | * *03* : Custom test is run where we verify if by default all traffic is blocked. 8 | * *04* : Create and assert a TrafficTarget which allows traffic from `service-a` to `service-b`. 9 | * *05* : Custom test is run where we verify if traffic from `service-a` to `service-b` succeeds. 10 | * *06* : Deletes the CRDs created in step *04* and asserts its deletion. 11 | * *07* : Custom test to verify if the traffic from `service-a` to `service-b` fails as the CRD has been deleted. -------------------------------------------------------------------------------- /service/go.sum: -------------------------------------------------------------------------------- 1 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 2 | github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= 3 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 4 | github.com/sirupsen/logrus v1.6.0 h1:UBcNElsrwanuuMsnGSlYmtmgbb23qDR5dG+6X6Oo89I= 5 | github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= 6 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 7 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894 h1:Cz4ceDQGXuKRnVBDTS23GTn/pU5OE2C0WrNTOYK1Uuc= 8 | golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 9 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/05-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: specs.smi-spec.io/v1alpha4 2 | kind: HTTPRouteGroup 3 | metadata: 4 | name: http-rg 5 | namespace: 6 | spec: 7 | matches: 8 | - name: testMatch 9 | pathRegex: ".*" 10 | methods: 11 | - GET 12 | --- 13 | apiVersion: access.smi-spec.io/v1alpha3 14 | kind: TrafficTarget 15 | metadata: 16 | name: service-targets 17 | namespace: 18 | spec: 19 | destination: 20 | kind: ServiceAccount 21 | name: service-b 22 | namespace: 23 | port: "9091" 24 | sources: 25 | - kind: ServiceAccount 26 | name: service-a 27 | namespace: 28 | rules: 29 | - kind: HTTPRouteGroup 30 | name: http-rg 31 | matches: 32 | - testMatch -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/05-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: specs.smi-spec.io/v1alpha4 2 | kind: HTTPRouteGroup 3 | metadata: 4 | name: http-rg 5 | namespace: 6 | spec: 7 | matches: 8 | - name: testMatch 9 | pathRegex: ".*" 10 | methods: 11 | - GET 12 | --- 13 | apiVersion: access.smi-spec.io/v1alpha3 14 | kind: TrafficTarget 15 | metadata: 16 | name: service-targets 17 | namespace: 18 | spec: 19 | destination: 20 | kind: ServiceAccount 21 | name: service-b 22 | namespace: 23 | port: "9091" 24 | sources: 25 | - kind: ServiceAccount 26 | name: service-a 27 | namespace: 28 | rules: 29 | - kind: HTTPRouteGroup 30 | name: http-rg 31 | matches: 32 | - testMatch -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documentation issue 3 | about: Issues related to documentation. 4 | title: '[Docs]' 5 | labels: 'docs' 6 | assignees: '' 7 | --- 8 | **Current State:** 9 | 10 | 11 | **Desired State:** 12 | 13 | 14 | --- 15 | **Contributor Resources** 16 | - [Meshery documentation site](https://meshery.layer5.io/docs/) 17 | - [Meshery documentation source](https://github.com/layer5io/meshery/tree/master/docs) 18 | - [Instructions for contributing to documentation](https://github.com/layer5io/meshery/blob/master/CONTRIBUTING.md#documentation-contribution-flow) 19 | - 🎨 Wireframes and [designs for Layer5 site](https://www.figma.com/file/5ZwEkSJwUPitURD59YHMEN/Layer5-Designs) in Figma [(open invite)](https://www.figma.com/team_invite/redeem/qJy1c95qirjgWQODApilR9) 20 | -------------------------------------------------------------------------------- /deploy/traffic-crd.yaml: -------------------------------------------------------------------------------- 1 | # TCPRoute for Counting Service 2 | --- 3 | apiVersion: specs.smi-spec.io/v1alpha1 4 | kind: TCPRoute 5 | metadata: 6 | name: service-tcp-route 7 | namespace: 8 | 9 | # TrafficTarget defines allowed routes for service-a 10 | # In this example service-a is allowed to connect using 11 | # TCP 12 | --- 13 | kind: TrafficTarget 14 | apiVersion: access.smi-spec.io/v1alpha1 15 | metadata: 16 | name: service-targets 17 | namespace: 18 | # namespace: default 19 | destination: 20 | kind: ServiceAccount 21 | name: service-b 22 | namespace: 23 | # namespace: default 24 | sources: 25 | - kind: ServiceAccount 26 | name: service-a 27 | namespace: 28 | # namespace: default 29 | specs: 30 | - kind: TCPRoute 31 | name: service-tcp-route -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 45 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 10 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - issue/willfix 8 | # Label to use when marking an issue as stale 9 | staleLabel: issue/stale 10 | # Comment to post when marking an issue as stale. Set to `false` to disable 11 | markComment: > 12 | This issue has been automatically marked as stale because it has not had 13 | recent activity. It will be closed if no further activity occurs. Thank you 14 | for your contributions. 15 | # Comment to post when closing a stale issue. Set to `false` to disable 16 | closeComment: > 17 | This issue is being automatically closed due to inactivity. 18 | However, you may choose to reopen this issue. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Suggest an enhancement to this project. 4 | title: '' 5 | labels: 'enhancement' 6 | assignees: '' 7 | --- 8 | 9 | **Current Behavior** 10 | 11 | 12 | 13 | **Desired Behavior** 14 | 15 | 16 | 17 | --- 18 | **Resources** 19 | 20 | 21 | **Alternatives / Additional Context** 22 | 23 | 24 | **Contributor Resources** 25 | - 🎨 Wireframes and [designs for Layer5 site](https://www.figma.com/file/5ZwEkSJwUPitURD59YHMEN/Layer5-Designs) in Figma [(open invite)](https://www.figma.com/team_invite/redeem/qJy1c95qirjgWQODApilR9) -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/Tests.md: -------------------------------------------------------------------------------- 1 | # Traffic Spec 2 | 3 | Note that the following tests are executed sequentially in an temporarily spawned namespace. 4 | 5 | * *01* : Asserts if the HttpRoute group CRD exists. 6 | * *02* : Deploys the app and asserts if the app has been deployed 7 | * *03* : Configures HTTPRouteGroup such that traffic from `service-a` to only `service-b:PORT/metrics` (all HTTP methods) is allowed and the rest is blocked. 8 | * *04* : Custom test which verifies if the above configuration works as intended. 9 | * *05* : Configures the above created HTTPRouteGroup such that traffic from `service-a` to `service-b:PORT/*` (only GET HTTP Method) is allowed and the rest is blocked. 10 | * *06* : Custom test which verifies if the above configuration works as intended. 11 | 12 | > We aren't validating TCPRouteGroup CRD here as it has been used in the traffic access tests, so if it is not conformant even TrafficAccess will not be. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug/issue report 3 | about: Report an issue to help improve the project. 4 | title: '' 5 | labels: 'bug' 6 | assignees: '' 7 | --- 8 | **Description** 9 | 10 | 11 | **Expected Behavior** 12 | 13 | 14 | **Screenshots** 15 | 16 | 17 | **Environment:** 18 | - OS: [e.g. Ubuntu] 19 | - Browser: [e.g. Chrome, Safari] 20 | - Version: [e.g. 22] 21 | - Device: [e.g. laptop, iPhone 8] 22 | 23 | --- 24 | [Optional] **To Reproduce** 25 | Steps to reproduce the behavior: 26 | 1. Go to '...' 27 | 2. Click on '....' 28 | 3. Scroll down to '....' 29 | 4. See error 30 | 31 | [Optional] **Additional Context** 32 | 33 | 34 | **Contributor Resources** 35 | - 🎨 Wireframes and [designs for Layer5 site](https://www.figma.com/file/5ZwEkSJwUPitURD59YHMEN/Layer5-Designs) in Figma [(open invite)](https://www.figma.com/team_invite/redeem/qJy1c95qirjgWQODApilR9) -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/Tests.md: -------------------------------------------------------------------------------- 1 | # Traffic Access 2 | 3 | Note that the following tests are executed sequentially in an temporarily spawned namespace. 4 | 5 | * *01* : Asserts if the TrafficSplit CRD exists. 6 | * *02* : Deploys the app and asserts that it is deployed. 7 | * *03* : Custom test which verifies that if in default scenario the traffic to `app-svc` is split randomly between `app-b` and `app-c`. 8 | * *04* : Configure a TrafficSplit CRD such that all traffic to `app-svc` is sent to only `app-b` and none to `app-c`. 9 | * *05* : Custom test which verifies the above scenario. 10 | * *06* : Configure a TrafficSplit CRD such that all traffic to `app-svc` is sent to only `app-c` and none to `app-b`. 11 | * *07* : Custom test which verifies the above scenario. 12 | * *08* : Configure a TrafficSplit CRD such that all traffic to `app-svc` is split between the two such that `app-b` gets more traffic (75%) than `app-c` (25%). 13 | * *09* : Custom test which verifies the above scenario. 14 | * *10* : Configure a TrafficSplit CRD such that all traffic to `app-svc` is split between the two such that `app-b` gets more traffic (25%) than `app-c` (75%). 15 | * *11* : Custom test which verifies the above scenario. -------------------------------------------------------------------------------- /charts/smi-conformance/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "smi-conformance.name" . }} 5 | namespace: {{ include "smi-conformance.namespace" . }} 6 | labels: 7 | {{- include "smi-conformance.labels" . | nindent 4 }} 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | {{- include "smi-conformance.labels" . | nindent 6 }} 13 | strategy: 14 | rollingUpdate: 15 | maxSurge: 10% 16 | maxUnavailable: 0 17 | type: RollingUpdate 18 | template: 19 | metadata: 20 | labels: 21 | {{- include "smi-conformance.labels" . | nindent 8 }} 22 | spec: 23 | serviceAccountName: {{ include "smi-conformance.serviceAccount" . }} 24 | containers: 25 | - name: {{ .Chart.Name }} 26 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.Version }}" 27 | imagePullPolicy: {{ .Values.image.pullPolicy }} 28 | ports: 29 | - name: grpc 30 | containerPort: {{ .Values.image.port }} 31 | protocol: TCP 32 | resources: 33 | {{- toYaml .Values.resources | nindent 12 }} 34 | restartPolicy: Always -------------------------------------------------------------------------------- /smi-conformance/.golangci.yml: -------------------------------------------------------------------------------- 1 | run: 2 | tests: true 3 | 4 | linters: 5 | enable: 6 | - goconst 7 | - gocyclo 8 | - gofmt 9 | - goimports 10 | - golint 11 | - gosec 12 | - govet 13 | - misspell 14 | - unused 15 | - whitespace 16 | 17 | linters-settings: 18 | goimports: 19 | local-prefixes: github.com/openservicemesh/osm 20 | 21 | issues: 22 | exclude-rules: 23 | # Ignore error for ginkgo and gomega dot imports 24 | - linters: 25 | - golint 26 | source: ". \"github.com/onsi/(ginkgo|gomega)\"" 27 | text: "dot imports" 28 | # Ignore error for test framework imports 29 | - linters: 30 | - golint 31 | source: ". \"github.com/openservicemesh/osm/tests/framework\"" 32 | text: "dot imports" 33 | # ignore unused linters on keyvault as this code isn't being used 34 | # TODO: disable this rule once keyvault is integrated 35 | - path: pkg/certificate/providers/keyvault/ 36 | linters: 37 | - unused 38 | - deadcode 39 | # Exclude staticcheck messages for deprecated function, variable or constant 40 | # This causes issues with package github.com/golang/protobuf/proto 41 | - linters: 42 | - staticcheck 43 | text: "SA1019:" 44 | exclude-use-default: false 45 | 46 | -------------------------------------------------------------------------------- /smi-conformance/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:1.14-alpine3.11 as build-img 2 | 3 | RUN apk update && apk add --no-cache git libc-dev gcc pkgconf && mkdir /home/meshery 4 | COPY ${PWD} /go/src/github.com/layer5io/learn-layer5/smi-conformance/ 5 | WORKDIR /go/src/github.com/layer5io/learn-layer5/smi-conformance/ 6 | # RUN git rev-parse HEAD > /home/meshery/version 7 | # RUN git describe --tags `git rev-list --tags --max-count=1` >> /home/com/version 8 | RUN go mod vendor && go build -a -ldflags "-s -w" -o /home/meshery/smi_conformance main.go 9 | 10 | FROM alpine:latest 11 | 12 | RUN apk --no-cache add ca-certificates && mkdir /home/test-yamls && mkdir /home/test-yamls/traffic-access && mkdir /home/test-yamls/traffic-spec && mkdir /home/test-yamls/traffic-split 13 | COPY --from=build-img /home/meshery/** /home/ 14 | COPY --from=build-img /go/src/github.com/layer5io/learn-layer5/smi-conformance/test-gen/test-yamls/traffic-access/** /home/test-yamls/traffic-access/ 15 | COPY --from=build-img /go/src/github.com/layer5io/learn-layer5/smi-conformance/test-gen/test-yamls/traffic-split/** /home/test-yamls/traffic-split/ 16 | COPY --from=build-img /go/src/github.com/layer5io/learn-layer5/smi-conformance/test-gen/test-yamls/traffic-spec/** /home/test-yamls/traffic-spec/ 17 | WORKDIR /home/ 18 | EXPOSE 10008 19 | CMD ["sh","-c","./smi_conformance"] -------------------------------------------------------------------------------- /smi-conformance/conformance/client.go: -------------------------------------------------------------------------------- 1 | package conformance 2 | 3 | import ( 4 | context "context" 5 | 6 | "github.com/sirupsen/logrus" 7 | "google.golang.org/grpc" 8 | ) 9 | 10 | // ConformanceClient represents a gRPC adapter client 11 | type ConformanceClient struct { 12 | CClient ConformanceTestingClient 13 | conn *grpc.ClientConn 14 | } 15 | 16 | // CreateClient creates a ConformanceClient for the given params 17 | func CreateClient(ctx context.Context, conformanceLocationURL string) (*ConformanceClient, error) { 18 | var opts []grpc.DialOption 19 | // creds, err := credentials.NewClientTLSFromFile(*caFile, *serverHostOverride) 20 | // if err != nil { 21 | // logrus.Errorf("Failed to create TLS credentials %v", err) 22 | // } 23 | // opts = append(opts, grpc.WithTransportCredentials(creds)) 24 | // } else { 25 | opts = append(opts, grpc.WithInsecure()) 26 | // } 27 | conn, err := grpc.Dial(conformanceLocationURL, opts...) 28 | if err != nil { 29 | logrus.Errorf("fail to dial: %v", err) 30 | } 31 | 32 | cClient := NewConformanceTestingClient(conn) 33 | 34 | return &ConformanceClient{ 35 | conn: conn, 36 | CClient: cClient, 37 | }, nil 38 | } 39 | 40 | // Close closes the ConformanceClient 41 | func (c *ConformanceClient) Close() error { 42 | if c.conn != nil { 43 | return c.conn.Close() 44 | } 45 | return nil 46 | } 47 | -------------------------------------------------------------------------------- /img/readme/community.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /charts/smi-conformance/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | 1. Get the application URL by running these commands: 2 | {{- if contains "NodePort" .Values.service.type }} 3 | export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "smi-conformance.fullname" . }}) 4 | export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") 5 | echo http://$NODE_IP:$NODE_PORT 6 | {{- else if contains "LoadBalancer" .Values.service.type }} 7 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 8 | You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "smi-conformance.fullname" . }}' 9 | export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "smi-conformance.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") 10 | echo http://$SERVICE_IP:{{ .Values.service.port }} 11 | {{- else if contains "ClusterIP" .Values.service.type }} 12 | export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "smi-conformance.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") 13 | echo "Visit http://127.0.0.1:8080 to use your application" 14 | kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:80 15 | {{- end }} 16 | -------------------------------------------------------------------------------- /smi-conformance/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/layer5io/learn-layer5/smi-conformance 2 | 3 | go 1.13 4 | 5 | require ( 6 | cloud.google.com/go v0.46.3 // indirect 7 | github.com/golang/protobuf v1.4.2 8 | github.com/google/go-cmp v0.5.2 // indirect 9 | github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 10 | github.com/kr/text v0.2.0 // indirect 11 | github.com/kudobuilder/kuttl v0.0.0-00010101000000-000000000000 12 | // github.com/layer5io/meshkit v0.2.0 13 | github.com/layer5io/service-mesh-performance v0.3.2-0.20210122142912-a94e0658b021 14 | github.com/mattn/go-isatty v0.0.12 // indirect 15 | github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect 16 | github.com/onsi/ginkgo v1.14.1 // indirect 17 | github.com/onsi/gomega v1.10.2 // indirect 18 | github.com/pkg/errors v0.9.1 // indirect 19 | github.com/sirupsen/logrus v1.7.0 20 | github.com/stretchr/testify v1.6.1 // indirect 21 | golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect 22 | golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634 // indirect 23 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 24 | google.golang.org/grpc v1.30.0 25 | google.golang.org/protobuf v1.24.0 26 | gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect 27 | k8s.io/api v0.17.3 28 | k8s.io/client-go v0.17.3 29 | sigs.k8s.io/controller-runtime v0.5.1 30 | ) 31 | 32 | replace github.com/kudobuilder/kuttl => github.com/layer5io/kuttl v0.4.1-0.20200806180306-b7e46afd657f 33 | -------------------------------------------------------------------------------- /smi-conformance/manifest.yml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: smi-conformance 6 | namespace: meshery 7 | labels: 8 | app.kubernetes.io/name: smi-conformance 9 | spec: 10 | type: LoadBalancer 11 | ports: 12 | - port: 10011 13 | targetPort: grpc 14 | protocol: TCP 15 | name: smi-conformance 16 | selector: 17 | app.kubernetes.io/name: smi-conformance 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: smi-conformance 23 | namespace: meshery 24 | labels: 25 | app.kubernetes.io/name: smi-conformance 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app.kubernetes.io/name: smi-conformance 31 | strategy: 32 | rollingUpdate: 33 | maxSurge: 10% 34 | maxUnavailable: 0 35 | type: RollingUpdate 36 | template: 37 | metadata: 38 | labels: 39 | app.kubernetes.io/name: smi-conformance 40 | spec: 41 | serviceAccountName: meshery-operator 42 | containers: 43 | - name: smi-conformance 44 | image: "layer5/learn-layer5:smi" 45 | imagePullPolicy: Always 46 | ports: 47 | - name: grpc 48 | containerPort: 10011 49 | protocol: TCP 50 | resources: 51 | limits: 52 | cpu: 500m 53 | memory: 1000Mi 54 | requests: 55 | cpu: 200m 56 | memory: 500Mi 57 | restartPolicy: Always 58 | -------------------------------------------------------------------------------- /smi-conformance/grpc/grpc.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "fmt" 5 | "net" 6 | "time" 7 | 8 | middleware "github.com/grpc-ecosystem/go-grpc-middleware" 9 | grpc_recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" 10 | "google.golang.org/grpc" 11 | 12 | "github.com/layer5io/learn-layer5/smi-conformance/conformance" 13 | ) 14 | 15 | // Service object holds all the information about the server parameters. 16 | type Service struct { 17 | Name string `json:"name"` 18 | Port string `json:"port"` 19 | Version string `json:"version"` 20 | StartedAt time.Time `json:"startedat"` 21 | } 22 | 23 | // panicHandler is the handler function to handle panic errors 24 | func panicHandler(r interface{}) error { 25 | fmt.Println("500 panic Error") 26 | return fmt.Errorf("Panic error for: %+v", r) 27 | } 28 | 29 | // Start grpc server 30 | func Start(s *Service) error { 31 | address := fmt.Sprintf(":%s", s.Port) 32 | listener, err := net.Listen("tcp", address) 33 | if err != nil { 34 | return err 35 | } 36 | 37 | middlewares := middleware.ChainUnaryServer( 38 | grpc_recovery.UnaryServerInterceptor( 39 | grpc_recovery.WithRecoveryHandler(panicHandler), 40 | ), 41 | ) 42 | 43 | server := grpc.NewServer( 44 | grpc.UnaryInterceptor(middlewares), 45 | ) 46 | 47 | //Register Proto 48 | conformance.RegisterConformanceTestingServer(server, s) 49 | 50 | // Start serving requests 51 | if err = server.Serve(listener); err != nil { 52 | return err 53 | } 54 | return nil 55 | } 56 | -------------------------------------------------------------------------------- /smi-conformance/conformance/conformance.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | import "google/protobuf/empty.proto"; 3 | import "service-mesh-performance/service/error.proto"; 4 | import "service-mesh-performance/service/health.proto"; 5 | import "service-mesh-performance/service/info.proto"; 6 | import "service-mesh-performance/protos/service_mesh.proto"; 7 | 8 | package smi_conformance; 9 | option go_package = "conformance;conformance"; 10 | 11 | enum Capability { 12 | FULL = 0; 13 | HALF = 1; 14 | NONE = 2; 15 | } 16 | 17 | enum TestStatus { 18 | COMPLETED = 0; 19 | INPROGRESS = 1; 20 | CRASHED = 2; 21 | } 22 | 23 | enum ResultStatus { 24 | PASSED = 0; 25 | FAILED = 1; 26 | } 27 | 28 | message Request { 29 | smp.ServiceMesh mesh = 1; 30 | } 31 | 32 | message Result { 33 | oneof result { 34 | string message = 1; 35 | service.CommonError error = 2; 36 | } 37 | } 38 | 39 | message Detail { 40 | string smispec = 1; 41 | string specversion = 2; 42 | string assertion = 3; 43 | string duration = 4; 44 | Result result = 5; 45 | Capability capability = 6; 46 | ResultStatus status = 7; 47 | } 48 | 49 | message Response { 50 | string passpercent = 1; 51 | string casespassed = 2; 52 | smp.ServiceMesh mesh = 3; 53 | repeated Detail details = 5; 54 | } 55 | 56 | service conformanceTesting{ 57 | rpc Info (google.protobuf.Empty) returns (service.ServiceInfo); 58 | rpc Health (google.protobuf.Empty) returns (service.ServiceHealth); 59 | rpc RunTest (Request) returns (Response); 60 | } -------------------------------------------------------------------------------- /img/readme/layer5-light-no-trim.svg: -------------------------------------------------------------------------------- 1 | layer5-light-no-trim -------------------------------------------------------------------------------- /img/readme/layer5-no-trim.svg: -------------------------------------------------------------------------------- 1 | layer5-no-trim -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: app-b 5 | namespace: 6 | spec: 7 | type: NodePort 8 | selector: 9 | app: app 10 | version: b 11 | ports: 12 | - name: http 13 | protocol: TCP 14 | port: 9091 15 | targetPort: 9091 16 | --- 17 | apiVersion: v1 18 | kind: Service 19 | metadata: 20 | name: app-c 21 | namespace: 22 | spec: 23 | type: NodePort 24 | selector: 25 | app: app 26 | version: c 27 | ports: 28 | - name: http 29 | protocol: TCP 30 | port: 9091 31 | targetPort: 9091 32 | --- 33 | apiVersion: v1 34 | kind: Service 35 | metadata: 36 | name: app-a 37 | namespace: 38 | spec: 39 | type: NodePort 40 | selector: 41 | app: app-a 42 | ports: 43 | - name: http 44 | protocol: TCP 45 | port: 9091 46 | targetPort: 9091 47 | --- 48 | apiVersion: v1 49 | kind: Service 50 | metadata: 51 | name: app-svc 52 | namespace: 53 | spec: 54 | type: NodePort 55 | selector: 56 | app: app 57 | ports: 58 | - name: http 59 | protocol: TCP 60 | port: 9091 61 | targetPort: 9091 62 | --- 63 | apiVersion: apps/v1 64 | kind: Deployment 65 | metadata: 66 | name: app-a-deployment 67 | namespace: 68 | status: 69 | readyReplicas: 1 70 | --- 71 | apiVersion: apps/v1 72 | kind: Deployment 73 | metadata: 74 | name: app-b-deployment 75 | namespace: 76 | status: 77 | readyReplicas: 1 78 | --- 79 | apiVersion: apps/v1 80 | kind: Deployment 81 | metadata: 82 | name: app-c-deployment 83 | namespace: 84 | status: 85 | readyReplicas: 1 -------------------------------------------------------------------------------- /.github/workflows/slack.yml: -------------------------------------------------------------------------------- 1 | name: Slack Notify 2 | 3 | on: 4 | watch: 5 | types: [started] 6 | issues: 7 | types: [labeled] 8 | 9 | jobs: 10 | star-notify: 11 | if: github.event_name == 'watch' 12 | name: Notify Slack on star 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Get current star count 16 | run: | 17 | echo "STARS=$(curl --silent 'https://api.github.com/repos/${{ github.repository }}' -H 'Accept: application/vnd.github.preview' | jq '.stargazers_count')" >> $GITHUB_ENV 18 | 19 | - name: Notify Slack 20 | uses: slackapi/slack-github-action@v2.1.1 21 | with: 22 | method: chat.postMessage 23 | token: ${{ secrets.SLACK_BOT_TOKEN }} 24 | payload: | 25 | channel: CSK7N9TGX 26 | type: "mrkdwn" 27 | text: " just starred bringing the total ⭐️ count up to: ${{ env.STARS }}" 28 | 29 | good-first-issue-notify: 30 | if: github.event_name == 'issues' && (github.event.label.name == 'good first issue' || github.event.label.name == 'first-timers-only') 31 | name: Notify Slack for new good-first-issue 32 | runs-on: ubuntu-latest 33 | steps: 34 | - name: Notify Slack 35 | uses: slackapi/slack-github-action@v2.1.1 36 | with: 37 | method: chat.postMessage 38 | token: ${{ secrets.SLACK_BOT_TOKEN }} 39 | payload: | 40 | channel: C019426UBNY 41 | text: ":new: Good first issue up for grabs: <${{ github.event.issue.html_url }}|${{ github.event.issue.title }}>" 42 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: service-a 5 | namespace: 6 | --- 7 | apiVersion: v1 8 | kind: ServiceAccount 9 | metadata: 10 | name: service-b 11 | namespace: 12 | --- 13 | apiVersion: v1 14 | kind: ServiceAccount 15 | metadata: 16 | name: service-c 17 | namespace: 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: app-a-deployment 23 | namespace: 24 | status: 25 | readyReplicas: 1 26 | --- 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: app-b-deployment 31 | namespace: 32 | status: 33 | readyReplicas: 1 34 | --- 35 | apiVersion: apps/v1 36 | kind: Deployment 37 | metadata: 38 | name: app-c-deployment 39 | namespace: 40 | status: 41 | readyReplicas: 1 42 | --- 43 | apiVersion: v1 44 | kind: Service 45 | metadata: 46 | name: app-a 47 | namespace: 48 | spec: 49 | type: NodePort 50 | selector: 51 | app: app-a 52 | ports: 53 | - name: http 54 | protocol: TCP 55 | port: 9091 56 | # targetPort: 9091 57 | --- 58 | apiVersion: v1 59 | kind: Service 60 | metadata: 61 | name: app-b 62 | namespace: 63 | spec: 64 | type: NodePort 65 | selector: 66 | app: app-b 67 | ports: 68 | - name: http 69 | protocol: TCP 70 | port: 9091 71 | # targetPort: 9091 72 | --- 73 | apiVersion: v1 74 | kind: Service 75 | metadata: 76 | name: app-c 77 | namespace: 78 | spec: 79 | type: NodePort 80 | selector: 81 | app: app-c 82 | ports: 83 | - name: http 84 | protocol: TCP 85 | port: 9091 86 | # targetPort: 9091 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/02-assert.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: service-a 5 | namespace: 6 | --- 7 | apiVersion: v1 8 | kind: ServiceAccount 9 | metadata: 10 | name: service-b 11 | namespace: 12 | --- 13 | apiVersion: v1 14 | kind: ServiceAccount 15 | metadata: 16 | name: service-c 17 | namespace: 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: app-a-deployment 23 | namespace: 24 | status: 25 | readyReplicas: 1 26 | --- 27 | apiVersion: apps/v1 28 | kind: Deployment 29 | metadata: 30 | name: app-b-deployment 31 | namespace: 32 | status: 33 | readyReplicas: 1 34 | --- 35 | apiVersion: apps/v1 36 | kind: Deployment 37 | metadata: 38 | name: app-c-deployment 39 | namespace: 40 | status: 41 | readyReplicas: 1 42 | --- 43 | apiVersion: v1 44 | kind: Service 45 | metadata: 46 | name: app-a 47 | namespace: 48 | spec: 49 | type: NodePort 50 | selector: 51 | app: app-a 52 | ports: 53 | - name: http 54 | protocol: TCP 55 | port: 9091 56 | # targetPort: 9091 57 | --- 58 | apiVersion: v1 59 | kind: Service 60 | metadata: 61 | name: app-b 62 | namespace: 63 | spec: 64 | type: NodePort 65 | selector: 66 | app: app-b 67 | ports: 68 | - name: http 69 | protocol: TCP 70 | port: 9091 71 | # targetPort: 9091 72 | --- 73 | apiVersion: v1 74 | kind: Service 75 | metadata: 76 | name: app-c 77 | namespace: 78 | spec: 79 | type: NodePort 80 | selector: 81 | app: app-c 82 | ports: 83 | - name: http 84 | protocol: TCP 85 | port: 9091 86 | # targetPort: 9091 -------------------------------------------------------------------------------- /charts/smi-conformance/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* vim: set filetype=mustache: */}} 2 | {{/* 3 | Expand the name of the chart. 4 | */}} 5 | {{- define "smi-conformance.name" -}} 6 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 7 | {{- end }} 8 | 9 | {{/* 10 | Create a default fully qualified app name. 11 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 12 | If release name contains chart name it will be used as a full name. 13 | */}} 14 | {{- define "smi-conformance.fullname" -}} 15 | {{- if .Values.fullnameOverride }} 16 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 17 | {{- else }} 18 | {{- $name := default .Chart.Name .Values.nameOverride }} 19 | {{- if contains $name .Release.Name }} 20 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 21 | {{- else }} 22 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 23 | {{- end }} 24 | {{- end }} 25 | {{- end }} 26 | 27 | {{/* 28 | Create chart name and version as used by the chart label. 29 | */}} 30 | {{- define "smi-conformance.chart" -}} 31 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 32 | {{- end }} 33 | 34 | {{/* 35 | Common labels 36 | */}} 37 | {{- define "smi-conformance.labels" -}} 38 | helm.sh/chart: {{ include "smi-conformance.chart" . }} 39 | {{ include "smi-conformance.selectorLabels" . }} 40 | {{- if .Chart.AppVersion }} 41 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 42 | {{- end }} 43 | app.kubernetes.io/managed-by: {{ .Release.Service }} 44 | {{- end }} 45 | 46 | {{/* 47 | Selector labels 48 | */}} 49 | {{- define "smi-conformance.selectorLabels" -}} 50 | app.kubernetes.io/name: {{ include "smi-conformance.name" . }} 51 | app.kubernetes.io/instance: {{ .Release.Name }} 52 | {{- end }} 53 | 54 | {{/* 55 | Create the name of the service account to use 56 | */}} 57 | {{- define "smi-conformance.serviceAccount" -}} 58 | {{- if .Values.serviceAccount }} 59 | {{- default (include "smi-conformance.fullname" .) .Values.serviceAccount }} 60 | {{- else }} 61 | {{- default "default" .Values.serviceAccount }} 62 | {{- end }} 63 | {{- end }} 64 | 65 | {{/* 66 | Create the name of the namespace to use 67 | */}} 68 | {{- define "smi-conformance.namespace" -}} 69 | {{- if .Values.namespace }} 70 | {{- default (include "smi-conformance.fullname" .) .Values.namespace }} 71 | {{- else }} 72 | {{- default "default" .Values.namespace }} 73 | {{- end }} 74 | {{- end }} 75 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Learn-Layer5 2 | on: 3 | push: 4 | branches: 5 | - 'master' 6 | tags: 7 | - 'v*' 8 | pull_request: 9 | branches: 10 | - 'master' 11 | 12 | jobs: 13 | docker: 14 | name: Docker build and push 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check out code 18 | if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master') && success() 19 | uses: actions/checkout@master 20 | with: 21 | fetch-depth: 1 22 | - name: Docker login 23 | if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master') && success() 24 | uses: azure/docker-login@v1 25 | with: 26 | username: ${{ secrets.DOCKER_USERNAME }} 27 | password: ${{ secrets.DOCKER_PASSWORD }} 28 | - name: Docker build & push services 29 | if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/') || github.ref == 'refs/heads/master') && success() 30 | run: | 31 | cd service && docker build --no-cache -t ${{ secrets.IMAGE_NAME }} . 32 | docker tag ${{ secrets.IMAGE_NAME }}:latest ${{ secrets.IMAGE_NAME }}:${GITHUB_SHA::6} 33 | docker push ${{ secrets.IMAGE_NAME }}:latest 34 | docker push ${{ secrets.IMAGE_NAME }}:${GITHUB_SHA::6} 35 | cd ../smi-conformance && docker build --no-cache -t ${{ secrets.IMAGE_NAME }}:smi . 36 | docker tag ${{ secrets.IMAGE_NAME }}:smi ${{ secrets.IMAGE_NAME }}:smi-${GITHUB_SHA::6} 37 | docker push ${{ secrets.IMAGE_NAME }}:smi 38 | docker push ${{ secrets.IMAGE_NAME }}:smi-${GITHUB_SHA::6} 39 | - name: Docker tag release & push 40 | if: github.event_name != 'pull_request' && startsWith(github.ref, 'refs/tags/') && success() 41 | run: | 42 | docker tag ${{ secrets.IMAGE_NAME }}:latest ${{ secrets.IMAGE_NAME }}:${GITHUB_REF/refs\/tags\//} 43 | docker push ${{ secrets.IMAGE_NAME }}:${GITHUB_REF/refs\/tags\//} 44 | docker tag ${{ secrets.IMAGE_NAME }}:smi ${{ secrets.IMAGE_NAME }}:smi-${GITHUB_REF/refs\/tags\//} 45 | docker push ${{ secrets.IMAGE_NAME }}:smi-${GITHUB_REF/refs\/tags\//} 46 | helm: 47 | name: Helm charts publish 48 | runs-on: ubuntu-latest 49 | steps: 50 | - name: Checkout code 51 | uses: actions/checkout@master 52 | with: 53 | fetch-depth: 1 54 | - name: Configure Git 55 | run: | 56 | git config user.name "$GITHUB_ACTOR" 57 | git config user.email "$GITHUB_ACTOR@users.noreply.github.com" 58 | - name: Run chart-releaser 59 | uses: helm/chart-releaser-action@v1.0.0 60 | with: 61 | version: ${GITHUB_REF/refs\/tags\//} 62 | charts_repo_url: https://layer5io.github.io/master/charts 63 | env: 64 | CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" 65 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | # Configuration for new-issue-welcome - https://github.com/behaviorbot/new-issue-welcome 3 | # Comment to be posted to on first time issues 4 | newIssueWelcomeComment: > 5 | Thanks for opening this issue. A contributor will be by to give feedback soon. In the meantime, please review the [Layer5 Community Welcome Guide](https://docs.google.com/document/d/17OPtDE_rdnPQxmk2Kauhm3GwXF1R5dZ3Cj8qZLKdo5E/edit?usp=sharing) and sure to join the [community Slack](http://slack.layer5.io/). 6 | # Configuration for new-pr-welcome - https://github.com/behaviorbot/new-pr-welcome 7 | # Comment to be posted to on PRs from first time contributors in your repository 8 | newPRWelcomeComment: > 9 | Yay, your first pull request! :thumbsup: A contributor will be by to give feedback soon. In the meantime, please review the [Layer5 Community Welcome Guide](https://docs.google.com/document/d/17OPtDE_rdnPQxmk2Kauhm3GwXF1R5dZ3Cj8qZLKdo5E/edit?usp=sharing) and sure to join the [community Slack](http://slack.layer5.io/). 10 | 11 | Be sure to double-check that you have signed your commits. Here are instructions for [making signing an implicit activity while peforming a commit](../CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin). 12 | 13 | 14 | #------------------------------------------------------------------------------- 15 | # Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge 16 | # Comment to be posted to on pull requests merged by a first time user 17 | firstPRMergeComment: > 18 | Thanks for your contribution to the Layer5 community! :tada: 19 | 20 | ![Congrats!](https://raw.githubusercontent.com/layer5io/learn-layer5/master/.github/welcome/Layer5-celebration.png) 21 | 22 |       :star: Please [star the project](../stargazers) if you have yet to do so and sure to join the [community Slack](http://slack.layer5.io/). 23 | 24 | 25 | #------------------------------------------------------------------------------- 26 | # Configuration for request-info - https://github.com/behaviorbot/request-info 27 | # Comment to reply with 28 | requestInfoReplyComment: > 29 | Thanks for opening this issue. We welcome all input! If you could provide a little more information, this will greatly aid in its resolution. :thumbsup: 30 | # *OPTIONAL* Add a list of people whose Issues/PRs will not be commented on 31 | # keys must be GitHub usernames 32 | #requestInfoUserstoExclude: 33 | # - layer5io/maintainers 34 | 35 | 36 | #------------------------------------------------------------------------------- 37 | # Configuration for sentiment-bot - https://github.com/behaviorbot/sentiment-bot 38 | # *Required* toxicity threshold between 0 and .99 with the higher numbers being the most toxic 39 | # Anything higher than this threshold will be marked as toxic and commented on 40 | sentimentBotToxicityThreshold: .9 41 | 42 | # *Required* Comment to reply with 43 | sentimentBotReplyComment: > 44 | Please be sure to review the code of conduct and be respectful of other users. // @layer5io/maintainers 45 | 46 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-access/02-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: service-a 5 | namespace: 6 | --- 7 | apiVersion: v1 8 | kind: ServiceAccount 9 | metadata: 10 | name: service-b 11 | namespace: 12 | --- 13 | apiVersion: v1 14 | kind: ServiceAccount 15 | metadata: 16 | name: service-c 17 | namespace: 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: app-a-deployment 23 | namespace: 24 | labels: 25 | app: app-a 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app: app-a 31 | template: 32 | metadata: 33 | labels: 34 | app: app-a 35 | spec: 36 | serviceAccountName: service-a 37 | containers: 38 | - name: app-a 39 | image: layer5/learn-layer5:latest 40 | ports: 41 | - containerPort: 9091 42 | name: http 43 | env: 44 | - name: SERVICE_NAME 45 | value: "app-a" 46 | --- 47 | apiVersion: apps/v1 48 | kind: Deployment 49 | metadata: 50 | name: app-b-deployment 51 | namespace: 52 | labels: 53 | app: app-b 54 | spec: 55 | replicas: 1 56 | selector: 57 | matchLabels: 58 | app: app-b 59 | template: 60 | metadata: 61 | labels: 62 | app: app-b 63 | spec: 64 | serviceAccountName: service-b 65 | containers: 66 | - name: app-b 67 | image: layer5/learn-layer5:latest 68 | ports: 69 | - containerPort: 9091 70 | name: http 71 | env: 72 | - name: SERVICE_NAME 73 | value: "app-b" 74 | --- 75 | apiVersion: apps/v1 76 | kind: Deployment 77 | metadata: 78 | name: app-c-deployment 79 | namespace: 80 | labels: 81 | app: app-c 82 | spec: 83 | replicas: 1 84 | selector: 85 | matchLabels: 86 | app: app-c 87 | template: 88 | metadata: 89 | labels: 90 | app: app-c 91 | spec: 92 | serviceAccountName: service-c 93 | containers: 94 | - name: app-c 95 | image: layer5/learn-layer5:latest 96 | ports: 97 | - containerPort: 9091 98 | name: http 99 | env: 100 | - name: SERVICE_NAME 101 | value: "app-c" 102 | --- 103 | apiVersion: v1 104 | kind: Service 105 | metadata: 106 | name: app-a 107 | namespace: 108 | spec: 109 | type: NodePort 110 | selector: 111 | app: app-a 112 | ports: 113 | - name: http 114 | protocol: TCP 115 | port: 9091 116 | targetPort: 9091 117 | --- 118 | apiVersion: v1 119 | kind: Service 120 | metadata: 121 | name: app-b 122 | namespace: 123 | spec: 124 | type: NodePort 125 | selector: 126 | app: app-b 127 | ports: 128 | - name: http 129 | protocol: TCP 130 | port: 9091 131 | targetPort: 9091 132 | --- 133 | apiVersion: v1 134 | kind: Service 135 | metadata: 136 | name: app-c 137 | namespace: 138 | spec: 139 | type: NodePort 140 | selector: 141 | app: app-c 142 | ports: 143 | - name: http 144 | protocol: TCP 145 | port: 9091 146 | targetPort: 9091 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-spec/02-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: service-a 5 | namespace: 6 | --- 7 | apiVersion: v1 8 | kind: ServiceAccount 9 | metadata: 10 | name: service-b 11 | namespace: 12 | --- 13 | apiVersion: v1 14 | kind: ServiceAccount 15 | metadata: 16 | name: service-c 17 | namespace: 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: app-a-deployment 23 | namespace: 24 | labels: 25 | app: app-a 26 | spec: 27 | replicas: 1 28 | selector: 29 | matchLabels: 30 | app: app-a 31 | template: 32 | metadata: 33 | labels: 34 | app: app-a 35 | spec: 36 | serviceAccountName: service-a 37 | containers: 38 | - name: app-a 39 | image: layer5/learn-layer5:latest 40 | ports: 41 | - containerPort: 9091 42 | name: http 43 | env: 44 | - name: SERVICE_NAME 45 | value: "app-a" 46 | --- 47 | apiVersion: apps/v1 48 | kind: Deployment 49 | metadata: 50 | name: app-b-deployment 51 | namespace: 52 | labels: 53 | app: app-b 54 | spec: 55 | replicas: 1 56 | selector: 57 | matchLabels: 58 | app: app-b 59 | template: 60 | metadata: 61 | labels: 62 | app: app-b 63 | spec: 64 | serviceAccountName: service-b 65 | containers: 66 | - name: app-b 67 | image: layer5/learn-layer5:latest 68 | ports: 69 | - containerPort: 9091 70 | name: http 71 | env: 72 | - name: SERVICE_NAME 73 | value: "app-b" 74 | --- 75 | apiVersion: apps/v1 76 | kind: Deployment 77 | metadata: 78 | name: app-c-deployment 79 | namespace: 80 | labels: 81 | app: app-c 82 | spec: 83 | replicas: 1 84 | selector: 85 | matchLabels: 86 | app: app-c 87 | template: 88 | metadata: 89 | labels: 90 | app: app-c 91 | spec: 92 | serviceAccountName: service-c 93 | containers: 94 | - name: app-c 95 | image: layer5/learn-layer5:latest 96 | ports: 97 | - containerPort: 9091 98 | name: http 99 | env: 100 | - name: SERVICE_NAME 101 | value: "app-c" 102 | --- 103 | apiVersion: v1 104 | kind: Service 105 | metadata: 106 | name: app-a 107 | namespace: 108 | spec: 109 | type: NodePort 110 | selector: 111 | app: app-a 112 | ports: 113 | - name: http 114 | protocol: TCP 115 | port: 9091 116 | targetPort: 9091 117 | --- 118 | apiVersion: v1 119 | kind: Service 120 | metadata: 121 | name: app-b 122 | namespace: 123 | spec: 124 | type: NodePort 125 | selector: 126 | app: app-b 127 | ports: 128 | - name: http 129 | protocol: TCP 130 | port: 9091 131 | targetPort: 9091 132 | --- 133 | apiVersion: v1 134 | kind: Service 135 | metadata: 136 | name: app-c 137 | namespace: 138 | spec: 139 | type: NodePort 140 | selector: 141 | app: app-c 142 | ports: 143 | - name: http 144 | protocol: TCP 145 | port: 9091 146 | targetPort: 9091 -------------------------------------------------------------------------------- /smi-conformance/test-gen/test-yamls/traffic-split/02-install.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: app-a-deployment 5 | namespace: 6 | labels: 7 | app: app-a 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: app-a 13 | template: 14 | metadata: 15 | labels: 16 | app: app-a 17 | spec: 18 | containers: 19 | - name: app-a 20 | image: layer5/learn-layer5:latest 21 | ports: 22 | - containerPort: 9091 23 | name: http 24 | env: 25 | - name: SERVICE_NAME 26 | value: "app-a" 27 | --- 28 | apiVersion: apps/v1 29 | kind: Deployment 30 | metadata: 31 | name: app-b-deployment 32 | namespace: 33 | labels: 34 | app: app 35 | version: b 36 | spec: 37 | replicas: 1 38 | selector: 39 | matchLabels: 40 | app: app 41 | version: b 42 | template: 43 | metadata: 44 | labels: 45 | app: app 46 | version: b 47 | spec: 48 | containers: 49 | - name: app-b 50 | image: layer5/learn-layer5:latest 51 | ports: 52 | - containerPort: 9091 53 | name: http 54 | protocol: TCP 55 | env: 56 | - name: SERVICE_NAME 57 | value: "app-b" 58 | --- 59 | apiVersion: apps/v1 60 | kind: Deployment 61 | metadata: 62 | name: app-c-deployment 63 | namespace: 64 | labels: 65 | app: app 66 | version: c 67 | spec: 68 | replicas: 1 69 | selector: 70 | matchLabels: 71 | app: app 72 | version: c 73 | template: 74 | metadata: 75 | labels: 76 | app: app 77 | version: c 78 | spec: 79 | containers: 80 | - name: app-c 81 | image: layer5/learn-layer5:latest 82 | ports: 83 | - containerPort: 9091 84 | name: http 85 | protocol: TCP 86 | env: 87 | - name: SERVICE_NAME 88 | value: "app-c" 89 | --- 90 | apiVersion: v1 91 | kind: Service 92 | metadata: 93 | name: app-a 94 | namespace: 95 | spec: 96 | type: NodePort 97 | selector: 98 | app: app-a 99 | ports: 100 | - name: http 101 | protocol: TCP 102 | port: 9091 103 | targetPort: 9091 104 | --- 105 | apiVersion: v1 106 | kind: Service 107 | metadata: 108 | name: app-b 109 | namespace: 110 | spec: 111 | type: NodePort 112 | selector: 113 | app: app 114 | version: b 115 | ports: 116 | - name: http 117 | protocol: TCP 118 | port: 9091 119 | targetPort: 9091 120 | --- 121 | apiVersion: v1 122 | kind: Service 123 | metadata: 124 | name: app-c 125 | namespace: 126 | spec: 127 | type: NodePort 128 | selector: 129 | app: app 130 | version: c 131 | ports: 132 | - name: http 133 | protocol: TCP 134 | port: 9091 135 | targetPort: 9091 136 | --- 137 | apiVersion: v1 138 | kind: Service 139 | metadata: 140 | name: app-svc 141 | namespace: 142 | spec: 143 | type: NodePort 144 | selector: 145 | app: app 146 | ports: 147 | - name: http 148 | protocol: TCP 149 | port: 9091 150 | targetPort: 9091 -------------------------------------------------------------------------------- /deploy/k8s-maesh.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: 5 | --- 6 | apiVersion: v1 7 | kind: ServiceAccount 8 | metadata: 9 | name: service-a 10 | namespace: 11 | --- 12 | apiVersion: v1 13 | kind: ServiceAccount 14 | metadata: 15 | name: service-b 16 | namespace: 17 | --- 18 | apiVersion: v1 19 | kind: ServiceAccount 20 | metadata: 21 | name: service-c 22 | namespace: 23 | --- 24 | apiVersion: apps/v1 25 | kind: Deployment 26 | metadata: 27 | name: app-a-deployment 28 | namespace: 29 | labels: 30 | app: app-a 31 | spec: 32 | replicas: 1 33 | selector: 34 | matchLabels: 35 | app: app-a 36 | template: 37 | metadata: 38 | labels: 39 | app: app-a 40 | spec: 41 | serviceAccountName: service-a 42 | containers: 43 | - name: app-a 44 | image: layer5/learn-layer5:latest 45 | ports: 46 | - containerPort: 9091 47 | name: http 48 | env: 49 | - name: SERVICE_NAME 50 | value: "Service-a" 51 | --- 52 | apiVersion: apps/v1 53 | kind: Deployment 54 | metadata: 55 | name: app-b-deployment 56 | namespace: 57 | labels: 58 | app: app-b 59 | spec: 60 | replicas: 1 61 | selector: 62 | matchLabels: 63 | app: app-b 64 | template: 65 | metadata: 66 | labels: 67 | app: app-b 68 | spec: 69 | serviceAccountName: service-b 70 | containers: 71 | - name: app-b 72 | image: layer5/learn-layer5:latest 73 | ports: 74 | - containerPort: 9091 75 | name: http 76 | env: 77 | - name: SERVICE_NAME 78 | value: "Service-b" 79 | --- 80 | apiVersion: apps/v1 81 | kind: Deployment 82 | metadata: 83 | name: app-c-deployment 84 | namespace: 85 | labels: 86 | app: app-c 87 | spec: 88 | replicas: 1 89 | selector: 90 | matchLabels: 91 | app: app-c 92 | template: 93 | metadata: 94 | labels: 95 | app: app-c 96 | spec: 97 | serviceAccountName: service-c 98 | containers: 99 | - name: app-c 100 | image: layer5/learn-layer5:latest 101 | ports: 102 | - containerPort: 9091 103 | name: http 104 | env: 105 | - name: SERVICE_NAME 106 | value: "Service-c" 107 | --- 108 | apiVersion: v1 109 | kind: Service 110 | metadata: 111 | name: app-a 112 | namespace: 113 | spec: 114 | type: NodePort 115 | selector: 116 | app: app-a 117 | ports: 118 | - name: http 119 | protocol: TCP 120 | port: 9091 121 | targetPort: 9091 122 | --- 123 | apiVersion: v1 124 | kind: Service 125 | metadata: 126 | name: app-b 127 | namespace: 128 | spec: 129 | type: NodePort 130 | selector: 131 | app: app-b 132 | ports: 133 | - name: http 134 | protocol: TCP 135 | port: 9091 136 | targetPort: 9091 137 | --- 138 | apiVersion: v1 139 | kind: Service 140 | metadata: 141 | name: app-c 142 | namespace: 143 | spec: 144 | type: NodePort 145 | selector: 146 | app: app-c 147 | ports: 148 | - name: http 149 | protocol: TCP 150 | port: 9091 151 | targetPort: 9091 -------------------------------------------------------------------------------- /deploy/linkerd/app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Namespace 3 | metadata: 4 | name: 5 | annotations: 6 | 'linkerd.io/inject': 'enabled' 7 | --- 8 | apiVersion: apps/v1 9 | kind: Deployment 10 | metadata: 11 | name: app-a-deployment 12 | namespace: 13 | labels: 14 | app: app-a 15 | spec: 16 | replicas: 1 17 | selector: 18 | matchLabels: 19 | app: app-a 20 | template: 21 | metadata: 22 | labels: 23 | app: app-a 24 | spec: 25 | containers: 26 | - name: app-a 27 | image: layer5/learn-layer5:latest 28 | ports: 29 | - containerPort: 9091 30 | name: http 31 | env: 32 | - name: SERVICE_NAME 33 | value: "app-a" 34 | --- 35 | apiVersion: apps/v1 36 | kind: Deployment 37 | metadata: 38 | name: app-b-deployment 39 | namespace: 40 | labels: 41 | app: app 42 | version: v1 43 | spec: 44 | replicas: 1 45 | selector: 46 | matchLabels: 47 | app: app 48 | version: v1 49 | template: 50 | metadata: 51 | labels: 52 | app: app 53 | version: v1 54 | spec: 55 | containers: 56 | - name: app-b 57 | image: layer5/learn-layer5:latest 58 | ports: 59 | - containerPort: 9091 60 | name: http 61 | protocol: TCP 62 | env: 63 | - name: SERVICE_NAME 64 | value: "app-b" 65 | --- 66 | apiVersion: apps/v1 67 | kind: Deployment 68 | metadata: 69 | name: app-c-deployment 70 | namespace: 71 | labels: 72 | app: app 73 | version: v2 74 | spec: 75 | replicas: 1 76 | selector: 77 | matchLabels: 78 | app: app 79 | version: v2 80 | template: 81 | metadata: 82 | labels: 83 | app: app 84 | version: v2 85 | spec: 86 | containers: 87 | - name: app-c 88 | image: layer5/learn-layer5:latest 89 | ports: 90 | - containerPort: 9091 91 | name: http 92 | protocol: TCP 93 | env: 94 | - name: SERVICE_NAME 95 | value: "app-c" 96 | --- 97 | apiVersion: v1 98 | kind: Service 99 | metadata: 100 | name: app-v1 101 | namespace: 102 | spec: 103 | type: NodePort 104 | selector: 105 | app: app 106 | version: v1 107 | ports: 108 | - name: http 109 | protocol: TCP 110 | port: 9091 111 | targetPort: 9091 112 | --- 113 | apiVersion: v1 114 | kind: Service 115 | metadata: 116 | name: app-v2 117 | namespace: 118 | spec: 119 | type: NodePort 120 | selector: 121 | app: app 122 | version: v2 123 | ports: 124 | - name: http 125 | protocol: TCP 126 | port: 9091 127 | targetPort: 9091 128 | --- 129 | apiVersion: v1 130 | kind: Service 131 | metadata: 132 | name: app-svc 133 | namespace: 134 | spec: 135 | type: NodePort 136 | selector: 137 | app: app 138 | ports: 139 | - name: http 140 | protocol: TCP 141 | port: 9091 142 | targetPort: 9091 143 | 144 | # for i in {1..20};do curl app-svc..svc.cluster.local.:9091/echo; echo; done 145 | # curl app-v1..svc.cluster.local.:9091/metrics 146 | # curl -X "DELETE" app-v1..svc.cluster.local.:9091/metrics -------------------------------------------------------------------------------- /smi-conformance/test-gen/utils.go: -------------------------------------------------------------------------------- 1 | package test_gen 2 | 3 | import ( 4 | "bytes" 5 | "context" 6 | "encoding/json" 7 | "errors" 8 | "fmt" 9 | "io/ioutil" 10 | "net/http" 11 | "time" 12 | 13 | v1 "k8s.io/api/core/v1" 14 | "sigs.k8s.io/controller-runtime/pkg/client" 15 | ) 16 | 17 | // App service names 18 | const ( 19 | SvcNameA = "app-a" 20 | SvcNameB = "app-b" 21 | SvcNameC = "app-c" 22 | ) 23 | 24 | // App API endpoints 25 | const ( 26 | METRICS = "metrics" 27 | CALL = "call" 28 | ECHO = "echo" 29 | ) 30 | 31 | // URLstruct is a part of the metrics exposed by the app 32 | type URLstruct struct { 33 | URL string 34 | Method string 35 | Headers map[string]string 36 | } 37 | 38 | // MetricResponse is a part of the metrics exposed by the app 39 | type MetricResponse struct { 40 | ReqReceived []string 41 | RespSucceeded []URLstruct 42 | RespFailed []URLstruct 43 | } 44 | 45 | // GetClusterIPs returns the ClusterIPs of various services exposed in the namespace 46 | func GetClusterIPs(kubeClient client.Client, namespace string) (map[string]string, error) { 47 | deps := &v1.ServiceList{} 48 | err := kubeClient.List(context.TODO(), deps, client.InNamespace(namespace)) 49 | if err != nil { 50 | return nil, err 51 | } 52 | ipMap := make(map[string]string) 53 | for _, svc := range deps.Items { 54 | ipMap[svc.Name] = svc.Spec.ClusterIP 55 | } 56 | return ipMap, nil 57 | } 58 | 59 | // GetHTTPClient returns a configured HTTP client 60 | func GetHTTPClient() http.Client { 61 | return http.Client{ 62 | Timeout: 30 * time.Second, 63 | } 64 | } 65 | 66 | // ClearMetrics remove all the resources 67 | func ClearMetrics(hostname string, port string) error { 68 | url := fmt.Sprintf("http://%s:%s/%s", hostname, port, METRICS) 69 | httpClient := GetHTTPClient() 70 | req, err := http.NewRequest(http.MethodDelete, url, nil) 71 | if err != nil { 72 | return err 73 | } 74 | resp, err := httpClient.Do(req) 75 | if err != nil { 76 | return err 77 | } 78 | if resp.StatusCode != http.StatusOK { 79 | return errors.New("Request failed") 80 | } 81 | return nil 82 | } 83 | 84 | // GetMetrics return a type MetricResponse 85 | func GetMetrics(hostname string, port string) (*MetricResponse, error) { 86 | url := fmt.Sprintf("http://%s:%s/%s", hostname, port, METRICS) 87 | httpClient := GetHTTPClient() 88 | resp, err := httpClient.Get(url) 89 | if err != nil { 90 | return nil, err 91 | } 92 | if resp.StatusCode != http.StatusOK { 93 | return nil, errors.New("Request failed") 94 | } 95 | data, err := ioutil.ReadAll(resp.Body) 96 | if err != nil { 97 | return nil, err 98 | } 99 | defer resp.Body.Close() 100 | metrics := MetricResponse{} 101 | if err := json.Unmarshal(data, &metrics); err != nil { 102 | return nil, err 103 | } 104 | return &metrics, nil 105 | } 106 | 107 | func generatePOSTLoad(no int, url string, body []byte) error { 108 | hclient := GetHTTPClient() 109 | for i := 0; i < no; i++ { 110 | if _, err := hclient.Post(url, "application/json", bytes.NewReader(body)); err != nil { 111 | return err 112 | } 113 | } 114 | return nil 115 | } 116 | 117 | // ClearAllMetrics aggregate all the svc metrics 118 | func ClearAllMetrics(clusterIPs map[string]string, smObj ServiceMesh) { 119 | ClearMetrics(clusterIPs[SvcNameA], smObj.SvcAGetPort()) 120 | ClearMetrics(clusterIPs[SvcNameB], smObj.SvcBGetPort()) 121 | ClearMetrics(clusterIPs[SvcNameC], smObj.SvcCGetPort()) 122 | } 123 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/test_gen.go: -------------------------------------------------------------------------------- 1 | package test_gen 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "testing" 7 | "time" 8 | 9 | harness "github.com/kudobuilder/kuttl/pkg/apis/testharness/v1beta1" 10 | "github.com/kudobuilder/kuttl/pkg/report" 11 | "github.com/kudobuilder/kuttl/pkg/test" 12 | testutils "github.com/kudobuilder/kuttl/pkg/test/utils" 13 | ) 14 | 15 | type Failure struct { 16 | Text string `json:"text,omitempty"` 17 | Message string `json:"message,omitempty"` 18 | } 19 | 20 | type Results struct { 21 | Name string `json:"name,omitempty"` 22 | Tests int `json:"tests,omitempty"` 23 | Failures int `json:"failures,omitempty"` 24 | Time string `json:"time,omitempty"` 25 | Testsuite []struct { 26 | Tests int `json:"tests,omitempty"` 27 | Failures int `json:"failures,omitempty"` 28 | Time string `json:"time,omitempty"` 29 | Name string `json:"name,omitempty"` 30 | Testcase []struct { 31 | Classname string `json:"classname,omitempty"` 32 | Name string `json:"name,omitempty"` 33 | Time string `json:"time,omitempty"` 34 | Assertions int `json:"assertions,omitempty"` 35 | Failure Failure `json:"failure,omitempty"` 36 | } `json:"testcase,omitempty"` 37 | } `json:"testsuite,omitempty"` 38 | } 39 | 40 | func RunTest(meshConfig ServiceMesh, annotations, labels map[string]string) Results { 41 | 42 | c := make(chan Results) 43 | go func() { 44 | manifestDirs := []string{} 45 | results := &report.Testsuites{} 46 | output := Results{} 47 | 48 | // Run all testCases 49 | testToRun := "" 50 | // Run only traffic-split 51 | // testToRun := "traffic-split" 52 | 53 | options := harness.TestSuite{} 54 | 55 | args := []string{"./test-yamls/"} 56 | 57 | options.TestDirs = args 58 | options.Timeout = 180 59 | options.Parallel = 1 60 | options.TestDirs = manifestDirs 61 | options.StartKIND = false 62 | options.SkipDelete = false 63 | 64 | if options.KINDContext == "" { 65 | options.KINDContext = harness.DefaultKINDContext 66 | } 67 | 68 | serviceMeshConfObj := SMIConformance{ 69 | SMObj: meshConfig, 70 | } 71 | 72 | if len(args) != 0 { 73 | options.TestDirs = args 74 | } 75 | 76 | testHandlers := make(map[string]map[string]test.CustomTest) 77 | testHandlers["traffic-access"] = serviceMeshConfObj.TrafficAccessGetTests() 78 | testHandlers["traffic-spec"] = serviceMeshConfObj.TrafficSpecGetTests() 79 | testHandlers["traffic-split"] = serviceMeshConfObj.TrafficSplitGetTests() 80 | 81 | testutils.RunTests("kudo", testToRun, options.Parallel, func(t *testing.T) { 82 | harness := test.Harness{ 83 | TestSuite: options, 84 | T: t, 85 | SuiteCustomTests: testHandlers, 86 | NamespaceAnnotations: annotations, 87 | NamespaceLabels: labels, 88 | } 89 | 90 | // Runs the test using the inCluster kubeConfig (runs only when the code is running inside the pod) 91 | harness.InCluster = true 92 | 93 | s, _ := json.MarshalIndent(options, "", " ") 94 | fmt.Printf("Running integration tests with following options:\n%s\n", string(s)) 95 | results = harness.Run() 96 | data, _ := json.Marshal(results) 97 | // Results of the test 98 | fmt.Printf("Results :\n%v\n", string(data)) 99 | err := json.Unmarshal([]byte(data), &output) 100 | if err != nil { 101 | fmt.Printf("Unable to unmarshal results") 102 | } 103 | c <- output 104 | time.Sleep(30 * time.Second) 105 | }) 106 | }() 107 | return <-c 108 | } 109 | -------------------------------------------------------------------------------- /deploy/k8s-consul.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ServiceAccount 3 | metadata: 4 | name: service-a 5 | automountServiceAccountToken: false 6 | --- 7 | apiVersion: v1 8 | kind: ServiceAccount 9 | metadata: 10 | name: service-b 11 | automountServiceAccountToken: false 12 | --- 13 | apiVersion: v1 14 | kind: ServiceAccount 15 | metadata: 16 | name: service-c 17 | automountServiceAccountToken: false 18 | --- 19 | apiVersion: apps/v1 20 | kind: Deployment 21 | metadata: 22 | name: service-a-deployment 23 | labels: 24 | app: service-a 25 | spec: 26 | replicas: 1 27 | selector: 28 | matchLabels: 29 | app: service-a 30 | template: 31 | metadata: 32 | name: service-a 33 | labels: 34 | app: service-a 35 | annotations: 36 | 'consul.hashicorp.com/connect-inject': 'true' 37 | 'consul.hashicorp.com/connect-service-upstreams': 'service-b:9092' 38 | spec: 39 | serviceAccountName: service-a 40 | automountServiceAccountToken: true 41 | containers: 42 | - name: service-a 43 | image: layer5/learn-layer5:latest 44 | ports: 45 | - containerPort: 9091 46 | name: http 47 | env: 48 | - name: SERVICE_NAME 49 | value: "Service-a" 50 | --- 51 | apiVersion: apps/v1 52 | kind: Deployment 53 | metadata: 54 | name: service-b-deployment 55 | labels: 56 | app: service-b 57 | spec: 58 | replicas: 1 59 | selector: 60 | matchLabels: 61 | app: service-b 62 | template: 63 | metadata: 64 | name: service-b 65 | annotations: 66 | 'consul.hashicorp.com/connect-inject': 'true' 67 | "consul.hashicorp.com/connect-service": "service-b" 68 | labels: 69 | app: service-b 70 | spec: 71 | serviceAccountName: service-b 72 | automountServiceAccountToken: true 73 | containers: 74 | - name: service-b 75 | image: layer5/learn-layer5:latest 76 | ports: 77 | - containerPort: 9091 78 | env: 79 | - name: SERVICE_NAME 80 | value: "Service-b" 81 | --- 82 | apiVersion: apps/v1 83 | kind: Deployment 84 | metadata: 85 | name: service-c-deployment 86 | labels: 87 | app: service-c 88 | spec: 89 | replicas: 1 90 | selector: 91 | matchLabels: 92 | app: service-c 93 | template: 94 | metadata: 95 | name: service-c 96 | annotations: 97 | 'consul.hashicorp.com/connect-inject': 'true' 98 | "consul.hashicorp.com/connect-service": "service-c" 99 | labels: 100 | app: service-c 101 | spec: 102 | serviceAccountName: service-c 103 | automountServiceAccountToken: true 104 | containers: 105 | - name: service-c 106 | image: layer5/learn-layer5:latest 107 | ports: 108 | - containerPort: 9091 109 | env: 110 | - name: SERVICE_NAME 111 | value: "Service-c" 112 | --- 113 | apiVersion: v1 114 | kind: Service 115 | metadata: 116 | name: app-a 117 | spec: 118 | type: LoadBalancer 119 | selector: 120 | app: app-a 121 | ports: 122 | - name: http 123 | protocol: TCP 124 | port: 9091 125 | # targetPort: 9091 126 | --- 127 | apiVersion: v1 128 | kind: Service 129 | metadata: 130 | name: app-b 131 | spec: 132 | type: LoadBalancer 133 | selector: 134 | app: app-b 135 | ports: 136 | - name: http 137 | protocol: TCP 138 | port: 9091 139 | # targetPort: 9091 140 | --- 141 | apiVersion: v1 142 | kind: Service 143 | metadata: 144 | name: app-c 145 | spec: 146 | type: LoadBalancer 147 | selector: 148 | app: app-c 149 | ports: 150 | - name: http 151 | protocol: TCP 152 | port: 9091 153 | # targetPort: 9091 154 | -------------------------------------------------------------------------------- /img/readme/meshery-logo-light-text.svg: -------------------------------------------------------------------------------- 1 | meshery-logo-light-text -------------------------------------------------------------------------------- /smi-conformance/test-gen/service-mesh.go: -------------------------------------------------------------------------------- 1 | package test_gen 2 | 3 | import "fmt" 4 | 5 | // SMIConformance holds the SMI conformance tests 6 | type SMIConformance struct { 7 | SMObj ServiceMesh 8 | } 9 | 10 | // ServiceMesh provides an abstract interface for different service meshes. 11 | // This is required as each service mesh has different ways to expose their internals. 12 | type ServiceMesh interface { 13 | SvcAGetInternalName(string) string 14 | SvcBGetInternalName(string) string 15 | SvcCGetInternalName(string) string 16 | 17 | SvcAGetPort() string 18 | SvcBGetPort() string 19 | SvcCGetPort() string 20 | } 21 | 22 | type Maesh struct { 23 | PortSvcA string 24 | PortSvcB string 25 | PortSvcC string 26 | } 27 | 28 | func (sm Maesh) SvcAGetInternalName(namespace string) string { 29 | return fmt.Sprintf("http://%s.%s.maesh:%s", SvcNameA, namespace, sm.PortSvcA) 30 | } 31 | 32 | func (sm Maesh) SvcBGetInternalName(namespace string) string { 33 | return fmt.Sprintf("http://%s.%s.maesh:%s", SvcNameB, namespace, sm.PortSvcB) 34 | } 35 | 36 | func (sm Maesh) SvcCGetInternalName(namespace string) string { 37 | return fmt.Sprintf("http://%s.%s.maesh:%s", SvcNameC, namespace, sm.PortSvcC) 38 | } 39 | 40 | func (sm Maesh) SvcAGetPort() string { 41 | return sm.PortSvcA 42 | } 43 | 44 | func (sm Maesh) SvcBGetPort() string { 45 | return sm.PortSvcB 46 | } 47 | 48 | func (sm Maesh) SvcCGetPort() string { 49 | return sm.PortSvcC 50 | } 51 | 52 | type Linkerd struct { 53 | PortSvcA string 54 | PortSvcB string 55 | PortSvcC string 56 | } 57 | 58 | func (sm Linkerd) SvcAGetInternalName(namespace string) string { 59 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameA, namespace, sm.PortSvcA) 60 | } 61 | 62 | func (sm Linkerd) SvcBGetInternalName(namespace string) string { 63 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameB, namespace, sm.PortSvcB) 64 | } 65 | 66 | func (sm Linkerd) SvcCGetInternalName(namespace string) string { 67 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameC, namespace, sm.PortSvcC) 68 | } 69 | 70 | func (sm Linkerd) SvcAGetPort() string { 71 | return sm.PortSvcA 72 | } 73 | 74 | func (sm Linkerd) SvcBGetPort() string { 75 | return sm.PortSvcB 76 | } 77 | 78 | func (sm Linkerd) SvcCGetPort() string { 79 | return sm.PortSvcC 80 | } 81 | 82 | type Istio struct { 83 | PortSvcA string 84 | PortSvcB string 85 | PortSvcC string 86 | } 87 | 88 | func (sm Istio) SvcAGetInternalName(namespace string) string { 89 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameA, namespace, sm.PortSvcA) 90 | } 91 | 92 | func (sm Istio) SvcBGetInternalName(namespace string) string { 93 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameB, namespace, sm.PortSvcB) 94 | } 95 | 96 | func (sm Istio) SvcCGetInternalName(namespace string) string { 97 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameC, namespace, sm.PortSvcC) 98 | } 99 | 100 | func (sm Istio) SvcAGetPort() string { 101 | return sm.PortSvcA 102 | } 103 | 104 | func (sm Istio) SvcBGetPort() string { 105 | return sm.PortSvcB 106 | } 107 | 108 | func (sm Istio) SvcCGetPort() string { 109 | return sm.PortSvcC 110 | } 111 | 112 | type OSM struct { 113 | PortSvcA string 114 | PortSvcB string 115 | PortSvcC string 116 | } 117 | 118 | func (sm OSM) SvcAGetInternalName(namespace string) string { 119 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameA, namespace, sm.PortSvcA) 120 | } 121 | 122 | func (sm OSM) SvcBGetInternalName(namespace string) string { 123 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameB, namespace, sm.PortSvcB) 124 | } 125 | 126 | func (sm OSM) SvcCGetInternalName(namespace string) string { 127 | return fmt.Sprintf("http://%s.%s..svc.cluster.local.:%s", SvcNameC, namespace, sm.PortSvcC) 128 | } 129 | 130 | func (sm OSM) SvcAGetPort() string { 131 | return sm.PortSvcA 132 | } 133 | 134 | func (sm OSM) SvcBGetPort() string { 135 | return sm.PortSvcB 136 | } 137 | 138 | func (sm OSM) SvcCGetPort() string { 139 | return sm.PortSvcC 140 | } 141 | -------------------------------------------------------------------------------- /deploy/maesh.yaml: -------------------------------------------------------------------------------- 1 | # Default values for Maesh. 2 | image: 3 | name: containous/maesh 4 | # (Optional) 5 | # pullPolicy: IfNotPresent 6 | # (Optional) 7 | # tag: v1.1.0 8 | # (Optional) 9 | # pullSecret: xxx 10 | 11 | acl: true 12 | 13 | kubedns: true 14 | 15 | # clusterDomain: cluster.local 16 | 17 | # logLevel: error 18 | # logFormat: common 19 | 20 | # defaultMode: http 21 | 22 | limits: 23 | http: 10 24 | tcp: 25 25 | udp: 25 26 | 27 | controller: 28 | # logLevel: error 29 | # logFormat: common 30 | 31 | # ignoreNamespaces: 32 | # - example 33 | 34 | # watchNamespaces: 35 | # - example 36 | 37 | resources: 38 | limit: 39 | mem: 100Mi 40 | cpu: 200m 41 | request: 42 | mem: 50Mi 43 | cpu: 100m 44 | 45 | # Added so we can launch on nodes with restrictions. 46 | nodeSelector: {} 47 | tolerations: [] 48 | affinity: {} 49 | 50 | mesh: 51 | # (Deprecated) 52 | # defaultMode: http 53 | 54 | # logLevel: error 55 | # logFormat: common 56 | 57 | # pollInterval: 1s 58 | # pollTimeout: 1s 59 | 60 | # forwardingTimeouts: 61 | # dialTimeout: 30s 62 | # (Optional) 63 | # responseHeaderTimeout: 0s 64 | # (Optional) 65 | # idleConnTimeout: 1s 66 | 67 | # env: 68 | # - name: NAME 69 | # value: "value" 70 | 71 | # envFrom: 72 | # - configMapRef: 73 | # name: config 74 | 75 | # additionalArguments: 76 | # - "--name=value" 77 | 78 | resources: 79 | limit: 80 | mem: 100Mi 81 | cpu: 200m 82 | request: 83 | mem: 50Mi 84 | cpu: 100m 85 | 86 | # Added so we can launch on nodes with restrictions. 87 | nodeSelector: {} 88 | tolerations: [] 89 | 90 | # Additional deployment annotations. 91 | # annotations: {} 92 | 93 | # Additional pod annotations. 94 | # podAnnotations: {} 95 | 96 | # 97 | # Tracing configuration. 98 | # 99 | tracing: 100 | deploy: false 101 | jaeger: 102 | image: 103 | name: groundnuty/k8s-wait-for:v1.3 104 | enabled: false 105 | localagenthostport: "" 106 | samplingserverurl: "" 107 | # datadog: 108 | # localagenthostport: "127.0.0.1:8126" 109 | # (Optional) 110 | # debug: true 111 | # (Optional) 112 | # globalTag: "sample" 113 | # (Optional) 114 | # prioritySampling: true 115 | # zipkin: 116 | # httpEndpoint: "127.0.0.1:8125" 117 | # (Optional) 118 | # sameSpan: true 119 | # (Optional) 120 | # id128Bit: true 121 | # (Optional) 122 | # sampleRate: 0.2 123 | # instana: 124 | # localAgentHost: "127.0.0.1" 125 | # localAgentPort: 42699 126 | # logLevel: info 127 | # haystack: 128 | # localAgentHost: "127.0.0.1" 129 | # localAgentPort: 42699 130 | # (Optional) 131 | # globalTag: "sample:test" 132 | # (Optional) 133 | # traceIDHeaderName: "sample" 134 | # (Optional) 135 | # parentIDHeaderName: "sample" 136 | # (Optional) 137 | # spanIDHeaderName: "sample" 138 | # (Optional) 139 | # baggagePrefixHeaderName: "sample" 140 | 141 | # 142 | # Metrics configuration. 143 | # 144 | metrics: 145 | deploy: false 146 | prometheus: 147 | # whether to expose Prometheus metrics 148 | enabled: false 149 | ## you can override values of the metrics subchart here. 150 | ## check charts/metrics/values.yaml for the defaults. 151 | ## example: 152 | # grafana: 153 | # storageClassName: "metrics-storage" 154 | # resources: 155 | # limit: 156 | # mem: "500Mi" 157 | # cpu: "500m" 158 | # request: 159 | # mem: "200Mi" 160 | # cpu: "200m" 161 | # datadog: 162 | # address: "127.0.0.1:8125" 163 | # (Optional) 164 | # addEntrypointsLabels: true 165 | # (Optional) 166 | # addServiceLabels: true 167 | # (Optional) 168 | # pushInterval: 10s 169 | # influxdb: 170 | # address: "localhost:8089" 171 | # protocol: "udp" 172 | # (Optional) 173 | # database: "db" 174 | # (Optional) 175 | # retentionPolicy: "two_hours" 176 | # (Optional) 177 | # username: "john" 178 | # (Optional) 179 | # password: "secret" 180 | # (Optional) 181 | # addEntrypointsLabels: true 182 | # (Optional) 183 | # addServiceLabels: true 184 | # (Optional) 185 | # pushInterval: 10s 186 | # statsd: 187 | # address: "127.0.0.1:8125" 188 | # (Optional) 189 | # addEntrypointsLabels: true 190 | # (Optional) 191 | # addServiceLabels: true 192 | # (Optional) 193 | # pushInterval: 10s 194 | -------------------------------------------------------------------------------- /.github/label-commenter-config.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | # header: "Please note the following requirement:" 3 | footer: "\ 4 | ---\n\n 5 | >         Be sure to [join the community](https://slack.meshery.io), if you haven't yet and please leave a :star: [star on the project](../stargazers) :smile: 6 | " 7 | 8 | labels: 9 | - name: issue/design required 10 | labeled: 11 | issue: 12 | body: This issue has been labeled with 'design-required'. Note that prior to commencing on implementation, a design specification needs to be created and reviewed for approval. See [Creating a Functional Specification](https://docs.google.com/document/d/1RP3IWLc-MiQS-QYasqCoVuCH7--G87p5ezE5f_nOzB8/edit?usp=sharing) to create a design spec. 13 | action: open 14 | - name: issue/remind 15 | labeled: 16 | issue: 17 | body: Checking in... it has been awhile since we've heard from you on this issue. Are you still working on it? Please let us know and please don't hesitate to contact a [MeshMate](https://layer5.io/community/meshmates/) or any other [community member](https://layer5.io/community/members) for assistance. 18 | action: open 19 | pr: 20 | body: Checking in... it has been awhile since we've heard from you on this issue. Are you still working on it? Please let us know and please don't hesitate to contact a [MeshMate](https://layer5.io/community/meshmates/) or any other [community member](https://layer5.io/community/members) for assistance. 21 | action: open 22 | - name: issue/dco 23 | labeled: 24 | issue: 25 | body: "🚨 Alert! Git Police! We couldn’t help but notice that one or more of your commits is missing a sign-off. _A what?_ A commit sign-off (your email address).\n\n 26 | To amend the commits in this PR with your signoff using the instructions provided in the DCO check. \n\n 27 | To configure your dev environment to automatically signoff on your commits in the future, see [these instructions](https://github.com/meshery/meshery/blob/master/CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)." 28 | action: open 29 | pr: 30 | body: "🚨 Alert! Git Police! We couldn’t help but notice that one or more of your commits is missing a sign-off. _A what?_ A commit sign-off (your email address).\n\n 31 | To amend the commits in this PR with your signoff using the instructions provided in the DCO check. \n\n 32 | To configure your dev environment to automatically signoff on your commits in the future, see [these instructions](https://github.com/meshery/meshery/blob/master/CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)." 33 | action: open 34 | - name: component/ui 35 | labeled: 36 | issue: 37 | body: This issue has been labeled with 'component/ui'. 🧰 Here are docs on [Contributing to Meshery UI](https://docs.meshery.io/project/contributing/contributing-ui). 🎨 Here is the [Meshery UI Figma File](https://www.figma.com/file/SMP3zxOjZztdOLtgN4dS2W/Meshery-UI?node-id=4%3A0) File. Lastly, here are docs on [Contributing to Meshery's End-to-End Tests Using Cypress](https://docs.meshery.io/project/contributing/contributing-cypress). 38 | action: open 39 | pr: 40 | body: This PR has been labeled with 'component/ui'. 🧰 Here are docs on [Contributing to Meshery UI](https://docs.meshery.io/project/contributing/contributing-ui). 🎨 Here is the [Meshery UI Figma File](https://www.figma.com/file/SMP3zxOjZztdOLtgN4dS2W/Meshery-UI?node-id=4%3A0) File. Lastly, here are docs on [Contributing to Meshery's End-to-End Tests Using Cypress](https://docs.meshery.io/project/contributing/contributing-cypress) 41 | action: open 42 | - name: component/mesheryctl 43 | labeled: 44 | issue: 45 | body: This issue has been labeled with 'component/mesheryctl'. Note that after making changes you need to update it in the [mesheryctl command tracker](https://docs.google.com/spreadsheets/d/1q63sIGAuCnIeDs8PeM-0BAkNj8BBgPUXhLbe1Y-318o/edit#gid=0) spreadsheet. 46 | action: open 47 | pr: 48 | body: This PR has been labeled with 'component/mesheryctl'. Note that after making changes you need to update it in the [mesheryctl command tracker](https://docs.google.com/spreadsheets/d/1q63sIGAuCnIeDs8PeM-0BAkNj8BBgPUXhLbe1Y-318o/edit#gid=0) spreadsheet. 49 | action: open 50 | # pr: 51 | # body: Hi, please note that this issue will need an approved design specification before implementation proceeds. See [Creating a Functional Specification](https://docs.google.com/document/d/1RP3IWLc-MiQS-QYasqCoVuCH7--G87p5ezE5f_nOzB8/edit?usp=sharing) to create a design spec. 52 | # action: open 53 | -------------------------------------------------------------------------------- /.github/workflows/label-commenter-config.yml: -------------------------------------------------------------------------------- 1 | comment: 2 | # header: "Please note the following requirement:" 3 | footer: "\ 4 | ---\n\n 5 | >         Be sure to [join the community](https://slack.meshery.io), if you haven't yet and please leave a :star: [star on the project](../stargazers) :smile: 6 | " 7 | 8 | labels: 9 | - name: issue/design required 10 | labeled: 11 | issue: 12 | body: This issue has been labeled with 'design-required'. Note that prior to commencing on implementation, a design specification needs to be created and reviewed for approval. See [Creating a Functional Specification](https://docs.google.com/document/d/1RP3IWLc-MiQS-QYasqCoVuCH7--G87p5ezE5f_nOzB8/edit?usp=sharing) to create a design spec. 13 | action: open 14 | - name: issue/remind 15 | labeled: 16 | issue: 17 | body: Checking in... it has been awhile since we've heard from you on this issue. Are you still working on it? Please let us know and please don't hesitate to contact a [MeshMate](https://layer5.io/community/meshmates/) or any other [community member](https://layer5.io/community/members) for assistance. 18 | action: open 19 | pr: 20 | body: Checking in... it has been awhile since we've heard from you on this issue. Are you still working on it? Please let us know and please don't hesitate to contact a [MeshMate](https://layer5.io/community/meshmates/) or any other [community member](https://layer5.io/community/members) for assistance. 21 | action: open 22 | - name: issue/dco 23 | labeled: 24 | issue: 25 | body: "🚨 Alert! Git Police! We couldn’t help but notice that one or more of your commits is missing a sign-off. _A what?_ A commit sign-off (your email address).\n\n 26 | To amend the commits in this PR with your signoff using the instructions provided in the DCO check. \n\n 27 | To configure your dev environment to automatically signoff on your commits in the future, see [these instructions](https://github.com/meshery/meshery/blob/master/CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)." 28 | action: open 29 | pr: 30 | body: "🚨 Alert! Git Police! We couldn’t help but notice that one or more of your commits is missing a sign-off. _A what?_ A commit sign-off (your email address).\n\n 31 | To amend the commits in this PR with your signoff using the instructions provided in the DCO check. \n\n 32 | To configure your dev environment to automatically signoff on your commits in the future, see [these instructions](https://github.com/meshery/meshery/blob/master/CONTRIBUTING.md#signing-off-on-commits-developer-certificate-of-origin)." 33 | action: open 34 | - name: component/ui 35 | labeled: 36 | issue: 37 | body: This issue has been labeled with 'component/ui'. 🧰 Here are docs on [Contributing to Meshery UI](https://docs.meshery.io/project/contributing/contributing-ui). 🎨 Here is the [Meshery UI Figma File](https://www.figma.com/file/SMP3zxOjZztdOLtgN4dS2W/Meshery-UI?node-id=4%3A0) File. Lastly, here are docs on [Contributing to Meshery's End-to-End Tests Using Cypress](https://docs.meshery.io/project/contributing/contributing-cypress). 38 | action: open 39 | pr: 40 | body: This PR has been labeled with 'component/ui'. 🧰 Here are docs on [Contributing to Meshery UI](https://docs.meshery.io/project/contributing/contributing-ui). 🎨 Here is the [Meshery UI Figma File](https://www.figma.com/file/SMP3zxOjZztdOLtgN4dS2W/Meshery-UI?node-id=4%3A0) File. Lastly, here are docs on [Contributing to Meshery's End-to-End Tests Using Cypress](https://docs.meshery.io/project/contributing/contributing-cypress) 41 | action: open 42 | - name: component/mesheryctl 43 | labeled: 44 | issue: 45 | body: This issue has been labeled with 'component/mesheryctl'. Note that after making changes you need to update it in the [mesheryctl command tracker](https://docs.google.com/spreadsheets/d/1q63sIGAuCnIeDs8PeM-0BAkNj8BBgPUXhLbe1Y-318o/edit#gid=0) spreadsheet. 46 | action: open 47 | pr: 48 | body: This PR has been labeled with 'component/mesheryctl'. Note that after making changes you need to update it in the [mesheryctl command tracker](https://docs.google.com/spreadsheets/d/1q63sIGAuCnIeDs8PeM-0BAkNj8BBgPUXhLbe1Y-318o/edit#gid=0) spreadsheet. 49 | action: open 50 | # pr: 51 | # body: Hi, please note that this issue will need an approved design specification before implementation proceeds. See [Creating a Functional Specification](https://docs.google.com/document/d/1RP3IWLc-MiQS-QYasqCoVuCH7--G87p5ezE5f_nOzB8/edit?usp=sharing) to create a design spec. 52 | # action: open 53 | 54 | 55 | -------------------------------------------------------------------------------- /smi-conformance/grpc/handlers.go: -------------------------------------------------------------------------------- 1 | package grpc 2 | 3 | import ( 4 | "context" 5 | "regexp" 6 | "strconv" 7 | 8 | empty "github.com/golang/protobuf/ptypes/empty" 9 | "github.com/layer5io/learn-layer5/smi-conformance/conformance" 10 | test_gen "github.com/layer5io/learn-layer5/smi-conformance/test-gen" 11 | service "github.com/layer5io/service-mesh-performance/service" 12 | smp "github.com/layer5io/service-mesh-performance/spec" 13 | ) 14 | 15 | var ( 16 | maeshConfig = &test_gen.Maesh{ 17 | PortSvcA: "9091", 18 | PortSvcB: "9091", 19 | PortSvcC: "9091", 20 | } 21 | 22 | linkerdConfig = &test_gen.Linkerd{ 23 | PortSvcA: "9091", 24 | PortSvcB: "9091", 25 | PortSvcC: "9091", 26 | } 27 | istioConfig = &test_gen.Istio{ 28 | PortSvcA: "9091", 29 | PortSvcB: "9091", 30 | PortSvcC: "9091", 31 | } 32 | osmConfig = &test_gen.OSM{ 33 | PortSvcA: "9091", 34 | PortSvcB: "9091", 35 | PortSvcC: "9091", 36 | } 37 | ) 38 | 39 | // RunTest return conformance response 40 | func (s *Service) RunTest(ctx context.Context, req *conformance.Request) (*conformance.Response, error) { 41 | var config test_gen.ServiceMesh 42 | 43 | config = linkerdConfig 44 | switch req.Mesh.Type { 45 | case smp.ServiceMesh_LINKERD: 46 | config = linkerdConfig 47 | req.Mesh.Annotations["linkerd.io/inject"] = "enabled" 48 | case smp.ServiceMesh_APP_MESH: 49 | config = linkerdConfig 50 | req.Mesh.Labels["appmesh.k8s.aws/sidecarInjectorWebhook"] = "enabled" 51 | case smp.ServiceMesh_MAESH: 52 | config = maeshConfig 53 | case smp.ServiceMesh_ISTIO: 54 | config = istioConfig 55 | req.Mesh.Labels["istio-injection"] = "enabled" 56 | case smp.ServiceMesh_OPEN_SERVICE_MESH: 57 | config = osmConfig 58 | req.Mesh.Labels["openservicemesh.io/monitored-by"] = "osm" 59 | case smp.ServiceMesh_KUMA: 60 | req.Mesh.Annotations["kuma.io/sidecar-injection"] = "enabled" 61 | case smp.ServiceMesh_NGINX_SERVICE_MESH: 62 | req.Mesh.Annotations["njector.nsm.nginx.com/auto-inject"] = "true" 63 | 64 | } 65 | 66 | result := test_gen.RunTest(config, req.Mesh.Annotations, req.Mesh.Labels) 67 | totalSteps := 24 68 | totalFailures := 0 69 | stepsCount := map[string]int{ 70 | "traffic-access": 7, 71 | "traffic-split": 11, 72 | "traffic-spec": 6, 73 | } 74 | specVersion := map[string]string{ 75 | "traffic-access": "v0.6.0/v1alpha3", 76 | "traffic-split": "v0.6.0/v1alpha4", 77 | "traffic-spec": "v0.6.0/v1alpha4", 78 | } 79 | 80 | details := make([]*conformance.Detail, 0) 81 | for _, res := range result.Testsuite[0].Testcase { 82 | d := &conformance.Detail{ 83 | Smispec: res.Name, 84 | Specversion: specVersion[res.Name], 85 | Assertion: strconv.Itoa(stepsCount[res.Name]), 86 | Duration: res.Time, 87 | Capability: conformance.Capability_FULL, 88 | Status: conformance.ResultStatus_PASSED, 89 | Result: &conformance.Result{ 90 | Result: &conformance.Result_Message{ 91 | Message: "All test passed", 92 | }, 93 | }, 94 | } 95 | if len(res.Failure.Text) > 2 { 96 | d.Result = &conformance.Result{ 97 | Result: &conformance.Result_Error{ 98 | Error: &service.CommonError{ 99 | Code: "", 100 | Severity: "", 101 | ShortDescription: res.Failure.Text, 102 | LongDescription: res.Failure.Message, 103 | ProbableCause: "", 104 | SuggestedRemediation: "", 105 | }, 106 | }, 107 | } 108 | d.Status = conformance.ResultStatus_FAILED 109 | d.Capability = conformance.Capability_NONE 110 | 111 | // A hacky way to see the testStep Failed, since KUDO only provides it in Failure.Message 112 | re := regexp.MustCompile(`[0-9]+`) 113 | if res.Failure.Message != "" { 114 | stepFailed := re.FindAllString(res.Failure.Message, 1) 115 | if len(stepFailed) != 0 { 116 | passed, _ := strconv.Atoi(stepFailed[0]) 117 | passed = passed - 1 118 | failures := stepsCount[res.Name] - passed 119 | totalFailures += failures 120 | if (passed) >= (stepsCount[res.Name] / 2) { 121 | d.Capability = conformance.Capability_HALF 122 | } 123 | } 124 | } 125 | } 126 | details = append(details, d) 127 | } 128 | 129 | return &conformance.Response{ 130 | Casespassed: strconv.Itoa(totalSteps - totalFailures), 131 | Passpercent: strconv.FormatFloat(float64(totalSteps-totalFailures)/float64(totalSteps)*100, 'f', 2, 64), 132 | Mesh: req.Mesh, 133 | Details: details, 134 | }, nil 135 | } 136 | 137 | func (s *Service) Info(context.Context, *empty.Empty) (*service.ServiceInfo, error) { 138 | return &service.ServiceInfo{}, nil 139 | } 140 | 141 | func (s *Service) Health(context.Context, *empty.Empty) (*service.ServiceHealth, error) { 142 | return &service.ServiceHealth{}, nil 143 | } 144 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/traffic-access.go: -------------------------------------------------------------------------------- 1 | package test_gen 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "testing" 7 | "time" 8 | 9 | "github.com/kudobuilder/kuttl/pkg/test" 10 | testutils "github.com/kudobuilder/kuttl/pkg/test/utils" 11 | "k8s.io/client-go/discovery" 12 | "sigs.k8s.io/controller-runtime/pkg/client" 13 | ) 14 | 15 | func (smi *SMIConformance) TrafficAccessGetTests() map[string]test.CustomTest { 16 | testHandlers := make(map[string]test.CustomTest) 17 | 18 | testHandlers["trafficDefault"] = smi.trafficBlocked 19 | testHandlers["trafficAllowed"] = smi.trafficAllow 20 | testHandlers["trafficBlocked"] = smi.trafficBlocked 21 | 22 | return testHandlers 23 | } 24 | 25 | func (smi *SMIConformance) trafficBlocked( 26 | t *testing.T, 27 | namespace string, 28 | clientFn func(forceNew bool) (client.Client, error), 29 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 30 | Logger testutils.Logger, 31 | ) []error { 32 | time.Sleep(5 * time.Second) 33 | 34 | httpClient := GetHTTPClient() 35 | kubeClient, err := clientFn(false) 36 | if err != nil { 37 | t.Fail() 38 | return []error{err} 39 | } 40 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 41 | if err != nil { 42 | t.Fail() 43 | return []error{err} 44 | } 45 | ClearAllMetrics(clusterIPs, smi.SMObj) 46 | 47 | // This test will make SERVICE A make a request to SERVICE B 48 | svcBTestURL := fmt.Sprintf("%s/%s", smi.SMObj.SvcBGetInternalName(namespace), ECHO) 49 | var jsonStr = []byte(`{"url":"` + svcBTestURL + `", "body":"", "method": "GET", "headers": {}}`) 50 | 51 | url := fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smi.SMObj.SvcAGetPort(), CALL) 52 | _, err = httpClient.Post(url, "application/json", bytes.NewBuffer(jsonStr)) 53 | 54 | Logger.Logf("URL : \n", url) 55 | Logger.Logf("Body : \n", string(jsonStr)) 56 | if err != nil { 57 | t.Fail() 58 | Logger.Logf("Error : %s", err.Error()) 59 | return []error{err} 60 | } 61 | 62 | metricsSvcA, err := GetMetrics(clusterIPs[SvcNameA], "9091") 63 | if err != nil { 64 | t.Fail() 65 | Logger.Logf("Error : %s", err.Error()) 66 | return []error{err} 67 | } 68 | 69 | Logger.Log("Service A : Response Failed", metricsSvcA.RespFailed) 70 | Logger.Log("Service A : Response Succeeded", metricsSvcA.RespSucceeded) 71 | Logger.Log("Service A : Requests Received", metricsSvcA.ReqReceived) 72 | 73 | // Validates if the request failed 74 | if !(len(metricsSvcA.RespFailed) == 1 && len(metricsSvcA.RespSucceeded) == 0) { 75 | t.Fail() 76 | return nil 77 | } 78 | Logger.Log("Validated: Response count") 79 | if metricsSvcA.RespFailed[0].URL != svcBTestURL { 80 | t.Fail() 81 | return nil 82 | } 83 | Logger.Log("Validated: Response destination") 84 | 85 | Logger.Log("Done") 86 | return nil 87 | } 88 | 89 | func (smi *SMIConformance) trafficAllow( 90 | t *testing.T, 91 | namespace string, 92 | clientFn func(forceNew bool) (client.Client, error), 93 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 94 | Logger testutils.Logger, 95 | ) []error { 96 | time.Sleep(5 * time.Second) 97 | 98 | httpClient := GetHTTPClient() 99 | kubeClient, err := clientFn(false) 100 | if err != nil { 101 | t.Fail() 102 | Logger.Logf("Error : %s", err.Error()) 103 | return []error{err} 104 | } 105 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 106 | if err!=nil{ 107 | t.Fail() 108 | Logger.Logf("Error : %s", err.Error()) 109 | return []error{err} 110 | } 111 | ClearAllMetrics(clusterIPs, smi.SMObj) 112 | 113 | // This test will make SERVICE A make a request to SERVICE B 114 | svcBTestURL := fmt.Sprintf("%s/%s", smi.SMObj.SvcBGetInternalName(namespace), ECHO) 115 | var jsonStr = []byte(`{"url":"` + svcBTestURL + `", "body":"", "method": "GET", "headers": {}}`) 116 | 117 | url := fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smi.SMObj.SvcAGetPort(), CALL) 118 | _, err = httpClient.Post(url, "application/json", bytes.NewBuffer(jsonStr)) 119 | 120 | Logger.Logf("URL : \n", url) 121 | Logger.Logf("Body : \n", string(jsonStr)) 122 | if err != nil { 123 | t.Fail() 124 | Logger.Logf("Error : %s", err.Error()) 125 | return []error{err} 126 | } 127 | 128 | metricsSvcA, err := GetMetrics(clusterIPs[SvcNameA], "9091") 129 | 130 | if err != nil { 131 | t.Fail() 132 | Logger.Logf("Error : %s", err.Error()) 133 | return []error{err} 134 | } 135 | 136 | Logger.Log("Service A : Response Failed", metricsSvcA.RespFailed) 137 | Logger.Log("Service A : Response Succeeded", metricsSvcA.RespSucceeded) 138 | Logger.Log("Service A : Requests Received", metricsSvcA.ReqReceived) 139 | 140 | // Validates if the request succeeded 141 | if !(len(metricsSvcA.RespFailed) == 0 && len(metricsSvcA.RespSucceeded) == 1) { 142 | t.Fail() 143 | return nil 144 | } 145 | Logger.Log("Validated: Response count") 146 | 147 | if metricsSvcA.RespSucceeded[0].URL != svcBTestURL { 148 | t.Fail() 149 | return nil 150 | } 151 | Logger.Log("Validated: Response destination") 152 | 153 | metricsSvcB, err := GetMetrics(clusterIPs[SvcNameB], "9091") 154 | if err != nil { 155 | t.Fail() 156 | Logger.Log("Error: ", err) 157 | return []error{err} 158 | } 159 | 160 | Logger.Log("Service B : Response Failed", metricsSvcB.RespFailed) 161 | Logger.Log("Service B : Response Succeeded", metricsSvcB.RespSucceeded) 162 | Logger.Log("Service B : Requests Received", metricsSvcB.ReqReceived) 163 | 164 | if !(len(metricsSvcB.ReqReceived) == 1) { 165 | t.Fail() 166 | return nil 167 | } 168 | Logger.Log("Validated: Request count") 169 | if metricsSvcB.ReqReceived[0] != "app-a" { 170 | t.Fail() 171 | return nil 172 | } 173 | Logger.Log("Validated: Request Source") 174 | 175 | Logger.Log("Done") 176 | return nil 177 | } 178 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/traffic-spec.go: -------------------------------------------------------------------------------- 1 | package test_gen 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "net/http" 7 | "testing" 8 | "time" 9 | 10 | "github.com/kudobuilder/kuttl/pkg/test" 11 | testutils "github.com/kudobuilder/kuttl/pkg/test/utils" 12 | "k8s.io/client-go/discovery" 13 | "sigs.k8s.io/controller-runtime/pkg/client" 14 | ) 15 | 16 | func (smi *SMIConformance) TrafficSpecGetTests() map[string]test.CustomTest { 17 | testHandlers := make(map[string]test.CustomTest) 18 | 19 | testHandlers["trafficPath"] = smi.trafficPath 20 | testHandlers["trafficMethod"] = smi.trafficMethod 21 | 22 | return testHandlers 23 | } 24 | 25 | func (smi *SMIConformance) trafficPath( 26 | t *testing.T, 27 | namespace string, 28 | clientFn func(forceNew bool) (client.Client, error), 29 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 30 | Logger testutils.Logger, 31 | ) []error { 32 | time.Sleep(5 * time.Second) 33 | 34 | httpClient := GetHTTPClient() 35 | kubeClient, err := clientFn(false) 36 | if err != nil { 37 | t.Fail() 38 | return []error{err} 39 | } 40 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 41 | if err!=nil{ 42 | t.Fail() 43 | return []error{err} 44 | } 45 | ClearAllMetrics(clusterIPs, smi.SMObj) 46 | 47 | // call to SERVICE B metrics (allowed) 48 | svcBTestURLMetrics := fmt.Sprintf("%s/%s", smi.SMObj.SvcBGetInternalName(namespace), METRICS) 49 | jsonStr := []byte(`{"url":"` + svcBTestURLMetrics + `", "body":"", "method": "GET", "headers": {}}`) 50 | 51 | url := fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smi.SMObj.SvcAGetPort(), CALL) 52 | _, err = httpClient.Post(url, "application/json", bytes.NewBuffer(jsonStr)) 53 | 54 | Logger.Logf("URL : \n", url) 55 | Logger.Logf("Body : \n", string(jsonStr)) 56 | if err != nil { 57 | t.Fail() 58 | Logger.Logf("Error : %s", err.Error()) 59 | return []error{err} 60 | } 61 | 62 | // call to SERVICE B echo (blocked) 63 | svcBTestURLEcho := fmt.Sprintf("%s/%s", smi.SMObj.SvcBGetInternalName(namespace), ECHO) 64 | jsonStr = []byte(`{"url":"` + svcBTestURLEcho + `", "body":"", "method": "GET", "headers": {}}`) 65 | 66 | url = fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smi.SMObj.SvcAGetPort(), CALL) 67 | _, err = httpClient.Post(url, "application/json", bytes.NewBuffer(jsonStr)) 68 | 69 | if err != nil { 70 | t.Fail() 71 | return []error{err} 72 | } 73 | 74 | metricsSvcA, err := GetMetrics(clusterIPs[SvcNameA], "9091") 75 | if err != nil { 76 | t.Fail() 77 | Logger.Logf("Error : %s", err.Error()) 78 | return []error{err} 79 | } 80 | 81 | Logger.Log("Service A : Response Failed", metricsSvcA.RespFailed) 82 | Logger.Log("Service A : Response Succeeded", metricsSvcA.RespSucceeded) 83 | Logger.Log("Service A : Requests Received", metricsSvcA.ReqReceived) 84 | 85 | // validates the requests that failed and the ones that succeeded 86 | if !(len(metricsSvcA.RespFailed) == 1 && len(metricsSvcA.RespSucceeded) == 1) { 87 | t.Fail() 88 | return nil 89 | } 90 | Logger.Log("Validated: Response count") 91 | if metricsSvcA.RespSucceeded[0].URL != svcBTestURLMetrics { 92 | t.Fail() 93 | return nil 94 | } 95 | Logger.Log("Validated: Allowed Path") 96 | if metricsSvcA.RespFailed[0].URL != svcBTestURLEcho { 97 | t.Fail() 98 | return nil 99 | } 100 | Logger.Log("Validated: Disallowed Path") 101 | 102 | Logger.Log("Done") 103 | return nil 104 | } 105 | 106 | func (smi *SMIConformance) trafficMethod( 107 | t *testing.T, 108 | namespace string, 109 | clientFn func(forceNew bool) (client.Client, error), 110 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 111 | Logger testutils.Logger, 112 | ) []error { 113 | time.Sleep(5 * time.Second) 114 | 115 | httpClient := GetHTTPClient() 116 | kubeClient, err := clientFn(false) 117 | if err != nil { 118 | t.Fail() 119 | return []error{err} 120 | } 121 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 122 | if err != nil { 123 | t.Fail() 124 | return []error{err} 125 | } 126 | ClearAllMetrics(clusterIPs, smi.SMObj) 127 | 128 | // GET to echo (allowed) 129 | svcBTestURL := fmt.Sprintf("%s/%s", smi.SMObj.SvcBGetInternalName(namespace), ECHO) 130 | jsonStr := []byte(`{"url":"` + svcBTestURL + `", "body":"", "method": "GET", "headers": {}}`) 131 | 132 | url := fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smi.SMObj.SvcAGetPort(), CALL) 133 | _, err = httpClient.Post(url, "application/json", bytes.NewBuffer(jsonStr)) 134 | 135 | Logger.Logf("URL : \n", url) 136 | Logger.Logf("Body : \n", string(jsonStr)) 137 | if err != nil { 138 | t.Fail() 139 | Logger.Logf("Error : %s", err.Error()) 140 | return []error{err} 141 | } 142 | 143 | // POST to echo (blocked) 144 | jsonStr = []byte(`{"url":"` + svcBTestURL + `", "body":"", "method": "POST", "headers": {}}`) 145 | 146 | url = fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smi.SMObj.SvcAGetPort(), CALL) 147 | _, err = httpClient.Post(url, "application/json", bytes.NewBuffer(jsonStr)) 148 | 149 | Logger.Logf("URL : \n", url) 150 | Logger.Logf("Body : \n", string(jsonStr)) 151 | if err != nil { 152 | t.Fail() 153 | Logger.Logf("Error : %s", err.Error()) 154 | return []error{err} 155 | } 156 | 157 | metricsSvcA, err := GetMetrics(clusterIPs[SvcNameA], "9091") 158 | if err != nil { 159 | t.Fail() 160 | Logger.Logf("Error : %s", err.Error()) 161 | return []error{err} 162 | } 163 | 164 | Logger.Log("Service A : Response Failed", metricsSvcA.RespFailed) 165 | Logger.Log("Service A : Response Succeeded", metricsSvcA.RespSucceeded) 166 | Logger.Log("Service A : Requests Received", metricsSvcA.ReqReceived) 167 | 168 | // validates the requests that failed and the ones that succeeded 169 | if !(len(metricsSvcA.RespFailed) == 1 && len(metricsSvcA.RespSucceeded) == 1) { 170 | t.Fail() 171 | return nil 172 | } 173 | Logger.Log("Validated: Response count") 174 | if metricsSvcA.RespSucceeded[0].Method != http.MethodGet { 175 | t.Fail() 176 | return nil 177 | } 178 | Logger.Log("Validated: Allowed Method") 179 | if metricsSvcA.RespFailed[0].Method != http.MethodPost { 180 | t.Fail() 181 | return nil 182 | } 183 | Logger.Log("Validated: Disallowed Method") 184 | 185 | Logger.Log("Done") 186 | return nil 187 | } 188 | -------------------------------------------------------------------------------- /service/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "io/ioutil" 6 | "net/http" 7 | "os" 8 | "strings" 9 | "sync" 10 | 11 | logrus "github.com/sirupsen/logrus" 12 | ) 13 | 14 | type MetricsResponse struct { 15 | URL string 16 | Method string 17 | Headers map[string]interface{} 18 | } 19 | 20 | type Metrics struct { 21 | ReqReceived []string 22 | RespSucceeded []MetricsResponse 23 | RespFailed []MetricsResponse 24 | } 25 | 26 | var metricsObj Metrics 27 | 28 | var mutex sync.Mutex 29 | 30 | func execExclusive(fn func()) { 31 | defer mutex.Unlock() 32 | mutex.Lock() 33 | fn() 34 | } 35 | 36 | const serviceID = "ServiceName" 37 | const defaultRequestID = "Default" 38 | 39 | var serviceName string 40 | 41 | func MetricsMiddleware(next http.Handler) http.Handler { 42 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 43 | execExclusive(func() { 44 | svcName := r.Header.Get(serviceID) 45 | if svcName == "" { 46 | svcName = "Unidentified" 47 | } 48 | metricsObj.ReqReceived = append(metricsObj.ReqReceived, svcName) 49 | }) 50 | next.ServeHTTP(w, r) 51 | }) 52 | } 53 | 54 | func call(w http.ResponseWriter, r *http.Request) { 55 | if r.Method != http.MethodPost { 56 | return 57 | } 58 | 59 | defer r.Body.Close() 60 | 61 | var data map[string]interface{} 62 | bytes, err := ioutil.ReadAll(r.Body) 63 | if err != nil { 64 | http.Error(w, "Error reading body", http.StatusBadRequest) 65 | logrus.Errorf("Error reading body: %s", err.Error()) 66 | return 67 | } 68 | logrus.Debugf("request body: %v", string(bytes)) 69 | 70 | if string(bytes) == "" { 71 | return 72 | } 73 | 74 | err = json.Unmarshal(bytes, &data) 75 | if err != nil { 76 | http.Error(w, "Error parsing body", http.StatusBadRequest) 77 | logrus.Errorf("Error parsing body: %s", err.Error()) 78 | return 79 | } 80 | 81 | url := data["url"].(string) 82 | method := data["method"].(string) 83 | headers := data["headers"] 84 | body := data["body"].(string) 85 | 86 | var req *http.Request 87 | if method == http.MethodPost || method == http.MethodPatch || method == http.MethodPut { 88 | req, err = http.NewRequest(method, url, strings.NewReader(body)) 89 | if err != nil { 90 | logrus.Errorf("Error creating request %s", err.Error()) 91 | http.Error(w, "Error creating request", http.StatusBadRequest) 92 | return 93 | } 94 | } else { 95 | req, err = http.NewRequest(method, url, nil) 96 | if err != nil { 97 | logrus.Errorf("Error creating request %s", err.Error()) 98 | http.Error(w, "Error creating request", http.StatusBadRequest) 99 | return 100 | } 101 | } 102 | 103 | client := http.Client{} 104 | 105 | if headers != nil { 106 | headers := headers.(map[string]interface{}) 107 | for key, val := range headers { 108 | req.Header.Add(key, val.(string)) 109 | } 110 | } 111 | req.Header.Add(serviceID, serviceName) 112 | 113 | resp, err := client.Do(req) 114 | if err != nil { 115 | logrus.Errorf("Error completing the request %s", err.Error()) 116 | http.Error(w, "Error completing the request", http.StatusInternalServerError) 117 | return 118 | } 119 | 120 | logrus.Debugf("Call response: %v", resp) 121 | if err != nil { 122 | http.Error(w, "Error making the calling", http.StatusBadRequest) 123 | logrus.Errorf("Error making the calling: %s", err.Error()) 124 | return 125 | } 126 | 127 | if resp.StatusCode >= 200 && resp.StatusCode < 400 { 128 | w.WriteHeader(http.StatusOK) 129 | execExclusive(func() { 130 | if headers != nil { 131 | headers := headers.(map[string]interface{}) 132 | metricsObj.RespSucceeded = append(metricsObj.RespSucceeded, MetricsResponse{ 133 | URL: url, 134 | Method: method, 135 | Headers: headers, 136 | }) 137 | } else { 138 | metricsObj.RespSucceeded = append(metricsObj.RespSucceeded, MetricsResponse{ 139 | URL: url, 140 | Method: method, 141 | }) 142 | } 143 | }) 144 | } else { 145 | execExclusive(func() { 146 | if headers != nil { 147 | headers := headers.(map[string]interface{}) 148 | metricsObj.RespFailed = append(metricsObj.RespFailed, MetricsResponse{ 149 | URL: url, 150 | Method: method, 151 | Headers: headers, 152 | }) 153 | } else { 154 | metricsObj.RespFailed = append(metricsObj.RespFailed, MetricsResponse{ 155 | URL: url, 156 | Method: method, 157 | }) 158 | } 159 | }) 160 | } 161 | 162 | bytes, err = ioutil.ReadAll(resp.Body) 163 | if err != nil { 164 | logrus.Errorf("Error parsing body: %s", err.Error()) 165 | return 166 | } 167 | logrus.Debugf("Response body: %s", string(bytes)) 168 | w.Write(bytes) 169 | } 170 | 171 | func echo(w http.ResponseWriter, req *http.Request) { 172 | req.Write(w) 173 | } 174 | 175 | func metrics(w http.ResponseWriter, req *http.Request) { 176 | if req.Method == http.MethodGet { 177 | w.Header().Set("Content-Type", "application/json") 178 | execExclusive(func() { 179 | if err := json.NewEncoder(w).Encode(&metricsObj); err != nil { 180 | w.WriteHeader(http.StatusInternalServerError) 181 | } 182 | }) 183 | } else if req.Method == http.MethodDelete { 184 | execExclusive(func() { 185 | metricsObj = Metrics{ 186 | RespSucceeded: []MetricsResponse{}, 187 | RespFailed: []MetricsResponse{}, 188 | ReqReceived: []string{}, 189 | } 190 | }) 191 | } else { 192 | http.Error(w, "Method not defined", http.StatusBadRequest) 193 | } 194 | } 195 | 196 | func main() { 197 | logrus.SetOutput(os.Stdout) 198 | logrus.SetLevel(logrus.DebugLevel) 199 | 200 | serviceName = os.Getenv("SERVICE_NAME") 201 | if serviceName == "" { 202 | serviceName = "Default" 203 | } 204 | 205 | port := os.Getenv("PORT") 206 | if port == "" { 207 | port = "9091" 208 | } 209 | 210 | metricsObj = Metrics{ 211 | RespSucceeded: []MetricsResponse{}, 212 | RespFailed: []MetricsResponse{}, 213 | ReqReceived: []string{}, 214 | } 215 | 216 | mux := http.NewServeMux() 217 | 218 | mux.Handle("/call", MetricsMiddleware(http.HandlerFunc(call))) 219 | mux.Handle("/metrics", http.HandlerFunc(metrics)) 220 | mux.Handle("/echo", MetricsMiddleware(http.HandlerFunc(echo))) 221 | logrus.Infof("Started serving at: %s", port) 222 | http.ListenAndServe(":"+port, mux) 223 | } 224 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Overview 2 | Please do! Thanks for your help improving the project! :balloon: 3 | 4 | All contributors are welcome. Please see the [newcomers welcome guide](https://docs.google.com/document/d/17OPtDE_rdnPQxmk2Kauhm3GwXF1R5dZ3Cj8qZLKdo5E/edit) for how, where and why to contribute. This project is community-built and welcomes collaboration. Contributors are expected to adhere to our [Code of Conduct](.CODE_OF_CONDUCT.md). 5 | 6 | Not sure where to start? First, see the [newcomers welcome guide](https://docs.google.com/document/d/17OPtDE_rdnPQxmk2Kauhm3GwXF1R5dZ3Cj8qZLKdo5E/edit). Grab an open issue with the [help-wanted label](../../labels/help%20wanted) and jump in. Join the [Slack account](http://slack.layer5.io) and engage in conversation. Create a [new issue](/../../issues/new/choose) if needed. All [pull requests](/../../pulls) should reference an open [issue](/../../issues). Include keywords in your pull request descriptions, as well as commit messages, to [automatically close issues in GitHub](https://help.github.com/en/github/managing-your-work-on-github/closing-issues-using-keywords). 7 | 8 | **Sections** 9 | - General Contribution Flow 10 | - Developer Certificate of Origin 11 | 12 | ## Issues & Pull Requests 13 | 14 | ### Creating an Issue 15 | 16 | Before **creating** an Issue i.e for `features`/`bugs`/`improvements` please follow these steps: 17 | 18 | 19 | 1. Search existing Issues before creating a new Issue (look to see if the Issue has already been created). 20 | 1. If it doesn't exist create a new Issue giving as much context as possible (please take note and select the correct Issue type, for example `bug`, `documentation` or `feature`. 21 | 1. If you wish to work on the Issue once it has been triaged, please include this in your Issue description. 22 | 23 | ### Working on an Issue 24 | 25 | Before working on an existing Issue please follow these steps: 26 | 27 | 1. Comment asking for the Issue to be assigned to you. 28 | 1. To best position yourself for Issues assignment, we recommend that you: 29 | 1. Confirm that you have read the CONTRIBUTING.md. 30 | 1. Have a functional development environment (have built and are able to run the project). 31 | 1. Convey your intended approach to solving the issue. 32 | 1. Put each of these items in writing in one or more comments. 33 | 1. After the Issue is assigned to you, you can start working on it. 34 | 1. In general, **only** start working on this Issue (and open a Pull Request) when it has been assigned to you. Doing so will prevent confusion, duplicate work (some of which may go unaccepted given its duplicity), incidental stepping on toes, and the headache involved for maintainers and contributors alike as Issue assignments collide and heads bump together. 35 | 1. Reference the Issue in your Pull Request (for example `This PR fixes #123`). so that the corresponding Issue is automatically closed upon merge of your Pull Request. 36 | 37 | > Notes: 38 | > 39 | > - Check the `Assignees` box at the top of the page to see if the Issue has been assigned to someone else before requesting this be assigned to you. If the issue has a current Assignee, but appears to be inactive, politely inquire with the current Assignee as to whether they are still working on a solution and/or if you might collaborate with them. 40 | > - Only request to be assigned an Issue if you know how to work on it. 41 | > - If an Issue is unclear, ask questions to get more clarity before asking to have the Issue assigned to you; avoid asking "what do I do next? how do I fix this?" (see the item above this line) 42 | > - An Issue can be assigned to multiple people, if you all agree to collaborate on the Issue (the Pull Request can contain commits from different collaborators) 43 | > - Any Issues that has no activity after 2 weeks will be unassigned and re-assigned to someone else. 44 | 45 | ## Reviewing Pull Requests 46 | 47 | We welcome everyone to review Pull Requests. It is a great way to learn, network, and support each other. 48 | 49 | ### DOs 50 | 51 | - Use inline comments to explain your suggestions 52 | - Use inline suggestions to propose changes 53 | - Exercise patience and empathy while offering critiques of the works of others. 54 | 55 | ### DON'Ts 56 | 57 | - Do not repeat feedback, this creates more noise than value (check the existing conversation), use GitHub reactions if you agree/disagree with a comment 58 | - Do not blindly approve Pull Requests to improve your GitHub contributors graph 59 | 60 | 61 | ## Signing-off on Commits (Developer Certificate of Origin) 62 | 63 | To contribute to this project, you must agree to the Developer Certificate of 64 | Origin (DCO) for each commit you make. The DCO is a simple statement that you, 65 | as a contributor, have the legal right to make the contribution. 66 | 67 | See the [DCO](https://developercertificate.org) file for the full text of what you must agree to 68 | and how it works [here](https://github.com/probot/dco#how-it-works). 69 | To signify that you agree to the DCO for contributions, you simply add a line to each of your 70 | git commit messages: 71 | 72 | ``` 73 | Signed-off-by: Jane Smith 74 | ``` 75 | 76 | In most cases, you can add this signoff to your commit automatically with the 77 | `-s` or `--signoff` flag to `git commit`. You must use your real name and a reachable email 78 | address (sorry, no pseudonyms or anonymous contributions). An example of signing off on a commit: 79 | ``` 80 | $ commit -s -m “my commit message w/signoff” 81 | ``` 82 | 83 | To ensure all your commits are signed, you may choose to add this alias to your global ```.gitconfig```: 84 | 85 | *~/.gitconfig* 86 | ``` 87 | [alias] 88 | amend = commit -s --amend 89 | cm = commit -s -m 90 | commit = commit -s 91 | ``` 92 | Or you may configure your IDE, for example, Visual Studio Code to automatically sign-off commits for you: 93 | 94 | 95 | 96 | # Reviews 97 | All contributors are invited to review pull requests. See this short video on [how to review a pull request](https://www.youtube.com/watch?v=isLfo7jfE6g&feature=youtu.be). 98 | 99 | # New to Git? 100 | Resources: https://lab.github.com and https://try.github.com/ 101 | 102 | ### License 103 | 104 | This repository and site are available as open source under the terms of the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). 105 | -------------------------------------------------------------------------------- /smi-conformance/test-gen/traffic-split.go: -------------------------------------------------------------------------------- 1 | package test_gen 2 | 3 | import ( 4 | "fmt" 5 | "testing" 6 | "time" 7 | 8 | "github.com/kudobuilder/kuttl/pkg/test" 9 | testutils "github.com/kudobuilder/kuttl/pkg/test/utils" 10 | "k8s.io/client-go/discovery" 11 | "sigs.k8s.io/controller-runtime/pkg/client" 12 | ) 13 | 14 | const reqNo = 50 15 | 16 | // TrafficSplitGetTests return type of map[string]test.CustomTest 17 | func (smi *SMIConformance) TrafficSplitGetTests() map[string]test.CustomTest { 18 | testHandlers := make(map[string]test.CustomTest) 19 | 20 | testHandlers["trafficDefault"] = smi.trafficSplitDefault 21 | testHandlers["trafficOnlyB"] = smi.trafficSplitOnlyB 22 | testHandlers["trafficOnlyC"] = smi.trafficSplitOnlyC 23 | testHandlers["trafficBGrtC"] = smi.trafficSplitBGrtC 24 | testHandlers["trafficCGrtB"] = smi.trafficSplitCGrtB 25 | 26 | return testHandlers 27 | } 28 | 29 | // Executes a Test Scenario where SERVICE A makes a request to the service named `app-svc` 30 | func trafficSplitTestScenario(clusterIPs map[string]string, namespace string, smObj ServiceMesh) error { 31 | svcTrafficSplit := fmt.Sprintf("http://app-svc.%s.svc.cluster.local.:9091/%s", namespace, ECHO) 32 | jsonStr := []byte(`{"url":"` + svcTrafficSplit + `", "body":"", "method": "GET", "headers": {}}`) 33 | 34 | url := fmt.Sprintf("http://%s:%s/%s", clusterIPs[SvcNameA], smObj.SvcAGetPort(), CALL) 35 | 36 | return generatePOSTLoad(reqNo, url, jsonStr) 37 | } 38 | 39 | func (smi *SMIConformance) trafficSplitDefault( 40 | t *testing.T, 41 | namespace string, 42 | clientFn func(forceNew bool) (client.Client, error), 43 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 44 | Logger testutils.Logger, 45 | ) []error { 46 | time.Sleep(5 * time.Second) 47 | 48 | kubeClient, err := clientFn(false) 49 | if err != nil { 50 | t.Fail() 51 | return []error{err} 52 | } 53 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 54 | if err != nil { 55 | t.Fail() 56 | return []error{err} 57 | } 58 | ClearAllMetrics(clusterIPs, smi.SMObj) 59 | 60 | if err = trafficSplitTestScenario(clusterIPs, namespace, smi.SMObj); err != nil { 61 | t.Fail() 62 | return []error{err} 63 | } 64 | 65 | metricsSvcB, err := GetMetrics(clusterIPs[SvcNameB], "9091") 66 | if err != nil { 67 | t.Fail() 68 | return []error{err} 69 | } 70 | Logger.Log("Service B : Requests Received", metricsSvcB.ReqReceived) 71 | 72 | metricsSvcC, err := GetMetrics(clusterIPs[SvcNameC], "9091") 73 | if err != nil { 74 | t.Fail() 75 | return []error{err} 76 | } 77 | Logger.Log("Service C : Requests Received", metricsSvcC.ReqReceived) 78 | 79 | if len(metricsSvcB.ReqReceived) == 0 || len(metricsSvcC.ReqReceived) == 0 { 80 | t.Fail() 81 | return nil 82 | } 83 | Logger.Log("Validated: Random Request count") 84 | 85 | Logger.Log("Done") 86 | return nil 87 | } 88 | 89 | func (smi *SMIConformance) trafficSplitOnlyB( 90 | t *testing.T, 91 | namespace string, 92 | clientFn func(forceNew bool) (client.Client, error), 93 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 94 | Logger testutils.Logger, 95 | ) []error { 96 | time.Sleep(5 * time.Second) 97 | 98 | kubeClient, err := clientFn(false) 99 | if err != nil { 100 | t.Fail() 101 | return []error{err} 102 | } 103 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 104 | if err != nil { 105 | t.Fail() 106 | return []error{err} 107 | } 108 | ClearAllMetrics(clusterIPs, smi.SMObj) 109 | 110 | if err = trafficSplitTestScenario(clusterIPs, namespace, smi.SMObj); err != nil { 111 | t.Fail() 112 | return []error{err} 113 | } 114 | 115 | metricsSvcB, err := GetMetrics(clusterIPs[SvcNameB], "9091") 116 | if err != nil { 117 | t.Fail() 118 | return []error{err} 119 | } 120 | Logger.Log("Service B : Requests Received", metricsSvcB.ReqReceived) 121 | 122 | metricsSvcC, err := GetMetrics(clusterIPs[SvcNameC], "9091") 123 | if err != nil { 124 | t.Fail() 125 | return []error{err} 126 | } 127 | Logger.Log("Service C : Requests Received", metricsSvcC.ReqReceived) 128 | 129 | if !(len(metricsSvcB.ReqReceived) == reqNo && len(metricsSvcC.ReqReceived) == 0) { 130 | t.Fail() 131 | return nil 132 | } 133 | Logger.Log("Validated: C Request count zero") 134 | 135 | Logger.Log("Done") 136 | return nil 137 | } 138 | 139 | func (smi *SMIConformance) trafficSplitOnlyC( 140 | t *testing.T, 141 | namespace string, 142 | clientFn func(forceNew bool) (client.Client, error), 143 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 144 | Logger testutils.Logger, 145 | ) []error { 146 | time.Sleep(5 * time.Second) 147 | 148 | kubeClient, err := clientFn(false) 149 | if err != nil { 150 | t.Fail() 151 | return []error{err} 152 | } 153 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 154 | if err != nil { 155 | t.Fail() 156 | return []error{err} 157 | } 158 | ClearAllMetrics(clusterIPs, smi.SMObj) 159 | 160 | if err = trafficSplitTestScenario(clusterIPs, namespace, smi.SMObj); err != nil { 161 | t.Fail() 162 | return []error{err} 163 | } 164 | 165 | metricsSvcB, err := GetMetrics(clusterIPs[SvcNameB], "9091") 166 | if err != nil { 167 | t.Fail() 168 | return []error{err} 169 | } 170 | Logger.Log("Service B : Requests Received", metricsSvcB.ReqReceived) 171 | 172 | metricsSvcC, err := GetMetrics(clusterIPs[SvcNameC], "9091") 173 | if err != nil { 174 | t.Fail() 175 | return []error{err} 176 | } 177 | Logger.Log("Service C : Requests Received", metricsSvcC.ReqReceived) 178 | 179 | if !(len(metricsSvcB.ReqReceived) == 0 && len(metricsSvcC.ReqReceived) == reqNo) { 180 | t.Fail() 181 | return nil 182 | } 183 | Logger.Log("Validated: B Request count zero") 184 | 185 | Logger.Log("Done") 186 | return nil 187 | } 188 | 189 | func (smi *SMIConformance) trafficSplitBGrtC( 190 | t *testing.T, 191 | namespace string, 192 | clientFn func(forceNew bool) (client.Client, error), 193 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 194 | Logger testutils.Logger, 195 | ) []error { 196 | time.Sleep(5 * time.Second) 197 | 198 | kubeClient, err := clientFn(false) 199 | if err != nil { 200 | t.Fail() 201 | return []error{err} 202 | } 203 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 204 | if err != nil { 205 | t.Fail() 206 | return []error{err} 207 | } 208 | ClearAllMetrics(clusterIPs, smi.SMObj) 209 | 210 | if err = trafficSplitTestScenario(clusterIPs, namespace, smi.SMObj); err != nil { 211 | t.Fail() 212 | return []error{err} 213 | } 214 | 215 | metricsSvcB, err := GetMetrics(clusterIPs[SvcNameB], "9091") 216 | if err != nil { 217 | t.Fail() 218 | return []error{err} 219 | } 220 | Logger.Log("Service B : Requests Received", metricsSvcB.ReqReceived) 221 | 222 | metricsSvcC, err := GetMetrics(clusterIPs[SvcNameC], "9091") 223 | if err != nil { 224 | t.Fail() 225 | return []error{err} 226 | } 227 | Logger.Log("Service C : Requests Received", metricsSvcC.ReqReceived) 228 | 229 | if !(len(metricsSvcB.ReqReceived) > len(metricsSvcC.ReqReceived)) { 230 | t.Fail() 231 | return nil 232 | } 233 | Logger.Log("Validated: B Request count greater than C") 234 | 235 | Logger.Log("Done") 236 | return nil 237 | } 238 | 239 | func (smi *SMIConformance) trafficSplitCGrtB( 240 | t *testing.T, 241 | namespace string, 242 | clientFn func(forceNew bool) (client.Client, error), 243 | DiscoveryClient func() (discovery.DiscoveryInterface, error), 244 | Logger testutils.Logger, 245 | ) []error { 246 | time.Sleep(5 * time.Second) 247 | 248 | kubeClient, err := clientFn(false) 249 | if err != nil { 250 | t.Fail() 251 | return []error{err} 252 | } 253 | clusterIPs, err := GetClusterIPs(kubeClient, namespace) 254 | if err != nil { 255 | t.Fail() 256 | return []error{err} 257 | } 258 | ClearAllMetrics(clusterIPs, smi.SMObj) 259 | 260 | if err = trafficSplitTestScenario(clusterIPs, namespace, smi.SMObj); err != nil { 261 | t.Fail() 262 | return []error{err} 263 | } 264 | 265 | metricsSvcB, err := GetMetrics(clusterIPs[SvcNameB], "9091") 266 | if err != nil { 267 | t.Fail() 268 | return []error{err} 269 | } 270 | Logger.Log("Service B : Requests Received", metricsSvcB.ReqReceived) 271 | 272 | metricsSvcC, err := GetMetrics(clusterIPs[SvcNameC], "9091") 273 | if err != nil { 274 | t.Fail() 275 | return []error{err} 276 | } 277 | Logger.Log("Service C : Requests Received", metricsSvcC.ReqReceived) 278 | 279 | if !(len(metricsSvcB.ReqReceived) < len(metricsSvcC.ReqReceived)) { 280 | t.Fail() 281 | return nil 282 | } 283 | Logger.Log("Validated: C Request count greater than B") 284 | 285 | Logger.Log("Done") 286 | return nil 287 | } 288 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | Shows a dark layer5 logo in light mode and a white logo in dark mode 6 | 7 |

8 | 9 | ![GitHub contributors](https://img.shields.io/github/contributors/layer5io/layer5.svg) 10 | ![GitHub](https://img.shields.io/github/license/layer5io/layer5.svg) 11 | [![Docker Pulls](https://img.shields.io/docker/pulls/layer5/learn-layer5.svg)](https://hub.docker.com/r/layer5/learn-layer5) 12 | [![Go Report Card](https://goreportcard.com/badge/github.com/layer5io/learn-layer5)](https://goreportcard.com/report/github.com/layer5io/learn-layer5) 13 | [![GitHub issues by-label](https://img.shields.io/github/issues/layer5io/learn-layer5/help%20wanted.svg)](https://github.com/issues?utf8=✓&q=is%3Aopen+is%3Aissue+archived%3Afalse+org%3Alayer5io+label%3A%22help+wanted%22+") 14 | [![Website](https://img.shields.io/website/https/layer5.io/meshery.svg)](https://layer5.io) 15 | [![Twitter Follow](https://img.shields.io/twitter/follow/layer5.svg?label=Follow&style=social)](https://twitter.com/intent/follow?screen_name=mesheryio) 16 | [![Slack](https://img.shields.io/badge/Slack-@layer5.svg?logo=slack)](http://slack.layer5.io) 17 | [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3564/badge)](https://bestpractices.coreinfrastructure.org/projects/3564) 18 | 19 |

20 | 21 | # Learn to service mesh 22 | 23 | The "Learn Layer5" sample application is to be available for use across all service meshes that Meshery supports and is to used as: 24 | 25 | - a learning device (for [service mesh workshops](https://layer5.io/workshops)) 26 | - for [Service Mesh Interface conformance](https://docs.google.com/document/d/1HL8Sk7NSLLj-9PRqoHYVIGyU6fZxUQFotrxbmfFtjwc/edit#) 27 | 28 | ## Application Architecture 29 | The Learn Layer5 application includes three services: `app-a`, `app-b`, and `app-c`. Though they are different services, they are defined using the same app (source code in ./service). Each service is listening on port `9091/tcp`. 30 | 31 | ### Service 32 | 33 | The following are the routes defined by the `service` app and their functionality. 34 | 35 | #### POST /call 36 | 37 | This route makes the service make requests to another service. Metrics are collected for this route. sample usage given below: 38 | 39 | 40 | ```shell 41 | # Command 42 | curl --location --request POST 'http://service-a:9091/call' \ 43 | --header 'Content-Type: application/json' \ 44 | --data-raw '{ 45 | "url": "http://service-b:9091/call", 46 | "body": "{\r\n\"url\": \"http:\/\/service-c:9091\/echo\",\r\n\"body\": \"\",\r\n\"method\": \"GET\"\r\n}", 47 | "method": "POST", 48 | "headers": { 49 | "h1":"v1" 50 | } 51 | }' 52 | 53 | # No Output 54 | GET /echo HTTP/1.1 55 | Host: service-c:9091 56 | User-Agent: Go-http-client/1.1 57 | Accept-Encoding: gzip 58 | Servicename: Service-B 59 | ``` 60 | 61 | In the above example, we are making a post request to `service-a` with the body: 62 | ```json 63 | { 64 | "url": "http://service-b:9091/call", 65 | "body": "{\r\n\"url\": \"http:\/\/service-c:9091\/echo\",\r\n\"body\": \"\",\r\n\"method\": \"GET\"\r\n}", 66 | "method": "POST", 67 | "headers": { 68 | "h1":"v1" 69 | } 70 | } 71 | ``` 72 | This will make `service-a` to make a `POST` request to `http://service-b:9091/call` with the headers specified above, and the body: 73 | ```json 74 | { 75 | "url": "http://service-c:9091/echo", 76 | "body":"", 77 | "method": "GET" 78 | } 79 | ``` 80 | This inturn will make `service-b` to make a `GET` request to `http://service-c:9091/echo`. 81 | 82 | #### GET /metrics 83 | 84 | Gets the metrics from `service-a` 85 | ```shell 86 | # Command 87 | curl --location --request GET 'http://service-b:9091/metrics' 88 | # Output 89 | { 90 | "ReqReceived": [ 91 | "Service-A" 92 | ], 93 | "RespSucceeded": [ 94 | { 95 | "URL": "http://service-c:9091/echo", 96 | "Method": "GET", 97 | "Headers": null 98 | } 99 | ], 100 | "RespFailed": [] 101 | } 102 | ``` 103 | * In ReqReceived we see list of requests `service-b` received and from whom it received. Here we see `service-A`. Actually each of the service sets a header `ServiceName` which is read by the service to determine the sender. 104 | * As `service-b` made a request to `service-c` and the request succeeded, we can see the details in the list of successful responses (RespSucceeded). 105 | 106 | #### DELETE /metrics 107 | 108 | Clears the counters in `service` 109 | ```shell 110 | # Command 111 | curl --location --request DELETE 'http://34.68.35.174:9091/metrics' 112 | # No Output 113 | ``` 114 | 115 | > Note: metrics are collected only for `/call` and `/echo`. 116 | 117 | # Service Mesh Interface (SMI) Conformance 118 | The `learn-layer5` application serves as a sample application to validate the conformance of any service mesh with the SMI specifications. To verify SMI conformance, run Meshery and the Meshery adapter for the specific service mesh you wish to test. Invoke the suite of SMI conformance tests on the specific service mesh you would like to validate. 119 | 120 | ## Invoking conformance tests 121 | 122 | **As a Service Mesh user** 123 | Meshery allows you to schedule tests and invoke them programmatically. Meshery will store these test results and allow you to retrieve them later. 124 | 125 | **As a Service Mesh maker** 126 | Meshery guarantees provenance of these tests and facilitates the public publicing of this suite of tests results into a versioned, public matrix of conformance status (consisting of both supported capabilities and test compliance). 127 | 146 | 147 |

If you’re using Learn Layer5 or if you like the project, please star this repository to show your support! 🤩

148 |

149 | 150 |

151 |

Community and Contributing

152 | Our projects are community-built and welcome collaboration. 👍 Be sure to see the Layer5 Community Welcome Guide for a tour of resources available to you and jump into our Slack! Contributors are expected to adhere to the CNCF Code of Conduct. 153 | 154 | 155 | 156 | 157 | 158 | 159 | Shows an illustrated light mode meshery logo in light color mode and a dark mode meshery logo dark color mode. 160 | 161 | 162 | 163 | Layer5 Service Mesh Community 164 | 165 |

166 | ✔️ Join any or all of the weekly meetings on the community calendar.
167 | ✔️ Watch community meeting recordings.
168 | ✔️ Access the community drive.
169 | ✔️ Discuss in the Community Forum.
170 |

171 |

172 | Not sure where to start? Grab an open issue with the help-wanted label. 173 |

174 | 175 | ## About Layer5 176 | 177 | [Layer5](https://layer5.io)'s cloud native application and infrastructure management software enables organizations to expect more from their infrastructure. We embrace developer-defined infrastructure. We empower engineer to change how they write applications, support operators in rethinking how they run modern infrastructure and enable product owners to regain full control over their product portfolio. 178 | 179 | **License** 180 | 181 | This repository and site are available as open source under the terms of the [Apache 2.0 License](https://opensource.org/licenses/Apache-2.0). 182 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2020 Layer5, Inc. 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /smi-conformance/conformance/conformance.pb.go: -------------------------------------------------------------------------------- 1 | // Code generated by protoc-gen-go. DO NOT EDIT. 2 | // versions: 3 | // protoc-gen-go v1.24.0 4 | // protoc v3.6.1 5 | // source: learn-layer5/smi-conformance/conformance/conformance.proto 6 | 7 | package conformance 8 | 9 | import ( 10 | context "context" 11 | proto "github.com/golang/protobuf/proto" 12 | empty "github.com/golang/protobuf/ptypes/empty" 13 | service "github.com/layer5io/service-mesh-performance/service" 14 | spec "github.com/layer5io/service-mesh-performance/spec" 15 | grpc "google.golang.org/grpc" 16 | codes "google.golang.org/grpc/codes" 17 | status "google.golang.org/grpc/status" 18 | protoreflect "google.golang.org/protobuf/reflect/protoreflect" 19 | protoimpl "google.golang.org/protobuf/runtime/protoimpl" 20 | reflect "reflect" 21 | sync "sync" 22 | ) 23 | 24 | const ( 25 | // Verify that this generated code is sufficiently up-to-date. 26 | _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) 27 | // Verify that runtime/protoimpl is sufficiently up-to-date. 28 | _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) 29 | ) 30 | 31 | // This is a compile-time assertion that a sufficiently up-to-date version 32 | // of the legacy proto package is being used. 33 | const _ = proto.ProtoPackageIsVersion4 34 | 35 | type Capability int32 36 | 37 | const ( 38 | Capability_FULL Capability = 0 39 | Capability_HALF Capability = 1 40 | Capability_NONE Capability = 2 41 | ) 42 | 43 | // Enum value maps for Capability. 44 | var ( 45 | Capability_name = map[int32]string{ 46 | 0: "FULL", 47 | 1: "HALF", 48 | 2: "NONE", 49 | } 50 | Capability_value = map[string]int32{ 51 | "FULL": 0, 52 | "HALF": 1, 53 | "NONE": 2, 54 | } 55 | ) 56 | 57 | func (x Capability) Enum() *Capability { 58 | p := new(Capability) 59 | *p = x 60 | return p 61 | } 62 | 63 | func (x Capability) String() string { 64 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 65 | } 66 | 67 | func (Capability) Descriptor() protoreflect.EnumDescriptor { 68 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes[0].Descriptor() 69 | } 70 | 71 | func (Capability) Type() protoreflect.EnumType { 72 | return &file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes[0] 73 | } 74 | 75 | func (x Capability) Number() protoreflect.EnumNumber { 76 | return protoreflect.EnumNumber(x) 77 | } 78 | 79 | // Deprecated: Use Capability.Descriptor instead. 80 | func (Capability) EnumDescriptor() ([]byte, []int) { 81 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{0} 82 | } 83 | 84 | type TestStatus int32 85 | 86 | const ( 87 | TestStatus_COMPLETED TestStatus = 0 88 | TestStatus_INPROGRESS TestStatus = 1 89 | TestStatus_CRASHED TestStatus = 2 90 | ) 91 | 92 | // Enum value maps for TestStatus. 93 | var ( 94 | TestStatus_name = map[int32]string{ 95 | 0: "COMPLETED", 96 | 1: "INPROGRESS", 97 | 2: "CRASHED", 98 | } 99 | TestStatus_value = map[string]int32{ 100 | "COMPLETED": 0, 101 | "INPROGRESS": 1, 102 | "CRASHED": 2, 103 | } 104 | ) 105 | 106 | func (x TestStatus) Enum() *TestStatus { 107 | p := new(TestStatus) 108 | *p = x 109 | return p 110 | } 111 | 112 | func (x TestStatus) String() string { 113 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 114 | } 115 | 116 | func (TestStatus) Descriptor() protoreflect.EnumDescriptor { 117 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes[1].Descriptor() 118 | } 119 | 120 | func (TestStatus) Type() protoreflect.EnumType { 121 | return &file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes[1] 122 | } 123 | 124 | func (x TestStatus) Number() protoreflect.EnumNumber { 125 | return protoreflect.EnumNumber(x) 126 | } 127 | 128 | // Deprecated: Use TestStatus.Descriptor instead. 129 | func (TestStatus) EnumDescriptor() ([]byte, []int) { 130 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{1} 131 | } 132 | 133 | type ResultStatus int32 134 | 135 | const ( 136 | ResultStatus_PASSED ResultStatus = 0 137 | ResultStatus_FAILED ResultStatus = 1 138 | ) 139 | 140 | // Enum value maps for ResultStatus. 141 | var ( 142 | ResultStatus_name = map[int32]string{ 143 | 0: "PASSED", 144 | 1: "FAILED", 145 | } 146 | ResultStatus_value = map[string]int32{ 147 | "PASSED": 0, 148 | "FAILED": 1, 149 | } 150 | ) 151 | 152 | func (x ResultStatus) Enum() *ResultStatus { 153 | p := new(ResultStatus) 154 | *p = x 155 | return p 156 | } 157 | 158 | func (x ResultStatus) String() string { 159 | return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) 160 | } 161 | 162 | func (ResultStatus) Descriptor() protoreflect.EnumDescriptor { 163 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes[2].Descriptor() 164 | } 165 | 166 | func (ResultStatus) Type() protoreflect.EnumType { 167 | return &file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes[2] 168 | } 169 | 170 | func (x ResultStatus) Number() protoreflect.EnumNumber { 171 | return protoreflect.EnumNumber(x) 172 | } 173 | 174 | // Deprecated: Use ResultStatus.Descriptor instead. 175 | func (ResultStatus) EnumDescriptor() ([]byte, []int) { 176 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{2} 177 | } 178 | 179 | type Request struct { 180 | state protoimpl.MessageState 181 | sizeCache protoimpl.SizeCache 182 | unknownFields protoimpl.UnknownFields 183 | 184 | Mesh *spec.ServiceMesh `protobuf:"bytes,1,opt,name=mesh,proto3" json:"mesh,omitempty"` 185 | } 186 | 187 | func (x *Request) Reset() { 188 | *x = Request{} 189 | if protoimpl.UnsafeEnabled { 190 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[0] 191 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 192 | ms.StoreMessageInfo(mi) 193 | } 194 | } 195 | 196 | func (x *Request) String() string { 197 | return protoimpl.X.MessageStringOf(x) 198 | } 199 | 200 | func (*Request) ProtoMessage() {} 201 | 202 | func (x *Request) ProtoReflect() protoreflect.Message { 203 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[0] 204 | if protoimpl.UnsafeEnabled && x != nil { 205 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 206 | if ms.LoadMessageInfo() == nil { 207 | ms.StoreMessageInfo(mi) 208 | } 209 | return ms 210 | } 211 | return mi.MessageOf(x) 212 | } 213 | 214 | // Deprecated: Use Request.ProtoReflect.Descriptor instead. 215 | func (*Request) Descriptor() ([]byte, []int) { 216 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{0} 217 | } 218 | 219 | func (x *Request) GetMesh() *spec.ServiceMesh { 220 | if x != nil { 221 | return x.Mesh 222 | } 223 | return nil 224 | } 225 | 226 | type Result struct { 227 | state protoimpl.MessageState 228 | sizeCache protoimpl.SizeCache 229 | unknownFields protoimpl.UnknownFields 230 | 231 | // Types that are assignable to Result: 232 | // *Result_Message 233 | // *Result_Error 234 | Result isResult_Result `protobuf_oneof:"result"` 235 | } 236 | 237 | func (x *Result) Reset() { 238 | *x = Result{} 239 | if protoimpl.UnsafeEnabled { 240 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[1] 241 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 242 | ms.StoreMessageInfo(mi) 243 | } 244 | } 245 | 246 | func (x *Result) String() string { 247 | return protoimpl.X.MessageStringOf(x) 248 | } 249 | 250 | func (*Result) ProtoMessage() {} 251 | 252 | func (x *Result) ProtoReflect() protoreflect.Message { 253 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[1] 254 | if protoimpl.UnsafeEnabled && x != nil { 255 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 256 | if ms.LoadMessageInfo() == nil { 257 | ms.StoreMessageInfo(mi) 258 | } 259 | return ms 260 | } 261 | return mi.MessageOf(x) 262 | } 263 | 264 | // Deprecated: Use Result.ProtoReflect.Descriptor instead. 265 | func (*Result) Descriptor() ([]byte, []int) { 266 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{1} 267 | } 268 | 269 | func (m *Result) GetResult() isResult_Result { 270 | if m != nil { 271 | return m.Result 272 | } 273 | return nil 274 | } 275 | 276 | func (x *Result) GetMessage() string { 277 | if x, ok := x.GetResult().(*Result_Message); ok { 278 | return x.Message 279 | } 280 | return "" 281 | } 282 | 283 | func (x *Result) GetError() *service.CommonError { 284 | if x, ok := x.GetResult().(*Result_Error); ok { 285 | return x.Error 286 | } 287 | return nil 288 | } 289 | 290 | type isResult_Result interface { 291 | isResult_Result() 292 | } 293 | 294 | type Result_Message struct { 295 | Message string `protobuf:"bytes,1,opt,name=message,proto3,oneof"` 296 | } 297 | 298 | type Result_Error struct { 299 | Error *service.CommonError `protobuf:"bytes,2,opt,name=error,proto3,oneof"` 300 | } 301 | 302 | func (*Result_Message) isResult_Result() {} 303 | 304 | func (*Result_Error) isResult_Result() {} 305 | 306 | type Detail struct { 307 | state protoimpl.MessageState 308 | sizeCache protoimpl.SizeCache 309 | unknownFields protoimpl.UnknownFields 310 | 311 | Smispec string `protobuf:"bytes,1,opt,name=smispec,proto3" json:"smispec,omitempty"` 312 | Specversion string `protobuf:"bytes,2,opt,name=specversion,proto3" json:"specversion,omitempty"` 313 | Assertion string `protobuf:"bytes,3,opt,name=assertion,proto3" json:"assertion,omitempty"` 314 | Duration string `protobuf:"bytes,4,opt,name=duration,proto3" json:"duration,omitempty"` 315 | Result *Result `protobuf:"bytes,5,opt,name=result,proto3" json:"result,omitempty"` 316 | Capability Capability `protobuf:"varint,6,opt,name=capability,proto3,enum=smi_conformance.Capability" json:"capability,omitempty"` 317 | Status ResultStatus `protobuf:"varint,7,opt,name=status,proto3,enum=smi_conformance.ResultStatus" json:"status,omitempty"` 318 | } 319 | 320 | func (x *Detail) Reset() { 321 | *x = Detail{} 322 | if protoimpl.UnsafeEnabled { 323 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[2] 324 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 325 | ms.StoreMessageInfo(mi) 326 | } 327 | } 328 | 329 | func (x *Detail) String() string { 330 | return protoimpl.X.MessageStringOf(x) 331 | } 332 | 333 | func (*Detail) ProtoMessage() {} 334 | 335 | func (x *Detail) ProtoReflect() protoreflect.Message { 336 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[2] 337 | if protoimpl.UnsafeEnabled && x != nil { 338 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 339 | if ms.LoadMessageInfo() == nil { 340 | ms.StoreMessageInfo(mi) 341 | } 342 | return ms 343 | } 344 | return mi.MessageOf(x) 345 | } 346 | 347 | // Deprecated: Use Detail.ProtoReflect.Descriptor instead. 348 | func (*Detail) Descriptor() ([]byte, []int) { 349 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{2} 350 | } 351 | 352 | func (x *Detail) GetSmispec() string { 353 | if x != nil { 354 | return x.Smispec 355 | } 356 | return "" 357 | } 358 | 359 | func (x *Detail) GetSpecversion() string { 360 | if x != nil { 361 | return x.Specversion 362 | } 363 | return "" 364 | } 365 | 366 | func (x *Detail) GetAssertion() string { 367 | if x != nil { 368 | return x.Assertion 369 | } 370 | return "" 371 | } 372 | 373 | func (x *Detail) GetDuration() string { 374 | if x != nil { 375 | return x.Duration 376 | } 377 | return "" 378 | } 379 | 380 | func (x *Detail) GetResult() *Result { 381 | if x != nil { 382 | return x.Result 383 | } 384 | return nil 385 | } 386 | 387 | func (x *Detail) GetCapability() Capability { 388 | if x != nil { 389 | return x.Capability 390 | } 391 | return Capability_FULL 392 | } 393 | 394 | func (x *Detail) GetStatus() ResultStatus { 395 | if x != nil { 396 | return x.Status 397 | } 398 | return ResultStatus_PASSED 399 | } 400 | 401 | type Response struct { 402 | state protoimpl.MessageState 403 | sizeCache protoimpl.SizeCache 404 | unknownFields protoimpl.UnknownFields 405 | 406 | Passpercent string `protobuf:"bytes,1,opt,name=passpercent,proto3" json:"passpercent,omitempty"` 407 | Casespassed string `protobuf:"bytes,2,opt,name=casespassed,proto3" json:"casespassed,omitempty"` 408 | Mesh *spec.ServiceMesh `protobuf:"bytes,3,opt,name=mesh,proto3" json:"mesh,omitempty"` 409 | Details []*Detail `protobuf:"bytes,5,rep,name=details,proto3" json:"details,omitempty"` 410 | } 411 | 412 | func (x *Response) Reset() { 413 | *x = Response{} 414 | if protoimpl.UnsafeEnabled { 415 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[3] 416 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 417 | ms.StoreMessageInfo(mi) 418 | } 419 | } 420 | 421 | func (x *Response) String() string { 422 | return protoimpl.X.MessageStringOf(x) 423 | } 424 | 425 | func (*Response) ProtoMessage() {} 426 | 427 | func (x *Response) ProtoReflect() protoreflect.Message { 428 | mi := &file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[3] 429 | if protoimpl.UnsafeEnabled && x != nil { 430 | ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) 431 | if ms.LoadMessageInfo() == nil { 432 | ms.StoreMessageInfo(mi) 433 | } 434 | return ms 435 | } 436 | return mi.MessageOf(x) 437 | } 438 | 439 | // Deprecated: Use Response.ProtoReflect.Descriptor instead. 440 | func (*Response) Descriptor() ([]byte, []int) { 441 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP(), []int{3} 442 | } 443 | 444 | func (x *Response) GetPasspercent() string { 445 | if x != nil { 446 | return x.Passpercent 447 | } 448 | return "" 449 | } 450 | 451 | func (x *Response) GetCasespassed() string { 452 | if x != nil { 453 | return x.Casespassed 454 | } 455 | return "" 456 | } 457 | 458 | func (x *Response) GetMesh() *spec.ServiceMesh { 459 | if x != nil { 460 | return x.Mesh 461 | } 462 | return nil 463 | } 464 | 465 | func (x *Response) GetDetails() []*Detail { 466 | if x != nil { 467 | return x.Details 468 | } 469 | return nil 470 | } 471 | 472 | var File_learn_layer5_smi_conformance_conformance_conformance_proto protoreflect.FileDescriptor 473 | 474 | var file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDesc = []byte{ 475 | 0x0a, 0x3a, 0x6c, 0x65, 0x61, 0x72, 0x6e, 0x2d, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x35, 0x2f, 0x73, 476 | 0x6d, 0x69, 0x2d, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x63, 477 | 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 478 | 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0f, 0x73, 0x6d, 479 | 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x1a, 0x1b, 0x67, 480 | 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 481 | 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x73, 0x65, 0x72, 0x76, 482 | 0x69, 0x63, 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x68, 0x2d, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 483 | 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x65, 0x72, 0x72, 484 | 0x6f, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 485 | 0x65, 0x2d, 0x6d, 0x65, 0x73, 0x68, 0x2d, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 486 | 0x63, 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x68, 0x65, 0x61, 0x6c, 0x74, 487 | 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2b, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 488 | 0x2d, 0x6d, 0x65, 0x73, 0x68, 0x2d, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 489 | 0x65, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x69, 0x6e, 0x66, 0x6f, 0x2e, 0x70, 490 | 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x32, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2d, 0x6d, 0x65, 491 | 0x73, 0x68, 0x2d, 0x70, 0x65, 0x72, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2f, 0x70, 492 | 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x6d, 0x65, 493 | 0x73, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x2f, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 494 | 0x65, 0x73, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x6d, 0x65, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 495 | 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x6d, 0x70, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 496 | 0x65, 0x73, 0x68, 0x52, 0x04, 0x6d, 0x65, 0x73, 0x68, 0x22, 0x5c, 0x0a, 0x06, 0x52, 0x65, 0x73, 497 | 0x75, 0x6c, 0x74, 0x12, 0x1a, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 498 | 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 499 | 0x2c, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 500 | 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x45, 501 | 0x72, 0x72, 0x6f, 0x72, 0x48, 0x00, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x42, 0x08, 0x0a, 502 | 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0xa3, 0x02, 0x0a, 0x06, 0x44, 0x65, 0x74, 0x61, 503 | 0x69, 0x6c, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x6d, 0x69, 0x73, 0x70, 0x65, 0x63, 0x18, 0x01, 0x20, 504 | 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x6d, 0x69, 0x73, 0x70, 0x65, 0x63, 0x12, 0x20, 0x0a, 0x0b, 505 | 0x73, 0x70, 0x65, 0x63, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 506 | 0x09, 0x52, 0x0b, 0x73, 0x70, 0x65, 0x63, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1c, 507 | 0x0a, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 508 | 0x09, 0x52, 0x09, 0x61, 0x73, 0x73, 0x65, 0x72, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 509 | 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 510 | 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x2f, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 511 | 0x6c, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6d, 0x69, 0x5f, 0x63, 512 | 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 513 | 0x74, 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3b, 0x0a, 0x0a, 0x63, 0x61, 0x70, 514 | 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 515 | 0x73, 0x6d, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 516 | 0x43, 0x61, 0x70, 0x61, 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x52, 0x0a, 0x63, 0x61, 0x70, 0x61, 517 | 0x62, 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x35, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 518 | 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x73, 0x6d, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 519 | 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, 520 | 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0xa7, 0x01, 521 | 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 522 | 0x73, 0x73, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 523 | 0x0b, 0x70, 0x61, 0x73, 0x73, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x12, 0x20, 0x0a, 0x0b, 524 | 0x63, 0x61, 0x73, 0x65, 0x73, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 525 | 0x09, 0x52, 0x0b, 0x63, 0x61, 0x73, 0x65, 0x73, 0x70, 0x61, 0x73, 0x73, 0x65, 0x64, 0x12, 0x24, 526 | 0x0a, 0x04, 0x6d, 0x65, 0x73, 0x68, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 527 | 0x6d, 0x70, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4d, 0x65, 0x73, 0x68, 0x52, 0x04, 528 | 0x6d, 0x65, 0x73, 0x68, 0x12, 0x31, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 529 | 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x6d, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 530 | 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x52, 0x07, 531 | 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2a, 0x2a, 0x0a, 0x0a, 0x43, 0x61, 0x70, 0x61, 0x62, 532 | 0x69, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x08, 0x0a, 0x04, 0x46, 0x55, 0x4c, 0x4c, 0x10, 0x00, 0x12, 533 | 0x08, 0x0a, 0x04, 0x48, 0x41, 0x4c, 0x46, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 534 | 0x45, 0x10, 0x02, 0x2a, 0x38, 0x0a, 0x0a, 0x54, 0x65, 0x73, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 535 | 0x73, 0x12, 0x0d, 0x0a, 0x09, 0x43, 0x4f, 0x4d, 0x50, 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x00, 536 | 0x12, 0x0e, 0x0a, 0x0a, 0x49, 0x4e, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 537 | 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x52, 0x41, 0x53, 0x48, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x26, 0x0a, 538 | 0x0c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0a, 0x0a, 539 | 0x06, 0x50, 0x41, 0x53, 0x53, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 540 | 0x4c, 0x45, 0x44, 0x10, 0x01, 0x32, 0xc4, 0x01, 0x0a, 0x12, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 541 | 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x34, 0x0a, 0x04, 542 | 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 543 | 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x14, 0x2e, 0x73, 544 | 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 545 | 0x66, 0x6f, 0x12, 0x38, 0x0a, 0x06, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x67, 546 | 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 547 | 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 548 | 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, 0x3e, 0x0a, 0x07, 549 | 0x52, 0x75, 0x6e, 0x54, 0x65, 0x73, 0x74, 0x12, 0x18, 0x2e, 0x73, 0x6d, 0x69, 0x5f, 0x63, 0x6f, 550 | 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 551 | 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x6d, 0x69, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 552 | 0x6e, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x19, 0x5a, 0x17, 553 | 0x63, 0x6f, 0x6e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x3b, 0x63, 0x6f, 0x6e, 0x66, 554 | 0x6f, 0x72, 0x6d, 0x61, 0x6e, 0x63, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 555 | } 556 | 557 | var ( 558 | file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescOnce sync.Once 559 | file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescData = file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDesc 560 | ) 561 | 562 | func file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescGZIP() []byte { 563 | file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescOnce.Do(func() { 564 | file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescData = protoimpl.X.CompressGZIP(file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescData) 565 | }) 566 | return file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDescData 567 | } 568 | 569 | var file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes = make([]protoimpl.EnumInfo, 3) 570 | var file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes = make([]protoimpl.MessageInfo, 4) 571 | var file_learn_layer5_smi_conformance_conformance_conformance_proto_goTypes = []interface{}{ 572 | (Capability)(0), // 0: smi_conformance.Capability 573 | (TestStatus)(0), // 1: smi_conformance.TestStatus 574 | (ResultStatus)(0), // 2: smi_conformance.ResultStatus 575 | (*Request)(nil), // 3: smi_conformance.Request 576 | (*Result)(nil), // 4: smi_conformance.Result 577 | (*Detail)(nil), // 5: smi_conformance.Detail 578 | (*Response)(nil), // 6: smi_conformance.Response 579 | (*spec.ServiceMesh)(nil), // 7: smp.ServiceMesh 580 | (*service.CommonError)(nil), // 8: service.CommonError 581 | (*empty.Empty)(nil), // 9: google.protobuf.Empty 582 | (*service.ServiceInfo)(nil), // 10: service.ServiceInfo 583 | (*service.ServiceHealth)(nil), // 11: service.ServiceHealth 584 | } 585 | var file_learn_layer5_smi_conformance_conformance_conformance_proto_depIdxs = []int32{ 586 | 7, // 0: smi_conformance.Request.mesh:type_name -> smp.ServiceMesh 587 | 8, // 1: smi_conformance.Result.error:type_name -> service.CommonError 588 | 4, // 2: smi_conformance.Detail.result:type_name -> smi_conformance.Result 589 | 0, // 3: smi_conformance.Detail.capability:type_name -> smi_conformance.Capability 590 | 2, // 4: smi_conformance.Detail.status:type_name -> smi_conformance.ResultStatus 591 | 7, // 5: smi_conformance.Response.mesh:type_name -> smp.ServiceMesh 592 | 5, // 6: smi_conformance.Response.details:type_name -> smi_conformance.Detail 593 | 9, // 7: smi_conformance.conformanceTesting.Info:input_type -> google.protobuf.Empty 594 | 9, // 8: smi_conformance.conformanceTesting.Health:input_type -> google.protobuf.Empty 595 | 3, // 9: smi_conformance.conformanceTesting.RunTest:input_type -> smi_conformance.Request 596 | 10, // 10: smi_conformance.conformanceTesting.Info:output_type -> service.ServiceInfo 597 | 11, // 11: smi_conformance.conformanceTesting.Health:output_type -> service.ServiceHealth 598 | 6, // 12: smi_conformance.conformanceTesting.RunTest:output_type -> smi_conformance.Response 599 | 10, // [10:13] is the sub-list for method output_type 600 | 7, // [7:10] is the sub-list for method input_type 601 | 7, // [7:7] is the sub-list for extension type_name 602 | 7, // [7:7] is the sub-list for extension extendee 603 | 0, // [0:7] is the sub-list for field type_name 604 | } 605 | 606 | func init() { file_learn_layer5_smi_conformance_conformance_conformance_proto_init() } 607 | func file_learn_layer5_smi_conformance_conformance_conformance_proto_init() { 608 | if File_learn_layer5_smi_conformance_conformance_conformance_proto != nil { 609 | return 610 | } 611 | if !protoimpl.UnsafeEnabled { 612 | file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { 613 | switch v := v.(*Request); i { 614 | case 0: 615 | return &v.state 616 | case 1: 617 | return &v.sizeCache 618 | case 2: 619 | return &v.unknownFields 620 | default: 621 | return nil 622 | } 623 | } 624 | file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { 625 | switch v := v.(*Result); i { 626 | case 0: 627 | return &v.state 628 | case 1: 629 | return &v.sizeCache 630 | case 2: 631 | return &v.unknownFields 632 | default: 633 | return nil 634 | } 635 | } 636 | file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { 637 | switch v := v.(*Detail); i { 638 | case 0: 639 | return &v.state 640 | case 1: 641 | return &v.sizeCache 642 | case 2: 643 | return &v.unknownFields 644 | default: 645 | return nil 646 | } 647 | } 648 | file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { 649 | switch v := v.(*Response); i { 650 | case 0: 651 | return &v.state 652 | case 1: 653 | return &v.sizeCache 654 | case 2: 655 | return &v.unknownFields 656 | default: 657 | return nil 658 | } 659 | } 660 | } 661 | file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes[1].OneofWrappers = []interface{}{ 662 | (*Result_Message)(nil), 663 | (*Result_Error)(nil), 664 | } 665 | type x struct{} 666 | out := protoimpl.TypeBuilder{ 667 | File: protoimpl.DescBuilder{ 668 | GoPackagePath: reflect.TypeOf(x{}).PkgPath(), 669 | RawDescriptor: file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDesc, 670 | NumEnums: 3, 671 | NumMessages: 4, 672 | NumExtensions: 0, 673 | NumServices: 1, 674 | }, 675 | GoTypes: file_learn_layer5_smi_conformance_conformance_conformance_proto_goTypes, 676 | DependencyIndexes: file_learn_layer5_smi_conformance_conformance_conformance_proto_depIdxs, 677 | EnumInfos: file_learn_layer5_smi_conformance_conformance_conformance_proto_enumTypes, 678 | MessageInfos: file_learn_layer5_smi_conformance_conformance_conformance_proto_msgTypes, 679 | }.Build() 680 | File_learn_layer5_smi_conformance_conformance_conformance_proto = out.File 681 | file_learn_layer5_smi_conformance_conformance_conformance_proto_rawDesc = nil 682 | file_learn_layer5_smi_conformance_conformance_conformance_proto_goTypes = nil 683 | file_learn_layer5_smi_conformance_conformance_conformance_proto_depIdxs = nil 684 | } 685 | 686 | // Reference imports to suppress errors if they are not otherwise used. 687 | var _ context.Context 688 | var _ grpc.ClientConnInterface 689 | 690 | // This is a compile-time assertion to ensure that this generated file 691 | // is compatible with the grpc package it is being compiled against. 692 | const _ = grpc.SupportPackageIsVersion6 693 | 694 | // ConformanceTestingClient is the client API for ConformanceTesting service. 695 | // 696 | // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. 697 | type ConformanceTestingClient interface { 698 | Info(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*service.ServiceInfo, error) 699 | Health(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*service.ServiceHealth, error) 700 | RunTest(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) 701 | } 702 | 703 | type conformanceTestingClient struct { 704 | cc grpc.ClientConnInterface 705 | } 706 | 707 | func NewConformanceTestingClient(cc grpc.ClientConnInterface) ConformanceTestingClient { 708 | return &conformanceTestingClient{cc} 709 | } 710 | 711 | func (c *conformanceTestingClient) Info(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*service.ServiceInfo, error) { 712 | out := new(service.ServiceInfo) 713 | err := c.cc.Invoke(ctx, "/smi_conformance.conformanceTesting/Info", in, out, opts...) 714 | if err != nil { 715 | return nil, err 716 | } 717 | return out, nil 718 | } 719 | 720 | func (c *conformanceTestingClient) Health(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*service.ServiceHealth, error) { 721 | out := new(service.ServiceHealth) 722 | err := c.cc.Invoke(ctx, "/smi_conformance.conformanceTesting/Health", in, out, opts...) 723 | if err != nil { 724 | return nil, err 725 | } 726 | return out, nil 727 | } 728 | 729 | func (c *conformanceTestingClient) RunTest(ctx context.Context, in *Request, opts ...grpc.CallOption) (*Response, error) { 730 | out := new(Response) 731 | err := c.cc.Invoke(ctx, "/smi_conformance.conformanceTesting/RunTest", in, out, opts...) 732 | if err != nil { 733 | return nil, err 734 | } 735 | return out, nil 736 | } 737 | 738 | // ConformanceTestingServer is the server API for ConformanceTesting service. 739 | type ConformanceTestingServer interface { 740 | Info(context.Context, *empty.Empty) (*service.ServiceInfo, error) 741 | Health(context.Context, *empty.Empty) (*service.ServiceHealth, error) 742 | RunTest(context.Context, *Request) (*Response, error) 743 | } 744 | 745 | // UnimplementedConformanceTestingServer can be embedded to have forward compatible implementations. 746 | type UnimplementedConformanceTestingServer struct { 747 | } 748 | 749 | func (*UnimplementedConformanceTestingServer) Info(context.Context, *empty.Empty) (*service.ServiceInfo, error) { 750 | return nil, status.Errorf(codes.Unimplemented, "method Info not implemented") 751 | } 752 | func (*UnimplementedConformanceTestingServer) Health(context.Context, *empty.Empty) (*service.ServiceHealth, error) { 753 | return nil, status.Errorf(codes.Unimplemented, "method Health not implemented") 754 | } 755 | func (*UnimplementedConformanceTestingServer) RunTest(context.Context, *Request) (*Response, error) { 756 | return nil, status.Errorf(codes.Unimplemented, "method RunTest not implemented") 757 | } 758 | 759 | func RegisterConformanceTestingServer(s *grpc.Server, srv ConformanceTestingServer) { 760 | s.RegisterService(&_ConformanceTesting_serviceDesc, srv) 761 | } 762 | 763 | func _ConformanceTesting_Info_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 764 | in := new(empty.Empty) 765 | if err := dec(in); err != nil { 766 | return nil, err 767 | } 768 | if interceptor == nil { 769 | return srv.(ConformanceTestingServer).Info(ctx, in) 770 | } 771 | info := &grpc.UnaryServerInfo{ 772 | Server: srv, 773 | FullMethod: "/smi_conformance.conformanceTesting/Info", 774 | } 775 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 776 | return srv.(ConformanceTestingServer).Info(ctx, req.(*empty.Empty)) 777 | } 778 | return interceptor(ctx, in, info, handler) 779 | } 780 | 781 | func _ConformanceTesting_Health_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 782 | in := new(empty.Empty) 783 | if err := dec(in); err != nil { 784 | return nil, err 785 | } 786 | if interceptor == nil { 787 | return srv.(ConformanceTestingServer).Health(ctx, in) 788 | } 789 | info := &grpc.UnaryServerInfo{ 790 | Server: srv, 791 | FullMethod: "/smi_conformance.conformanceTesting/Health", 792 | } 793 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 794 | return srv.(ConformanceTestingServer).Health(ctx, req.(*empty.Empty)) 795 | } 796 | return interceptor(ctx, in, info, handler) 797 | } 798 | 799 | func _ConformanceTesting_RunTest_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { 800 | in := new(Request) 801 | if err := dec(in); err != nil { 802 | return nil, err 803 | } 804 | if interceptor == nil { 805 | return srv.(ConformanceTestingServer).RunTest(ctx, in) 806 | } 807 | info := &grpc.UnaryServerInfo{ 808 | Server: srv, 809 | FullMethod: "/smi_conformance.conformanceTesting/RunTest", 810 | } 811 | handler := func(ctx context.Context, req interface{}) (interface{}, error) { 812 | return srv.(ConformanceTestingServer).RunTest(ctx, req.(*Request)) 813 | } 814 | return interceptor(ctx, in, info, handler) 815 | } 816 | 817 | var _ConformanceTesting_serviceDesc = grpc.ServiceDesc{ 818 | ServiceName: "smi_conformance.conformanceTesting", 819 | HandlerType: (*ConformanceTestingServer)(nil), 820 | Methods: []grpc.MethodDesc{ 821 | { 822 | MethodName: "Info", 823 | Handler: _ConformanceTesting_Info_Handler, 824 | }, 825 | { 826 | MethodName: "Health", 827 | Handler: _ConformanceTesting_Health_Handler, 828 | }, 829 | { 830 | MethodName: "RunTest", 831 | Handler: _ConformanceTesting_RunTest_Handler, 832 | }, 833 | }, 834 | Streams: []grpc.StreamDesc{}, 835 | Metadata: "learn-layer5/smi-conformance/conformance/conformance.proto", 836 | } 837 | --------------------------------------------------------------------------------