Skip to content

Commit

Permalink
Merge pull request #144 from replicatedhq/dx/sc-103251/add-configmaps
Browse files Browse the repository at this point in the history
feat(sbctl): add support get configmaps -o yaml
  • Loading branch information
DexterYan authored Apr 22, 2024
2 parents d7b2d5a + da8ef53 commit e12a6c1
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 0 deletions.
26 changes: 26 additions & 0 deletions pkg/api/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,15 @@ func (h handler) getAPIV1ClusterResources(w http.ResponseWriter, r *http.Request
w.WriteHeader(http.StatusInternalServerError)
return
}
case "configmaps":
result = k8s.GetEmptyConfigMapList()
dirName := filepath.Join(h.clusterData.ClusterResourcesDir, sbctlutil.GetSBCompatibleResourceName(resource))
filenames, err = getJSONFileListFromDir(dirName)
if err != nil {
log.Error("failed to get configmap files from dir: ", err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}

for _, fileName := range filenames {
Expand Down Expand Up @@ -359,6 +368,9 @@ func (h handler) getAPIV1ClusterResources(w http.ResponseWriter, r *http.Request
case *corev1.PersistentVolumeClaimList:
r := result.(*corev1.PersistentVolumeClaimList)
r.Items = append(r.Items, o.Items...)
case *corev1.ConfigMapList:
r := result.(*corev1.ConfigMapList)
r.Items = append(r.Items, o.Items...)
default:
result, err = sbctl.ToUnstructuredList(decoded)
if err != nil {
Expand Down Expand Up @@ -580,6 +592,13 @@ func (h handler) getAPIV1NamespaceResource(w http.ResponseWriter, r *http.Reques
return
}
}
case *corev1.ConfigMapList:
for _, item := range o.Items {
if item.Name == name {
JSON(w, http.StatusOK, item)
return
}
}
default:
uObjList, err := sbctl.ToUnstructuredList(decoded)
if err != nil {
Expand Down Expand Up @@ -1601,6 +1620,13 @@ func toTable(object runtime.Object, r *http.Request) (runtime.Object, error) {
return nil, errors.Wrap(err, "failed to convert ingress list")
}
object = converted
case *corev1.ConfigMapList:
converted := &apicore.ConfigMapList{}
err := apicorev1.Convert_v1_ConfigMapList_To_core_ConfigMapList(o, converted, nil)
if err != nil {
return nil, errors.Wrap(err, "failed to convert configmap list")
}
object = converted
}

ctx := context.TODO()
Expand Down
11 changes: 11 additions & 0 deletions pkg/k8s/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,14 @@ func GetEmptyPersistentVolumeClaimList() *corev1.PersistentVolumeClaimList {
})
return r
}

func GetEmptyConfigMapList() *corev1.ConfigMapList {
r := &corev1.ConfigMapList{
Items: []corev1.ConfigMap{},
}
r.GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Version: "v1",
Kind: "ConfigMapList",
})
return r
}
7 changes: 7 additions & 0 deletions pkg/sbctl/compatibility.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ func Decode(resource string, data []byte) (runtime.Object, *schema.GroupVersionK
Version: "v1",
})
}
case *corev1.ConfigMapList:
for i := range o.Items {
o.Items[i].GetObjectKind().SetGroupVersionKind(schema.GroupVersionKind{
Kind: "ConfigMap",
Version: "v1",
})
}
}

return decoded, gvk, nil
Expand Down
38 changes: 38 additions & 0 deletions tests/configmaps_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package tests

