mirror of https://github.com/status-im/consul.git
Add CLI support for json (#18991)
* add cli support for json format * add tests for json parsing * make owner and id pointers. * add copyright header * remove print --------- Co-authored-by: Poonam Jadhav <poonam.jadhav@hashicorp.com>
This commit is contained in:
parent
11d6b0df45
commit
d3bb5ff21a
|
@ -4,9 +4,12 @@
|
||||||
package resource
|
package resource
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"google.golang.org/protobuf/encoding/protojson"
|
||||||
|
"google.golang.org/protobuf/types/known/anypb"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
@ -17,14 +20,87 @@ import (
|
||||||
"github.com/hashicorp/consul/proto-public/pbresource"
|
"github.com/hashicorp/consul/proto-public/pbresource"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type OuterResource struct {
|
||||||
|
ID *ID `json:"id"`
|
||||||
|
Owner *ID `json:"owner"`
|
||||||
|
Generation string `json:"generation"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Metadata map[string]any `json:"metadata"`
|
||||||
|
Data map[string]any `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Tenancy struct {
|
||||||
|
Namespace string `json:"namespace"`
|
||||||
|
Partition string `json:"partition"`
|
||||||
|
PeerName string `json:"peerName"`
|
||||||
|
}
|
||||||
|
type Type struct {
|
||||||
|
Group string `json:"group"`
|
||||||
|
GroupVersion string `json:"groupVersion"`
|
||||||
|
Kind string `json:"kind"`
|
||||||
|
}
|
||||||
|
type ID struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Tenancy Tenancy `json:"tenancy"`
|
||||||
|
Type Type `json:"type"`
|
||||||
|
UID string `json:"uid"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseJson(js string) (*pbresource.Resource, error) {
|
||||||
|
|
||||||
|
parsedResource := new(pbresource.Resource)
|
||||||
|
|
||||||
|
var outerResource OuterResource
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(js), &outerResource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if outerResource.ID == nil {
|
||||||
|
return nil, fmt.Errorf("\"id\" field need to be provided")
|
||||||
|
}
|
||||||
|
|
||||||
|
typ := pbresource.Type{
|
||||||
|
Kind: outerResource.ID.Type.Kind,
|
||||||
|
Group: outerResource.ID.Type.Group,
|
||||||
|
GroupVersion: outerResource.ID.Type.GroupVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
reg, ok := consul.NewTypeRegistry().Resolve(&typ)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("invalid type %v", parsedResource)
|
||||||
|
}
|
||||||
|
data := reg.Proto.ProtoReflect().New().Interface()
|
||||||
|
anyProtoMsg, err := anypb.New(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
outerResource.Data["@type"] = anyProtoMsg.TypeUrl
|
||||||
|
|
||||||
|
marshal, err := json.Marshal(outerResource)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := protojson.Unmarshal(marshal, parsedResource); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return parsedResource, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ParseResourceFromFile(filePath string) (*pbresource.Resource, error) {
|
func ParseResourceFromFile(filePath string) (*pbresource.Resource, error) {
|
||||||
data, err := helpers.LoadDataSourceNoRaw(filePath, nil)
|
data, err := helpers.LoadDataSourceNoRaw(filePath, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to load data: %v", err)
|
return nil, fmt.Errorf("Failed to load data: %v", err)
|
||||||
}
|
}
|
||||||
parsedResource, err := resourcehcl.Unmarshal([]byte(data), consul.NewTypeRegistry())
|
var parsedResource *pbresource.Resource
|
||||||
|
parsedResource, err = resourcehcl.Unmarshal([]byte(data), consul.NewTypeRegistry())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("Failed to decode resource from input file: %v", err)
|
parsedResource, err = parseJson(data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("Failed to decode resource from input file: %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return parsedResource, nil
|
return parsedResource, nil
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: BUSL-1.1
|
||||||
|
|
||||||
|
package resource
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_parseJson(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
js string
|
||||||
|
wantErr bool
|
||||||
|
}{
|
||||||
|
{"valid resource", "{\n \"data\": {\n \"genre\": \"GENRE_METAL\",\n \"name\": \"Korn\"\n },\n \"generation\": \"01HAYWBPV1KMT2KWECJ6CEWDQ0\",\n \"id\": {\n \"name\": \"korn\",\n \"tenancy\": {\n \"namespace\": \"default\",\n \"partition\": \"default\",\n \"peerName\": \"local\"\n },\n \"type\": {\n \"group\": \"demo\",\n \"groupVersion\": \"v2\",\n \"kind\": \"Artist\"\n },\n \"uid\": \"01HAYWBPV1KMT2KWECJ4NW88S1\"\n },\n \"metadata\": {\n \"foo\": \"bar\"\n },\n \"version\": \"18\"\n}", false},
|
||||||
|
{"invalid resource", "{\n \"data\": {\n \"genre\": \"GENRE_METAL\",\n \"name\": \"Korn\"\n },\n \"id\": {\n \"name\": \"korn\",\n \"tenancy\": {\n \"namespace\": \"default\",\n \"partition\": \"default\",\n \"peerName\": \"local\"\n },\n \"type\": \"\"\n },\n \"metadata\": {\n \"foo\": \"bar\"\n }\n}\n", true},
|
||||||
|
}
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := parseJson(tt.js)
|
||||||
|
if tt.wantErr {
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Nil(t, got)
|
||||||
|
} else {
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, got)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue