Adapt OAP V9 query protocol (#133)

diff --git a/.github/workflows/command-tests.yml b/.github/workflows/command-tests.yml
index cd81384..f8203dc 100644
--- a/.github/workflows/command-tests.yml
+++ b/.github/workflows/command-tests.yml
@@ -28,6 +28,11 @@
 jobs:
   command-test:
     runs-on: ubuntu-latest
+    strategy:
+      matrix:
+        oap:
+          - 8.8.1
+          - 9.0.0
     steps:
       - uses: actions/checkout@v2
       - name: Check for go file changes
@@ -47,4 +52,4 @@
         if: steps.changes.outputs.src == 'true'
         uses: apache/skywalking-infra-e2e@d714677324e31cd4ab45782e58cea0946a065132
         with:
-          e2e-file: test/test.yaml
+          e2e-file: test/cases/${{ matrix.oap }}/test.yaml
diff --git a/CHANGES.md b/CHANGES.md
index 3017d4e..32119ba 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -8,6 +8,8 @@
 ### Features
 
 - Add the sub-command `dependency instance` to query instance relationships (#117)
+- Add the sub-command `service layer` to query services according to layer.(#133)
+- Add the sub-command `layer list` to query layer list.(#133)
 
 ### Bug Fixes
 
diff --git a/assets/graphqls/common/version.graphql b/assets/graphqls/common/version.graphql
new file mode 100644
index 0000000..8a57514
--- /dev/null
+++ b/assets/graphqls/common/version.graphql
@@ -0,0 +1,20 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query {
+    result: version
+}
diff --git a/assets/graphqls/metadata/AllBrowserServices.graphql b/assets/graphqls/metadata/v1/AllBrowserServices.graphql
similarity index 100%
rename from assets/graphqls/metadata/AllBrowserServices.graphql
rename to assets/graphqls/metadata/v1/AllBrowserServices.graphql
diff --git a/assets/graphqls/metadata/AllServices.graphql b/assets/graphqls/metadata/v1/AllServices.graphql
similarity index 100%
rename from assets/graphqls/metadata/AllServices.graphql
rename to assets/graphqls/metadata/v1/AllServices.graphql
diff --git a/assets/graphqls/metadata/Instances.graphql b/assets/graphqls/metadata/v1/Instances.graphql
similarity index 100%
rename from assets/graphqls/metadata/Instances.graphql
rename to assets/graphqls/metadata/v1/Instances.graphql
diff --git a/assets/graphqls/metadata/SearchBrowserService.graphql b/assets/graphqls/metadata/v1/SearchBrowserService.graphql
similarity index 100%
rename from assets/graphqls/metadata/SearchBrowserService.graphql
rename to assets/graphqls/metadata/v1/SearchBrowserService.graphql
diff --git a/assets/graphqls/metadata/SearchEndpoints.graphql b/assets/graphqls/metadata/v1/SearchEndpoints.graphql
similarity index 100%
rename from assets/graphqls/metadata/SearchEndpoints.graphql
rename to assets/graphqls/metadata/v1/SearchEndpoints.graphql
diff --git a/assets/graphqls/metadata/SearchService.graphql b/assets/graphqls/metadata/v1/SearchService.graphql
similarity index 100%
rename from assets/graphqls/metadata/SearchService.graphql
rename to assets/graphqls/metadata/v1/SearchService.graphql
diff --git a/assets/graphqls/metadata/ServerTimeInfo.graphql b/assets/graphqls/metadata/v1/ServerTimeInfo.graphql
similarity index 100%
rename from assets/graphqls/metadata/ServerTimeInfo.graphql
rename to assets/graphqls/metadata/v1/ServerTimeInfo.graphql
diff --git a/assets/graphqls/metadata/v2/AllBrowserServices.graphql b/assets/graphqls/metadata/v2/AllBrowserServices.graphql
new file mode 100644
index 0000000..c477c82
--- /dev/null
+++ b/assets/graphqls/metadata/v2/AllBrowserServices.graphql
@@ -0,0 +1,22 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query ($duration: Duration!) {
+    result: getAllBrowserServices(duration: $duration) {
+        id name group shortName layers
+    }
+}
diff --git a/assets/graphqls/metadata/v2/AllServices.graphql b/assets/graphqls/metadata/v2/AllServices.graphql
new file mode 100644
index 0000000..6229982
--- /dev/null
+++ b/assets/graphqls/metadata/v2/AllServices.graphql
@@ -0,0 +1,22 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query ($duration: Duration!) {
+    result: getAllServices(duration: $duration) {
+        id name group shortName layers
+    }
+}
diff --git a/assets/graphqls/metadata/v2/Instances.graphql b/assets/graphqls/metadata/v2/Instances.graphql
new file mode 100644
index 0000000..0a78de3
--- /dev/null
+++ b/assets/graphqls/metadata/v2/Instances.graphql
@@ -0,0 +1,31 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+
+query ($serviceId: ID!, $duration: Duration!) {
+    result: getServiceInstances(duration: $duration, serviceId: $serviceId) {
+        id
+        name
+        language
+        instanceUUID
+        layer
+        attributes {
+            name
+            value
+        }
+    }
+}
diff --git a/assets/graphqls/metadata/v2/ListLayers.graphql b/assets/graphqls/metadata/v2/ListLayers.graphql
new file mode 100644
index 0000000..57dfc30
--- /dev/null
+++ b/assets/graphqls/metadata/v2/ListLayers.graphql
@@ -0,0 +1,20 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query {
+    result: listLayers
+}
\ No newline at end of file
diff --git a/assets/graphqls/metadata/v2/ListService.graphql b/assets/graphqls/metadata/v2/ListService.graphql
new file mode 100644
index 0000000..d0fe6a2
--- /dev/null
+++ b/assets/graphqls/metadata/v2/ListService.graphql
@@ -0,0 +1,22 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query ($layer: String!) {
+    result: listServices(layer: $layer) {
+        id name group shortName layers
+    }
+}
diff --git a/assets/graphqls/metadata/v2/SearchBrowserService.graphql b/assets/graphqls/metadata/v2/SearchBrowserService.graphql
new file mode 100644
index 0000000..7de17f1
--- /dev/null
+++ b/assets/graphqls/metadata/v2/SearchBrowserService.graphql
@@ -0,0 +1,22 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query ($serviceCode: String!) {
+    result: searchBrowserService(serviceCode: $serviceCode) {
+        id name group shortName layers
+    }
+}
diff --git a/assets/graphqls/metadata/v2/SearchService.graphql b/assets/graphqls/metadata/v2/SearchService.graphql
new file mode 100644
index 0000000..f40d2c1
--- /dev/null
+++ b/assets/graphqls/metadata/v2/SearchService.graphql
@@ -0,0 +1,22 @@
+# Licensed to Apache Software Foundation (ASF) under one or more contributor
+# license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright
+# ownership. Apache Software Foundation (ASF) licenses this file to you under
+# the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+query searchService($serviceCode: String!) {
+    result: searchService(serviceCode: $serviceCode) {
+        id name group shortName layers
+    }
+}
diff --git a/assets/graphqls/metadata/ServerTimeInfo.graphql b/assets/graphqls/metadata/v2/ServerTimeInfo.graphql
similarity index 100%
copy from assets/graphqls/metadata/ServerTimeInfo.graphql
copy to assets/graphqls/metadata/v2/ServerTimeInfo.graphql
diff --git a/cmd/swctl/main.go b/cmd/swctl/main.go
index f52ea7e..27f9b2e 100644
--- a/cmd/swctl/main.go
+++ b/cmd/swctl/main.go
@@ -32,6 +32,7 @@
 	"github.com/apache/skywalking-cli/internal/commands/install"
 	"github.com/apache/skywalking-cli/internal/commands/instance"
 	"github.com/apache/skywalking-cli/internal/commands/interceptor"
+	"github.com/apache/skywalking-cli/internal/commands/layer"
 	"github.com/apache/skywalking-cli/internal/commands/logs"
 	"github.com/apache/skywalking-cli/internal/commands/metrics"
 	"github.com/apache/skywalking-cli/internal/commands/profile"
@@ -98,6 +99,7 @@
 		completion.Command,
 		dependency.Command,
 		alarm.Command,
+		layer.Command,
 	}
 
 	app.Before = interceptor.BeforeChain(
diff --git a/go.mod b/go.mod
index b92ea26..463d752 100644
--- a/go.mod
+++ b/go.mod
@@ -16,9 +16,9 @@
 	github.com/spf13/viper v1.7.0
 	github.com/urfave/cli/v2 v2.3.0
 	golang.org/x/crypto v0.0.0-20201216223049-8b5274cf687f // indirect
-	google.golang.org/grpc v1.38.0
+	google.golang.org/grpc v1.40.0
 	gopkg.in/yaml.v2 v2.4.0
 	k8s.io/apimachinery v0.21.1
 	sigs.k8s.io/controller-runtime v0.7.0
-	skywalking.apache.org/repo/goapi v0.0.0-20210820070710-e10b78bbf481
+	skywalking.apache.org/repo/goapi v0.0.0-20220105035505-48cad5270f49
 )
diff --git a/go.sum b/go.sum
index d213767..b361ae8 100644
--- a/go.sum
+++ b/go.sum
@@ -67,6 +67,7 @@
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
+github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/apache/skywalking-cli v0.0.0-20201125155244-ffee47d2e83d/go.mod h1:kUqj2ESaiYz89JFJUr+cL6EDmzlEYSrlEMOkWg9wuS4=
 github.com/apache/skywalking-swck v0.2.0 h1:/D4EZQxHWc4CEvCr0YuYMxrzz/Qmmh7+LRYk6cyEbzA=
 github.com/apache/skywalking-swck v0.2.0/go.mod h1:kU75U5Tb3aEi1Vk1KX7hzyh8Hv7sUMNx0Djq5PLEPWI=
@@ -93,7 +94,9 @@
 github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
 github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
+github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@@ -128,7 +131,10 @@
 github.com/emicklei/go-restful-swagger12 v0.0.0-20201014110547-68ccff494617/go.mod h1:qr0VowGBT4CS4Q8vFF8BSeKz34PuqKGxs/L0IAQA9DQ=
 github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
+github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
@@ -235,8 +241,9 @@
 github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
 github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
 github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
 github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
+github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@@ -245,8 +252,9 @@
 github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
 github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
+github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
 github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
 github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@@ -277,6 +285,7 @@
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
 github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
 github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -452,6 +461,7 @@
 github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
@@ -516,6 +526,7 @@
 github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
 go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
@@ -528,6 +539,7 @@
 go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
 go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
 go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.6.0 h1:Ezj3JGmsOnG1MoRWQkPBsKLe9DwWD9QeXzTRzzldNVk=
@@ -577,8 +589,9 @@
 golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
 golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
 golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
+golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
 golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
 golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
 golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
@@ -587,6 +600,7 @@
 golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -618,10 +632,13 @@
 golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
 golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420 h1:a8jGStKg0XqKDlKqjLrXn0ioF5MH36pT7Z0BRTqLhbk=
+golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -635,6 +652,7 @@
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -664,7 +682,6 @@
 golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -677,8 +694,12 @@
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201112073958-5cba982894dd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M=
 golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210917161153-d61c044b1678 h1:J27LZFQBFoihqXoegpscI10HpjZ7B5WQLLKL2FZXQKw=
+golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -687,8 +708,10 @@
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
 golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -740,8 +763,9 @@
 golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
-golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.1.3 h1:L69ShwSZEyCsLKoAxDKeMvLDZkumEe8gXUZAjab0tX8=
+golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -784,9 +808,11 @@
 google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
+google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
 google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a h1:pOwg4OoaRYScjmR4LlLgdtnyoHYTSAVhhqe5uPdpII8=
 google.golang.org/genproto v0.0.0-20201110150050-8816d57aaa9a/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84 h1:R1r5J0u6Cx+RNl/6mezTw6oA14cmKC96FeUwL6A9bd4=
+google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -797,8 +823,11 @@
 google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
 google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
+google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
+google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
+google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
+google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
 google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
 google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
 google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
@@ -810,6 +839,7 @@
 google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
 google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
 google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
 google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
@@ -910,5 +940,5 @@
 sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
 sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
 sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
-skywalking.apache.org/repo/goapi v0.0.0-20210820070710-e10b78bbf481 h1:K8jQuADJdwsl4+3P6g/nFjRo9ADNhal2MWUW2R4D8Xk=
-skywalking.apache.org/repo/goapi v0.0.0-20210820070710-e10b78bbf481/go.mod h1:2abOB2LaQEsJLmollzCt5kNfVMWFGKE58905uYzs+sc=
+skywalking.apache.org/repo/goapi v0.0.0-20220105035505-48cad5270f49 h1:qg8EPR0uBCuxQ0ZLhFYhX8OjtzHKyD17ZMTHRifYcY4=
+skywalking.apache.org/repo/goapi v0.0.0-20220105035505-48cad5270f49/go.mod h1:4KrWd+Oi4lkB+PtxZgIlf+3T6EECPru4fOWNMEHjxRk=
diff --git a/internal/commands/layer/layer.go b/internal/commands/layer/layer.go
new file mode 100644
index 0000000..a77371c
--- /dev/null
+++ b/internal/commands/layer/layer.go
@@ -0,0 +1,30 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package layer
+
+import (
+	"github.com/urfave/cli/v2"
+)
+
+var Command = &cli.Command{
+	Name:  "layer",
+	Usage: "Layer related sub-command",
+	Subcommands: []*cli.Command{
+		listCommand,
+	},
+}
diff --git a/internal/commands/layer/list.go b/internal/commands/layer/list.go
new file mode 100644
index 0000000..fb9d500
--- /dev/null
+++ b/internal/commands/layer/list.go
@@ -0,0 +1,46 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package layer
+
+import (
+	"github.com/apache/skywalking-cli/pkg/display"
+	"github.com/apache/skywalking-cli/pkg/display/displayable"
+	"github.com/apache/skywalking-cli/pkg/graphql/metadata"
+
+	"github.com/urfave/cli/v2"
+)
+
+var listCommand = &cli.Command{
+	Name:    "list",
+	Aliases: []string{"ls"},
+	Usage:   "List layers",
+	UsageText: `List layers
+
+Examples:
+1. List all layers:
+$ swctl layer list
+`,
+	Action: func(ctx *cli.Context) error {
+		layers, err := metadata.ListLayers(ctx)
+		if err != nil {
+			return err
+		}
+
+		return display.Display(ctx, &displayable.Displayable{Data: layers})
+	},
+}
diff --git a/internal/commands/service/layer.go b/internal/commands/service/layer.go
new file mode 100644
index 0000000..ec5ce3e
--- /dev/null
+++ b/internal/commands/service/layer.go
@@ -0,0 +1,55 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package service
+
+import (
+	"fmt"
+
+	"github.com/urfave/cli/v2"
+
+	api "skywalking.apache.org/repo/goapi/query"
+
+	"github.com/apache/skywalking-cli/pkg/display"
+	"github.com/apache/skywalking-cli/pkg/display/displayable"
+	"github.com/apache/skywalking-cli/pkg/graphql/metadata"
+)
+
+var LayerCommand = &cli.Command{
+	Name:      "layer",
+	Aliases:   []string{"ly"},
+	Usage:     `list the service list according to layer`,
+	ArgsUsage: "<layer name>",
+	UsageText: `This command lists the services matching the given "<layer name>".
+
+Examples:
+2. List services in "GENERAL" layer:
+$ swctl svc ly GENERAL`,
+	Action: func(ctx *cli.Context) error {
+		var services []api.Service
+
+		if args := ctx.Args(); args.Len() == 0 {
+			return fmt.Errorf("layer must be provide")
+		}
+		services, err := metadata.ListLayerService(ctx, ctx.Args().First())
+		if err != nil {
+			return err
+		}
+
+		return display.Display(ctx, &displayable.Displayable{Data: services})
+	},
+}
diff --git a/internal/commands/service/service.go b/internal/commands/service/service.go
index 9e85b2a..adbaf9b 100644
--- a/internal/commands/service/service.go
+++ b/internal/commands/service/service.go
@@ -27,5 +27,6 @@
 	Usage:   "Service related sub-command",
 	Subcommands: cli.Commands{
 		ListCommand,
+		LayerCommand,
 	},
 }
diff --git a/pkg/graphql/common/common.go b/pkg/graphql/common/common.go
new file mode 100644
index 0000000..4a17d19
--- /dev/null
+++ b/pkg/graphql/common/common.go
@@ -0,0 +1,37 @@
+// Licensed to Apache Software Foundation (ASF) under one or more contributor
+// license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright
+// ownership. Apache Software Foundation (ASF) licenses this file to you under
+// the Apache License, Version 2.0 (the "License"); you may
+// not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package common
+
+import (
+	"github.com/machinebox/graphql"
+
+	"github.com/urfave/cli/v2"
+
+	"github.com/apache/skywalking-cli/assets"
+	"github.com/apache/skywalking-cli/pkg/graphql/client"
+)
+
+func Version(ctx *cli.Context) (string, error) {
+	var response map[string]string
+
+	request := graphql.NewRequest(assets.Read("graphqls/common/version.graphql"))
+
+	err := client.ExecuteQuery(ctx, request, &response)
+
+	return response["result"], err
+}
diff --git a/pkg/graphql/metadata/metadata.go b/pkg/graphql/metadata/metadata.go
index 8b7e60a..af5a171 100644
--- a/pkg/graphql/metadata/metadata.go
+++ b/pkg/graphql/metadata/metadata.go
@@ -19,6 +19,10 @@
 
 import (
 	"fmt"
+	"strconv"
+	"strings"
+
+	"github.com/apache/skywalking-cli/pkg/graphql/common"
 
 	api "skywalking.apache.org/repo/goapi/query"
 
@@ -33,10 +37,14 @@
 func AllServices(cliCtx *cli.Context, duration api.Duration) ([]api.Service, error) {
 	var response map[string][]api.Service
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/AllServices.graphql"))
+	version, err := protocolVersion(cliCtx)
+	if err != nil {
+		return nil, err
+	}
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/" + version + "/AllServices.graphql"))
 	request.Var("duration", duration)
 
-	err := client.ExecuteQuery(cliCtx, request, &response)
+	err = client.ExecuteQuery(cliCtx, request, &response)
 
 	return response["result"], err
 }
@@ -44,7 +52,11 @@
 func SearchService(cliCtx *cli.Context, serviceCode string) (service api.Service, err error) {
 	var response map[string]api.Service
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/SearchService.graphql"))
+	version, err := protocolVersion(cliCtx)
+	if err != nil {
+		return api.Service{}, err
+	}
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/" + version + "/SearchService.graphql"))
 	request.Var("serviceCode", serviceCode)
 
 	err = client.ExecuteQuery(cliCtx, request, &response)
@@ -61,10 +73,14 @@
 func AllBrowserServices(cliCtx *cli.Context, duration api.Duration) ([]api.Service, error) {
 	var response map[string][]api.Service
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/AllBrowserServices.graphql"))
+	version, err := protocolVersion(cliCtx)
+	if err != nil {
+		return nil, err
+	}
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/" + version + "/AllBrowserServices.graphql"))
 	request.Var("duration", duration)
 
-	err := client.ExecuteQuery(cliCtx, request, &response)
+	err = client.ExecuteQuery(cliCtx, request, &response)
 
 	return response["result"], err
 }
@@ -72,7 +88,11 @@
 func SearchBrowserService(cliCtx *cli.Context, serviceCode string) (service api.Service, err error) {
 	var response map[string]api.Service
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/SearchBrowserService.graphql"))
+	version, err := protocolVersion(cliCtx)
+	if err != nil {
+		return api.Service{}, err
+	}
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/" + version + "/SearchBrowserService.graphql"))
 	request.Var("serviceCode", serviceCode)
 
 	err = client.ExecuteQuery(cliCtx, request, &response)
@@ -89,7 +109,7 @@
 func SearchEndpoints(cliCtx *cli.Context, serviceID, keyword string, limit int) ([]api.Endpoint, error) {
 	var response map[string][]api.Endpoint
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/SearchEndpoints.graphql"))
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/v1/SearchEndpoints.graphql"))
 	request.Var("serviceId", serviceID)
 	request.Var("keyword", keyword)
 	request.Var("limit", limit)
@@ -102,11 +122,15 @@
 func Instances(cliCtx *cli.Context, serviceID string, duration api.Duration) ([]api.ServiceInstance, error) {
 	var response map[string][]api.ServiceInstance
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/Instances.graphql"))
+	version, err := protocolVersion(cliCtx)
+	if err != nil {
+		return nil, err
+	}
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/" + version + "/Instances.graphql"))
 	request.Var("serviceId", serviceID)
 	request.Var("duration", duration)
 
-	err := client.ExecuteQuery(cliCtx, request, &response)
+	err = client.ExecuteQuery(cliCtx, request, &response)
 
 	return response["result"], err
 }
@@ -114,7 +138,7 @@
 func ServerTimeInfo(cliCtx *cli.Context) (api.TimeInfo, error) {
 	var response map[string]api.TimeInfo
 
-	request := graphql.NewRequest(assets.Read("graphqls/metadata/ServerTimeInfo.graphql"))
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/v2/ServerTimeInfo.graphql"))
 
 	if err := client.ExecuteQuery(cliCtx, request, &response); err != nil {
 		return api.TimeInfo{}, err
@@ -122,3 +146,51 @@
 
 	return response["result"], nil
 }
+
+func ListLayers(cliCtx *cli.Context) ([]string, error) {
+	var response map[string][]string
+
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/v2/ListLayers.graphql"))
+
+	if err := client.ExecuteQuery(cliCtx, request, &response); err != nil {
+		return make([]string, 0), err
+	}
+
+	return response["result"], nil
+}
+
+func ListLayerService(cliCtx *cli.Context, layer string) ([]api.Service, error) {
+	var response map[string][]api.Service
+
+	request := graphql.NewRequest(assets.Read("graphqls/metadata/v2/ListService.graphql"))
+	request.Var("layer", layer)
+
+	err := client.ExecuteQuery(cliCtx, request, &response)
+
+	return response["result"], err
+}
+
+func protocolVersion(cliCtx *cli.Context) (string, error) {
+	if majorVersion, err := backendMajorVersion(cliCtx); err != nil {
+		return "", err
+	} else if majorVersion >= 9 {
+		return "v2", nil
+	}
+	return "v1", nil
+}
+
+func backendMajorVersion(cliCtx *cli.Context) (int, error) {
+	version, err := common.Version(cliCtx)
+	if err != nil {
+		return 0, err
+	}
+	if version == "" {
+		return 0, fmt.Errorf("failed to detect OAP version")
+	}
+	majorVersion := version[:strings.Index(version, ".")]
+	atoi, err := strconv.Atoi(majorVersion)
+	if err != nil {
+		return 0, err
+	}
+	return atoi, nil
+}
diff --git a/test/docker-compose.yml b/test/base/docker-compose.yml
similarity index 93%
rename from test/docker-compose.yml
rename to test/base/docker-compose.yml
index 0db3d4b..cf06d9b 100644
--- a/test/docker-compose.yml
+++ b/test/base/docker-compose.yml
@@ -42,9 +42,6 @@
     volumes:
       - ./services/provider.py:/app.py
     entrypoint: [ "sw-python", "run", "python", "/app.py" ]
-    depends_on:
-      oap:
-        condition: service_healthy
     networks:
       - test
     healthcheck:
@@ -64,9 +61,6 @@
     volumes:
       - ./services/consumer.py:/app.py
     entrypoint: [ "sw-python", "run", "python", "/app.py" ]
-    depends_on:
-      provider:
-        condition: service_healthy
     networks:
       - test
 
diff --git a/test/services/consumer.py b/test/base/services/consumer.py
similarity index 100%
rename from test/services/consumer.py
rename to test/base/services/consumer.py
diff --git a/test/services/provider.py b/test/base/services/provider.py
similarity index 100%
rename from test/services/provider.py
rename to test/base/services/provider.py
diff --git a/test/cases/8.8.1/docker-compose.yml b/test/cases/8.8.1/docker-compose.yml
new file mode 100644
index 0000000..ebd113c
--- /dev/null
+++ b/test/cases/8.8.1/docker-compose.yml
@@ -0,0 +1,46 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: '2.1'
+
+services:
+  oap:
+    extends:
+      file: ../../base/docker-compose.yml
+      service: oap
+    image: apache/skywalking-oap-server:8.8.1
+    ports:
+      - 12800
+
+  provider:
+    extends:
+      file: ../../base/docker-compose.yml
+      service: provider
+    depends_on:
+      oap:
+        condition: service_healthy
+
+  consumer:
+    extends:
+      file: ../../base/docker-compose.yml
+      service: consumer
+    ports:
+      - 9090
+    depends_on:
+      provider:
+        condition: service_healthy
+
+networks:
+  test:
diff --git a/test/expected/dashboard-global-metrics.yml b/test/cases/8.8.1/expected/dashboard-global-metrics.yml
similarity index 100%
rename from test/expected/dashboard-global-metrics.yml
rename to test/cases/8.8.1/expected/dashboard-global-metrics.yml
diff --git a/test/expected/dashboard-global.yml b/test/cases/8.8.1/expected/dashboard-global.yml
similarity index 100%
rename from test/expected/dashboard-global.yml
rename to test/cases/8.8.1/expected/dashboard-global.yml
diff --git a/test/expected/dependency-endpoint.yml b/test/cases/8.8.1/expected/dependency-endpoint.yml
similarity index 100%
rename from test/expected/dependency-endpoint.yml
rename to test/cases/8.8.1/expected/dependency-endpoint.yml
diff --git a/test/expected/dependency-instance.yml b/test/cases/8.8.1/expected/dependency-instance.yml
similarity index 100%
rename from test/expected/dependency-instance.yml
rename to test/cases/8.8.1/expected/dependency-instance.yml
diff --git a/test/expected/dependency-service.yml b/test/cases/8.8.1/expected/dependency-service.yml
similarity index 100%
rename from test/expected/dependency-service.yml
rename to test/cases/8.8.1/expected/dependency-service.yml
diff --git a/test/expected/empty-array.yml b/test/cases/8.8.1/expected/empty-array.yml
similarity index 100%
rename from test/expected/empty-array.yml
rename to test/cases/8.8.1/expected/empty-array.yml
diff --git a/test/expected/endpoint-list.yml b/test/cases/8.8.1/expected/endpoint-list.yml
similarity index 100%
rename from test/expected/endpoint-list.yml
rename to test/cases/8.8.1/expected/endpoint-list.yml
diff --git a/test/expected/instance-list.yml b/test/cases/8.8.1/expected/instance-list.yml
similarity index 98%
rename from test/expected/instance-list.yml
rename to test/cases/8.8.1/expected/instance-list.yml
index 310b83b..dc11872 100644
--- a/test/expected/instance-list.yml
+++ b/test/cases/8.8.1/expected/instance-list.yml
@@ -23,4 +23,5 @@
     {{- end }}
   language: {{ .language }}
   instanceuuid: {{ b64enc "provider" }}.1_{{ b64enc "provider1" }}
+  layer: ""
   {{- end }}
diff --git a/test/expected/metrics-has-value.yml b/test/cases/8.8.1/expected/metrics-has-value.yml
similarity index 100%
rename from test/expected/metrics-has-value.yml
rename to test/cases/8.8.1/expected/metrics-has-value.yml
diff --git a/test/expected/metrics-top-endpoint-sla-provider.yml b/test/cases/8.8.1/expected/metrics-top-endpoint-sla-provider.yml
similarity index 100%
rename from test/expected/metrics-top-endpoint-sla-provider.yml
rename to test/cases/8.8.1/expected/metrics-top-endpoint-sla-provider.yml
diff --git a/test/expected/metrics-top-service-sla.yml b/test/cases/8.8.1/expected/metrics-top-service-sla.yml
similarity index 100%
rename from test/expected/metrics-top-service-sla.yml
rename to test/cases/8.8.1/expected/metrics-top-service-sla.yml
diff --git a/test/expected/service-endpoint.yml b/test/cases/8.8.1/expected/service-endpoint.yml
similarity index 100%
rename from test/expected/service-endpoint.yml
rename to test/cases/8.8.1/expected/service-endpoint.yml
diff --git a/test/expected/service-provider.yml b/test/cases/8.8.1/expected/service-provider.yml
similarity index 96%
rename from test/expected/service-provider.yml
rename to test/cases/8.8.1/expected/service-provider.yml
index 0a4d631..7b5669a 100644
--- a/test/expected/service-provider.yml
+++ b/test/cases/8.8.1/expected/service-provider.yml
@@ -16,3 +16,5 @@
 - id: {{ b64enc "provider" }}.1
   name: provider
   group: ""
+  shortname: ""
+  layers: []
diff --git a/test/expected/service.yml b/test/cases/8.8.1/expected/service.yml
similarity index 93%
rename from test/expected/service.yml
rename to test/cases/8.8.1/expected/service.yml
index 598cedd..29e52a1 100644
--- a/test/expected/service.yml
+++ b/test/cases/8.8.1/expected/service.yml
@@ -17,7 +17,11 @@
 - id: {{ b64enc "provider" }}.1
   name: provider
   group: ""
+  shortname: ""
+  layers: []
 - id: {{ b64enc "consumer" }}.1
   name: consumer
   group: ""
+  shortname: ""
+  layers: []
   {{- end }}
diff --git a/test/expected/trace-users-detail.yml b/test/cases/8.8.1/expected/trace-users-detail.yml
similarity index 100%
rename from test/expected/trace-users-detail.yml
rename to test/cases/8.8.1/expected/trace-users-detail.yml
diff --git a/test/expected/traces-list.yml b/test/cases/8.8.1/expected/traces-list.yml
similarity index 100%
rename from test/expected/traces-list.yml
rename to test/cases/8.8.1/expected/traces-list.yml
diff --git a/test/expected/value.yml b/test/cases/8.8.1/expected/value.yml
similarity index 100%
rename from test/expected/value.yml
rename to test/cases/8.8.1/expected/value.yml
diff --git a/test/cases/8.8.1/test.yaml b/test/cases/8.8.1/test.yaml
new file mode 100644
index 0000000..4cfc28c
--- /dev/null
+++ b/test/cases/8.8.1/test.yaml
@@ -0,0 +1,99 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is used to show how to write configuration files and can be used to test.
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 1200
+  steps:
+    - name: install yq
+      command: yq > /dev/null 2>&1 || go install github.com/mikefarah/yq/v4@latest
+    - name: install swctl
+      command: make install DESTDIR=/usr/local/bin > /dev/null 2>&1
+
+trigger:
+  action: http
+  interval: 3s
+  times: 10
+  url: http://${consumer_host}:${consumer_9090}/users
+  method: POST
+
+verify:
+  retry:
+    count: 200
+    interval: 5s
+  cases:
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dashboard global
+      expected: expected/dashboard-global.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dashboard global-metrics
+      expected: expected/dashboard-global-metrics.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency endpoint --service-name provider --endpoint-name /users
+      expected: expected/dependency-endpoint.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency instance --service-name consumer --dest-service-name provider
+      expected: expected/dependency-instance.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency service --service-name consumer
+      expected: expected/dependency-service.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql endpoint ls --service-name provider
+      expected: expected/endpoint-list.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance ls --service-name provider
+      expected: expected/instance-list.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance search --service-name provider --regex ".*vid.*"
+      expected: expected/instance-list.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance search --service-name provider --regex not-exist
+      expected: expected/empty-array.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics top --name service_sla 5
+      expected: expected/metrics-top-service-sla.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics top --name endpoint_sla --service-name provider 5
+      expected: expected/metrics-top-endpoint-sla-provider.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_instance_resp_time --service-name provider --instance-name provider1 | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_resp_time --service-name provider | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=endpoint_sla --service-name provider --endpoint-name /users | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_relation_client_cpm --service-name consumer --dest-service-name provider | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_instance_relation_client_cpm --service-name consumer --instance-name consumer1 --dest-service-name provider --dest-instance-name provider1 | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name endpoint_cpm --service-name provider --endpoint-name /users
+      expected: expected/value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name service_cpm --service-name provider
+      expected: expected/value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name endpoint_cpm --service-name provider --endpoint-name /users
+      expected: expected/value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name service_instance_cpm --service-name provider --instance-name provider1
+      expected: expected/value.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service list
+      expected: expected/service.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service list provider
+      expected: expected/service-provider.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls
+      expected: expected/traces-list.yml
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace $( \
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls \
+            | yq e '.traces | select(.[].endpointnames[0]=="/users") | .[0].traceids[0]' -
+        )
+      expected: expected/trace-users-detail.yml
diff --git a/test/cases/9.0.0/docker-compose.yml b/test/cases/9.0.0/docker-compose.yml
new file mode 100644
index 0000000..d334b97
--- /dev/null
+++ b/test/cases/9.0.0/docker-compose.yml
@@ -0,0 +1,51 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+version: '2.1'
+
+services:
+  oap:
+    extends:
+      file: ../../base/docker-compose.yml
+      service: oap
+    image: ghcr.io/apache/skywalking/oap:e97b2d2165703c9d5bcdb0556134aa7cbd1382f5
+    ports:
+      - 12800
+    healthcheck:
+      test: [ "CMD", "bash", "-c", "cat < /dev/null > /dev/tcp/127.0.0.1/12800" ]
+      interval: 5s
+      timeout: 60s
+      retries: 120
+
+  provider:
+    extends:
+      file: ../../base/docker-compose.yml
+      service: provider
+    depends_on:
+      oap:
+        condition: service_healthy
+
+  consumer:
+    extends:
+      file: ../../base/docker-compose.yml
+      service: consumer
+    ports:
+      - 9090
+    depends_on:
+      provider:
+        condition: service_healthy
+
+networks:
+  test:
diff --git a/test/expected/dashboard-global-metrics.yml b/test/cases/9.0.0/expected/dashboard-global-metrics.yml
similarity index 100%
copy from test/expected/dashboard-global-metrics.yml
copy to test/cases/9.0.0/expected/dashboard-global-metrics.yml
diff --git a/test/expected/dashboard-global.yml b/test/cases/9.0.0/expected/dashboard-global.yml
similarity index 100%
copy from test/expected/dashboard-global.yml
copy to test/cases/9.0.0/expected/dashboard-global.yml
diff --git a/test/expected/dependency-endpoint.yml b/test/cases/9.0.0/expected/dependency-endpoint.yml
similarity index 100%
copy from test/expected/dependency-endpoint.yml
copy to test/cases/9.0.0/expected/dependency-endpoint.yml
diff --git a/test/expected/dependency-instance.yml b/test/cases/9.0.0/expected/dependency-instance.yml
similarity index 100%
copy from test/expected/dependency-instance.yml
copy to test/cases/9.0.0/expected/dependency-instance.yml
diff --git a/test/expected/dependency-service.yml b/test/cases/9.0.0/expected/dependency-service.yml
similarity index 100%
copy from test/expected/dependency-service.yml
copy to test/cases/9.0.0/expected/dependency-service.yml
diff --git a/test/expected/empty-array.yml b/test/cases/9.0.0/expected/empty-array.yml
similarity index 100%
copy from test/expected/empty-array.yml
copy to test/cases/9.0.0/expected/empty-array.yml
diff --git a/test/expected/endpoint-list.yml b/test/cases/9.0.0/expected/endpoint-list.yml
similarity index 100%
copy from test/expected/endpoint-list.yml
copy to test/cases/9.0.0/expected/endpoint-list.yml
diff --git a/test/expected/instance-list.yml b/test/cases/9.0.0/expected/instance-list.yml
similarity index 98%
copy from test/expected/instance-list.yml
copy to test/cases/9.0.0/expected/instance-list.yml
index 310b83b..870f57b 100644
--- a/test/expected/instance-list.yml
+++ b/test/cases/9.0.0/expected/instance-list.yml
@@ -23,4 +23,5 @@
     {{- end }}
   language: {{ .language }}
   instanceuuid: {{ b64enc "provider" }}.1_{{ b64enc "provider1" }}
+  layer: GENERAL
   {{- end }}
diff --git a/test/expected/service-provider.yml b/test/cases/9.0.0/expected/layer-list.yml
similarity index 92%
copy from test/expected/service-provider.yml
copy to test/cases/9.0.0/expected/layer-list.yml
index 0a4d631..9ab52ca 100644
--- a/test/expected/service-provider.yml
+++ b/test/cases/9.0.0/expected/layer-list.yml
@@ -13,6 +13,4 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-- id: {{ b64enc "provider" }}.1
-  name: provider
-  group: ""
+- GENERAL
diff --git a/test/expected/metrics-has-value.yml b/test/cases/9.0.0/expected/metrics-has-value.yml
similarity index 100%
copy from test/expected/metrics-has-value.yml
copy to test/cases/9.0.0/expected/metrics-has-value.yml
diff --git a/test/expected/metrics-top-endpoint-sla-provider.yml b/test/cases/9.0.0/expected/metrics-top-endpoint-sla-provider.yml
similarity index 100%
copy from test/expected/metrics-top-endpoint-sla-provider.yml
copy to test/cases/9.0.0/expected/metrics-top-endpoint-sla-provider.yml
diff --git a/test/expected/metrics-top-service-sla.yml b/test/cases/9.0.0/expected/metrics-top-service-sla.yml
similarity index 100%
copy from test/expected/metrics-top-service-sla.yml
copy to test/cases/9.0.0/expected/metrics-top-service-sla.yml
diff --git a/test/expected/service-endpoint.yml b/test/cases/9.0.0/expected/service-endpoint.yml
similarity index 100%
copy from test/expected/service-endpoint.yml
copy to test/cases/9.0.0/expected/service-endpoint.yml
diff --git a/test/expected/service-provider.yml b/test/cases/9.0.0/expected/service-provider.yml
similarity index 94%
copy from test/expected/service-provider.yml
copy to test/cases/9.0.0/expected/service-provider.yml
index 0a4d631..e81ad75 100644
--- a/test/expected/service-provider.yml
+++ b/test/cases/9.0.0/expected/service-provider.yml
@@ -16,3 +16,6 @@
 - id: {{ b64enc "provider" }}.1
   name: provider
   group: ""
+  shortname: provider
+  layers:
+    - GENERAL
diff --git a/test/expected/service.yml b/test/cases/9.0.0/expected/service.yml
similarity index 90%
copy from test/expected/service.yml
copy to test/cases/9.0.0/expected/service.yml
index 598cedd..b1b7cbf 100644
--- a/test/expected/service.yml
+++ b/test/cases/9.0.0/expected/service.yml
@@ -17,7 +17,13 @@
 - id: {{ b64enc "provider" }}.1
   name: provider
   group: ""
+  shortname: provider
+  layers:
+    - GENERAL
 - id: {{ b64enc "consumer" }}.1
   name: consumer
   group: ""
+  shortname: consumer
+  layers:
+    - GENERAL
   {{- end }}
diff --git a/test/expected/trace-users-detail.yml b/test/cases/9.0.0/expected/trace-users-detail.yml
similarity index 100%
copy from test/expected/trace-users-detail.yml
copy to test/cases/9.0.0/expected/trace-users-detail.yml
diff --git a/test/expected/traces-list.yml b/test/cases/9.0.0/expected/traces-list.yml
similarity index 100%
copy from test/expected/traces-list.yml
copy to test/cases/9.0.0/expected/traces-list.yml
diff --git a/test/expected/value.yml b/test/cases/9.0.0/expected/value.yml
similarity index 100%
copy from test/expected/value.yml
copy to test/cases/9.0.0/expected/value.yml
diff --git a/test/cases/9.0.0/test.yaml b/test/cases/9.0.0/test.yaml
new file mode 100644
index 0000000..b40d07f
--- /dev/null
+++ b/test/cases/9.0.0/test.yaml
@@ -0,0 +1,104 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This file is used to show how to write configuration files and can be used to test.
+
+setup:
+  env: compose
+  file: docker-compose.yml
+  timeout: 1200
+  steps:
+    - name: install yq
+      command: yq > /dev/null 2>&1 || go install github.com/mikefarah/yq/v4@latest
+    - name: install swctl
+      command: make install DESTDIR=/usr/local/bin > /dev/null 2>&1
+
+trigger:
+  action: http
+  interval: 3s
+  times: 10
+  url: http://${consumer_host}:${consumer_9090}/users
+  method: POST
+
+verify:
+  retry:
+    count: 200
+    interval: 5s
+  cases:
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dashboard global
+      expected: expected/dashboard-global.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dashboard global-metrics
+      expected: expected/dashboard-global-metrics.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency endpoint --service-name provider --endpoint-name /users
+      expected: expected/dependency-endpoint.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency instance --service-name consumer --dest-service-name provider
+      expected: expected/dependency-instance.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql dependency service --service-name consumer
+      expected: expected/dependency-service.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql endpoint ls --service-name provider
+      expected: expected/endpoint-list.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance ls --service-name provider
+      expected: expected/instance-list.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance search --service-name provider --regex ".*vid.*"
+      expected: expected/instance-list.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql instance search --service-name provider --regex not-exist
+      expected: expected/empty-array.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics top --name service_sla 5
+      expected: expected/metrics-top-service-sla.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics top --name endpoint_sla --service-name provider 5
+      expected: expected/metrics-top-endpoint-sla-provider.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_instance_resp_time --service-name provider --instance-name provider1 | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_resp_time --service-name provider | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=endpoint_sla --service-name provider --endpoint-name /users | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_relation_client_cpm --service-name consumer --dest-service-name provider | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_instance_relation_client_cpm --service-name consumer --instance-name consumer1 --dest-service-name provider --dest-instance-name provider1 | yq e 'to_entries' -
+      expected: expected/metrics-has-value.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name endpoint_cpm --service-name provider --endpoint-name /users
+      expected: expected/value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name service_cpm --service-name provider
+      expected: expected/value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name endpoint_cpm --service-name provider --endpoint-name /users
+      expected: expected/value.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics single --name service_instance_cpm --service-name provider --instance-name provider1
+      expected: expected/value.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql layer list
+      expected: expected/layer-list.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service list
+      expected: expected/service.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service list provider
+      expected: expected/service-provider.yml
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql service layer GENERAL
+      expected: expected/service.yml
+
+    - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls
+      expected: expected/traces-list.yml
+    - query: |
+        swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace $( \
+          swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql trace ls \
+            | yq e '.traces | select(.[].endpointnames[0]=="/users") | .[0].traceids[0]' -
+        )
+      expected: expected/trace-users-detail.yml