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:
Dhia Ayachi 2023-09-22 16:51:18 -04:00 committed by GitHub
parent 11d6b0df45
commit d3bb5ff21a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 111 additions and 2 deletions

View File

@ -4,9 +4,12 @@
package resource
import (
"encoding/json"
"errors"
"flag"
"fmt"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/types/known/anypb"
"net/http"
"strings"
@ -17,15 +20,88 @@ import (
"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) {
data, err := helpers.LoadDataSourceNoRaw(filePath, nil)
if err != nil {
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 {
parsedResource, err = parseJson(data)
if err != nil {
return nil, fmt.Errorf("Failed to decode resource from input file: %v", err)
}
}
return parsedResource, nil
}

View File

@ -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)
}
})
}
}