import (
_ "embed"
"fmt"
"net/http"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

//go:embed results/configmaps_all_namespaces.json
var expectedGetAllConfigmapsResult string

//go:embed results/configmaps_kube_public_namespace.json
var expectedGetKubePublicConfigmapsResult string

var _ = Describe("GET /api/v1/configmaps", func() {
Context("When getting configmaps in all namespaces", func() {
It("Returns all configmaps", func() {
resp, statusCode, err := HTTPExec("GET", fmt.Sprintf("%s/api/v1/configmaps", apiServerEndpoint), getHeaders)
Expect(err).NotTo(HaveOccurred())
Expect(statusCode).To(Equal(http.StatusOK))
Expect(resp).To(Similar(expectedGetAllConfigmapsResult))
})
})
})

var _ = Describe("GET /api/v1/namespaces/{namespace}/configmaps", func() {
Context("When getting configmaps in kube-public namespace", func() {
It("Returns kube-public configmaps", func() {
resp, statusCode, err := HTTPExec("GET", fmt.Sprintf("%s/api/v1/namespaces/kube-public/configmaps", apiServerEndpoint), getHeaders)
Expect(err).NotTo(HaveOccurred())
Expect(statusCode).To(Equal(http.StatusOK))
Expect(resp).To(Similar(expectedGetKubePublicConfigmapsResult))
})
})
})
1 change: 1 addition & 0 deletions tests/results/configmaps_all_namespaces.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"kind":"Table","apiVersion":"meta.k8s.io/v1","metadata":{},"columnDefinitions":[{"name":"Name","type":"string","format":"name","description":"Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names","priority":0},{"name":"Data","type":"string","format":"","description":"Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.","priority":0},{"name":"Age","type":"string","format":"","description":"CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata","priority":0}],"rows":[{"cells":["kotsadm-application-metadata",2,"64d"],"object":{"kind":"PartialObjectMetadata","apiVersion":"meta.k8s.io/v1","metadata":{"name":"kotsadm-application-metadata","namespace":"default","uid":"eb16ac64-ffce-4963-83e9-de63850b736e","resourceVersion":"5021","creationTimestamp":"2024-02-17T06:16:47Z","labels":{"kots.io/backup":"velero","kots.io/kotsadm":"true","kotsadm":"application"},"managedFields":[{"manager":"kubectl-kots","operation":"Update","apiVersion":"v1","time":"2024-02-17T06:16:47Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:application.yaml":{},"f:upstreamUri":{}},"f:metadata":{"f:labels":{".":{},"f:kots.io/backup":{},"f:kots.io/kotsadm":{},"f:kotsadm":{}}}}}]}}},{"cells":["kube-root-ca.crt",1,"64d"],"object":{"kind":"PartialObjectMetadata","apiVersion":"meta.k8s.io/v1","metadata":{"name":"kube-root-ca.crt","namespace":"default","uid":"f3f8cc0f-8434-465b-87a8-d58a44fdb575","resourceVersion":"331","creationTimestamp":"2024-02-17T05:55:36Z","annotations":{"kubernetes.io/description":"Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."},"managedFields":[{"manager":"kube-controller-manager","operation":"Update","apiVersion":"v1","time":"2024-02-17T05:55:36Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:ca.crt":{}},"f:metadata":{"f:annotations":{".":{},"f:kubernetes.io/description":{}}}}}]}}},{"cells":["kube-root-ca.crt",1,"64d"],"object":{"kind":"PartialObjectMetadata","apiVersion":"meta.k8s.io/v1","metadata":{"name":"kube-root-ca.crt","namespace":"kube-node-lease","uid":"01acb543-79cc-4e17-a3de-e846b80a20f9","resourceVersion":"332","creationTimestamp":"2024-02-17T05:55:36Z","annotations":{"kubernetes.io/description":"Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."},"managedFields":[{"manager":"kube-controller-manager","operation":"Update","apiVersion":"v1","time":"2024-02-17T05:55:36Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:ca.crt":{}},"f:metadata":{"f:annotations":{".":{},"f:kubernetes.io/description":{}}}}}]}}},{"cells":["kube-root-ca.crt",1,"64d"],"object":{"kind":"PartialObjectMetadata","apiVersion":"meta.k8s.io/v1","metadata":{"name":"kube-root-ca.crt","namespace":"kube-public","uid":"c42025cc-2d96-4626-805a-b7fc0575f24c","resourceVersion":"333","creationTimestamp":"2024-02-17T05:55:36Z","annotations":{"kubernetes.io/description":"Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."},"managedFields":[{"manager":"kube-controller-manager","operation":"Update","apiVersion":"v1","time":"2024-02-17T05:55:36Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:ca.crt":{}},"f:metadata":{"f:annotations":{".":{},"f:kubernetes.io/description":{}}}}}]}}}]}
1 change: 1 addition & 0 deletions tests/results/configmaps_kube_public_namespace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"kind":"Table","apiVersion":"meta.k8s.io/v1","metadata":{"resourceVersion":"32367474"},"columnDefinitions":[{"name":"Name","type":"string","format":"name","description":"Name must be unique within a namespace. Is required when creating resources, although some resources may allow a client to request the generation of an appropriate name automatically. Name is primarily intended for creation idempotence and configuration definition. Cannot be updated. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names#names","priority":0},{"name":"Data","type":"string","format":"","description":"Data contains the configuration data. Each key must consist of alphanumeric characters, '-', '_' or '.'. Values with non-UTF-8 byte sequences must use the BinaryData field. The keys stored in Data must not overlap with the keys in the BinaryData field, this is enforced during validation process.","priority":0},{"name":"Age","type":"string","format":"","description":"CreationTimestamp is a timestamp representing the server time when this object was created. It is not guaranteed to be set in happens-before order across separate operations. Clients may not set this value. It is represented in RFC3339 form and is in UTC.\n\nPopulated by the system. Read-only. Null for lists. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata","priority":0}],"rows":[{"cells":["kube-root-ca.crt",1,"64d"],"object":{"kind":"PartialObjectMetadata","apiVersion":"meta.k8s.io/v1","metadata":{"name":"kube-root-ca.crt","namespace":"kube-public","uid":"c42025cc-2d96-4626-805a-b7fc0575f24c","resourceVersion":"333","creationTimestamp":"2024-02-17T05:55:36Z","annotations":{"kubernetes.io/description":"Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."},"managedFields":[{"manager":"kube-controller-manager","operation":"Update","apiVersion":"v1","time":"2024-02-17T05:55:36Z","fieldsType":"FieldsV1","fieldsV1":{"f:data":{".":{},"f:ca.crt":{}},"f:metadata":{"f:annotations":{".":{},"f:kubernetes.io/description":{}}}}}]}}}]}
92 changes: 92 additions & 0 deletions tests/support-bundle/cluster-resources/configmaps/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
{
"kind": "ConfigMapList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "32367468"
},
"items": [
{
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"name": "kotsadm-application-metadata",
"namespace": "default",
"uid": "eb16ac64-ffce-4963-83e9-de63850b736e",
"resourceVersion": "5021",
"creationTimestamp": "2024-02-17T06:16:47Z",
"labels": {
"kots.io/backup": "velero",
"kots.io/kotsadm": "true",
"kotsadm": "application"
},
"managedFields": [
{
"manager": "kubectl-kots",
"operation": "Update",
"apiVersion": "v1",
"time": "2024-02-17T06:16:47Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:data": {
".": {},
"f:application.yaml": {},
"f:upstreamUri": {}
},
"f:metadata": {
"f:labels": {
".": {},
"f:kots.io/backup": {},
"f:kots.io/kotsadm": {},
"f:kotsadm": {}
}
}
}
}
]
},
"data": {
"application.yaml": "apiVersion: kots.io/v1beta1\nkind: Application\nmetadata:\n annotations:\n kots.io/exclude: \"true\"\n creationTimestamp: null\n name: Stoplight\nspec:\n icon: https://stoplight.io/images/mark_light_bg.png\n releaseNotes: See https://stoplight.io/blog/ for release updates.\n requireMinimalRBACPrivileges: true\n statusInformers:\n - deployment/platform-worker\n title: Stoplight\nstatus: {}\n",
"upstreamUri": "replicated://replicatehq/stable"
}
},
{
"kind": "ConfigMap",
"Kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"name": "kube-root-ca.crt",
"namespace": "default",
"uid": "f3f8cc0f-8434-465b-87a8-d58a44fdb575",
"resourceVersion": "331",
"creationTimestamp": "2024-02-17T05:55:36Z",
"annotations": {
"kubernetes.io/description": "Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."
},
"managedFields": [
{
"manager": "kube-controller-manager",
"operation": "Update",
"apiVersion": "v1",
"time": "2024-02-17T05:55:36Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:data": {
".": {},
"f:ca.crt": {}
},
"f:metadata": {
"f:annotations": {
".": {},
"f:kubernetes.io/description": {}
}
}
}
}
]
},
"data": {
"ca.crt": "-----BEGIN CERTIFICATE-----\nMIIDBTCCAe2gAwIBAgIIaDHtQlkhzfMwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE\nAxMKa3ViZXJuZXRlczAeFw0yNDAyMTcwNTQ5NTdaFw0zNDAyMTQwNTU0NTdaMBUx\nEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQDH/Q7uWgAMLl/KKv4jL9N+eRdcvU00S08IWF81aAW9vCKkrn9fUhdjznP0\njHXhTnRIyOjkLsRif60pFM9eziHPHMLMlwqvPzVq4RPtOJCLGvWsdm18DTzBIM0v\ncvj3ZhCHqwNoHpEcmeLcIPZhXUTP9P/HymHN7McPWlCubkUK0Rd3ZJcZTwlzNiSV\nLVm34/28sY0zQZslDKIz3prUQ9r4LtEX4Vj56Zj4H+DH+82JpIh3CQ2BCiLzUzrg\n5c1L4uQ6FKj9FH/Hgyz2ttVcCU38ObgX1ASaBXZtsHZPY07S7GLi6czrdcxdSEvb\nZDeCuG5c/4M0dP6Skz07sr3tF26tAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP\nBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSzYh2i904R82VVx7d3syCW0ZkS7DAV\nBgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQC+T2TvKB/V\ncPQ5QIeSNEolAe/B5MoSCao+WZTpo9P46Xq5kU9pGUVRFPi1/fVdHSgd1ZuRUPxl\n83GVy4Wsf2squXW8IrYFMeX2jZKVEGh6roAb4wUexTpouSyv+5Mln5Ov/dt8oV1a\nMUeRfWUiDlwunEX9Luly6BITE9uB5m3VR4GxlnuFL4f92rurXXNVoGMBwJohaYSj\nwYoZ+HvG2rl8aB7pnjiypAcZUpBtB9xkY4wtTOZ1lrR5jXjAYwDh4N1TvSRsSk60\nLUpoWZ+nAq3qvKoe1/511lKNWYvHW6cx//Bn3MZKfILInBLA0VK0OJJ0x+Kh6TFl\nV77zhWyQ9IXN\n-----END CERTIFICATE-----\n"
}
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"kind": "ConfigMapList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "32367473"
},
"items": [
{
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"name": "kube-root-ca.crt",
"namespace": "kube-node-lease",
"uid": "01acb543-79cc-4e17-a3de-e846b80a20f9",
"resourceVersion": "332",
"creationTimestamp": "2024-02-17T05:55:36Z",
"annotations": {
"kubernetes.io/description": "Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."
},
"managedFields": [
{
"manager": "kube-controller-manager",
"operation": "Update",
"apiVersion": "v1",
"time": "2024-02-17T05:55:36Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:data": {
".": {},
"f:ca.crt": {}
},
"f:metadata": {
"f:annotations": {
".": {},
"f:kubernetes.io/description": {}
}
}
}
}
]
},
"data": {
"ca.crt": "-----BEGIN CERTIFICATE-----\nMIIDBTCCAe2gAwIBAgIIaDHtQlkhzfMwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE\nAxMKa3ViZXJuZXRlczAeFw0yNDAyMTcwNTQ5NTdaFw0zNDAyMTQwNTU0NTdaMBUx\nEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQDH/Q7uWgAMLl/KKv4jL9N+eRdcvU00S08IWF81aAW9vCKkrn9fUhdjznP0\njHXhTnRIyOjkLsRif60pFM9eziHPHMLMlwqvPzVq4RPtOJCLGvWsdm18DTzBIM0v\ncvj3ZhCHqwNoHpEcmeLcIPZhXUTP9P/HymHN7McPWlCubkUK0Rd3ZJcZTwlzNiSV\nLVm34/28sY0zQZslDKIz3prUQ9r4LtEX4Vj56Zj4H+DH+82JpIh3CQ2BCiLzUzrg\n5c1L4uQ6FKj9FH/Hgyz2ttVcCU38ObgX1ASaBXZtsHZPY07S7GLi6czrdcxdSEvb\nZDeCuG5c/4M0dP6Skz07sr3tF26tAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP\nBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSzYh2i904R82VVx7d3syCW0ZkS7DAV\nBgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQC+T2TvKB/V\ncPQ5QIeSNEolAe/B5MoSCao+WZTpo9P46Xq5kU9pGUVRFPi1/fVdHSgd1ZuRUPxl\n83GVy4Wsf2squXW8IrYFMeX2jZKVEGh6roAb4wUexTpouSyv+5Mln5Ov/dt8oV1a\nMUeRfWUiDlwunEX9Luly6BITE9uB5m3VR4GxlnuFL4f92rurXXNVoGMBwJohaYSj\nwYoZ+HvG2rl8aB7pnjiypAcZUpBtB9xkY4wtTOZ1lrR5jXjAYwDh4N1TvSRsSk60\nLUpoWZ+nAq3qvKoe1/511lKNWYvHW6cx//Bn3MZKfILInBLA0VK0OJJ0x+Kh6TFl\nV77zhWyQ9IXN\n-----END CERTIFICATE-----\n"
}
}
]
}
47 changes: 47 additions & 0 deletions tests/support-bundle/cluster-resources/configmaps/kube-public.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"kind": "ConfigMapList",
"apiVersion": "v1",
"metadata": {
"resourceVersion": "32367474"
},
"items": [
{
"kind": "ConfigMap",
"apiVersion": "v1",
"metadata": {
"name": "kube-root-ca.crt",
"namespace": "kube-public",
"uid": "c42025cc-2d96-4626-805a-b7fc0575f24c",
"resourceVersion": "333",
"creationTimestamp": "2024-02-17T05:55:36Z",
"annotations": {
"kubernetes.io/description": "Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."
},
"managedFields": [
{
"manager": "kube-controller-manager",
"operation": "Update",
"apiVersion": "v1",
"time": "2024-02-17T05:55:36Z",
"fieldsType": "FieldsV1",
"fieldsV1": {
"f:data": {
".": {},
"f:ca.crt": {}
},
"f:metadata": {
"f:annotations": {
".": {},
"f:kubernetes.io/description": {}
}
}
}
}
]
},
"data": {
"ca.crt": "-----BEGIN CERTIFICATE-----\nMIIDBTCCAe2gAwIBAgIIaDHtQlkhzfMwDQYJKoZIhvcNAQELBQAwFTETMBEGA1UE\nAxMKa3ViZXJuZXRlczAeFw0yNDAyMTcwNTQ5NTdaFw0zNDAyMTQwNTU0NTdaMBUx\nEzARBgNVBAMTCmt1YmVybmV0ZXMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK\nAoIBAQDH/Q7uWgAMLl/KKv4jL9N+eRdcvU00S08IWF81aAW9vCKkrn9fUhdjznP0\njHXhTnRIyOjkLsRif60pFM9eziHPHMLMlwqvPzVq4RPtOJCLGvWsdm18DTzBIM0v\ncvj3ZhCHqwNoHpEcmeLcIPZhXUTP9P/HymHN7McPWlCubkUK0Rd3ZJcZTwlzNiSV\nLVm34/28sY0zQZslDKIz3prUQ9r4LtEX4Vj56Zj4H+DH+82JpIh3CQ2BCiLzUzrg\n5c1L4uQ6FKj9FH/Hgyz2ttVcCU38ObgX1ASaBXZtsHZPY07S7GLi6czrdcxdSEvb\nZDeCuG5c/4M0dP6Skz07sr3tF26tAgMBAAGjWTBXMA4GA1UdDwEB/wQEAwICpDAP\nBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSzYh2i904R82VVx7d3syCW0ZkS7DAV\nBgNVHREEDjAMggprdWJlcm5ldGVzMA0GCSqGSIb3DQEBCwUAA4IBAQC+T2TvKB/V\ncPQ5QIeSNEolAe/B5MoSCao+WZTpo9P46Xq5kU9pGUVRFPi1/fVdHSgd1ZuRUPxl\n83GVy4Wsf2squXW8IrYFMeX2jZKVEGh6roAb4wUexTpouSyv+5Mln5Ov/dt8oV1a\nMUeRfWUiDlwunEX9Luly6BITE9uB5m3VR4GxlnuFL4f92rurXXNVoGMBwJohaYSj\nwYoZ+HvG2rl8aB7pnjiypAcZUpBtB9xkY4wtTOZ1lrR5jXjAYwDh4N1TvSRsSk60\nLUpoWZ+nAq3qvKoe1/511lKNWYvHW6cx//Bn3MZKfILInBLA0VK0OJJ0x+Kh6TFl\nV77zhWyQ9IXN\n-----END CERTIFICATE-----\n"
}
}
]
}

0 comments on commit e12a6c1

Please sign in to comment.