diff --git a/Makefile b/Makefile
index 619cbafd..0ca24070 100644
--- a/Makefile
+++ b/Makefile
@@ -62,7 +62,6 @@ mocks-gen: mocks-rm ## Generate mocks for all the defined interfaces.
mockgen -package=mockschemaclientbound -source=pkg/datastore/clients/schema/schemaClientBound.go -destination=$(MOCKDIR)/mockschemaclientbound/client.go
mockgen -package=mockcacheclient -source=pkg/cache/cache.go -destination=$(MOCKDIR)/mockcacheclient/client.go
mockgen -package=mocktarget -source=pkg/datastore/target/target.go -destination=$(MOCKDIR)/mocktarget/target.go
- mockgen -package=mockvalidationclient -source=pkg/datastore/clients/validationClient.go -destination=$(MOCKDIR)/mockvalidationclient/client.go
mockgen -package=mockTreeEntry -source=pkg/tree/entry.go -destination=$(MOCKDIR)/mocktreeentry/entry.go
.PHONY: mocks-rm
@@ -88,4 +87,13 @@ format_yang:
.PHONY: goreleaser-nightly
goreleaser-nightly:
go install github.com/goreleaser/goreleaser/v2@latest
- goreleaser release --clean -f .goreleaser.nightlies.yml --skip=validate
\ No newline at end of file
+ goreleaser release --clean -f .goreleaser.nightlies.yml --skip=validate
+
+.PHONY: proto
+CACHE_OUT_DIR := $(CURDIR)/pkg/tree/tree_persist
+
+proto:
+ clang-format -i -style=file:$(CURDIR)/proto/clang-format.style $(CURDIR)/proto/tree_persist.proto
+
+ mkdir -p $(CACHE_OUT_DIR)
+ protoc --go_out=$(CACHE_OUT_DIR) --go-grpc_out=$(CACHE_OUT_DIR) -I $(CURDIR)/proto $(CURDIR)/proto/tree_persist.proto
\ No newline at end of file
diff --git a/client/cmd/data.go b/client/cmd/data.go
index 39c477e3..6aeabc27 100644
--- a/client/cmd/data.go
+++ b/client/cmd/data.go
@@ -26,7 +26,5 @@ var dataCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(dataCmd)
-
- dataCmd.PersistentFlags().StringVarP(&candidate, "candidate", "", "", "datastore (candidate) name")
dataCmd.PersistentFlags().StringVarP(&datastoreName, "ds", "", "", "datastore target name")
}
diff --git a/client/cmd/data_diff.go b/client/cmd/data_diff.go
deleted file mode 100644
index 9fd010b4..00000000
--- a/client/cmd/data_diff.go
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cmd
-
-import (
- "context"
- "fmt"
-
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "github.com/spf13/cobra"
- "google.golang.org/protobuf/encoding/prototext"
-
- "github.com/sdcio/data-server/pkg/utils"
-)
-
-// dataDiffCmd represents the diff command
-var dataDiffCmd = &cobra.Command{
- Use: "diff",
- Short: "diff candidate and its baseline",
- SilenceUsage: true,
- RunE: func(cmd *cobra.Command, _ []string) error {
- ctx, cancel := context.WithCancel(cmd.Context())
- defer cancel()
- dataClient, err := createDataClient(ctx, addr)
- if err != nil {
- return err
- }
- req := &sdcpb.DiffRequest{
- Name: datastoreName,
- Datastore: &sdcpb.DataStore{
- Type: sdcpb.Type_CANDIDATE,
- Name: candidate,
- },
- }
- fmt.Println("request:")
- fmt.Println(prototext.Format(req))
- rsp, err := dataClient.Diff(ctx, req)
- if err != nil {
- return err
- }
- fmt.Println("response:")
- fmt.Println(prototext.Format(rsp))
- printDiffResponse(rsp)
- return nil
- },
-}
-
-func init() {
- dataCmd.AddCommand(dataDiffCmd)
-}
-
-func printDiffResponse(rsp *sdcpb.DiffResponse) {
- if rsp == nil {
- return
- }
- prefix := fmt.Sprintf("%s: %s/%s/%d:", rsp.GetName(), rsp.GetDatastore().GetName(), rsp.GetDatastore().GetOwner(), rsp.GetDatastore().GetPriority())
- for _, diff := range rsp.GetDiff() {
- p := utils.ToXPath(diff.GetPath(), false)
- fmt.Printf("%s\n\tpath=%s:\n\tmain->candidate: %s -> %s\n",
- prefix, p,
- diff.GetMainValue(), diff.GetCandidateValue())
- }
-}
diff --git a/client/cmd/data_get.go b/client/cmd/data_get.go
deleted file mode 100644
index 887dc4bb..00000000
--- a/client/cmd/data_get.go
+++ /dev/null
@@ -1,151 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cmd
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "strings"
-
- "github.com/sdcio/schema-server/pkg/utils"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "github.com/spf13/cobra"
- "google.golang.org/protobuf/encoding/prototext"
-)
-
-var paths []string
-var dataType string
-var format string
-var intended bool
-var encoding string
-
-// dataGetCmd represents the get command
-var dataGetCmd = &cobra.Command{
- Use: "get",
- Short: "get data",
- SilenceUsage: true,
- RunE: func(cmd *cobra.Command, _ []string) error {
- if candidate != "" && intended {
- return fmt.Errorf("cannot set a candidate name and intended store at the same time")
- }
- var dt sdcpb.DataType
- switch dataType {
- case "ALL":
- case "CONFIG":
- dt = sdcpb.DataType_CONFIG
- case "STATE":
- dt = sdcpb.DataType_STATE
- default:
- return fmt.Errorf("invalid flag value --type %s", dataType)
- }
-
- var enc sdcpb.Encoding
- switch encoding {
- case "STRING":
- enc = sdcpb.Encoding_STRING
- case "JSON":
- enc = sdcpb.Encoding_JSON
- case "JSON_IETF":
- enc = sdcpb.Encoding_JSON_IETF
- case "PROTO":
- enc = sdcpb.Encoding_PROTO
- }
-
- req := &sdcpb.GetDataRequest{
- Name: datastoreName,
- DataType: dt,
- Encoding: enc,
- }
- for _, p := range paths {
- xp, err := utils.ParsePath(p)
- if err != nil {
- return err
- }
- req.Path = append(req.Path, xp)
- }
- if candidate != "" {
- req.Datastore = &sdcpb.DataStore{
- Type: sdcpb.Type_CANDIDATE,
- Name: candidate,
- }
- }
- if intended {
- req.Datastore = &sdcpb.DataStore{
- Type: sdcpb.Type_INTENDED,
- Owner: owner,
- Priority: priority,
- }
- }
- ctx, cancel := context.WithCancel(cmd.Context())
- defer cancel()
- dataClient, err := createDataClient(ctx, addr)
- if err != nil {
- return err
- }
- fmt.Println("request:")
- fmt.Println(prototext.Format(req))
- stream, err := dataClient.GetData(ctx, req)
- if err != nil {
- return err
- }
- count := 0
- for {
- rsp, err := stream.Recv()
- if err != nil {
- if strings.Contains(err.Error(), "EOF") {
- break
- }
- return err
- }
- count++
- switch format {
- case "json":
- b, err := json.MarshalIndent(rsp, "", " ")
- if err != nil {
- return err
- }
- fmt.Println(string(b))
- case "flat":
- for _, n := range rsp.GetNotification() {
- for _, upd := range n.GetUpdate() {
- p := utils.ToXPath(upd.GetPath(), false)
- // upd.GetValue()
- fmt.Printf("%s: %s\n", p, upd.GetValue())
- }
- }
-
- default:
- fmt.Println(prototext.Format(rsp))
- }
-
- }
-
- fmt.Println("num notifications:", count)
- return nil
- },
-}
-
-func init() {
- dataCmd.AddCommand(dataGetCmd)
- dataGetCmd.Flags().StringArrayVarP(&paths, "path", "", []string{}, "get path(s)")
- dataGetCmd.Flags().StringVarP(&dataType, "type", "", "ALL", "data type, one of: ALL, CONFIG, STATE")
- dataGetCmd.Flags().StringVarP(&encoding, "encoding", "", "STRING", "encoding of the returned data: STRING, JSON, JSON_IETF or PROTO")
-
- // intended store
- dataGetCmd.Flags().BoolVarP(&intended, "intended", "", false, "get data from intended store")
- dataGetCmd.Flags().StringVarP(&owner, "owner", "", "", "intended store owner to query")
- dataGetCmd.Flags().Int32VarP(&priority, "priority", "", 0, "intended store priority")
-}
diff --git a/client/cmd/data_getIntent.go b/client/cmd/data_getIntent.go
index 329a7ad7..f88636b0 100644
--- a/client/cmd/data_getIntent.go
+++ b/client/cmd/data_getIntent.go
@@ -32,9 +32,9 @@ var dataGetIntentCmd = &cobra.Command{
SilenceUsage: true,
RunE: func(cmd *cobra.Command, _ []string) error {
req := &sdcpb.GetIntentRequest{
- Name: datastoreName,
- Intent: intentName,
- Priority: priority,
+ DatastoreName: datastoreName,
+ Intent: intentName,
+ Format: sdcpb.Format_Intent_Format_JSON,
}
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()
diff --git a/client/cmd/data_listIntent.go b/client/cmd/data_listIntent.go
index c1bfc346..01ca1bb9 100644
--- a/client/cmd/data_listIntent.go
+++ b/client/cmd/data_listIntent.go
@@ -30,7 +30,7 @@ var dataListIntentCmd = &cobra.Command{
SilenceUsage: true,
RunE: func(cmd *cobra.Command, _ []string) error {
req := &sdcpb.ListIntentRequest{
- Name: datastoreName,
+ DatastoreName: datastoreName,
}
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()
diff --git a/client/cmd/data_setIntent.go b/client/cmd/data_setIntent.go
deleted file mode 100644
index ee1d540f..00000000
--- a/client/cmd/data_setIntent.go
+++ /dev/null
@@ -1,108 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cmd
-
-import (
- "context"
- "encoding/json"
- "errors"
- "fmt"
- "os"
-
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "github.com/spf13/cobra"
- "google.golang.org/protobuf/encoding/prototext"
-
- "github.com/sdcio/data-server/pkg/utils"
-)
-
-var deleteFlag bool
-var intentDefinition string
-
-// dataSetIntentCmd represents the set-intent command
-var dataSetIntentCmd = &cobra.Command{
- Use: "set-intent",
- Short: "set intent data",
- SilenceUsage: true,
- RunE: func(cmd *cobra.Command, _ []string) error {
- if deleteFlag && intentDefinition != "" {
- return errors.New("cannot set an intent body and the delete flag at the same time")
- }
- req := &sdcpb.SetIntentRequest{
- Name: datastoreName,
- Intent: intentName,
- Priority: priority,
- Update: make([]*sdcpb.Update, 0),
- }
- if deleteFlag {
- req.Delete = true
- }
- if intentDefinition != "" {
- b, err := os.ReadFile(intentDefinition)
- if err != nil {
- return err
- }
- intentDefs := make([]*intentDef, 0)
- err = json.Unmarshal(b, &intentDefs)
- if err != nil {
- return err
- }
- for _, idef := range intentDefs {
- p, err := utils.ParsePath(idef.Path)
- if err != nil {
- return err
- }
- bb, err := json.Marshal(idef.Value)
- if err != nil {
- return err
- }
- req.Update = append(req.Update, &sdcpb.Update{
- Path: p,
- Value: &sdcpb.TypedValue{
- Value: &sdcpb.TypedValue_JsonVal{JsonVal: bb},
- },
- })
- }
- }
- ctx, cancel := context.WithCancel(cmd.Context())
- defer cancel()
- dataClient, err := createDataClient(ctx, addr)
- if err != nil {
- return err
- }
- fmt.Println("request:")
- fmt.Println(prototext.Format(req))
- rsp, err := dataClient.SetIntent(ctx, req)
- if err != nil {
- return err
- }
- fmt.Println("response:")
- fmt.Println(prototext.Format(rsp))
- return nil
- },
-}
-
-func init() {
- dataCmd.AddCommand(dataSetIntentCmd)
- dataSetIntentCmd.Flags().StringVarP(&intentName, "intent", "", "", "intent name")
- dataSetIntentCmd.Flags().StringVarP(&intentDefinition, "body", "", "", "intent body")
- dataSetIntentCmd.Flags().Int32VarP(&priority, "priority", "", 0, "intent priority")
- dataSetIntentCmd.Flags().BoolVarP(&deleteFlag, "delete", "", false, "delete intent")
-}
-
-type intentDef struct {
- Path string `json:"path,omitempty"`
- Value any `json:"value,omitempty"`
-}
diff --git a/client/cmd/data_subscribe.go b/client/cmd/data_subscribe.go
deleted file mode 100644
index 988d246f..00000000
--- a/client/cmd/data_subscribe.go
+++ /dev/null
@@ -1,192 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cmd
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "os"
- "strings"
- "time"
-
- "github.com/sdcio/schema-server/pkg/utils"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "github.com/spf13/cobra"
- "google.golang.org/protobuf/encoding/prototext"
- "gopkg.in/yaml.v2"
-)
-
-var sampleInterval time.Duration
-var subscriptionFile string
-
-// dataSubscribeCmd represents the subscribe command
-var dataSubscribeCmd = &cobra.Command{
- Use: "subscribe",
- Aliases: []string{"sub"},
- Short: "subscribe to data",
- SilenceUsage: true,
- RunE: func(cmd *cobra.Command, _ []string) error {
- var err error
- var req *sdcpb.SubscribeRequest
- if subscriptionFile != "" {
- req, err = subscribeRequestFromFile(subscriptionFile)
- if err != nil {
- return err
- }
- } else {
- var dt sdcpb.DataType
- switch strings.ToUpper(dataType) {
- case "ALL":
- case "CONFIG":
- dt = sdcpb.DataType_CONFIG
- case "STATE":
- dt = sdcpb.DataType_STATE
- default:
- return fmt.Errorf("invalid flag value --type %s", dataType)
- }
-
- xps := make([]*sdcpb.Path, 0, len(paths))
- for _, p := range paths {
- xp, err := utils.ParsePath(p)
- if err != nil {
- return err
- }
- xps = append(xps, xp)
- }
-
- req = &sdcpb.SubscribeRequest{
- Name: datastoreName,
- Subscription: []*sdcpb.Subscription{
- {
- Path: xps,
- SampleInterval: uint64(sampleInterval),
- DataType: dt,
- },
- },
- }
- }
- fmt.Println("request:")
- fmt.Println(prototext.Format(req))
-
- ctx, cancel := context.WithCancel(cmd.Context())
- defer cancel()
- dataClient, err := createDataClient(ctx, addr)
- if err != nil {
- return err
- }
- stream, err := dataClient.Subscribe(ctx, req)
- if err != nil {
- return err
- }
- fmt.Println("responses:")
- count := 0
- for {
- rsp, err := stream.Recv()
- if err != nil {
- if strings.Contains(err.Error(), "EOF") {
- break
- }
- return err
- }
- count++
- switch format {
- case "json":
- b, err := json.MarshalIndent(rsp, "", " ")
- if err != nil {
- return err
- }
- fmt.Println(string(b))
- case "flat":
- for _, upd := range rsp.GetUpdate().GetUpdate() {
- p := utils.ToXPath(upd.GetPath(), false)
- fmt.Printf("%s: %s\n", p, upd.GetValue())
- }
-
- default:
- fmt.Println(prototext.Format(rsp))
- }
- }
-
- fmt.Println("num notifications:", count)
- return nil
- },
-}
-
-func init() {
- dataCmd.AddCommand(dataSubscribeCmd)
- dataSubscribeCmd.Flags().StringArrayVarP(&paths, "path", "", []string{}, "get path(s)")
- dataSubscribeCmd.Flags().DurationVarP(&sampleInterval, "sample-interval", "", 10*time.Second, "sample interval")
- dataSubscribeCmd.Flags().StringVarP(&dataType, "type", "", "ALL", "data type, one of: ALL, CONFIG, STATE")
- dataSubscribeCmd.Flags().StringVarP(&subscriptionFile, "file", "", "", "file with a subscription definition")
- dataSubscribeCmd.Flags().StringVarP(&format, "format", "", "", "print format, '', 'flat' or 'json'")
-}
-
-type subscribeDefinition struct {
- Subscription []*subscription `yaml:"subscription,omitempty"`
-}
-
-type subscription struct {
- Paths []string `yaml:"paths,omitempty"`
- SampleInterval time.Duration `yaml:"sample-interval,omitempty"`
- DataType string `yaml:"data-type,omitempty"`
- SuppressRedundant bool `yaml:"suppress-redundant,omitempty"`
-}
-
-func subscribeRequestFromFile(file string) (*sdcpb.SubscribeRequest, error) {
- b, err := os.ReadFile(subscriptionFile)
- if err != nil {
- return nil, err
- }
- subDef := new(subscribeDefinition)
- err = yaml.Unmarshal(b, subDef)
- if err != nil {
- return nil, err
- }
- req := &sdcpb.SubscribeRequest{
- Name: datastoreName,
- Subscription: make([]*sdcpb.Subscription, 0, len(subDef.Subscription)),
- }
- for _, subcd := range subDef.Subscription {
- if subcd.DataType == "" {
- subcd.DataType = "ALL"
- }
- var dt sdcpb.DataType
- switch strings.ToUpper(subcd.DataType) {
- case "ALL":
- case "CONFIG":
- dt = sdcpb.DataType_CONFIG
- case "STATE":
- dt = sdcpb.DataType_STATE
- default:
- return nil, fmt.Errorf("invalid data type %s", subcd.DataType)
- }
- subsc := &sdcpb.Subscription{
- Path: make([]*sdcpb.Path, 0, len(subcd.Paths)),
- DataType: dt,
- SampleInterval: uint64(subcd.SampleInterval),
- SuppressRedundant: subcd.SuppressRedundant,
- }
- for _, p := range subcd.Paths {
- xp, err := utils.ParsePath(p)
- if err != nil {
- return nil, err
- }
- subsc.Path = append(subsc.Path, xp)
- }
- req.Subscription = append(req.Subscription, subsc)
- }
- return req, nil
-}
diff --git a/client/cmd/datastore.go b/client/cmd/datastore.go
index ec189b8c..dcd34936 100644
--- a/client/cmd/datastore.go
+++ b/client/cmd/datastore.go
@@ -29,5 +29,4 @@ var datastoreCmd = &cobra.Command{
func init() {
rootCmd.AddCommand(datastoreCmd)
datastoreCmd.PersistentFlags().StringVarP(&datastoreName, "ds", "", "", "datastore (main) name")
- datastoreCmd.PersistentFlags().StringVarP(&candidate, "candidate", "", "", "datastore candidate name")
}
diff --git a/client/cmd/datastore_commit.go b/client/cmd/datastore_commit.go
deleted file mode 100644
index 47b15d06..00000000
--- a/client/cmd/datastore_commit.go
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cmd
-
-import (
- "context"
- "fmt"
-
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "github.com/spf13/cobra"
- "google.golang.org/protobuf/encoding/prototext"
-)
-
-// datastoreCommitCmd represents the commit command
-var datastoreCommitCmd = &cobra.Command{
- Use: "commit",
- Short: "commit candidate datastore to target",
- SilenceUsage: true,
- RunE: func(cmd *cobra.Command, _ []string) error {
- ctx, cancel := context.WithCancel(cmd.Context())
- defer cancel()
- dataClient, err := createDataClient(ctx, addr)
- if err != nil {
- return err
- }
- req := &sdcpb.CommitRequest{
- Name: datastoreName,
- Datastore: &sdcpb.DataStore{
- Type: sdcpb.Type_CANDIDATE,
- Name: candidate,
- },
- Rebase: rebase,
- Stay: stay,
- }
- fmt.Println("request:")
- fmt.Println(prototext.Format(req))
- rsp, err := dataClient.Commit(ctx, req)
- if err != nil {
- return err
- }
- fmt.Println("response:")
- fmt.Println(prototext.Format(rsp))
- return nil
- },
-}
-
-func init() {
- datastoreCmd.AddCommand(datastoreCommitCmd)
-
- datastoreCommitCmd.Flags().BoolVarP(&rebase, "rebase", "", false, "rebase before commit")
- datastoreCommitCmd.Flags().BoolVarP(&stay, "stay", "", false, "do not delete candidate after commit")
-}
-
-var rebase, stay bool
diff --git a/client/cmd/datastore_create.go b/client/cmd/datastore_create.go
index fd07de23..c62fa104 100644
--- a/client/cmd/datastore_create.go
+++ b/client/cmd/datastore_create.go
@@ -20,16 +20,13 @@ import (
"fmt"
"os"
- "github.com/sdcio/data-server/pkg/datastore"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"github.com/spf13/cobra"
"google.golang.org/protobuf/encoding/prototext"
)
-var candidate string
var target string
var syncFile string
-var owner string
var priority int32
// datastoreCreateCmd represents the create command
@@ -57,7 +54,7 @@ var datastoreCreateCmd = &cobra.Command{
}
}
req := &sdcpb.CreateDataStoreRequest{
- Name: datastoreName,
+ DatastoreName: datastoreName,
}
if syncFile != "" {
b, err := os.ReadFile(syncFile)
@@ -72,25 +69,14 @@ var datastoreCreateCmd = &cobra.Command{
req.Sync = sync
}
- switch {
- // create a candidate datastore
- case candidate != "":
- req.Datastore = &sdcpb.DataStore{
- Type: sdcpb.Type_CANDIDATE,
- Name: candidate,
- Owner: owner,
- Priority: priority,
- }
- req.Target = tg
- //create a main datastore
- default:
- req.Schema = &sdcpb.Schema{
- Name: schemaName,
- Vendor: schemaVendor,
- Version: schemaVersion,
- }
- req.Target = tg
+ //create a datastore
+ req.Schema = &sdcpb.Schema{
+ Name: schemaName,
+ Vendor: schemaVendor,
+ Version: schemaVersion,
}
+ req.Target = tg
+
fmt.Println("request:")
fmt.Println(prototext.Format(req))
rsp, err := dataClient.CreateDataStore(ctx, req)
@@ -108,7 +94,5 @@ func init() {
datastoreCreateCmd.Flags().StringVarP(&target, "target", "", "", "target definition file")
datastoreCreateCmd.Flags().StringVarP(&syncFile, "sync", "", "", "target sync definition file")
- datastoreCreateCmd.Flags().StringVarP(&owner, "owner", "", datastore.DefaultOwner, "candidate owner")
datastoreCreateCmd.Flags().Int32VarP(&priority, "priority", "", 1, "candidate priority")
-
}
diff --git a/client/cmd/datastore_delete.go b/client/cmd/datastore_delete.go
index 6419efa7..9914ab85 100644
--- a/client/cmd/datastore_delete.go
+++ b/client/cmd/datastore_delete.go
@@ -32,12 +32,6 @@ var datastoreDeleteCmd = &cobra.Command{
req := &sdcpb.DeleteDataStoreRequest{
Name: datastoreName,
}
- if candidate != "" {
- req.Datastore = &sdcpb.DataStore{
- Type: sdcpb.Type_CANDIDATE,
- Name: candidate,
- }
- }
ctx, cancel := context.WithCancel(cmd.Context())
defer cancel()
dataClient, err := createDataClient(ctx, addr)
diff --git a/client/cmd/datastore_discard.go b/client/cmd/datastore_discard.go
deleted file mode 100644
index f622d9f0..00000000
--- a/client/cmd/datastore_discard.go
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cmd
-
-import (
- "context"
- "fmt"
-
- schema_server "github.com/sdcio/sdc-protos/sdcpb"
- "github.com/spf13/cobra"
- "google.golang.org/protobuf/encoding/prototext"
-)
-
-// datastoreDiscardCmd represents the discard command
-var datastoreDiscardCmd = &cobra.Command{
- Use: "discard",
- Short: "discard changes made to a candidate datastore",
- SilenceUsage: true,
- RunE: func(cmd *cobra.Command, _ []string) error {
- ctx, cancel := context.WithCancel(cmd.Context())
- defer cancel()
- dataClient, err := createDataClient(ctx, addr)
- if err != nil {
- return err
- }
- req := &schema_server.DiscardRequest{
- Name: datastoreName,
- Datastore: &schema_server.DataStore{
- Type: schema_server.Type_CANDIDATE,
- Name: candidate,
- },
- Stay: stay,
- }
- fmt.Println("request:")
- fmt.Println(prototext.Format(req))
- rsp, err := dataClient.Discard(ctx, req)
- if err != nil {
- return err
- }
- fmt.Println("response:")
- fmt.Println(prototext.Format(rsp))
- return nil
- },
-}
-
-func init() {
- datastoreCmd.AddCommand(datastoreDiscardCmd)
-}
diff --git a/client/cmd/datastore_get.go b/client/cmd/datastore_get.go
index 5904e3f4..01bcc4d5 100644
--- a/client/cmd/datastore_get.go
+++ b/client/cmd/datastore_get.go
@@ -19,8 +19,6 @@ import (
"encoding/json"
"fmt"
"os"
- "strconv"
- "strings"
"github.com/olekukonko/tablewriter"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
@@ -41,7 +39,7 @@ var datastoreGetCmd = &cobra.Command{
return err
}
req := &sdcpb.GetDataStoreRequest{
- Name: datastoreName,
+ DatastoreName: datastoreName,
}
// fmt.Println("request:")
// fmt.Println(prototext.Format(req))
@@ -72,7 +70,7 @@ func init() {
func printDataStoreTable(rsp *sdcpb.GetDataStoreResponse) {
table := tablewriter.NewWriter(os.Stdout)
- table.SetHeader([]string{"Name", "Schema", "Protocol", "Address", "State", "Candidate (C/O/P)"})
+ table.SetHeader([]string{"Name", "Schema", "Protocol", "Address", "State"})
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetAutoFormatHeaders(false)
table.SetAutoWrapText(false)
@@ -81,28 +79,13 @@ func printDataStoreTable(rsp *sdcpb.GetDataStoreResponse) {
}
func toTableData(rsp *sdcpb.GetDataStoreResponse) [][]string {
- candidates := make([]string, 0, len(rsp.GetDatastore()))
- for _, ds := range rsp.GetDatastore() {
- if ds.GetType() == sdcpb.Type_MAIN {
- continue
- }
- candidateName := "- " + ds.GetName()
- if ds.Owner != "" {
- candidateName += "/" + ds.Owner
- }
- if ds.Priority != 0 {
- candidateName += "/" + strconv.Itoa(int(ds.Priority))
- }
- candidates = append(candidates, candidateName)
- }
return [][]string{
{
- rsp.GetName(),
+ rsp.GetDatastoreName(),
fmt.Sprintf("%s/%s/%s", rsp.GetSchema().GetName(), rsp.GetSchema().GetVendor(), rsp.GetSchema().GetVersion()),
rsp.GetTarget().GetType(),
rsp.GetTarget().GetAddress(),
rsp.GetTarget().GetStatus().String(),
- strings.Join(candidates, "\n"),
},
}
}
diff --git a/client/cmd/root.go b/client/cmd/root.go
index 4f0ee773..69aa2b2e 100644
--- a/client/cmd/root.go
+++ b/client/cmd/root.go
@@ -28,6 +28,7 @@ import (
var schemaName string
var schemaVendor string
var schemaVersion string
+var format string
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
diff --git a/go.mod b/go.mod
index 54a408c0..1fc9047e 100644
--- a/go.mod
+++ b/go.mod
@@ -4,7 +4,11 @@ go 1.23.4
toolchain go1.23.5
-replace github.com/openconfig/goyang v1.6.0 => github.com/sdcio/goyang v1.6.0-2
+replace github.com/openconfig/goyang v1.6.0 => /home/mava/projects/goyang
+
+replace github.com/sdcio/cache => /home/mava/projects/cachev2
+
+replace github.com/sdcio/sdc-protos => /home/mava/projects/sdc-protos
require (
github.com/AlekSi/pointer v1.2.0
@@ -15,7 +19,7 @@ require (
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
github.com/jellydator/ttlcache/v3 v3.3.0
github.com/olekukonko/tablewriter v0.0.5
- github.com/openconfig/gnmi v0.13.0
+ github.com/openconfig/gnmi v0.14.0
github.com/openconfig/gnmic/pkg/api v0.1.8
github.com/openconfig/gnmic/pkg/target v0.1.4
github.com/openconfig/gnmic/pkg/types v0.1.2
@@ -31,7 +35,6 @@ require (
github.com/spf13/cobra v1.8.1
github.com/spf13/pflag v1.0.6
go.uber.org/mock v0.5.0
- golang.org/x/sync v0.10.0
google.golang.org/grpc v1.70.0
google.golang.org/protobuf v1.36.5
gopkg.in/yaml.v2 v2.4.0
@@ -82,7 +85,6 @@ require (
github.com/prometheus/common v0.60.1 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
- github.com/rs/xid v1.6.0 // indirect
github.com/sirikothe/gotextfsm v1.0.1-0.20200816110946-6aa2cfd355e4 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.opencensus.io v0.24.0 // indirect
@@ -90,6 +92,7 @@ require (
golang.org/x/exp v0.0.0-20241108190413-2d47ceb2692f // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/oauth2 v0.24.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
diff --git a/go.sum b/go.sum
index 83c2725d..f84325b2 100644
--- a/go.sum
+++ b/go.sum
@@ -1,12 +1,9 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo=
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
github.com/AlekSi/pointer v1.2.0 h1:glcy/gc4h8HnG2Z3ZECSzZ1IX1x2JxRVuDzaJwQE0+w=
github.com/AlekSi/pointer v1.2.0/go.mod h1:gZGfd3dpW4vEc/UlyfKKi1roIqcCgwOIvb0tSNSBle0=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/beevik/etree v1.5.0 h1:iaQZFSDS+3kYZiGoc9uKeOkUY3nYMXOKLl6KIJxiJWs=
github.com/beevik/etree v1.5.0/go.mod h1:gPNJNaBGVZ9AwsidazFZyygnd+0pAU38N4D+WemwKNs=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -14,15 +11,11 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bufbuild/protocompile v0.14.1 h1:iA73zAf/fyljNjQKwYzUHD6AD4R8KMasmwa/FBatYVw=
github.com/bufbuild/protocompile v0.14.1/go.mod h1:ppVdAIhbr2H8asPk6k4pY7t9zB1OU5DoEw9xY/FUi1c=
-github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
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/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=
github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE=
@@ -43,8 +36,6 @@ github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRr
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.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/v5 v5.9.0 h1:kcBlZQbplgElYIlo/n1hJbls2z/1awpXxpRi0/FOJfg=
github.com/evanphx/json-patch/v5 v5.9.0/go.mod h1:VNkHZ/282BpEyt/tObQO8s5CMPmYYq14uClGH4abBuQ=
@@ -52,7 +43,6 @@ github.com/fsnotify/fsnotify v1.8.0 h1:dAwr6QBTBZIkG8roQaJjGof0pp0EeF+tNV7YBP3F/
github.com/fsnotify/fsnotify v1.8.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
@@ -88,10 +78,7 @@ github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrU
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
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/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
@@ -106,8 +93,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
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.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
@@ -125,7 +110,6 @@ github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDa
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/jellydator/ttlcache/v3 v3.3.0 h1:BdoC9cE81qXfrxeb9eoJi9dWrdhSuwXMAnHTbnBm4Wc=
@@ -157,7 +141,6 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -171,9 +154,8 @@ github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
-github.com/openconfig/gnmi v0.10.0/go.mod h1:Y9os75GmSkhHw2wX8sMsxfI7qRGAEcDh8NTa5a8vj6E=
-github.com/openconfig/gnmi v0.13.0 h1:4aVopzMZVYtfrRqlpDqM0liutE+3/AiDMzNtI2r7em4=
-github.com/openconfig/gnmi v0.13.0/go.mod h1:YJwAQ6qkU06TU/g4ZqjxSkajOm0adoBK86/s6w0ow3w=
+github.com/openconfig/gnmi v0.14.0 h1:lXAd3HgjtNBnLypevp0pxzpEXmsUD0TbKzaNJ/FboPM=
+github.com/openconfig/gnmi v0.14.0/go.mod h1:whr6zVq9PCU8mV1D0K9v7Ajd3+swoN6Yam9n8OH3eT0=
github.com/openconfig/gnmic/pkg/api v0.1.8 h1:3N9oFduU204Ta3g7r3dC4pcYdT/Dr7PrSC13Lyc7Ymc=
github.com/openconfig/gnmic/pkg/api v0.1.8/go.mod h1:WbME6stT7zcYzQnCwQO42a23WgZRqFQVGVsp0C4FHtc=
github.com/openconfig/gnmic/pkg/target v0.1.4 h1:zO7gOke9RVnkockM2lZv5MqgNdfysUSqxyp91OnEjOQ=
@@ -182,15 +164,11 @@ github.com/openconfig/gnmic/pkg/types v0.1.2 h1:FRjERZrbcuqhwRKHZ7ux4UXr4fc1DlgX
github.com/openconfig/gnmic/pkg/types v0.1.2/go.mod h1:Gwc9suBy/s17bP8BaCrp3dE5E+RkcHqVIkFqdXopog4=
github.com/openconfig/gnmic/pkg/utils v0.1.1 h1:LgfI/c/O8VpuZg1RS9G6XEeRhAQSlOalE52/8tsdf00=
github.com/openconfig/gnmic/pkg/utils v0.1.1/go.mod h1:DQm/e8cdRwdmUORjODWteDU0HG0CWNYBAhLWqnPQegE=
-github.com/openconfig/goyang v0.0.0-20200115183954-d0a48929f0ea/go.mod h1:dhXaV0JgHJzdrHi2l+w0fZrwArtXL7jEFoiqLEdmkvU=
-github.com/openconfig/grpctunnel v0.0.0-20220819142823-6f5422b8ca70/go.mod h1:OmTWe7RyZj2CIzIgy4ovEBzCLBJzRvWSZmn7u02U9gU=
github.com/openconfig/grpctunnel v0.1.0 h1:EN99qtlExZczgQgp5ANnHRC/Rs62cAG+Tz2BQ5m/maM=
github.com/openconfig/grpctunnel v0.1.0/go.mod h1:G04Pdu0pml98tdvXrvLaU+EBo3PxYfI9MYqpvdaEHLo=
-github.com/openconfig/ygot v0.6.0/go.mod h1:o30svNf7O0xK+R35tlx95odkDmZWS9JyWWQSmIhqwAs=
github.com/openconfig/ygot v0.29.20 h1:XHLpwCN91QuKc2LAvnEqtCmH8OuxgLlErDhrdl2mJw8=
github.com/openconfig/ygot v0.29.20/go.mod h1:K8HbrPm/v8/emtGQ9+RsJXx6UPKC5JzS/FqK7pN+tMo=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
-github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -206,26 +184,16 @@ github.com/prometheus/common v0.60.1 h1:FUas6GcOw66yB/73KC+BOZoFJmbo/1pojoILArPA
github.com/prometheus/common v0.60.1/go.mod h1:h0LYf1R1deLSKtD4Vdg8gy4RuOvENW2J/h19V5NADQw=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
-github.com/protocolbuffers/txtpbfmt v0.0.0-20220608084003-fc78c767cd6a/go.mod h1:KjY0wibdYKc4DYkerHSbguaf3JeIPGhNJBp2BNiFH78=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/rs/xid v1.6.0 h1:fV591PaemRlL6JfRxGDEPl69wICngIQ3shQtzfy2gxU=
-github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/scrapli/scrapligo v1.3.3 h1:D9zj1QrOYNYAQ30YT7wfQBINvPGxvs5L5Lz+2LnL7V4=
github.com/scrapli/scrapligo v1.3.3/go.mod h1:pOWxVyPsQRrWTrkoSSDg05tjOqtWfLffAZtAsCc0w3M=
-github.com/sdcio/cache v0.0.35 h1:E0PZl+37qr/MwdQecvZPaiAhgVlUvN/KNiLE9r/XYgA=
-github.com/sdcio/cache v0.0.35/go.mod h1:ZQCmt2KtpsuwXZtBCoIksKGBxdjPVHoCDnjo6s49oC0=
-github.com/sdcio/goyang v1.6.0-2 h1:jUphRX+NWTliDR7fTthlcJVr3MAZENYqkje2rkMECL8=
-github.com/sdcio/goyang v1.6.0-2/go.mod h1:sdNZi/wdTZyLNBNfgLzmmbi7kISm7FskMDKKzMY+x1M=
github.com/sdcio/schema-server v0.0.30 h1:71/tb5T9qCC5qskbxfd3RYE/rQAyNUr2gOrU0NcsLSM=
github.com/sdcio/schema-server v0.0.30/go.mod h1:q/S7DAIGTI5b7PZFlpzZ34cVXAtawVoGZtfju6uIaCo=
-github.com/sdcio/sdc-protos v0.0.39 h1:GDpiUcMmOnHDSCD92t3brZ315QfmkN4yBiFdaZJv5B0=
-github.com/sdcio/sdc-protos v0.0.39/go.mod h1:uG2jk1oV3iQ6WRypxJA+vssPqtfZchQzGwAXueV9z6A=
github.com/sdcio/yang-parser v0.0.10 h1:N+DTuOM40kkx7y2eXhxL2BAokFntwkfsp6xQxP3VQ+I=
github.com/sdcio/yang-parser v0.0.10/go.mod h1:y/d8lg/mqSnZwaO2bkxyVuFBtuDQm9ys9hpsBs/WizU=
github.com/sirikothe/gotextfsm v1.0.1-0.20200816110946-6aa2cfd355e4 h1:FHUL2HofYJuslFOQdy/JjjP36zxqIpd/dcoiwLMIs7k=
@@ -233,7 +201,6 @@ github.com/sirikothe/gotextfsm v1.0.1-0.20200816110946-6aa2cfd355e4/go.mod h1:CJ
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
-github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
@@ -246,7 +213,6 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
@@ -257,7 +223,6 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
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.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
go.opentelemetry.io/otel v1.32.0 h1:WnBN+Xjcteh0zdk01SVqV55d/m62NJLJdIyb4y/WO5U=
@@ -270,7 +235,6 @@ go.opentelemetry.io/otel/sdk/metric v1.32.0 h1:rZvFnvmvawYb0alrYkjraqJq0Z4ZUJAiy
go.opentelemetry.io/otel/sdk/metric v1.32.0/go.mod h1:PWeZlq0zt9YkYAp3gjKZ0eicRYvOh1Gd+X99x6GHpCQ=
go.opentelemetry.io/otel/trace v1.32.0 h1:WIC9mYrXf8TmY/EXuULKc8hR17vE+Hjv2cssQDe03fM=
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
@@ -295,62 +259,42 @@ golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/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-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-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-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
-golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
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/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.8.0 h1:9i3RxcPv3PZnitoVGMPDKZSq1xW1gK1Xy3ArNOGZfEg=
@@ -362,10 +306,8 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
-golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -379,9 +321,7 @@ google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/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-20210811021853-ddbe55d93216/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422 h1:3UsHvIr4Wc2aW4brOaSCmcxh9ksica6fHEr8P1XhkYw=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250106144421-5f5ef82da422/go.mod h1:3ENsm/5D1mzDyhpzeRi1NR784I0BcofWBoSc5QqqMK4=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
@@ -389,14 +329,9 @@ google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyac
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.39.1/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE=
-google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
google.golang.org/grpc v1.70.0 h1:pWFv03aZoHzlRKHWicjsZytKAiYCtNS0dHbXnIdq7jQ=
google.golang.org/grpc v1.70.0/go.mod h1:ofIJqVKDXx/JiXrwr2IG4/zwdH9txy3IlF40RmcJSQw=
-google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
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=
@@ -406,10 +341,6 @@ google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
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/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -421,7 +352,6 @@ gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWM
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
diff --git a/mocks/mockcacheclient/client.go b/mocks/mockcacheclient/client.go
index b66fe171..bfd26f6a 100644
--- a/mocks/mockcacheclient/client.go
+++ b/mocks/mockcacheclient/client.go
@@ -12,12 +12,8 @@ package mockcacheclient
import (
context "context"
reflect "reflect"
- time "time"
- cache "github.com/sdcio/cache/pkg/cache"
- cachepb "github.com/sdcio/cache/proto/cachepb"
- cache0 "github.com/sdcio/data-server/pkg/cache"
- schema_server "github.com/sdcio/sdc-protos/sdcpb"
+ tree_persist "github.com/sdcio/data-server/pkg/tree/tree_persist"
gomock "go.uber.org/mock/gomock"
)
@@ -45,290 +41,157 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder {
return m.recorder
}
-// ApplyPrune mocks base method.
-func (m *MockClient) ApplyPrune(ctx context.Context, name, id string) error {
+// InstanceClose mocks base method.
+func (m *MockClient) InstanceClose(ctx context.Context, cacheInstanceName string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ApplyPrune", ctx, name, id)
+ ret := m.ctrl.Call(m, "InstanceClose", ctx, cacheInstanceName)
ret0, _ := ret[0].(error)
return ret0
}
-// ApplyPrune indicates an expected call of ApplyPrune.
-func (mr *MockClientMockRecorder) ApplyPrune(ctx, name, id any) *gomock.Call {
+// InstanceClose indicates an expected call of InstanceClose.
+func (mr *MockClientMockRecorder) InstanceClose(ctx, cacheInstanceName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ApplyPrune", reflect.TypeOf((*MockClient)(nil).ApplyPrune), ctx, name, id)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceClose", reflect.TypeOf((*MockClient)(nil).InstanceClose), ctx, cacheInstanceName)
}
-// Clone mocks base method.
-func (m *MockClient) Clone(ctx context.Context, name, clone string) error {
+// InstanceCreate mocks base method.
+func (m *MockClient) InstanceCreate(ctx context.Context, cacheInstanceName string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Clone", ctx, name, clone)
+ ret := m.ctrl.Call(m, "InstanceCreate", ctx, cacheInstanceName)
ret0, _ := ret[0].(error)
return ret0
}
-// Clone indicates an expected call of Clone.
-func (mr *MockClientMockRecorder) Clone(ctx, name, clone any) *gomock.Call {
+// InstanceCreate indicates an expected call of InstanceCreate.
+func (mr *MockClientMockRecorder) InstanceCreate(ctx, cacheInstanceName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clone", reflect.TypeOf((*MockClient)(nil).Clone), ctx, name, clone)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceCreate", reflect.TypeOf((*MockClient)(nil).InstanceCreate), ctx, cacheInstanceName)
}
-// Close mocks base method.
-func (m *MockClient) Close() error {
+// InstanceDelete mocks base method.
+func (m *MockClient) InstanceDelete(ctx context.Context, cacheInstanceName string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Close")
+ ret := m.ctrl.Call(m, "InstanceDelete", ctx, cacheInstanceName)
ret0, _ := ret[0].(error)
return ret0
}
-// Close indicates an expected call of Close.
-func (mr *MockClientMockRecorder) Close() *gomock.Call {
+// InstanceDelete indicates an expected call of InstanceDelete.
+func (mr *MockClientMockRecorder) InstanceDelete(ctx, cacheInstanceName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockClient)(nil).Close))
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceDelete", reflect.TypeOf((*MockClient)(nil).InstanceDelete), ctx, cacheInstanceName)
}
-// Commit mocks base method.
-func (m *MockClient) Commit(ctx context.Context, name, candidate string) error {
+// InstanceExists mocks base method.
+func (m *MockClient) InstanceExists(ctx context.Context, cacheInstanceName string) bool {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Commit", ctx, name, candidate)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Commit indicates an expected call of Commit.
-func (mr *MockClientMockRecorder) Commit(ctx, name, candidate any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Commit", reflect.TypeOf((*MockClient)(nil).Commit), ctx, name, candidate)
-}
-
-// Create mocks base method.
-func (m *MockClient) Create(ctx context.Context, name string, ephemeral, cached bool) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Create", ctx, name, ephemeral, cached)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Create indicates an expected call of Create.
-func (mr *MockClientMockRecorder) Create(ctx, name, ephemeral, cached any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockClient)(nil).Create), ctx, name, ephemeral, cached)
-}
-
-// CreateCandidate mocks base method.
-func (m *MockClient) CreateCandidate(ctx context.Context, name, candidate, owner string, priority int32) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreateCandidate", ctx, name, candidate, owner, priority)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// CreateCandidate indicates an expected call of CreateCandidate.
-func (mr *MockClientMockRecorder) CreateCandidate(ctx, name, candidate, owner, priority any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCandidate", reflect.TypeOf((*MockClient)(nil).CreateCandidate), ctx, name, candidate, owner, priority)
-}
-
-// CreatePruneID mocks base method.
-func (m *MockClient) CreatePruneID(ctx context.Context, name string, force bool) (string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "CreatePruneID", ctx, name, force)
- ret0, _ := ret[0].(string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// CreatePruneID indicates an expected call of CreatePruneID.
-func (mr *MockClientMockRecorder) CreatePruneID(ctx, name, force any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreatePruneID", reflect.TypeOf((*MockClient)(nil).CreatePruneID), ctx, name, force)
-}
-
-// Delete mocks base method.
-func (m *MockClient) Delete(ctx context.Context, name string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Delete", ctx, name)
- ret0, _ := ret[0].(error)
- return ret0
-}
-
-// Delete indicates an expected call of Delete.
-func (mr *MockClientMockRecorder) Delete(ctx, name any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockClient)(nil).Delete), ctx, name)
-}
-
-// DeleteCandidate mocks base method.
-func (m *MockClient) DeleteCandidate(ctx context.Context, name, candidate string) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "DeleteCandidate", ctx, name, candidate)
- ret0, _ := ret[0].(error)
+ ret := m.ctrl.Call(m, "InstanceExists", ctx, cacheInstanceName)
+ ret0, _ := ret[0].(bool)
return ret0
}
-// DeleteCandidate indicates an expected call of DeleteCandidate.
-func (mr *MockClientMockRecorder) DeleteCandidate(ctx, name, candidate any) *gomock.Call {
+// InstanceExists indicates an expected call of InstanceExists.
+func (mr *MockClientMockRecorder) InstanceExists(ctx, cacheInstanceName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCandidate", reflect.TypeOf((*MockClient)(nil).DeleteCandidate), ctx, name, candidate)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceExists", reflect.TypeOf((*MockClient)(nil).InstanceExists), ctx, cacheInstanceName)
}
-// Discard mocks base method.
-func (m *MockClient) Discard(ctx context.Context, name, candidate string) error {
+// InstanceIntentDelete mocks base method.
+func (m *MockClient) InstanceIntentDelete(ctx context.Context, cacheName, intentName string) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Discard", ctx, name, candidate)
+ ret := m.ctrl.Call(m, "InstanceIntentDelete", ctx, cacheName, intentName)
ret0, _ := ret[0].(error)
return ret0
}
-// Discard indicates an expected call of Discard.
-func (mr *MockClientMockRecorder) Discard(ctx, name, candidate any) *gomock.Call {
+// InstanceIntentDelete indicates an expected call of InstanceIntentDelete.
+func (mr *MockClientMockRecorder) InstanceIntentDelete(ctx, cacheName, intentName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Discard", reflect.TypeOf((*MockClient)(nil).Discard), ctx, name, candidate)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIntentDelete", reflect.TypeOf((*MockClient)(nil).InstanceIntentDelete), ctx, cacheName, intentName)
}
-// Exists mocks base method.
-func (m *MockClient) Exists(ctx context.Context, name string) (bool, error) {
+// InstanceIntentExists mocks base method.
+func (m *MockClient) InstanceIntentExists(ctx context.Context, cacheName, intentName string) (bool, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Exists", ctx, name)
+ ret := m.ctrl.Call(m, "InstanceIntentExists", ctx, cacheName, intentName)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// Exists indicates an expected call of Exists.
-func (mr *MockClientMockRecorder) Exists(ctx, name any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Exists", reflect.TypeOf((*MockClient)(nil).Exists), ctx, name)
-}
-
-// GetCandidates mocks base method.
-func (m *MockClient) GetCandidates(ctx context.Context, name string) ([]*cache.CandidateDetails, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetCandidates", ctx, name)
- ret0, _ := ret[0].([]*cache.CandidateDetails)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetCandidates indicates an expected call of GetCandidates.
-func (mr *MockClientMockRecorder) GetCandidates(ctx, name any) *gomock.Call {
+// InstanceIntentExists indicates an expected call of InstanceIntentExists.
+func (mr *MockClientMockRecorder) InstanceIntentExists(ctx, cacheName, intentName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetCandidates", reflect.TypeOf((*MockClient)(nil).GetCandidates), ctx, name)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIntentExists", reflect.TypeOf((*MockClient)(nil).InstanceIntentExists), ctx, cacheName, intentName)
}
-// GetChanges mocks base method.
-func (m *MockClient) GetChanges(ctx context.Context, name, candidate string) ([]*cache0.Change, error) {
+// InstanceIntentGet mocks base method.
+func (m *MockClient) InstanceIntentGet(ctx context.Context, cacheName, intentName string) (*tree_persist.Intent, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetChanges", ctx, name, candidate)
- ret0, _ := ret[0].([]*cache0.Change)
+ ret := m.ctrl.Call(m, "InstanceIntentGet", ctx, cacheName, intentName)
+ ret0, _ := ret[0].(*tree_persist.Intent)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// GetChanges indicates an expected call of GetChanges.
-func (mr *MockClientMockRecorder) GetChanges(ctx, name, candidate any) *gomock.Call {
+// InstanceIntentGet indicates an expected call of InstanceIntentGet.
+func (mr *MockClientMockRecorder) InstanceIntentGet(ctx, cacheName, intentName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetChanges", reflect.TypeOf((*MockClient)(nil).GetChanges), ctx, name, candidate)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIntentGet", reflect.TypeOf((*MockClient)(nil).InstanceIntentGet), ctx, cacheName, intentName)
}
-// GetKeys mocks base method.
-func (m *MockClient) GetKeys(ctx context.Context, name string, store cachepb.Store) (chan *cache0.Update, error) {
+// InstanceIntentGetAll mocks base method.
+func (m *MockClient) InstanceIntentGetAll(ctx context.Context, cacheName string, intentChan chan<- *tree_persist.Intent, errChan chan<- error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetKeys", ctx, name, store)
- ret0, _ := ret[0].(chan *cache0.Update)
- ret1, _ := ret[1].(error)
- return ret0, ret1
+ m.ctrl.Call(m, "InstanceIntentGetAll", ctx, cacheName, intentChan, errChan)
}
-// GetKeys indicates an expected call of GetKeys.
-func (mr *MockClientMockRecorder) GetKeys(ctx, name, store any) *gomock.Call {
+// InstanceIntentGetAll indicates an expected call of InstanceIntentGetAll.
+func (mr *MockClientMockRecorder) InstanceIntentGetAll(ctx, cacheName, intentChan, errChan any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetKeys", reflect.TypeOf((*MockClient)(nil).GetKeys), ctx, name, store)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIntentGetAll", reflect.TypeOf((*MockClient)(nil).InstanceIntentGetAll), ctx, cacheName, intentChan, errChan)
}
-// HasCandidate mocks base method.
-func (m *MockClient) HasCandidate(ctx context.Context, name, candidate string) (bool, error) {
+// InstanceIntentModify mocks base method.
+func (m *MockClient) InstanceIntentModify(ctx context.Context, cacheName string, intent *tree_persist.Intent) error {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "HasCandidate", ctx, name, candidate)
- ret0, _ := ret[0].(bool)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// HasCandidate indicates an expected call of HasCandidate.
-func (mr *MockClientMockRecorder) HasCandidate(ctx, name, candidate any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasCandidate", reflect.TypeOf((*MockClient)(nil).HasCandidate), ctx, name, candidate)
-}
-
-// List mocks base method.
-func (m *MockClient) List(ctx context.Context) ([]string, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "List", ctx)
- ret0, _ := ret[0].([]string)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// List indicates an expected call of List.
-func (mr *MockClientMockRecorder) List(ctx any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockClient)(nil).List), ctx)
-}
-
-// Modify mocks base method.
-func (m *MockClient) Modify(ctx context.Context, name string, opts *cache0.Opts, dels [][]string, upds []*cache0.Update) error {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Modify", ctx, name, opts, dels, upds)
+ ret := m.ctrl.Call(m, "InstanceIntentModify", ctx, cacheName, intent)
ret0, _ := ret[0].(error)
return ret0
}
-// Modify indicates an expected call of Modify.
-func (mr *MockClientMockRecorder) Modify(ctx, name, opts, dels, upds any) *gomock.Call {
+// InstanceIntentModify indicates an expected call of InstanceIntentModify.
+func (mr *MockClientMockRecorder) InstanceIntentModify(ctx, cacheName, intent any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Modify", reflect.TypeOf((*MockClient)(nil).Modify), ctx, name, opts, dels, upds)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIntentModify", reflect.TypeOf((*MockClient)(nil).InstanceIntentModify), ctx, cacheName, intent)
}
-// NewUpdate mocks base method.
-func (m *MockClient) NewUpdate(arg0 *schema_server.Update) (*cache0.Update, error) {
+// InstanceIntentsList mocks base method.
+func (m *MockClient) InstanceIntentsList(ctx context.Context, cacheInstanceName string) ([]string, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "NewUpdate", arg0)
- ret0, _ := ret[0].(*cache0.Update)
+ ret := m.ctrl.Call(m, "InstanceIntentsList", ctx, cacheInstanceName)
+ ret0, _ := ret[0].([]string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// NewUpdate indicates an expected call of NewUpdate.
-func (mr *MockClientMockRecorder) NewUpdate(arg0 any) *gomock.Call {
+// InstanceIntentsList indicates an expected call of InstanceIntentsList.
+func (mr *MockClientMockRecorder) InstanceIntentsList(ctx, cacheInstanceName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewUpdate", reflect.TypeOf((*MockClient)(nil).NewUpdate), arg0)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstanceIntentsList", reflect.TypeOf((*MockClient)(nil).InstanceIntentsList), ctx, cacheInstanceName)
}
-// Read mocks base method.
-func (m *MockClient) Read(ctx context.Context, name string, opts *cache0.Opts, paths [][]string, period time.Duration) []*cache0.Update {
+// InstancesList mocks base method.
+func (m *MockClient) InstancesList(ctx context.Context) []string {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "Read", ctx, name, opts, paths, period)
- ret0, _ := ret[0].([]*cache0.Update)
- return ret0
-}
-
-// Read indicates an expected call of Read.
-func (mr *MockClientMockRecorder) Read(ctx, name, opts, paths, period any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Read", reflect.TypeOf((*MockClient)(nil).Read), ctx, name, opts, paths, period)
-}
-
-// ReadCh mocks base method.
-func (m *MockClient) ReadCh(ctx context.Context, name string, opts *cache0.Opts, paths [][]string, period time.Duration) chan *cache0.Update {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ReadCh", ctx, name, opts, paths, period)
- ret0, _ := ret[0].(chan *cache0.Update)
+ ret := m.ctrl.Call(m, "InstancesList", ctx)
+ ret0, _ := ret[0].([]string)
return ret0
}
-// ReadCh indicates an expected call of ReadCh.
-func (mr *MockClientMockRecorder) ReadCh(ctx, name, opts, paths, period any) *gomock.Call {
+// InstancesList indicates an expected call of InstancesList.
+func (mr *MockClientMockRecorder) InstancesList(ctx any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadCh", reflect.TypeOf((*MockClient)(nil).ReadCh), ctx, name, opts, paths, period)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InstancesList", reflect.TypeOf((*MockClient)(nil).InstancesList), ctx)
}
diff --git a/mocks/mocktreeentry/entry.go b/mocks/mocktreeentry/entry.go
index a79b8f2c..032e640a 100644
--- a/mocks/mocktreeentry/entry.go
+++ b/mocks/mocktreeentry/entry.go
@@ -14,10 +14,10 @@ import (
reflect "reflect"
etree "github.com/beevik/etree"
- cache "github.com/sdcio/data-server/pkg/cache"
tree "github.com/sdcio/data-server/pkg/tree"
importer "github.com/sdcio/data-server/pkg/tree/importer"
- types "github.com/sdcio/data-server/pkg/types"
+ tree_persist "github.com/sdcio/data-server/pkg/tree/tree_persist"
+ types "github.com/sdcio/data-server/pkg/tree/types"
schema_server "github.com/sdcio/sdc-protos/sdcpb"
gomock "go.uber.org/mock/gomock"
)
@@ -46,19 +46,19 @@ func (m *MockEntry) EXPECT() *MockEntryMockRecorder {
return m.recorder
}
-// AddCacheUpdateRecursive mocks base method.
-func (m *MockEntry) AddCacheUpdateRecursive(ctx context.Context, u *cache.Update, flags *tree.UpdateInsertFlags) (tree.Entry, error) {
+// AddUpdateRecursive mocks base method.
+func (m *MockEntry) AddUpdateRecursive(ctx context.Context, u *types.Update, flags *types.UpdateInsertFlags) (tree.Entry, error) {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "AddCacheUpdateRecursive", ctx, u, flags)
+ ret := m.ctrl.Call(m, "AddUpdateRecursive", ctx, u, flags)
ret0, _ := ret[0].(tree.Entry)
ret1, _ := ret[1].(error)
return ret0, ret1
}
-// AddCacheUpdateRecursive indicates an expected call of AddCacheUpdateRecursive.
-func (mr *MockEntryMockRecorder) AddCacheUpdateRecursive(ctx, u, flags any) *gomock.Call {
+// AddUpdateRecursive indicates an expected call of AddUpdateRecursive.
+func (mr *MockEntryMockRecorder) AddUpdateRecursive(ctx, u, flags any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCacheUpdateRecursive", reflect.TypeOf((*MockEntry)(nil).AddCacheUpdateRecursive), ctx, u, flags)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUpdateRecursive", reflect.TypeOf((*MockEntry)(nil).AddUpdateRecursive), ctx, u, flags)
}
// FilterChilds mocks base method.
@@ -77,9 +77,11 @@ func (mr *MockEntryMockRecorder) FilterChilds(keys any) *gomock.Call {
}
// FinishInsertionPhase mocks base method.
-func (m *MockEntry) FinishInsertionPhase(ctx context.Context) {
+func (m *MockEntry) FinishInsertionPhase(ctx context.Context) error {
m.ctrl.T.Helper()
- m.ctrl.Call(m, "FinishInsertionPhase", ctx)
+ ret := m.ctrl.Call(m, "FinishInsertionPhase", ctx)
+ ret0, _ := ret[0].(error)
+ return ret0
}
// FinishInsertionPhase indicates an expected call of FinishInsertionPhase.
@@ -89,10 +91,10 @@ func (mr *MockEntryMockRecorder) FinishInsertionPhase(ctx any) *gomock.Call {
}
// GetByOwner mocks base method.
-func (m *MockEntry) GetByOwner(owner string, result []*tree.LeafEntry) []*tree.LeafEntry {
+func (m *MockEntry) GetByOwner(owner string, result []*tree.LeafEntry) tree.LeafVariantSlice {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetByOwner", owner, result)
- ret0, _ := ret[0].([]*tree.LeafEntry)
+ ret0, _ := ret[0].(tree.LeafVariantSlice)
return ret0
}
@@ -103,10 +105,10 @@ func (mr *MockEntryMockRecorder) GetByOwner(owner, result any) *gomock.Call {
}
// GetDeletes mocks base method.
-func (m *MockEntry) GetDeletes(entries []tree.DeleteEntry, aggregatePaths bool) ([]tree.DeleteEntry, error) {
+func (m *MockEntry) GetDeletes(entries []types.DeleteEntry, aggregatePaths bool) ([]types.DeleteEntry, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetDeletes", entries, aggregatePaths)
- ret0, _ := ret[0].([]tree.DeleteEntry)
+ ret0, _ := ret[0].([]types.DeleteEntry)
ret1, _ := ret[1].(error)
return ret0, ret1
}
@@ -244,6 +246,18 @@ func (mr *MockEntryMockRecorder) IsRoot() *gomock.Call {
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsRoot", reflect.TypeOf((*MockEntry)(nil).IsRoot))
}
+// MarkOwnerDelete mocks base method.
+func (m *MockEntry) MarkOwnerDelete(o string, onlyIntended bool) {
+ m.ctrl.T.Helper()
+ m.ctrl.Call(m, "MarkOwnerDelete", o, onlyIntended)
+}
+
+// MarkOwnerDelete indicates an expected call of MarkOwnerDelete.
+func (mr *MockEntryMockRecorder) MarkOwnerDelete(o, onlyIntended any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MarkOwnerDelete", reflect.TypeOf((*MockEntry)(nil).MarkOwnerDelete), o, onlyIntended)
+}
+
// Navigate mocks base method.
func (m *MockEntry) Navigate(ctx context.Context, path []string, isRootPath bool) (tree.Entry, error) {
m.ctrl.T.Helper()
@@ -290,10 +304,10 @@ func (mr *MockEntryMockRecorder) NavigateSdcpbPath(ctx, path, isRootPath any) *g
}
// Path mocks base method.
-func (m *MockEntry) Path() tree.PathSlice {
+func (m *MockEntry) Path() types.PathSlice {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Path")
- ret0, _ := ret[0].(tree.PathSlice)
+ ret0, _ := ret[0].(types.PathSlice)
return ret0
}
@@ -406,6 +420,21 @@ func (mr *MockEntryMockRecorder) ToXML(onlyNewOrUpdated, honorNamespace, operati
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToXML", reflect.TypeOf((*MockEntry)(nil).ToXML), onlyNewOrUpdated, honorNamespace, operationWithNamespace, useOperationRemove)
}
+// TreeExport mocks base method.
+func (m *MockEntry) TreeExport(owner string) ([]*tree_persist.TreeElement, error) {
+ m.ctrl.T.Helper()
+ ret := m.ctrl.Call(m, "TreeExport", owner)
+ ret0, _ := ret[0].([]*tree_persist.TreeElement)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+// TreeExport indicates an expected call of TreeExport.
+func (mr *MockEntryMockRecorder) TreeExport(owner any) *gomock.Call {
+ mr.mock.ctrl.T.Helper()
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TreeExport", reflect.TypeOf((*MockEntry)(nil).TreeExport), owner)
+}
+
// Validate mocks base method.
func (m *MockEntry) Validate(ctx context.Context, resultChan chan<- *types.ValidationResultEntry, concurrent bool) {
m.ctrl.T.Helper()
@@ -490,29 +519,17 @@ func (mr *MockEntryMockRecorder) getHighestPrecedenceLeafValue(arg0 any) *gomock
}
// getHighestPrecedenceValueOfBranch mocks base method.
-func (m *MockEntry) getHighestPrecedenceValueOfBranch() int32 {
+func (m *MockEntry) getHighestPrecedenceValueOfBranch(includeDeleted bool) int32 {
m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "getHighestPrecedenceValueOfBranch")
+ ret := m.ctrl.Call(m, "getHighestPrecedenceValueOfBranch", includeDeleted)
ret0, _ := ret[0].(int32)
return ret0
}
// getHighestPrecedenceValueOfBranch indicates an expected call of getHighestPrecedenceValueOfBranch.
-func (mr *MockEntryMockRecorder) getHighestPrecedenceValueOfBranch() *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getHighestPrecedenceValueOfBranch", reflect.TypeOf((*MockEntry)(nil).getHighestPrecedenceValueOfBranch))
-}
-
-// markOwnerDelete mocks base method.
-func (m *MockEntry) markOwnerDelete(o string, onlyIntended bool) {
- m.ctrl.T.Helper()
- m.ctrl.Call(m, "markOwnerDelete", o, onlyIntended)
-}
-
-// markOwnerDelete indicates an expected call of markOwnerDelete.
-func (mr *MockEntryMockRecorder) markOwnerDelete(o, onlyIntended any) *gomock.Call {
+func (mr *MockEntryMockRecorder) getHighestPrecedenceValueOfBranch(includeDeleted any) *gomock.Call {
mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "markOwnerDelete", reflect.TypeOf((*MockEntry)(nil).markOwnerDelete), o, onlyIntended)
+ return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "getHighestPrecedenceValueOfBranch", reflect.TypeOf((*MockEntry)(nil).getHighestPrecedenceValueOfBranch), includeDeleted)
}
// remainsToExist mocks base method.
diff --git a/mocks/mockvalidationclient/client.go b/mocks/mockvalidationclient/client.go
deleted file mode 100644
index 3a4077e5..00000000
--- a/mocks/mockvalidationclient/client.go
+++ /dev/null
@@ -1,148 +0,0 @@
-// Code generated by MockGen. DO NOT EDIT.
-// Source: pkg/datastore/clients/validationClient.go
-//
-// Generated by this command:
-//
-// mockgen -package=mockvalidationclient -source=pkg/datastore/clients/validationClient.go -destination=./mocks/mockvalidationclient/client.go
-//
-
-// Package mockvalidationclient is a generated GoMock package.
-package mockvalidationclient
-
-import (
- context "context"
- reflect "reflect"
- time "time"
-
- cache "github.com/sdcio/data-server/pkg/cache"
- schema_server "github.com/sdcio/sdc-protos/sdcpb"
- gomock "go.uber.org/mock/gomock"
-)
-
-// MockValidationClient is a mock of ValidationClient interface.
-type MockValidationClient struct {
- ctrl *gomock.Controller
- recorder *MockValidationClientMockRecorder
- isgomock struct{}
-}
-
-// MockValidationClientMockRecorder is the mock recorder for MockValidationClient.
-type MockValidationClientMockRecorder struct {
- mock *MockValidationClient
-}
-
-// NewMockValidationClient creates a new mock instance.
-func NewMockValidationClient(ctrl *gomock.Controller) *MockValidationClient {
- mock := &MockValidationClient{ctrl: ctrl}
- mock.recorder = &MockValidationClientMockRecorder{mock}
- return mock
-}
-
-// EXPECT returns an object that allows the caller to indicate expected use.
-func (m *MockValidationClient) EXPECT() *MockValidationClientMockRecorder {
- return m.recorder
-}
-
-// GetSchemaElements mocks base method.
-func (m *MockValidationClient) GetSchemaElements(ctx context.Context, p *schema_server.Path, done chan struct{}) (chan *schema_server.GetSchemaResponse, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetSchemaElements", ctx, p, done)
- ret0, _ := ret[0].(chan *schema_server.GetSchemaResponse)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetSchemaElements indicates an expected call of GetSchemaElements.
-func (mr *MockValidationClientMockRecorder) GetSchemaElements(ctx, p, done any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchemaElements", reflect.TypeOf((*MockValidationClient)(nil).GetSchemaElements), ctx, p, done)
-}
-
-// GetSchemaSdcpbPath mocks base method.
-func (m *MockValidationClient) GetSchemaSdcpbPath(ctx context.Context, path *schema_server.Path) (*schema_server.GetSchemaResponse, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetSchemaSdcpbPath", ctx, path)
- ret0, _ := ret[0].(*schema_server.GetSchemaResponse)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetSchemaSdcpbPath indicates an expected call of GetSchemaSdcpbPath.
-func (mr *MockValidationClientMockRecorder) GetSchemaSdcpbPath(ctx, path any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchemaSdcpbPath", reflect.TypeOf((*MockValidationClient)(nil).GetSchemaSdcpbPath), ctx, path)
-}
-
-// GetSchemaSlicePath mocks base method.
-func (m *MockValidationClient) GetSchemaSlicePath(ctx context.Context, path []string) (*schema_server.GetSchemaResponse, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetSchemaSlicePath", ctx, path)
- ret0, _ := ret[0].(*schema_server.GetSchemaResponse)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetSchemaSlicePath indicates an expected call of GetSchemaSlicePath.
-func (mr *MockValidationClientMockRecorder) GetSchemaSlicePath(ctx, path any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSchemaSlicePath", reflect.TypeOf((*MockValidationClient)(nil).GetSchemaSlicePath), ctx, path)
-}
-
-// GetValue mocks base method.
-func (m *MockValidationClient) GetValue(ctx context.Context, candidateName string, path *schema_server.Path) (*schema_server.TypedValue, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetValue", ctx, candidateName, path)
- ret0, _ := ret[0].(*schema_server.TypedValue)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetValue indicates an expected call of GetValue.
-func (mr *MockValidationClientMockRecorder) GetValue(ctx, candidateName, path any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValue", reflect.TypeOf((*MockValidationClient)(nil).GetValue), ctx, candidateName, path)
-}
-
-// GetValues mocks base method.
-func (m *MockValidationClient) GetValues(ctx context.Context, candidateName string, path *schema_server.Path) ([]*schema_server.TypedValue, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "GetValues", ctx, candidateName, path)
- ret0, _ := ret[0].([]*schema_server.TypedValue)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// GetValues indicates an expected call of GetValues.
-func (mr *MockValidationClientMockRecorder) GetValues(ctx, candidateName, path any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValues", reflect.TypeOf((*MockValidationClient)(nil).GetValues), ctx, candidateName, path)
-}
-
-// ReadIntended mocks base method.
-func (m *MockValidationClient) ReadIntended(ctx context.Context, opts *cache.Opts, paths [][]string, period time.Duration) []*cache.Update {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ReadIntended", ctx, opts, paths, period)
- ret0, _ := ret[0].([]*cache.Update)
- return ret0
-}
-
-// ReadIntended indicates an expected call of ReadIntended.
-func (mr *MockValidationClientMockRecorder) ReadIntended(ctx, opts, paths, period any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReadIntended", reflect.TypeOf((*MockValidationClient)(nil).ReadIntended), ctx, opts, paths, period)
-}
-
-// ToPath mocks base method.
-func (m *MockValidationClient) ToPath(ctx context.Context, path []string) (*schema_server.Path, error) {
- m.ctrl.T.Helper()
- ret := m.ctrl.Call(m, "ToPath", ctx, path)
- ret0, _ := ret[0].(*schema_server.Path)
- ret1, _ := ret[1].(error)
- return ret0, ret1
-}
-
-// ToPath indicates an expected call of ToPath.
-func (mr *MockValidationClientMockRecorder) ToPath(ctx, path any) *gomock.Call {
- mr.mock.ctrl.T.Helper()
- return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToPath", reflect.TypeOf((*MockValidationClient)(nil).ToPath), ctx, path)
-}
diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go
index 0bc4e7bc..4a58f8a0 100644
--- a/pkg/cache/cache.go
+++ b/pkg/cache/cache.go
@@ -15,69 +15,26 @@
package cache
import (
- "bytes"
"context"
"fmt"
- "time"
- "github.com/sdcio/cache/pkg/cache"
- "github.com/sdcio/cache/proto/cachepb"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"google.golang.org/protobuf/proto"
)
type Client interface {
- // Create a cache
- Create(ctx context.Context, name string, ephemeral bool, cached bool) error
- // List caches
- List(ctx context.Context) ([]string, error)
- // Delete delete cache or cache candidate
- Delete(ctx context.Context, name string) error
- // Exists check if cache instance exists
- Exists(ctx context.Context, name string) (bool, error)
- // CreateCandidate create a candidate
- CreateCandidate(ctx context.Context, name, candidate, owner string, priority int32) error
- // GetCandidates get list of candidates
- GetCandidates(ctx context.Context, name string) ([]*cache.CandidateDetails, error)
- // HasCandidate check if a candidate exists
- HasCandidate(ctx context.Context, name, candidate string) (bool, error)
- // DeleteCandidate deletes a candidate
- DeleteCandidate(ctx context.Context, name, candidate string) error
- // Clone a cache
- Clone(ctx context.Context, name, clone string) error
- // CreatePruneID
- CreatePruneID(ctx context.Context, name string, force bool) (string, error)
- // ApplyPrune
- ApplyPrune(ctx context.Context, name, id string) error
- // Modify send a stream of modifications (update or delete) to a cache, or candidate
- Modify(ctx context.Context, name string, opts *Opts, dels [][]string, upds []*Update) error
- // Read from a cache or candidate
- Read(ctx context.Context, name string, opts *Opts, paths [][]string, period time.Duration) []*Update
- // ReadCh read from a cache or candidate, get results through a channel
- ReadCh(ctx context.Context, name string, opts *Opts, paths [][]string, period time.Duration) chan *Update
- // GetChanges present in a candidate
- GetChanges(ctx context.Context, name, candidate string) ([]*Change, error)
- // Discard changes made to a candidate
- Discard(ctx context.Context, name, candidate string) error
- // Commit a candidate changes into the intended store
- Commit(ctx context.Context, name, candidate string) error
- // NewUpdate build a cache update from a sdcpb.Update
- NewUpdate(*sdcpb.Update) (*Update, error)
- // GetKeys retrieve the Keys of the specified store
- GetKeys(ctx context.Context, name string, store cachepb.Store) (chan *Update, error)
- // disconnect from the cache
- Close() error
-}
-
-type KeyData struct {
- Path []string
- Intents []IntentMeta
-}
-
-type IntentMeta struct {
- Owner string
- Priority int32
- Ts int64
+ InstanceCreate(ctx context.Context, cacheInstanceName string) error
+ InstanceDelete(ctx context.Context, cacheInstanceName string) error
+ InstanceClose(ctx context.Context, cacheInstanceName string) error
+ InstanceExists(ctx context.Context, cacheInstanceName string) bool
+ InstancesList(ctx context.Context) []string
+ InstanceIntentsList(ctx context.Context, cacheInstanceName string) ([]string, error)
+ InstanceIntentGet(ctx context.Context, cacheName string, intentName string) (*tree_persist.Intent, error)
+ InstanceIntentModify(ctx context.Context, cacheName string, intent *tree_persist.Intent) error
+ InstanceIntentDelete(ctx context.Context, cacheName string, intentName string) error
+ InstanceIntentExists(ctx context.Context, cacheName string, intentName string) (bool, error)
+ InstanceIntentGetAll(ctx context.Context, cacheName string, excludeIntentNames []string, intentChan chan<- *tree_persist.Intent, errChan chan<- error)
}
type Update struct {
@@ -136,36 +93,3 @@ func (u *Update) String() string {
}
return fmt.Sprintf("path: %s, owner: %s, priority: %d, value: %s", u.path, u.owner, u.priority, val)
}
-
-// EqualSkipPath checks the equality of two updates.
-// It however skips comparing paths and timestamps.
-// This is a shortcut for performace, for cases in which it is already clear that the path is definately equal.
-func (u *Update) EqualSkipPath(other *Update) bool {
- return u.owner == other.owner && u.priority == other.priority && bytes.Equal(u.value, other.value)
-}
-
-type Change struct {
- Update *Update
- Delete []string
-}
-
-type Opts struct {
- Store cachepb.Store
- Owner string // represents the intent name
- Priority int32
- PriorityCount uint64
- KeysOnly bool
-}
-
-func getStore(s cachepb.Store) cache.Store {
- switch s {
- default: //case cachepb.Store_CONFIG:
- return cache.StoreConfig
- case cachepb.Store_STATE:
- return cache.StoreState
- case cachepb.Store_INTENDED:
- return cache.StoreIntended
- case cachepb.Store_INTENTS:
- return cache.StoreIntents
- }
-}
diff --git a/pkg/cache/cacheClientBound.go b/pkg/cache/cacheClientBound.go
new file mode 100644
index 00000000..65cef808
--- /dev/null
+++ b/pkg/cache/cacheClientBound.go
@@ -0,0 +1,77 @@
+// Copyright 2024 Nokia
+//
+// Licensed 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 cache
+
+import (
+ "context"
+
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
+)
+
+type CacheClientBound interface {
+ InstanceCreate(ctx context.Context) error
+ InstanceDelete(ctx context.Context) error
+ InstanceExists(ctx context.Context) bool
+ IntentsList(ctx context.Context) ([]string, error)
+ IntentGet(ctx context.Context, intentName string) (*tree_persist.Intent, error)
+ IntentModify(ctx context.Context, intent *tree_persist.Intent) error
+ IntentDelete(ctx context.Context, intentName string) error
+ IntentExists(ctx context.Context, intentName string) (bool, error)
+ IntentGetAll(ctx context.Context, excludeIntentNames []string, intentChan chan<- *tree_persist.Intent, errChan chan<- error)
+ InstanceClose(ctx context.Context) error
+}
+
+type CacheClientBoundImpl struct {
+ cacheClient Client
+ cacheName string
+}
+
+func NewCacheClientBound(name string, c Client) *CacheClientBoundImpl {
+ return &CacheClientBoundImpl{
+ cacheClient: c,
+ cacheName: name,
+ }
+}
+
+func (c *CacheClientBoundImpl) InstanceCreate(ctx context.Context) error {
+ return c.cacheClient.InstanceCreate(ctx, c.cacheName)
+}
+func (c *CacheClientBoundImpl) InstanceDelete(ctx context.Context) error {
+ return c.cacheClient.InstanceDelete(ctx, c.cacheName)
+}
+func (c *CacheClientBoundImpl) InstanceClose(ctx context.Context) error {
+ return c.cacheClient.InstanceClose(ctx, c.cacheName)
+}
+func (c *CacheClientBoundImpl) InstanceExists(ctx context.Context) bool {
+ return c.cacheClient.InstanceExists(ctx, c.cacheName)
+}
+func (c *CacheClientBoundImpl) IntentsList(ctx context.Context) ([]string, error) {
+ return c.cacheClient.InstanceIntentsList(ctx, c.cacheName)
+}
+func (c *CacheClientBoundImpl) IntentGet(ctx context.Context, intentName string) (*tree_persist.Intent, error) {
+ return c.cacheClient.InstanceIntentGet(ctx, c.cacheName, intentName)
+}
+func (c *CacheClientBoundImpl) IntentModify(ctx context.Context, intent *tree_persist.Intent) error {
+ return c.cacheClient.InstanceIntentModify(ctx, c.cacheName, intent)
+}
+func (c *CacheClientBoundImpl) IntentDelete(ctx context.Context, intentName string) error {
+ return c.cacheClient.InstanceIntentDelete(ctx, c.cacheName, intentName)
+}
+func (c *CacheClientBoundImpl) IntentExists(ctx context.Context, intentName string) (bool, error) {
+ return c.cacheClient.InstanceIntentExists(ctx, c.cacheName, intentName)
+}
+func (c *CacheClientBoundImpl) IntentGetAll(ctx context.Context, excludeIntentNames []string, intentChan chan<- *tree_persist.Intent, errChan chan<- error) {
+ c.cacheClient.InstanceIntentGetAll(ctx, c.cacheName, excludeIntentNames, intentChan, errChan)
+}
diff --git a/pkg/cache/local.go b/pkg/cache/local.go
index 9d9a8568..348a868a 100644
--- a/pkg/cache/local.go
+++ b/pkg/cache/local.go
@@ -16,262 +16,92 @@ package cache
import (
"context"
- "fmt"
- "sort"
- "time"
"github.com/sdcio/cache/pkg/cache"
"github.com/sdcio/cache/pkg/config"
- "github.com/sdcio/cache/proto/cachepb"
- "github.com/sdcio/schema-server/pkg/utils"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- log "github.com/sirupsen/logrus"
+ "github.com/sdcio/cache/pkg/store/filesystem"
+ "github.com/sdcio/cache/pkg/types"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
"google.golang.org/protobuf/proto"
)
-type localCache struct {
- c cache.Cache
-}
-
func NewLocalCache(cfg *config.CacheConfig) (Client, error) {
- lc := &localCache{
- c: cache.New(cfg),
- }
- err := lc.c.Init(context.TODO())
+
+ fnc, err := filesystem.PreConfigureFilesystemInitFunc(cfg.Dir)
if err != nil {
return nil, err
}
- return lc, nil
-}
-
-func (c *localCache) Create(ctx context.Context, name string, _ bool, _ bool) error {
- return c.c.Create(ctx, &cache.CacheInstanceConfig{
- Name: name,
- })
-}
-
-func (c *localCache) List(ctx context.Context) ([]string, error) {
- return c.c.List(ctx), nil
-}
-func (c *localCache) HasCandidate(ctx context.Context, name, candidate string) (bool, error) {
- cands, err := c.GetCandidates(ctx, name)
+ cache, err := cache.NewCache(fnc)
if err != nil {
- return false, err
- }
- for _, cand := range cands {
- if cand.CandidateName == candidate {
- return true, nil
- }
+ return nil, err
}
- return false, nil
-}
-func (c *localCache) GetCandidates(ctx context.Context, name string) ([]*cache.CandidateDetails, error) {
- return c.c.Candidates(ctx, name)
+ return &LocalCache{
+ Cache: cache,
+ }, nil
}
-func (c *localCache) Delete(ctx context.Context, name string) error {
- return c.c.Delete(ctx, name)
+type LocalCache struct {
+ *cache.Cache
}
-func (c *localCache) DeleteCandidate(ctx context.Context, name, candidate string) error {
- return c.c.Delete(ctx, fmt.Sprintf("%s/%s", name, candidate))
-}
-
-func (c *localCache) Exists(ctx context.Context, name string) (bool, error) {
- return c.c.Exists(ctx, name), nil
-}
+func (l *LocalCache) InstanceIntentGet(ctx context.Context, cacheName string, intentName string) (*tree_persist.Intent, error) {
+ b, err := l.Cache.InstanceIntentGet(ctx, cacheName, intentName)
+ if err != nil {
+ return nil, err
+ }
-func (c *localCache) CreateCandidate(ctx context.Context, name, candidate, owner string, priority int32) error {
- _, err := c.c.CreateCandidate(ctx, name, candidate, owner, priority)
- return err
+ result := &tree_persist.Intent{}
+ err = proto.Unmarshal(b, result)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
}
-func (c *localCache) Clone(ctx context.Context, name, clone string) error {
- _, err := c.c.Clone(ctx, name, clone)
- return err
-}
+func (l *LocalCache) InstanceIntentGetAll(ctx context.Context, cacheName string, excludeIntentNames []string, intentChanOrig chan<- *tree_persist.Intent, errChanOrig chan<- error) {
+ // create new channels
+ intentChan := make(chan *types.Intent, 5)
+ errChan := make(chan error, 1)
-func (c *localCache) Modify(ctx context.Context, name string, opts *Opts, dels [][]string, upds []*Update) error {
- if opts == nil {
- opts = &Opts{}
- }
- //
- var err error
- for _, del := range dels {
- err = c.c.DeletePrefix(ctx, name, &cache.Opts{
- Store: getStore(opts.Store),
- Path: [][]string{del}, // TODO:
- Owner: opts.Owner,
- Priority: opts.Priority,
- })
- if err != nil {
- return err
- }
- }
+ go l.Cache.InstanceIntentGetAll(ctx, cacheName, excludeIntentNames, intentChan, errChan)
- for _, upd := range upds {
- err = c.c.WriteValue(ctx, name, &cache.Opts{
- Store: getStore(opts.Store),
- Path: [][]string{upd.GetPath()},
- Owner: opts.Owner,
- Priority: opts.Priority,
- }, upd.Bytes())
- if err != nil {
- return err
- }
- }
- return nil
-}
+ defer close(intentChanOrig)
+ defer close(errChanOrig)
-func (c *localCache) Read(ctx context.Context, name string, opts *Opts, paths [][]string, period time.Duration) []*Update {
- ch := c.ReadCh(ctx, name, opts, paths, period)
- var upds = make([]*Update, 0, len(paths))
for {
select {
- case <-ctx.Done():
- return nil
- case u, ok := <-ch:
+ case <-ctx.Done(): // Or stop if context is canceled
+ return
+ case intent, ok := <-intentChan: // retieve intent
if !ok {
- sort.Slice(upds, func(i, j int) bool {
- return upds[i].ts < upds[j].ts
- })
- return upds
- }
- upds = append(upds, u)
- }
- }
-}
-
-func (c *localCache) GetKeys(ctx context.Context, name string, store cachepb.Store) (chan *Update, error) {
-
- if store != cachepb.Store_CONFIG && store != cachepb.Store_INTENDED {
- return nil, fmt.Errorf("getkeys only available with config or intended store")
- }
-
- cacheStore := getStore(store)
- entryCh, err := c.c.ReadKeys(ctx, name, cacheStore)
- outCh := make(chan *Update)
- if err != nil {
- close(outCh)
- return nil, err
- }
- go func() {
- defer close(outCh)
- for {
- select {
- case <-ctx.Done():
return
- case e, ok := <-entryCh:
- if !ok {
- return
- }
- if e == nil {
- continue //
- }
- outCh <- &Update{
- path: e.P,
- value: nil,
- priority: e.Priority,
- owner: e.Owner,
- ts: int64(e.Timestamp),
- }
}
- }
- }()
- return outCh, nil
-}
-
-func (c *localCache) ReadCh(ctx context.Context, name string, opts *Opts, paths [][]string, period time.Duration) chan *Update {
- if opts == nil {
- opts = &Opts{}
- }
- outCh := make(chan *Update, len(paths))
- go func() {
- defer close(outCh)
- ch, err := c.c.ReadValue(ctx, name, &cache.Opts{
- Store: getStore(opts.Store),
- Path: paths,
- Owner: opts.Owner,
- Priority: opts.Priority,
- PriorityCount: opts.PriorityCount,
- KeysOnly: opts.KeysOnly,
- })
- if err != nil {
- log.Errorf("failed to read path %v: %v", paths, err)
- return
- }
- for {
- select {
- case <-ctx.Done():
+ // unmarshall it into a tree_persit.Intent
+ tpIntent := &tree_persist.Intent{}
+ err := proto.Unmarshal(intent.Data(), tpIntent)
+ if err != nil {
+ errChanOrig <- err
return
- case e, ok := <-ch:
- if !ok {
- return
- }
- if e == nil {
- continue //
- }
- outCh <- &Update{
- path: e.P,
- value: e.V,
- priority: e.Priority,
- owner: e.Owner,
- ts: int64(e.Timestamp),
- }
}
+ // forward to caller
+ intentChanOrig <- tpIntent
+ case err, ok := <-errChan: // Handle errors after intents
+ if !ok {
+ errChan = nil // Mark errChan as nil so select ignores it
+ continue
+ }
+ errChanOrig <- err
+ return
}
- }()
- return outCh
-}
-
-func (c *localCache) GetChanges(ctx context.Context, name, candidate string) ([]*Change, error) {
- dels, entries, err := c.c.Diff(ctx, name, candidate)
- if err != nil {
- return nil, err
- }
- changes := make([]*Change, 0, len(dels)+len(entries))
- for _, del := range dels {
- changes = append(changes, &Change{Delete: del})
- }
- for _, entry := range entries {
- changes = append(changes, &Change{Update: &Update{
- path: entry.P,
- value: entry.V,
- }})
}
- return changes, nil
-}
-
-func (c *localCache) Discard(ctx context.Context, name, candidate string) error {
- return c.c.Discard(ctx, name, candidate)
-}
-
-func (c *localCache) Commit(ctx context.Context, name, candidate string) error {
- return c.c.Commit(ctx, name, candidate)
}
-func (c *localCache) CreatePruneID(ctx context.Context, name string, force bool) (string, error) {
- return c.c.CreatePruneID(ctx, name, force)
-}
-
-func (c *localCache) ApplyPrune(ctx context.Context, name, id string) error {
- return c.c.ApplyPrune(ctx, name, id)
-}
-
-func (c *localCache) NewUpdate(upd *sdcpb.Update) (*Update, error) {
- b, err := proto.Marshal(upd.Value)
+func (l *LocalCache) InstanceIntentModify(ctx context.Context, cacheName string, intent *tree_persist.Intent) error {
+ b, err := proto.Marshal(intent)
if err != nil {
- return nil, err
- }
- lupd := &Update{
- path: utils.ToStrings(upd.GetPath(), false, false),
- value: b,
+ return err
}
- return lupd, nil
-}
-
-func (c *localCache) Close() error {
- return c.c.Close()
+ return l.Cache.InstanceIntentModify(ctx, cacheName, intent.GetIntentName(), b)
}
diff --git a/pkg/cache/remote.go b/pkg/cache/remote.go
deleted file mode 100644
index 2844cf6d..00000000
--- a/pkg/cache/remote.go
+++ /dev/null
@@ -1,287 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 cache
-
-import (
- "context"
- "errors"
- "fmt"
- "sort"
- "time"
-
- "github.com/sdcio/cache/pkg/cache"
- "github.com/sdcio/cache/pkg/client"
- "github.com/sdcio/cache/proto/cachepb"
- "github.com/sdcio/schema-server/pkg/utils"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- log "github.com/sirupsen/logrus"
- "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/types/known/anypb"
-)
-
-type remoteCache struct {
- c *client.Client
-}
-
-func NewRemoteCache(ctx context.Context, addr string) (Client, error) {
- cc, err := client.New(ctx, &client.ClientConfig{Address: addr})
- if err != nil {
- return nil, err
- }
- return &remoteCache{
- c: cc,
- }, nil
-}
-
-func (c *remoteCache) Create(ctx context.Context, name string, ephemeral bool, cached bool) error {
- return c.c.Create(ctx, name)
-}
-
-func (c *remoteCache) List(ctx context.Context) ([]string, error) {
- return c.c.List(ctx)
-}
-
-func (c *remoteCache) GetKeys(ctx context.Context, name string, store cachepb.Store) (chan *Update, error) {
-
- if store != cachepb.Store_CONFIG && store != cachepb.Store_INTENDED {
- return nil, fmt.Errorf("getkeys only available with config or intended store")
- }
-
- outCh := make(chan *Update)
- entryCh, err := c.c.ReadKeys(ctx, name, store)
- if err != nil {
- close(outCh)
- return nil, err
- }
-
- go func() {
- defer close(outCh)
- for {
- select {
- case <-ctx.Done():
- return
- case e, ok := <-entryCh:
- if !ok {
- return
- }
- if e == nil {
- continue //
- }
- outCh <- &Update{
- path: e.Path,
- value: nil,
- priority: e.Priority,
- owner: e.Owner,
- ts: int64(e.Timestamp),
- }
- }
- }
- }()
- return outCh, nil
-}
-
-func (c *remoteCache) GetCandidates(ctx context.Context, name string) ([]*cache.CandidateDetails, error) {
- rsp, err := c.c.Get(ctx, name)
- if err != nil {
- return nil, err
- }
- rs := make([]*cache.CandidateDetails, 0, len(rsp.GetCandidate()))
- for _, candpb := range rsp.GetCandidate() {
- rs = append(rs, &cache.CandidateDetails{
- CacheName: name,
- CandidateName: candpb.GetName(),
- Owner: candpb.GetOwner(),
- Priority: candpb.GetPriority(),
- })
- }
- return rs, nil
-}
-
-func (c *remoteCache) HasCandidate(ctx context.Context, name, candidate string) (bool, error) {
- cands, err := c.GetCandidates(ctx, name)
- if err != nil {
- return false, err
- }
- for _, cand := range cands {
- if cand.CandidateName == candidate {
- return true, nil
- }
- }
- return false, nil
-}
-
-func (c *remoteCache) Delete(ctx context.Context, name string) error {
- return c.c.Delete(ctx, name)
-}
-
-func (c *remoteCache) Exists(ctx context.Context, name string) (bool, error) {
- return c.c.Exists(ctx, name)
-}
-
-func (c *remoteCache) CreateCandidate(ctx context.Context, name, candidate, owner string, priority int32) error {
- return c.c.CreateCandidate(ctx, name, candidate, owner, priority)
-}
-
-func (c *remoteCache) DeleteCandidate(ctx context.Context, name, candidate string) error {
- return c.c.Delete(ctx, fmt.Sprintf("%s/%s", name, candidate))
-}
-
-func (c *remoteCache) Clone(ctx context.Context, name, clone string) error {
- return c.c.Clone(ctx, name, clone)
-}
-
-func (c *remoteCache) Modify(ctx context.Context, name string, opts *Opts, dels [][]string, upds []*Update) error {
- pbUpds := make([]*cachepb.Update, 0, len(upds))
- for _, upd := range upds {
- pbUpds = append(pbUpds,
- &cachepb.Update{
- Path: upd.GetPath(),
- Value: &anypb.Any{
- Value: upd.Bytes(),
- },
- },
- )
- }
-
- wo := &client.ClientOpts{
- Owner: opts.Owner,
- Priority: opts.Priority,
- Store: getStore(opts.Store),
- PriorityCount: opts.PriorityCount,
- }
-
- return c.c.Modify(ctx, name, wo, dels, pbUpds)
-}
-
-func (c *remoteCache) Read(ctx context.Context, name string, opts *Opts, paths [][]string, period time.Duration) []*Update {
- outCh := c.ReadCh(ctx, name, opts, paths, period)
- updates := make([]*Update, 0)
- for {
- select {
- case <-ctx.Done():
- return nil
- case upd, ok := <-outCh:
- if !ok {
- sort.Slice(updates, func(i, j int) bool {
- return updates[i].ts < updates[j].ts
- })
- return updates
- }
- updates = append(updates, upd)
- }
- }
-}
-
-func (c *remoteCache) ReadCh(ctx context.Context, name string, opts *Opts, paths [][]string, period time.Duration) chan *Update {
- ro := &client.ClientOpts{
- Owner: opts.Owner,
- Priority: opts.Priority,
- Store: getStore(opts.Store),
- PriorityCount: opts.PriorityCount,
- KeysOnly: opts.KeysOnly,
- }
- inCh := c.c.Read(ctx, name, ro, paths, period)
- outCh := make(chan *Update, len(paths))
- go func() {
- defer close(outCh)
- for {
- select {
- case <-ctx.Done():
- if !errors.Is(ctx.Err(), context.Canceled) {
- log.Errorf("ctx done: %v", ctx.Err())
- }
- return
- case readResponse, ok := <-inCh:
- if !ok {
- return
- }
- rUpd := &Update{
- path: readResponse.GetPath(),
- value: readResponse.GetValue().GetValue(),
- priority: readResponse.GetPriority(),
- owner: readResponse.GetOwner(),
- ts: readResponse.GetTimestamp(),
- }
- select {
- case <-ctx.Done():
- if !errors.Is(ctx.Err(), context.Canceled) {
- log.Errorf("ctx done: %v", ctx.Err())
- }
- return
- case outCh <- rUpd:
- }
- }
- }
- }()
- return outCh
-}
-
-func (c *remoteCache) GetChanges(ctx context.Context, name, candidate string) ([]*Change, error) {
- changes, err := c.c.GetChanges(ctx, name, candidate)
- if err != nil {
- return nil, err
- }
- lcs := make([]*Change, 0, len(changes))
- for _, change := range changes {
- lcs = append(lcs, &Change{
- Update: &Update{
- path: change.GetUpdate().GetPath(),
- value: change.GetUpdate().GetValue().GetValue(),
- },
- Delete: change.GetDelete(),
- })
- }
- return lcs, nil
-}
-
-func (c *remoteCache) Discard(ctx context.Context, name, candidate string) error {
- return c.c.Discard(ctx, name, candidate)
-}
-
-func (c *remoteCache) Commit(ctx context.Context, name, candidate string) error {
- return c.c.Commit(ctx, name, candidate)
-}
-
-func (c *remoteCache) CreatePruneID(ctx context.Context, name string, force bool) (string, error) {
- rsp, err := c.c.Prune(ctx, name, "", force)
- if err != nil {
- return "", err
- }
- return rsp.GetId(), nil
-}
-
-func (c *remoteCache) ApplyPrune(ctx context.Context, name, id string) error {
- _, err := c.c.Prune(ctx, name, id, false)
- if err != nil {
- return err
- }
- return err
-}
-
-func (c *remoteCache) NewUpdate(upd *sdcpb.Update) (*Update, error) {
- b, err := proto.Marshal(upd.GetValue())
- if err != nil {
- return nil, err
- }
- rupd := &Update{
- path: utils.ToStrings(upd.GetPath(), false, false),
- value: b,
- }
- return rupd, nil
-}
-
-func (c *remoteCache) Close() error {
- return c.c.Close()
-}
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 1a32a117..0dac8f83 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -109,6 +109,9 @@ func (c *Config) validateSetDefaults() error {
return fmt.Errorf("unknown schema store type %q", c.SchemaStore.Type)
}
}
+ if c.SchemaStore != nil && c.SchemaStore.UploadPath == "" {
+ c.SchemaStore.UploadPath = "/schemas"
+ }
if c.SchemaStore == nil && (c.GRPCServer.SchemaServer == nil || !c.GRPCServer.SchemaServer.Enabled) {
return errors.New("schema-server RPCs cannot be exposed if the schema server is not enabled")
}
diff --git a/pkg/datastore/clients/cache/cacheClientBound.go b/pkg/datastore/clients/cache/cacheClientBound.go
deleted file mode 100644
index 7017c97a..00000000
--- a/pkg/datastore/clients/cache/cacheClientBound.go
+++ /dev/null
@@ -1,103 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 CacheClient
-
-import (
- "context"
- "time"
-
- "github.com/sdcio/cache/proto/cachepb"
- "github.com/sdcio/schema-server/pkg/utils"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
-
- "github.com/sdcio/data-server/pkg/cache"
-)
-
-type CacheClientBoundImpl struct {
- cacheClient cache.Client
- name string
-}
-
-type CacheClientBound interface {
- // GetValue retrieves config value for the provided path
- GetValue(ctx context.Context, candidateName string, path *sdcpb.Path) (*sdcpb.TypedValue, error)
- // GetValues retrieves config value from the provided path. If path is not a leaf path, all the sub paths will be returned.
- GetValues(ctx context.Context, candidateName string, path *sdcpb.Path) ([]*sdcpb.TypedValue, error)
- // ReadIntended retrieves the highes priority value from the intended store
- ReadIntended(ctx context.Context, opts *cache.Opts, paths [][]string, period time.Duration) []*cache.Update
-}
-
-func NewCacheClientBound(name string, c cache.Client) *CacheClientBoundImpl {
- return &CacheClientBoundImpl{
- cacheClient: c,
- name: name, // the datastore name
- }
-}
-
-// GetValue retrieves config value for the provided path
-func (ccb *CacheClientBoundImpl) GetValue(ctx context.Context, candidateName string, path *sdcpb.Path) (*sdcpb.TypedValue, error) {
- cacheupds, err := ccb.getValues(ctx, candidateName, path)
- if err != nil {
- return nil, err
- }
- if len(cacheupds) == 0 {
- return nil, nil
- }
- return cacheupds[0].Value()
-}
-
-// GetValues retrieves config value from the provided path. If path is not a leaf path, all the sub paths will be returned.
-func (ccb *CacheClientBoundImpl) GetValues(ctx context.Context, candidateName string, path *sdcpb.Path) ([]*sdcpb.TypedValue, error) {
- cacheupds, err := ccb.getValues(ctx, candidateName, path)
- if err != nil {
- return nil, err
- }
-
- result := make([]*sdcpb.TypedValue, 0, len(cacheupds))
-
- // collect the cachupdate Values to return them
- for _, c := range cacheupds {
- val, err := c.Value()
- if err != nil {
- return nil, err
- }
- result = append(result, val)
- }
-
- return result, nil
-}
-
-// getValues internal function that retrieves config value for the provided path, with its sub-paths
-func (ccb *CacheClientBoundImpl) getValues(ctx context.Context, candidateName string, path *sdcpb.Path) ([]*cache.Update, error) {
- spath, err := utils.CompletePath(nil, path)
- if err != nil {
- return nil, err
- }
- cacheupds := ccb.cacheClient.Read(ctx, ccb.name+"/"+candidateName, &cache.Opts{Store: cachepb.Store_CONFIG}, [][]string{spath}, 0)
- if len(cacheupds) == 0 {
- return nil, nil
- }
- return cacheupds, nil
-}
-
-// Read
-func (ccb *CacheClientBoundImpl) ReadIntended(ctx context.Context, opts *cache.Opts, paths [][]string, period time.Duration) []*cache.Update {
- if opts == nil {
- opts = &cache.Opts{}
- }
- opts.Store = cachepb.Store_INTENDED
- opts.PriorityCount = 1
- return ccb.cacheClient.Read(ctx, ccb.name, opts, paths, period)
-}
diff --git a/pkg/datastore/clients/schema/schemaClientBound.go b/pkg/datastore/clients/schema/schemaClientBound.go
index abced38d..064486c1 100644
--- a/pkg/datastore/clients/schema/schemaClientBound.go
+++ b/pkg/datastore/clients/schema/schemaClientBound.go
@@ -21,6 +21,7 @@ import (
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+ "github.com/sdcio/data-server/pkg/config"
"github.com/sdcio/data-server/pkg/schema"
"github.com/sdcio/data-server/pkg/utils"
)
@@ -47,9 +48,9 @@ type SchemaClientBoundImpl struct {
indexMutex sync.RWMutex
}
-func NewSchemaClientBound(s *sdcpb.Schema, sc schema.Client) *SchemaClientBoundImpl {
+func NewSchemaClientBound(s *config.SchemaConfig, sc schema.Client) *SchemaClientBoundImpl {
result := &SchemaClientBoundImpl{
- schema: s,
+ schema: s.GetSchema(),
schemaClient: sc,
index: sync.Map{},
}
diff --git a/pkg/datastore/clients/validationClient.go b/pkg/datastore/clients/validationClient.go
deleted file mode 100644
index d33306ad..00000000
--- a/pkg/datastore/clients/validationClient.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 clients
-
-import (
- schema_server "github.com/sdcio/sdc-protos/sdcpb"
-
- "github.com/sdcio/data-server/pkg/cache"
- CacheClient "github.com/sdcio/data-server/pkg/datastore/clients/cache"
- SchemaClient "github.com/sdcio/data-server/pkg/datastore/clients/schema"
- "github.com/sdcio/data-server/pkg/schema"
-)
-
-type ValidationClientImpl struct {
- CacheClient.CacheClientBound
- SchemaClient.SchemaClientBound
-}
-
-func NewValidationClient(datastoreName string, c cache.Client, s *schema_server.Schema, sc schema.Client) *ValidationClientImpl {
- return &ValidationClientImpl{
- CacheClientBound: CacheClient.NewCacheClientBound(datastoreName, c),
- SchemaClientBound: SchemaClient.NewSchemaClientBound(s, sc),
- }
-}
-
-// ValidationClient provides a client that bundles the bound clients for the cache as well as for the schema, of a certain device.
-type ValidationClient interface {
- CacheClient.CacheClientBound
- SchemaClient.SchemaClientBound
-}
diff --git a/pkg/datastore/data_rpc_test.go b/pkg/datastore/converter_test.go
similarity index 97%
rename from pkg/datastore/data_rpc_test.go
rename to pkg/datastore/converter_test.go
index c9027ea2..eba8cbff 100644
--- a/pkg/datastore/data_rpc_test.go
+++ b/pkg/datastore/converter_test.go
@@ -229,7 +229,8 @@ func TestDatastore_expandUpdateLeafAsKeys(t *testing.T) {
t.Fatal(err)
}
- converter := utils.NewConverter(SchemaClient.NewSchemaClientBound(schema.GetSchema(), schemaClient))
+ scb := SchemaClient.NewSchemaClientBound(schema, schemaClient)
+ converter := utils.NewConverter(scb)
got, err := converter.ExpandUpdateKeysAsLeaf(tt.args.ctx, tt.args.upd)
if (err != nil) != tt.wantErr {
diff --git a/pkg/datastore/data_rpc.go b/pkg/datastore/data_rpc.go
deleted file mode 100644
index de695378..00000000
--- a/pkg/datastore/data_rpc.go
+++ /dev/null
@@ -1,710 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 datastore
-
-import (
- "context"
- "encoding/json"
- "fmt"
- "math"
- "strconv"
- "strings"
- "sync"
- "time"
-
- "github.com/sdcio/cache/proto/cachepb"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- log "github.com/sirupsen/logrus"
- "google.golang.org/grpc/codes"
- status "google.golang.org/grpc/status"
- "google.golang.org/protobuf/proto"
- "google.golang.org/protobuf/types/known/emptypb"
-
- "github.com/sdcio/data-server/pkg/cache"
- "github.com/sdcio/data-server/pkg/tree"
- "github.com/sdcio/data-server/pkg/utils"
-)
-
-const (
- // to be used for candidates created without an owner
- DefaultOwner = "__sdcio"
-)
-
-func (d *Datastore) Get(ctx context.Context, req *sdcpb.GetDataRequest, nCh chan *sdcpb.GetDataResponse) error {
- defer close(nCh)
- switch req.GetDatastore().GetType() {
- case sdcpb.Type_MAIN:
- case sdcpb.Type_CANDIDATE:
- case sdcpb.Type_INTENDED:
- if req.GetDataType() == sdcpb.DataType_STATE {
- return status.Error(codes.InvalidArgument, "cannot query STATE data from INTENDED store")
- }
- }
-
- switch req.GetEncoding() {
- case sdcpb.Encoding_STRING:
- case sdcpb.Encoding_JSON:
- case sdcpb.Encoding_JSON_IETF:
- case sdcpb.Encoding_PROTO:
- default:
- return fmt.Errorf("unknown encoding: %v", req.GetEncoding())
- }
-
- var err error
- // validate that path(s) exist in the schema
- for _, p := range req.GetPath() {
- err = d.validatePath(ctx, p)
- if err != nil {
- return err
- }
- }
-
- // build target cache name
- name := req.GetName()
- if req.GetDatastore().GetName() != "" {
- name = fmt.Sprintf("%s/%s", req.GetName(), req.GetDatastore().GetName())
- }
-
- // convert sdcpb paths to a string list
- paths := make([][]string, 0, len(req.GetPath()))
- for _, p := range req.GetPath() {
- paths = append(paths, utils.ToStrings(p, false, false))
- }
-
- ctx, cancel := context.WithCancel(ctx)
- defer cancel()
-
- switch req.GetEncoding() {
- case sdcpb.Encoding_STRING:
- err = d.handleGetDataUpdatesSTRING(ctx, name, req, paths, nCh)
- case sdcpb.Encoding_JSON:
- err = d.handleGetDataUpdatesJSON(ctx, name, req, paths, nCh, false)
- case sdcpb.Encoding_JSON_IETF:
- err = d.handleGetDataUpdatesJSON(ctx, name, req, paths, nCh, true)
- case sdcpb.Encoding_PROTO:
- err = d.handleGetDataUpdatesPROTO(ctx, name, req, paths, nCh)
- }
- if err != nil {
- return err
- }
- return nil
-}
-
-func (d *Datastore) handleGetDataUpdatesSTRING(ctx context.Context, name string, req *sdcpb.GetDataRequest, paths [][]string, out chan *sdcpb.GetDataResponse) error {
-NEXT_STORE:
- for _, store := range getStores(req) {
- in := d.cacheClient.ReadCh(ctx, name, &cache.Opts{
- Store: store,
- Owner: req.GetDatastore().GetOwner(),
- Priority: req.GetDatastore().GetPriority(),
- }, paths, 0)
-
- for {
- select {
- case <-ctx.Done():
- return ctx.Err()
- case upd, ok := <-in:
- //log.Debugf("ds=%s read path=%v from store=%v: %v", name, paths, store, upd)
- if !ok {
- continue NEXT_STORE
- }
- if len(upd.GetPath()) == 0 {
- continue
- }
- scp, err := d.schemaClient.ToPath(ctx, upd.GetPath())
- if err != nil {
- return err
- }
- switch len(scp.GetElem()) {
- case 0:
- continue
- case 1:
- if scp.GetElem()[0].GetName() == "" {
- continue
- }
- }
- tv, err := upd.Value()
- if err != nil {
- return err
- }
- notification := &sdcpb.Notification{
- Timestamp: time.Now().UnixNano(),
- Update: []*sdcpb.Update{{
- Path: scp,
- Value: tv,
- }},
- }
- rsp := &sdcpb.GetDataResponse{
- Notification: []*sdcpb.Notification{notification},
- }
- select {
- case <-ctx.Done():
- return ctx.Err()
- case out <- rsp:
- }
- }
- }
- }
- return nil
-}
-
-func (d *Datastore) handleGetDataUpdatesJSON(ctx context.Context, name string, req *sdcpb.GetDataRequest, paths [][]string, out chan *sdcpb.GetDataResponse, ietf bool) error {
- now := time.Now().UnixNano()
-
- treeSCC := tree.NewTreeCacheClient(d.Name(), d.cacheClient)
- tc := tree.NewTreeContext(treeSCC, d.schemaClient, "")
- root, err := tree.NewTreeRoot(ctx, tc)
- if err != nil {
- return err
- }
-
- flagsExisting := tree.NewUpdateInsertFlags()
-
- for _, store := range getStores(req) {
- in := d.cacheClient.ReadCh(ctx, name, &cache.Opts{
- Store: store,
- Owner: req.GetDatastore().GetOwner(),
- Priority: req.GetDatastore().GetPriority(),
- }, paths, 0)
- OUTER:
- for {
- select {
- case <-ctx.Done():
- return ctx.Err()
- case upd, ok := <-in:
- if !ok {
- break OUTER
- }
-
- if len(upd.GetPath()) == 0 {
- continue
- }
-
- scp, err := d.schemaClient.ToPath(ctx, upd.GetPath())
- if err != nil {
- return err
- }
- switch len(scp.GetElem()) {
- case 0:
- continue
- case 1:
- if scp.GetElem()[0].GetName() == "" {
- continue
- }
- }
- root.AddCacheUpdateRecursive(ctx, upd, flagsExisting)
- }
- }
- }
-
- root.FinishInsertionPhase(ctx)
-
- var j any
- // marshal map into JSON bytes
- if ietf {
- j, err = root.ToJsonIETF(false)
- if err != nil {
- return err
- }
- } else {
- j, err = root.ToJson(false)
- if err != nil {
- return err
- }
- }
- b, err := json.Marshal(j)
- if err != nil {
- err = fmt.Errorf("failed json builder indent : %v", err)
- log.Error(err)
- return err
- }
-
- select {
- case <-ctx.Done():
- return ctx.Err()
- case out <- &sdcpb.GetDataResponse{
- Notification: []*sdcpb.Notification{
- {
- Timestamp: now,
- Update: []*sdcpb.Update{{
- Value: &sdcpb.TypedValue{Value: &sdcpb.TypedValue_JsonVal{JsonVal: b}},
- }},
- },
- },
- }:
- }
- return nil
-}
-
-func (d *Datastore) handleGetDataUpdatesPROTO(ctx context.Context, name string, req *sdcpb.GetDataRequest, paths [][]string, out chan *sdcpb.GetDataResponse) error {
- converter := utils.NewConverter(d.schemaClient)
-NEXT_STORE:
- for _, store := range getStores(req) {
- in := d.cacheClient.ReadCh(ctx, name, &cache.Opts{
- Store: store,
- Owner: req.GetDatastore().GetOwner(),
- Priority: req.GetDatastore().GetPriority(),
- }, paths, 0)
- for {
- select {
- case <-ctx.Done():
- return ctx.Err()
- case upd, ok := <-in:
- //log.Debugf("ds=%s read path=%v from store=%v: %v", name, paths, store, upd)
- if !ok {
- continue NEXT_STORE
- }
-
- if len(upd.GetPath()) == 0 {
- continue
- }
- scp, err := d.schemaClient.ToPath(ctx, upd.GetPath())
- if err != nil {
- return err
- }
- switch len(scp.GetElem()) {
- case 0:
- continue
- case 1:
- if scp.GetElem()[0].GetName() == "" {
- continue
- }
- }
- tv, err := upd.Value()
- if err != nil {
- return err
- }
- ctv, err := converter.ConvertTypedValueToProto(ctx, scp, tv)
- if err != nil {
- return err
- }
- notification := &sdcpb.Notification{
- Timestamp: time.Now().UnixNano(),
- Update: []*sdcpb.Update{{
- Path: scp,
- Value: ctv,
- }},
- }
- rsp := &sdcpb.GetDataResponse{
- Notification: []*sdcpb.Notification{notification},
- }
- select {
- case <-ctx.Done():
- return ctx.Err()
- case out <- rsp:
- }
- }
- }
- }
- return nil
-}
-
-func (d *Datastore) Subscribe(req *sdcpb.SubscribeRequest, stream sdcpb.DataServer_SubscribeServer) error {
- ctx, cancel := context.WithCancel(stream.Context())
- defer cancel()
- var err error
- for _, subsc := range req.GetSubscription() {
- err := d.doSubscribeOnce(ctx, subsc, stream)
- if err != nil {
- return err
- }
- }
- err = stream.Send(&sdcpb.SubscribeResponse{
- Response: &sdcpb.SubscribeResponse_SyncResponse{
- SyncResponse: true,
- },
- })
- if err != nil {
- return err
- }
- // start periodic gets, TODO: optimize using cache RPC
- wg := new(sync.WaitGroup)
- wg.Add(len(req.GetSubscription()))
- errCh := make(chan error, 1)
- doneCh := make(chan struct{})
- for _, subsc := range req.GetSubscription() {
- go func(subsc *sdcpb.Subscription) {
- ticker := time.NewTicker(time.Duration(subsc.GetSampleInterval()))
- defer ticker.Stop()
- defer wg.Done()
- for {
- select {
- case <-doneCh:
- return
- case <-ctx.Done():
- errCh <- ctx.Err()
- return
- case <-ticker.C:
- err := d.doSubscribeOnce(ctx, subsc, stream)
- if err != nil {
- errCh <- err
- close(doneCh)
- return
- }
- }
- }
- }(subsc)
- }
- wg.Wait()
- return nil
-}
-
-func (d *Datastore) validateUpdate(ctx context.Context, upd *sdcpb.Update) error {
- // 1.validate the path i.e check that the path exists
- // 2.validate that the value is compliant with the schema
-
- // 1. validate the path
- rsp, err := d.schemaClient.GetSchemaSdcpbPath(ctx, upd.GetPath())
- if err != nil {
- return err
- }
- // 2. convert value to its YANG type
- upd.Value, err = utils.ConvertTypedValueToYANGType(rsp.GetSchema(), upd.GetValue())
- if err != nil {
- return err
- }
- // 2. validate value
- val, err := utils.GetSchemaValue(upd.GetValue())
- if err != nil {
- return err
- }
- switch obj := rsp.GetSchema().Schema.(type) {
- case *sdcpb.SchemaElem_Container:
- if !pathIsKeyAsLeaf(upd.GetPath()) && !obj.Container.IsPresence {
- return fmt.Errorf("cannot set value on container %q object", obj.Container.Name)
- }
- // TODO: validate key as leaf
- case *sdcpb.SchemaElem_Field:
- if obj.Field.IsState {
- return fmt.Errorf("cannot set state field: %v", obj.Field.Name)
- }
- err = validateFieldValue(obj.Field, val)
- if err != nil {
- return err
- }
- case *sdcpb.SchemaElem_Leaflist:
- err = validateLeafListValue(obj.Leaflist, val)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func validateFieldValue(f *sdcpb.LeafSchema, v any) error {
- return validateLeafTypeValue(f.GetType(), v)
-}
-
-func validateLeafTypeValue(lt *sdcpb.SchemaLeafType, v any) error {
- switch lt.GetType() {
- case "string":
- // TODO: validate length and range
- return nil
- case "int8":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseInt(v, 10, 8)
- if err != nil {
- return err
- }
- case int64:
- if v > math.MaxInt8 || v < math.MinInt8 {
- return fmt.Errorf("value %v out of bound for type %s", v, lt.GetType())
- }
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "int16":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseInt(v, 10, 16)
- if err != nil {
- return err
- }
- case int64:
- if v > math.MaxInt16 || v < math.MinInt16 {
- return fmt.Errorf("value %v out of bound for type %s", v, lt.GetType())
- }
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "int32":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseInt(v, 10, 32)
- if err != nil {
- return err
- }
- case int64:
- if v > math.MaxInt32 || v < math.MinInt32 {
- return fmt.Errorf("value %v out of bound for type %s", v, lt.GetType())
- }
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "int64":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseInt(v, 10, 64)
- if err != nil {
- return err
- }
- case int64:
- // No need to do anything, same type
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "uint8":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseUint(v, 10, 8)
- if err != nil {
- return err
- }
- case uint64:
- if v > math.MaxUint8 {
- return fmt.Errorf("value %v out of bound for type %s", v, lt.GetType())
- }
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "uint16":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseUint(v, 10, 16)
- if err != nil {
- return err
- }
- case uint64:
- if v > math.MaxUint16 {
- return fmt.Errorf("value %v out of bound for type %s", v, lt.GetType())
- }
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "uint32":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseUint(v, 10, 32)
- if err != nil {
- return err
- }
- case uint64:
- if v > math.MaxUint32 {
- return fmt.Errorf("value %v out of bound for type %s", v, lt.GetType())
- }
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "uint64":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseUint(v, 10, 64)
- if err != nil {
- return err
- }
- case uint64:
- // No need to do anything, same type
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "boolean":
- switch v := v.(type) {
- case string:
- _, err := strconv.ParseBool(v)
- if err != nil {
- return fmt.Errorf("value %v must be a boolean: %v", v, err)
- }
- case bool:
- return nil
- default:
- return fmt.Errorf("unexpected casted type %T in %v", v, lt.GetType())
- }
- return nil
- case "enumeration":
- valid := false
- for _, vv := range lt.EnumNames {
- if fmt.Sprintf("%s", v) == vv {
- valid = true
- break
- }
- }
- if !valid {
- return fmt.Errorf("value %q does not match enum type %q, must be one of [%s]", v, lt.TypeName, strings.Join(lt.EnumNames, ", "))
- }
- return nil
- case "union":
- valid := false
- for _, ut := range lt.GetUnionTypes() {
- err := validateLeafTypeValue(ut, v)
- if err == nil {
- valid = true
- break
- }
- }
- if !valid {
- return fmt.Errorf("value %v does not match union type %v", v, lt.TypeName)
- }
- return nil
- case "identityref":
- valid := false
- identities := make([]string, 0, len(lt.IdentityPrefixesMap))
- for vv := range lt.IdentityPrefixesMap {
- identities = append(identities, vv)
- if fmt.Sprintf("%s", v) == vv {
- valid = true
- break
- }
- }
- if !valid {
- return fmt.Errorf("value %q does not match identityRef type %q, must be one of [%s]", v, lt.TypeName, strings.Join(identities, ", "))
- }
- return nil
- case "decimal64":
- switch v := v.(type) {
- case float64: // if it's a float64 then it's a valid decimal64
- case string:
- if c := strings.Count(v, "."); c == 0 || c > 1 {
- return fmt.Errorf("value %q is not a valid Decimal64", v)
- }
- case sdcpb.Decimal64, *sdcpb.Decimal64:
- // No need to do anything, same type
- default:
- return fmt.Errorf("unexpected type for a Decimal64 value %q: %T", v, v)
- }
- return nil
- case "leafref":
- // TODO: does this need extra validation?
- return nil
- case "empty":
- switch v.(type) {
- case *emptypb.Empty:
- return nil
- }
- return fmt.Errorf("value %v is not an empty JSON object '{}' so does not match empty type", v)
- default:
- return fmt.Errorf("unhandled type %v for value %q", lt.GetType(), v)
- }
-}
-
-func validateLeafListValue(ll *sdcpb.LeafListSchema, v any) error {
- switch vTyped := v.(type) {
- case *sdcpb.ScalarArray:
- for _, elem := range vTyped.Element {
- val, err := utils.GetSchemaValue(elem)
- if err != nil {
- return err
- }
- err = validateLeafTypeValue(ll.GetType(), val)
- if err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-func (d *Datastore) doSubscribeOnce(ctx context.Context, subscription *sdcpb.Subscription, stream sdcpb.DataServer_SubscribeServer) error {
- paths := make([][]string, 0, len(subscription.GetPath()))
- for _, path := range subscription.GetPath() {
- paths = append(paths, utils.ToStrings(path, false, false))
- }
-
- for _, store := range getStores(subscription) {
- for upd := range d.cacheClient.ReadCh(ctx, d.config.Name, &cache.Opts{
- Store: store,
- }, paths, 0) {
- log.Debugf("ds=%s read path=%v from store=%v: %v", d.config.Name, paths, store, upd)
- rsp, err := d.subscribeResponseFromCacheUpdate(ctx, upd)
- if err != nil {
- return err
- }
- log.Debugf("ds=%s sending subscribe response: %v", d.config.Name, rsp)
- select {
- case <-ctx.Done():
- return ctx.Err()
- default:
- err = stream.Send(rsp)
- if err != nil {
- return err
- }
- }
- }
- }
- return nil
-}
-
-func getStores(req proto.Message) []cachepb.Store {
- var dt sdcpb.DataType
- var candName string
- switch req := req.(type) {
- case *sdcpb.GetDataRequest:
- if req.GetDatastore().GetType() == sdcpb.Type_INTENDED {
- return []cachepb.Store{cachepb.Store_INTENDED}
- }
- dt = req.GetDataType()
- candName = req.GetDatastore().GetName()
- case *sdcpb.Subscription:
- dt = req.GetDataType()
- }
-
- var stores []cachepb.Store
- switch dt {
- case sdcpb.DataType_ALL:
- stores = []cachepb.Store{cachepb.Store_CONFIG}
- if candName == "" {
- stores = append(stores, cachepb.Store_STATE)
- }
- case sdcpb.DataType_CONFIG:
- stores = []cachepb.Store{cachepb.Store_CONFIG}
- case sdcpb.DataType_STATE:
- if candName == "" {
- stores = []cachepb.Store{cachepb.Store_STATE}
- }
- }
- return stores
-}
-
-func (d *Datastore) subscribeResponseFromCacheUpdate(ctx context.Context, upd *cache.Update) (*sdcpb.SubscribeResponse, error) {
- scp, err := d.schemaClient.ToPath(ctx, upd.GetPath())
- if err != nil {
- return nil, err
- }
- tv, err := upd.Value()
- if err != nil {
- return nil, err
- }
- notification := &sdcpb.Notification{
- Timestamp: time.Now().UnixNano(),
- Update: []*sdcpb.Update{{
- Path: scp,
- Value: tv,
- }},
- }
- return &sdcpb.SubscribeResponse{
- Response: &sdcpb.SubscribeResponse_Update{
- Update: notification,
- },
- }, nil
-}
diff --git a/pkg/datastore/datastore_rpc.go b/pkg/datastore/datastore_rpc.go
index f56b65f5..5b248930 100644
--- a/pkg/datastore/datastore_rpc.go
+++ b/pkg/datastore/datastore_rpc.go
@@ -17,16 +17,11 @@ package datastore
import (
"context"
"errors"
- "fmt"
- "sort"
- "strings"
"sync"
"time"
- "github.com/sdcio/cache/proto/cachepb"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
log "github.com/sirupsen/logrus"
- "golang.org/x/sync/semaphore"
"google.golang.org/grpc"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/peer"
@@ -38,14 +33,15 @@ import (
"github.com/sdcio/data-server/pkg/datastore/target"
"github.com/sdcio/data-server/pkg/datastore/types"
"github.com/sdcio/data-server/pkg/schema"
- "github.com/sdcio/data-server/pkg/utils"
+ "github.com/sdcio/data-server/pkg/tree"
+ treetypes "github.com/sdcio/data-server/pkg/tree/types"
)
type Datastore struct {
// datastore config
config *config.DatastoreConfig
- cacheClient cache.Client
+ cacheClient cache.CacheClientBound
// SBI target of this datastore
sbi target.Target
@@ -73,20 +69,39 @@ type Datastore struct {
// TransactionManager
transactionManager *types.TransactionManager
+
+ // SyncTree
+ syncTree *tree.RootEntry
+ syncTreeMutex *sync.RWMutex
+
+ // owned by sync
+ syncTreeCandidat *tree.RootEntry
}
// New creates a new datastore, its schema server client and initializes the SBI target
// func New(c *config.DatastoreConfig, schemaServer *config.RemoteSchemaServer) *Datastore {
-func New(ctx context.Context, c *config.DatastoreConfig, sc schema.Client, cc cache.Client, opts ...grpc.DialOption) *Datastore {
+func New(ctx context.Context, c *config.DatastoreConfig, sc schema.Client, cc cache.Client, opts ...grpc.DialOption) (*Datastore, error) {
+
+ scb := schemaClient.NewSchemaClientBound(c.Schema, sc)
+ tc := tree.NewTreeContext(scb, tree.RunningIntentName)
+ syncTreeRoot, err := tree.NewTreeRoot(ctx, tc)
+ if err != nil {
+ return nil, err
+ }
+
+ ccb := cache.NewCacheClientBound(c.Name, cc)
+
ds := &Datastore{
config: c,
- schemaClient: schemaClient.NewSchemaClientBound(c.Schema.GetSchema(), sc),
- cacheClient: cc,
+ schemaClient: scb,
+ cacheClient: ccb,
m: &sync.RWMutex{},
md: &sync.RWMutex{},
dmutex: &sync.Mutex{},
deviationClients: make(map[string]sdcpb.DataServer_WatchDeviationsServer),
currentIntentsDeviations: make(map[string][]*sdcpb.WatchDeviationResponse),
+ syncTree: syncTreeRoot,
+ syncTreeMutex: &sync.RWMutex{},
}
ds.transactionManager = types.NewTransactionManager(NewDatastoreRollbackAdapter(ds))
@@ -97,7 +112,7 @@ func New(ctx context.Context, c *config.DatastoreConfig, sc schema.Client, cc ca
ds.cfn = cancel
// create cache instance if needed
- // this is a blocking call
+ // this is a blocking call
ds.initCache(ctx)
go func() {
@@ -117,25 +132,23 @@ func New(ctx context.Context, c *config.DatastoreConfig, sc schema.Client, cc ca
// start deviation goroutine
ds.DeviationMgr(ctx)
}()
- return ds
+ return ds, nil
+}
+
+func (d *Datastore) IntentsList(ctx context.Context) ([]string, error) {
+ return d.cacheClient.IntentsList(ctx)
}
func (d *Datastore) initCache(ctx context.Context) {
-START:
- ok, err := d.cacheClient.Exists(ctx, d.config.Name)
- if err != nil {
- log.Errorf("failed to check cache instance %s, %s", d.config.Name, err)
- time.Sleep(time.Second)
- goto START
- }
- if ok {
+
+ exists := d.cacheClient.InstanceExists(ctx)
+ if exists {
log.Debugf("cache %q already exists", d.config.Name)
return
}
-
log.Infof("cache %s does not exist, creating it", d.config.Name)
CREATE:
- err = d.cacheClient.Create(ctx, d.config.Name, false, false)
+ err := d.cacheClient.InstanceCreate(ctx)
if err != nil {
log.Errorf("failed to create cache %s: %v", d.config.Name, err)
time.Sleep(time.Second)
@@ -181,42 +194,8 @@ func (d *Datastore) Config() *config.DatastoreConfig {
return d.config
}
-func (d *Datastore) Candidates(ctx context.Context) ([]*sdcpb.DataStore, error) {
- cand, err := d.cacheClient.GetCandidates(ctx, d.Name())
- if err != nil {
- return nil, err
- }
- rsp := make([]*sdcpb.DataStore, 0, len(cand))
- for _, cd := range cand {
- rsp = append(rsp, &sdcpb.DataStore{
- Type: sdcpb.Type_CANDIDATE,
- Name: cd.CandidateName,
- Owner: cd.Owner,
- Priority: cd.Priority,
- })
- }
- return rsp, nil
-}
-
-func (d *Datastore) Discard(ctx context.Context, req *sdcpb.DiscardRequest) error {
- return d.cacheClient.Discard(ctx, req.GetName(), req.Datastore.GetName())
-}
-
-func (d *Datastore) CreateCandidate(ctx context.Context, ds *sdcpb.DataStore) error {
- if ds.GetPriority() < 0 {
- return fmt.Errorf("invalid priority value must be >0")
- }
- if ds.GetPriority() <= 0 {
- ds.Priority = 1
- }
- if ds.GetOwner() == "" {
- ds.Owner = DefaultOwner
- }
- return d.cacheClient.CreateCandidate(ctx, d.Name(), ds.GetName(), ds.GetOwner(), ds.GetPriority())
-}
-
-func (d *Datastore) DeleteCandidate(ctx context.Context, name string) error {
- return d.cacheClient.DeleteCandidate(ctx, d.Name(), name)
+func (d *Datastore) Delete(ctx context.Context) error {
+ return d.cacheClient.InstanceDelete(ctx)
}
func (d *Datastore) ConnectionState() *target.TargetStatus {
@@ -241,21 +220,21 @@ func (d *Datastore) Stop() error {
return nil
}
-func (d *Datastore) DeleteCache(ctx context.Context) error {
- return d.cacheClient.Delete(ctx, d.config.Name)
-}
-
func (d *Datastore) Sync(ctx context.Context) {
- // this semaphore controls the number of concurrent writes to the cache
- sem := semaphore.NewWeighted(d.config.Sync.WriteWorkers)
go d.sbi.Sync(ctx,
d.config.Sync,
d.synCh,
)
var err error
- var pruneID string
-MAIN:
+ var startTs int64
+
+ d.syncTreeCandidat, err = tree.NewTreeRoot(ctx, tree.NewTreeContext(d.schemaClient, tree.RunningIntentName))
+ if err != nil {
+ log.Errorf("creating a new synctree candidate: %v", err)
+ return
+ }
+
for {
select {
case <-ctx.Done():
@@ -264,179 +243,64 @@ MAIN:
}
return
case syncup := <-d.synCh:
- if syncup.Start {
+ switch {
+ case syncup.Start:
log.Debugf("%s: sync start", d.Name())
- for {
- pruneID, err = d.cacheClient.CreatePruneID(ctx, d.Name(), syncup.Force)
- if err != nil {
- log.Errorf("datastore %s failed to create prune ID: %v", d.Name(), err)
- time.Sleep(time.Second)
- continue // retry
- }
- continue MAIN
- }
- }
- if syncup.End && pruneID != "" {
- log.Debugf("%s: sync end", d.Name())
- for {
- err = d.cacheClient.ApplyPrune(ctx, d.Name(), pruneID)
- if err != nil {
- log.Errorf("datastore %s failed to prune cache after update: %v", d.Name(), err)
- time.Sleep(time.Second)
- continue // retry
- }
- break
- }
- log.Debugf("%s: sync resetting pruneID", d.Name())
- pruneID = ""
- continue // MAIN FOR loop
- }
- // a regular notification
- log.Debugf("%s: sync acquire semaphore", d.Name())
- err = sem.Acquire(ctx, 1)
- if err != nil {
- if errors.Is(err, context.Canceled) {
- log.Infof("datastore %s sync stopped", d.config.Name)
- return
- }
- log.Errorf("failed to acquire semaphore: %v", err)
- continue
- }
- log.Debugf("%s: sync acquired semaphore", d.Name())
- go d.storeSyncMsg(ctx, syncup, sem)
- }
- }
-}
+ startTs = time.Now().Unix()
-func isState(r *sdcpb.GetSchemaResponse) bool {
- switch r := r.Schema.Schema.(type) {
- case *sdcpb.SchemaElem_Container:
- return r.Container.IsState
- case *sdcpb.SchemaElem_Field:
- return r.Field.IsState
- case *sdcpb.SchemaElem_Leaflist:
- return r.Leaflist.IsState
- }
- return false
-}
-
-func (d *Datastore) storeSyncMsg(ctx context.Context, syncup *target.SyncUpdate, sem *semaphore.Weighted) {
- defer sem.Release(1)
-
- converter := utils.NewConverter(d.schemaClient)
-
- cNotification, err := converter.ConvertNotificationTypedValues(ctx, syncup.Update)
- if err != nil {
- log.Errorf("failed to convert notification typedValue: %v", err)
- return
- }
+ case syncup.End:
+ log.Debugf("%s: sync end", d.Name())
- upds := NewSdcpbUpdateDedup()
- for _, x := range cNotification.GetUpdate() {
- addUpds, err := converter.ExpandUpdateKeysAsLeaf(ctx, x)
- if err != nil {
- continue
- }
- upds.AddUpdate(x)
- upds.AddUpdates(addUpds)
- }
- cNotification.Update = upds.Updates()
+ startTs = 0
- for _, x := range cNotification.GetUpdate() {
- fmt.Printf("%s\n", x.String())
- }
+ d.syncTreeMutex.Lock()
+ d.syncTree = d.syncTreeCandidat
+ d.syncTreeMutex.Unlock()
- for _, del := range cNotification.GetDelete() {
- store := cachepb.Store_CONFIG
- if d.config.Sync != nil && d.config.Sync.Validate {
- scRsp, err := d.schemaClient.GetSchemaSdcpbPath(ctx, del)
- if err != nil {
- log.Errorf("datastore %s failed to get schema for delete path %v: %v", d.config.Name, del, err)
- continue
- }
- if isState(scRsp) {
- store = cachepb.Store_STATE
- }
- }
- delPath := utils.ToStrings(del, false, false)
- rctx, cancel := context.WithTimeout(ctx, time.Minute) // TODO:
- defer cancel()
- err = d.cacheClient.Modify(rctx, d.Config().Name,
- &cache.Opts{
- Store: store,
- },
- [][]string{delPath}, nil)
- if err != nil {
- log.Errorf("datastore %s failed to delete path %v: %v", d.config.Name, delPath, err)
- }
- }
+ // create new syncTreeCandidat
+ d.syncTreeCandidat, err = tree.NewTreeRoot(ctx, tree.NewTreeContext(d.schemaClient, tree.RunningIntentName))
+ if err != nil {
+ log.Errorf("creating a new synctree candidate: %v", err)
+ return
+ }
- for _, upd := range cNotification.GetUpdate() {
- store := cachepb.Store_CONFIG
- if d.config.Sync != nil && d.config.Sync.Validate {
- scRsp, err := d.schemaClient.GetSchemaSdcpbPath(ctx, upd.GetPath())
- if err != nil {
- log.Errorf("datastore %s failed to get schema for update path %v: %v", d.config.Name, upd.GetPath(), err)
- continue
- }
- if isState(scRsp) {
- store = cachepb.Store_STATE
+ // export and write to cache
+ runningExport, err := d.syncTree.TreeExport(tree.RunningIntentName, tree.RunningValuesPrio)
+ if err != nil {
+ log.Error(err)
+ continue
+ }
+ err = d.cacheClient.IntentModify(ctx, runningExport)
+ if err != nil {
+ log.Errorf("issue modifying running cache content: %v", err)
+ continue
+ }
+ default:
+ if startTs == 0 {
+ startTs = time.Now().Unix()
+ }
+ err := d.writeToSyncTreeCandidate(ctx, syncup.Update.GetUpdate(), startTs)
+ if err != nil {
+ log.Errorf("failed to write to sync tree: %v", err)
+ }
}
}
- // TODO:[KR] convert update typedValue if needed
- cUpd, err := d.cacheClient.NewUpdate(upd)
- if err != nil {
- log.Errorf("datastore %s failed to create update from %v: %v", d.config.Name, upd, err)
- continue
- }
-
- rctx, cancel := context.WithTimeout(ctx, time.Minute) // TODO:[KR] make this timeout configurable ?
- defer cancel()
- err = d.cacheClient.Modify(rctx, d.Config().Name, &cache.Opts{
- Store: store,
- }, nil, []*cache.Update{cUpd})
- if err != nil {
- log.Errorf("datastore %s failed to send modify request to cache: %v", d.config.Name, err)
- }
}
}
-type SdcpbUpdateDedup struct {
- lookup map[string]*sdcpb.Update
-}
-
-func NewSdcpbUpdateDedup() *SdcpbUpdateDedup {
- return &SdcpbUpdateDedup{
- lookup: map[string]*sdcpb.Update{},
+func (d *Datastore) writeToSyncTreeCandidate(ctx context.Context, updates []*sdcpb.Update, ts int64) error {
+ upds, err := treetypes.ExpandAndConvertIntent(ctx, d.schemaClient, tree.RunningIntentName, tree.RunningValuesPrio, updates, ts)
+ if err != nil {
+ return err
}
-}
-func (s *SdcpbUpdateDedup) AddUpdates(upds []*sdcpb.Update) {
for _, upd := range upds {
- s.AddUpdate(upd)
- }
-}
-
-func (s *SdcpbUpdateDedup) AddUpdate(upd *sdcpb.Update) {
- path := upd.Path.String()
- if _, exists := s.lookup[path]; exists {
- return
- }
- s.lookup[path] = upd
-}
-
-func (s *SdcpbUpdateDedup) Updates() []*sdcpb.Update {
- result := make([]*sdcpb.Update, 0, len(s.lookup))
-
- for _, v := range s.lookup {
- result = append(result, v)
+ _, err := d.syncTreeCandidat.AddUpdateRecursive(ctx, upd, treetypes.NewUpdateInsertFlags())
+ if err != nil {
+ return err
+ }
}
- return result
-}
-
-func (d *Datastore) validatePath(ctx context.Context, p *sdcpb.Path) error {
- _, err := d.schemaClient.GetSchemaSdcpbPath(ctx, p)
- return err
+ return nil
}
func (d *Datastore) WatchDeviations(req *sdcpb.WatchDeviationRequest, stream sdcpb.DataServer_WatchDeviationsServer) error {
@@ -467,261 +331,113 @@ func (d *Datastore) StopDeviationsWatch(peer string) {
func (d *Datastore) DeviationMgr(ctx context.Context) {
log.Infof("%s: starting deviationMgr...", d.Name())
ticker := time.NewTicker(30 * time.Second)
- defer ticker.Stop()
+ defer func() {
+ ticker.Stop()
+ }()
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
- // TODO: send deviation START
d.m.RLock()
- // copy deviation streams
- dm := make(map[string]sdcpb.DataServer_WatchDeviationsServer)
- for n, devStream := range d.deviationClients {
- dm[n] = devStream
+ deviationClients := make([]sdcpb.DataServer_WatchDeviationsServer, 0, len(d.deviationClients))
+ for _, devStream := range d.deviationClients {
+ deviationClients = append(deviationClients, devStream)
}
d.m.RUnlock()
- d.runDeviationUpdate(ctx, dm)
- }
- }
-}
-
-func (d *Datastore) runDeviationUpdate(ctx context.Context, dm map[string]sdcpb.DataServer_WatchDeviationsServer) {
-
- sep := "/"
-
- // send deviation START
- for _, dc := range dm {
- err := dc.Send(&sdcpb.WatchDeviationResponse{
- Name: d.Name(),
- Event: sdcpb.DeviationEvent_START,
- })
- if err != nil {
- log.Errorf("%s: failed to send deviation start: %v", d.Name(), err)
- continue
- }
- }
- // collect intent deviations and store them for clearing
- newDeviations := make(map[string][]*sdcpb.WatchDeviationResponse)
-
- configPaths := map[string]struct{}{}
-
- // go through config and calculate deviations
- for upd := range d.cacheClient.ReadCh(ctx, d.Name(), &cache.Opts{Store: cachepb.Store_CONFIG}, [][]string{nil}, 0) {
- // save the updates path as an already checked path
- configPaths[strings.Join(upd.GetPath(), sep)] = struct{}{}
-
- v, err := upd.Value()
- if err != nil {
- log.Errorf("%s: failed to convert value: %v", d.Name(), err)
- continue
- }
-
- intentsUpdates := d.cacheClient.Read(ctx, d.Name(), &cache.Opts{
- Store: cachepb.Store_INTENDED,
- Owner: "",
- Priority: 0,
- PriorityCount: 0,
- }, [][]string{upd.GetPath()}, 0)
- if len(intentsUpdates) == 0 {
- log.Debugf("%s: has unhandled config %v: %v", d.Name(), upd.GetPath(), v)
- // TODO: generate an unhandled config deviation
- sp, err := d.schemaClient.ToPath(ctx, upd.GetPath())
- if err != nil {
- log.Errorf("%s: failed to convert cached path to xpath: %v", d.Name(), err)
- }
-
- rsp := &sdcpb.WatchDeviationResponse{
- Name: d.Name(),
- Intent: upd.Owner(),
- Event: sdcpb.DeviationEvent_UPDATE,
- Reason: sdcpb.DeviationReason_UNHANDLED,
- Path: sp,
- CurrentValue: v,
- }
- for _, dc := range dm {
- err = dc.Send(rsp)
- if err != nil {
- log.Errorf("%s: failed to send deviation: %v", d.Name(), err)
- continue
- }
- }
- continue
- }
- // NOT_APPLIED or OVERRULED deviation
- // sort intent updates by priority/TS
- sort.Slice(intentsUpdates, func(i, j int) bool {
- if intentsUpdates[i].Priority() == intentsUpdates[j].Priority() {
- return intentsUpdates[i].TS() < intentsUpdates[j].TS()
- }
- return intentsUpdates[i].Priority() < intentsUpdates[j].Priority()
- })
- // first intent
- // // compare values with config
- fiv, err := intentsUpdates[0].Value()
- if err != nil {
- log.Errorf("%s: failed to convert intent value: %v", d.Name(), err)
- continue
- }
- sp, err := d.schemaClient.ToPath(ctx, intentsUpdates[0].GetPath())
- if err != nil {
- log.Errorf("%s: failed to convert path %v: %v", d.Name(), intentsUpdates[0].GetPath(), err)
- continue
- }
- scRsp, err := d.schemaClient.GetSchemaSdcpbPath(ctx, sp)
- if err != nil {
- log.Errorf("%s: failed to get path schema: %v ", d.Name(), err)
- continue
- }
- nfiv, err := utils.TypedValueToYANGType(fiv, scRsp.GetSchema())
- if err != nil {
- log.Errorf("%s: failed to convert value to its YANG type: %v ", d.Name(), err)
- continue
- }
- if !utils.EqualTypedValues(nfiv, v) {
- log.Debugf("%s: intent %s has a NOT_APPLIED deviation: configured: %v -> expected %v",
- d.Name(), intentsUpdates[0].Owner(), v, nfiv)
- rsp := &sdcpb.WatchDeviationResponse{
- Name: d.Name(),
- Intent: intentsUpdates[0].Owner(),
- Event: sdcpb.DeviationEvent_UPDATE,
- Reason: sdcpb.DeviationReason_NOT_APPLIED,
- Path: sp,
- ExpectedValue: nfiv,
- CurrentValue: v,
- }
- for _, dc := range dm {
- err = dc.Send(rsp)
- if err != nil {
- log.Errorf("%s: failed to send deviation: %v", d.Name(), err)
- continue
- }
- }
- xp := utils.ToXPath(sp, false)
- if _, ok := newDeviations[xp]; !ok {
- newDeviations[xp] = make([]*sdcpb.WatchDeviationResponse, 0, 1)
- }
- newDeviations[xp] = append(newDeviations[xp], rsp)
- }
- // remaining intents
- for _, intUpd := range intentsUpdates[1:] {
- iv, err := intUpd.Value()
- if err != nil {
- log.Errorf("%s: failed to convert intent value: %v", d.Name(), err)
+ if len(deviationClients) == 0 {
continue
}
- sp, err := d.schemaClient.ToPath(ctx, intUpd.GetPath())
- if err != nil {
- log.Errorf("%s: failed to convert path %v: %v", d.Name(), intUpd.GetPath(), err)
- continue
+ for _, dc := range deviationClients {
+ dc.Send(&sdcpb.WatchDeviationResponse{
+ Name: d.config.Name,
+ Event: sdcpb.DeviationEvent_START,
+ })
}
- scRsp, err := d.schemaClient.GetSchemaSdcpbPath(ctx, sp)
+ deviationChan, err := d.calculateDeviations(ctx)
if err != nil {
- log.Errorf("%s: failed to get path schema: %v ", d.Name(), err)
+ log.Error(err)
continue
}
- niv, err := utils.TypedValueToYANGType(iv, scRsp.GetSchema())
- if err != nil {
- log.Errorf("%s: failed to convert value to its YANG type: %v ", d.Name(), err)
- continue
+ d.SendDeviations(deviationChan, deviationClients)
+ for _, dc := range deviationClients {
+ dc.Send(&sdcpb.WatchDeviationResponse{
+ Name: d.config.Name,
+ Event: sdcpb.DeviationEvent_END,
+ })
}
- if !utils.EqualTypedValues(nfiv, niv) {
- log.Debugf("%s: intent %s has an OVERRULED deviation: ruling intent has: %v -> overruled intent has: %v",
- d.Name(), intUpd.Owner(), nfiv, niv)
- // TODO: generate an OVERRULED deviation
-
- rsp := &sdcpb.WatchDeviationResponse{
- Name: d.Name(),
- Intent: intUpd.Owner(),
- Event: sdcpb.DeviationEvent_UPDATE,
- Reason: sdcpb.DeviationReason_OVERRULED,
- Path: sp,
- ExpectedValue: iv,
- CurrentValue: fiv,
- }
- for _, dc := range dm {
- err = dc.Send(rsp)
- if err != nil {
- log.Errorf("%s: failed to send deviation: %v", d.Name(), err)
- continue
- }
- }
- xp := utils.ToXPath(sp, false)
- if _, ok := newDeviations[xp]; !ok {
- newDeviations[xp] = make([]*sdcpb.WatchDeviationResponse, 0, 1)
- }
- newDeviations[xp] = append(newDeviations[xp], rsp)
+ }
+ }
+}
+
+func (d *Datastore) SendDeviations(ch <-chan *treetypes.DeviationEntry, deviationClients []sdcpb.DataServer_WatchDeviationsServer) {
+ wg := &sync.WaitGroup{}
+ for {
+ select {
+ case de, ok := <-ch:
+ if !ok {
+ wg.Wait()
+ return
}
+ wg.Add(1)
+ go func(de DeviationEntry, dcs []sdcpb.DataServer_WatchDeviationsServer) {
+ for _, dc := range dcs {
+ dc.Send(&sdcpb.WatchDeviationResponse{
+ Name: d.config.Name,
+ Intent: de.IntentName(),
+ Event: sdcpb.DeviationEvent_UPDATE,
+ Reason: sdcpb.DeviationReason(de.Reason()),
+ Path: de.Path(),
+ ExpectedValue: de.ExpectedValue(),
+ CurrentValue: de.CurrentValue(),
+ })
+ }
+ wg.Done()
+ }(de, deviationClients)
}
}
+}
+
+type DeviationEntry interface {
+ IntentName() string
+ Reason() treetypes.DeviationReason
+ Path() *sdcpb.Path
+ CurrentValue() *sdcpb.TypedValue
+ ExpectedValue() *sdcpb.TypedValue
+}
+
+func (d *Datastore) calculateDeviations(ctx context.Context) (<-chan *treetypes.DeviationEntry, error) {
+ deviationChan := make(chan *treetypes.DeviationEntry, 10)
- intendedUpdates, err := d.readStoreKeysMeta(ctx, cachepb.Store_INTENDED)
+ d.syncTreeMutex.RLock()
+ defer d.syncTreeMutex.RUnlock()
+
+ deviationTree, err := d.syncTree.DeepCopy(ctx)
if err != nil {
- log.Error(err)
- return
+ return nil, err
}
- for _, upds := range intendedUpdates {
- for _, upd := range upds {
- path := strings.Join(upd.GetPath(), sep)
- if _, exists := configPaths[path]; !exists {
-
- // iv, err := upd.Value()
- // if err != nil {
- // log.Errorf("%s: failed to convert intent value: %v", d.Name(), err)
- // continue
- // }
+ addedIntentNames, err := d.LoadAllButRunningIntents(ctx, deviationTree)
+ if err != nil {
+ return nil, err
+ }
- path, err := d.schemaClient.ToPath(ctx, upd.GetPath())
- if err != nil {
- log.Error(err)
- continue
- }
- // scRsp, err := d.getSchema(ctx, path)
- // if err != nil {
- // log.Errorf("%s: failed to get path schema: %v ", d.Name(), err)
- // continue
- // }
- // niv, err := d.typedValueToYANGType(iv, scRsp.GetSchema())
- // if err != nil {
- // log.Errorf("%s: failed to convert value to its YANG type: %v ", d.Name(), err)
- // continue
- // }
-
- rsp := &sdcpb.WatchDeviationResponse{
- Name: d.Name(),
- Intent: upd.Owner(),
- Event: sdcpb.DeviationEvent_UPDATE,
- Reason: sdcpb.DeviationReason_NOT_APPLIED,
- Path: path,
- ExpectedValue: nil, // TODO this need to be fixed
- CurrentValue: nil,
- }
- for _, dc := range dm {
- err = dc.Send(rsp)
- if err != nil {
- log.Errorf("%s: failed to send deviation: %v", d.Name(), err)
- continue
- }
- }
- }
- }
+ // Send IntentExists
+ for _, n := range addedIntentNames {
+ deviationChan <- treetypes.NewDeviationEntry(n, treetypes.DeviationReasonIntentExists, nil)
}
- // send deviation event END
- for _, dc := range dm {
- err := dc.Send(&sdcpb.WatchDeviationResponse{
- Name: d.Name(),
- Event: sdcpb.DeviationEvent_END,
- })
- if err != nil {
- log.Errorf("%s: failed to send deviation end: %v", d.Name(), err)
- continue
- }
+ err = deviationTree.FinishInsertionPhase(ctx)
+ if err != nil {
+ return nil, err
}
- d.md.Lock()
- d.currentIntentsDeviations = newDeviations
- d.md.Unlock()
+
+ go func() {
+ deviationTree.GetDeviations(deviationChan)
+ close(deviationChan)
+ }()
+
+ return deviationChan, nil
}
// DatastoreRollbackAdapter implements the types.RollbackInterface and encapsulates the Datastore.
diff --git a/pkg/datastore/intent_rpc.go b/pkg/datastore/intent_rpc.go
index 9ebe1a73..f14d62be 100644
--- a/pkg/datastore/intent_rpc.go
+++ b/pkg/datastore/intent_rpc.go
@@ -18,17 +18,15 @@ import (
"context"
"errors"
"fmt"
- "sort"
- "strconv"
- "strings"
- "github.com/sdcio/cache/proto/cachepb"
+ "github.com/beevik/etree"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
log "github.com/sirupsen/logrus"
- "google.golang.org/protobuf/proto"
- "github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/datastore/target"
+ "github.com/sdcio/data-server/pkg/tree"
+ "github.com/sdcio/data-server/pkg/tree/importer/proto"
+ "github.com/sdcio/data-server/pkg/tree/types"
)
var rawIntentPrefix = "__raw_intent__"
@@ -39,69 +37,6 @@ const (
var ErrIntentNotFound = errors.New("intent not found")
-func (d *Datastore) GetIntent(ctx context.Context, req *sdcpb.GetIntentRequest) (*sdcpb.GetIntentResponse, error) {
- r, err := d.getRawIntent(ctx, req.GetIntent(), req.GetPriority())
- if err != nil {
- return nil, err
- }
-
- rsp := &sdcpb.GetIntentResponse{
- Name: d.Name(),
- Intent: &sdcpb.Intent{
- Intent: r.GetIntent(),
- Priority: r.GetPriority(),
- Update: r.GetUpdate(),
- },
- }
- return rsp, nil
-}
-
-// func (d *Datastore) SetIntent(ctx context.Context, req *sdcpb.SetIntentRequest) (*sdcpb.SetIntentResponse, error) {
-// if !d.intentMutex.TryLock() {
-// return nil, status.Errorf(codes.ResourceExhausted, "datastore %s has an ongoing SetIntentRequest", d.Name())
-// }
-// defer d.intentMutex.Unlock()
-
-// log.Infof("received SetIntentRequest: ds=%s intent=%s", req.GetName(), req.GetIntent())
-// now := time.Now().UnixNano()
-// candidateName := fmt.Sprintf("%s-%d", req.GetIntent(), now)
-// err := d.CreateCandidate(ctx, &sdcpb.DataStore{
-// Type: sdcpb.Type_CANDIDATE,
-// Name: candidateName,
-// Owner: req.GetIntent(),
-// Priority: req.GetPriority(),
-// })
-// if err != nil {
-// return nil, err
-// }
-// defer func() {
-// // delete candidate
-// err := d.cacheClient.DeleteCandidate(ctx, d.Name(), candidateName)
-// if err != nil {
-// log.Errorf("%s: failed to delete candidate %s: %v", d.Name(), candidateName, err)
-// }
-// }()
-
-// setIntentResponse, err := d.SetIntentUpdate(ctx, req, candidateName)
-// if err != nil {
-// log.Errorf("%s: failed to SetIntentUpdate: %v", d.Name(), err)
-// return nil, err
-// }
-
-// return setIntentResponse, nil
-// }
-
-func (d *Datastore) ListIntent(ctx context.Context, req *sdcpb.ListIntentRequest) (*sdcpb.ListIntentResponse, error) {
- intents, err := d.listRawIntent(ctx)
- if err != nil {
- return nil, err
- }
- return &sdcpb.ListIntentResponse{
- Name: req.GetName(),
- Intent: intents,
- }, nil
-}
-
func (d *Datastore) applyIntent(ctx context.Context, source target.TargetSource) (*sdcpb.SetDataResponse, error) {
var err error
@@ -121,107 +56,62 @@ func (d *Datastore) applyIntent(ctx context.Context, source target.TargetSource)
return rsp, nil
}
-func (d *Datastore) saveRawIntent(ctx context.Context, intentName string, req *sdcpb.SetIntentRequest) error {
- b, err := proto.Marshal(req)
- if err != nil {
- return err
- }
- //
- rin := rawIntentName(intentName, req.GetPriority())
- upd, err := d.cacheClient.NewUpdate(
- &sdcpb.Update{
- Path: &sdcpb.Path{
- Elem: []*sdcpb.PathElem{{Name: rin}},
- },
- Value: &sdcpb.TypedValue{
- Value: &sdcpb.TypedValue_BytesVal{BytesVal: b},
- },
- },
- )
+func (d *Datastore) GetIntent(ctx context.Context, intentName string) (GetIntentResponse, error) {
+ root, err := tree.NewTreeRoot(ctx, tree.NewTreeContext(d.schemaClient, intentName))
if err != nil {
- return err
- }
- err = d.cacheClient.Modify(ctx, d.config.Name,
- &cache.Opts{
- Store: cachepb.Store_INTENTS,
- },
- nil,
- []*cache.Update{upd})
- if err != nil {
- return err
+ return nil, err
}
- return nil
-}
-func (d *Datastore) getRawIntent(ctx context.Context, intentName string, priority int32) (*sdcpb.SetIntentRequest, error) {
- rin := rawIntentName(intentName, priority)
- upds := d.cacheClient.Read(ctx, d.config.Name, &cache.Opts{
- Store: cachepb.Store_INTENTS,
- }, [][]string{{rin}}, 0)
- if len(upds) == 0 {
- return nil, ErrIntentNotFound
+ tp, err := d.cacheClient.IntentGet(ctx, intentName)
+ if err != nil {
+ return nil, err
}
+ protoImporter := proto.NewProtoTreeImporter(tp.GetRoot())
- val, err := upds[0].Value()
+ err = root.ImportConfig(ctx, nil, protoImporter, tp.GetIntentName(), tp.GetPriority(), types.NewUpdateInsertFlags())
if err != nil {
return nil, err
}
- req := &sdcpb.SetIntentRequest{}
- err = proto.Unmarshal(val.GetBytesVal(), req)
+
+ err = root.FinishInsertionPhase(ctx)
if err != nil {
return nil, err
}
- return req, nil
+ return newTreeRootToGetIntentResponse(root), nil
}
-func (d *Datastore) listRawIntent(ctx context.Context) ([]*sdcpb.Intent, error) {
- upds := d.cacheClient.Read(ctx, d.config.Name, &cache.Opts{
- Store: cachepb.Store_INTENTS,
- KeysOnly: true,
- }, [][]string{{"*"}}, 0)
- numUpds := len(upds)
- if numUpds == 0 {
- return nil, nil
- }
- intents := make([]*sdcpb.Intent, 0, numUpds)
- for _, upd := range upds {
- if len(upd.GetPath()) == 0 {
- return nil, fmt.Errorf("malformed raw intent name: %q", upd.GetPath()[0])
- }
- intentRawName := strings.TrimPrefix(upd.GetPath()[0], rawIntentPrefix)
- intentNameComp := strings.Split(intentRawName, intentRawNameSep)
- inc := len(intentNameComp)
- if inc < 2 {
- return nil, fmt.Errorf("malformed raw intent name: %q", upd.GetPath()[0])
- }
- pr, err := strconv.Atoi(intentNameComp[inc-1])
- if err != nil {
- return nil, fmt.Errorf("malformed raw intent name: %q: %v", upd.GetPath()[0], err)
- }
- in := &sdcpb.Intent{
- Intent: strings.Join(intentNameComp[:inc-1], intentRawNameSep),
- Priority: int32(pr),
- }
- intents = append(intents, in)
+type GetIntentResponse interface {
+ // ToJson returns the Tree contained structure as JSON
+ // use e.g. json.MarshalIndent() on the returned struct
+ ToJson() (any, error)
+ // ToJsonIETF returns the Tree contained structure as JSON_IETF
+ // use e.g. json.MarshalIndent() on the returned struct
+ ToJsonIETF() (any, error)
+ ToXML() (*etree.Document, error)
+ ToProtoUpdates(ctx context.Context) ([]*sdcpb.Update, error)
+}
+
+type treeRootToGetIntentResponse struct {
+ root *tree.RootEntry
+}
+
+func newTreeRootToGetIntentResponse(root *tree.RootEntry) *treeRootToGetIntentResponse {
+ return &treeRootToGetIntentResponse{
+ root: root,
}
- sort.Slice(intents, func(i, j int) bool {
- if intents[i].GetPriority() == intents[j].GetPriority() {
- return intents[i].GetIntent() < intents[j].GetIntent()
- }
- return intents[i].GetPriority() < intents[j].GetPriority()
- })
- return intents, nil
}
-func (d *Datastore) deleteRawIntent(ctx context.Context, intentName string, priority int32) error {
- return d.cacheClient.Modify(ctx, d.config.Name,
- &cache.Opts{
- Store: cachepb.Store_INTENTS,
- },
- [][]string{{rawIntentName(intentName, priority)}},
- nil)
+func (t *treeRootToGetIntentResponse) ToJson() (any, error) {
+ return t.root.ToJson(false)
}
-func rawIntentName(name string, pr int32) string {
- return fmt.Sprintf("%s%s%s%d", rawIntentPrefix, name, intentRawNameSep, pr)
+func (t *treeRootToGetIntentResponse) ToJsonIETF() (any, error) {
+ return t.root.ToJsonIETF(false)
+}
+
+func (t *treeRootToGetIntentResponse) ToXML() (*etree.Document, error) {
+ return t.root.ToXML(false, true, false, false)
+}
+func (t *treeRootToGetIntentResponse) ToProtoUpdates(ctx context.Context) ([]*sdcpb.Update, error) {
+ return t.root.ToProtoUpdates(ctx, false)
}
diff --git a/pkg/datastore/target/gnmi.go b/pkg/datastore/target/gnmi.go
index 3f09e2c5..579d4405 100644
--- a/pkg/datastore/target/gnmi.go
+++ b/pkg/datastore/target/gnmi.go
@@ -26,8 +26,8 @@ import (
"github.com/AlekSi/pointer"
"github.com/openconfig/gnmi/proto/gnmi"
gapi "github.com/openconfig/gnmic/pkg/api"
- gtarget "github.com/openconfig/gnmic/pkg/target"
- "github.com/openconfig/gnmic/pkg/types"
+ gtarget "github.com/openconfig/gnmic/pkg/api/target"
+ "github.com/openconfig/gnmic/pkg/api/types"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
log "github.com/sirupsen/logrus"
"google.golang.org/grpc"
@@ -376,9 +376,6 @@ func (t *gnmiTarget) getSync(ctx context.Context, gnmiSync *config.SyncProtocol,
Name: gnmiSync.Name,
Path: paths,
DataType: sdcpb.DataType_CONFIG,
- Datastore: &sdcpb.DataStore{
- Type: sdcpb.Type_MAIN,
- },
Encoding: sdcpb.Encoding(sdcpbEncoding(gnmiSync.Encoding)),
}
@@ -413,6 +410,7 @@ func (t *gnmiTarget) internalGetSync(ctx context.Context, req *sdcpb.GetDataRequ
Start: true,
}
notificationsCount := 0
+
for _, n := range resp.GetNotification() {
syncCh <- &SyncUpdate{
Update: n,
diff --git a/pkg/datastore/target/nc.go b/pkg/datastore/target/nc.go
index 4cea0702..9ab93740 100644
--- a/pkg/datastore/target/nc.go
+++ b/pkg/datastore/target/nc.go
@@ -65,14 +65,7 @@ func (t *ncTarget) Get(ctx context.Context, req *sdcpb.GetDataRequest) (*sdcpb.G
if !t.Status().IsConnected() {
return nil, fmt.Errorf("%s", TargetStatusNotConnected)
}
- var source string
-
- switch req.Datastore.Type {
- case sdcpb.Type_MAIN:
- source = "running"
- case sdcpb.Type_CANDIDATE:
- source = "candidate"
- }
+ source := "running"
// init a new XMLConfigBuilder for the pathfilter
pathfilterXmlBuilder := netconf.NewXMLConfigBuilder(t.schemaClient,
@@ -205,9 +198,6 @@ func (t *ncTarget) internalSync(ctx context.Context, sc *config.SyncProtocol, fo
Name: sc.Name,
Path: paths,
DataType: sdcpb.DataType_CONFIG,
- Datastore: &sdcpb.DataStore{
- Type: sdcpb.Type_MAIN,
- },
}
// execute netconf get
diff --git a/pkg/datastore/target/nc_test.go b/pkg/datastore/target/nc_test.go
index 20c9c3de..7fc82359 100644
--- a/pkg/datastore/target/nc_test.go
+++ b/pkg/datastore/target/nc_test.go
@@ -159,9 +159,6 @@ func Test_ncTarget_Get(t *testing.T) {
args: args{
ctx: context.Background(),
req: &sdcpb.GetDataRequest{
- Datastore: &sdcpb.DataStore{
- Type: sdcpb.Type_MAIN,
- },
Path: []*sdcpb.Path{
{
Elem: []*sdcpb.PathElem{
diff --git a/pkg/datastore/transaction_rpc.go b/pkg/datastore/transaction_rpc.go
index 9b26782a..4a803307 100644
--- a/pkg/datastore/transaction_rpc.go
+++ b/pkg/datastore/transaction_rpc.go
@@ -4,64 +4,27 @@ import (
"context"
"errors"
"fmt"
- "slices"
"strings"
"time"
- "github.com/sdcio/cache/proto/cachepb"
- "github.com/sdcio/data-server/pkg/cache"
+ "github.com/sdcio/data-server/pkg/config"
"github.com/sdcio/data-server/pkg/datastore/types"
"github.com/sdcio/data-server/pkg/tree"
- "github.com/sdcio/data-server/pkg/utils"
+ treeproto "github.com/sdcio/data-server/pkg/tree/importer/proto"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
+ treetypes "github.com/sdcio/data-server/pkg/tree/types"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
log "github.com/sirupsen/logrus"
- "google.golang.org/protobuf/proto"
)
var (
- ErrDatastoreLocked = errors.New("Datastore is locked, other action is ongoing.")
+ ErrDatastoreLocked = errors.New("Datastore is locked, other action is ongoing")
+ ErrValidationError = errors.New("validation error")
)
-// expandAndConvertIntent takes a slice of Updates ([]*sdcpb.Update) and converts it into a tree.UpdateSlice, that contains *cache.Updates.
-func (d *Datastore) expandAndConvertIntent(ctx context.Context, intentName string, priority int32, upds []*sdcpb.Update) (tree.UpdateSlice, error) {
- converter := utils.NewConverter(d.schemaClient)
-
- // list of updates to be added to the cache
- // Expands the value, in case of json to single typed value updates
- expandedReqUpdates, err := converter.ExpandUpdates(ctx, upds, true)
- if err != nil {
- return nil, err
- }
-
- // temp storage for cache.Update of the req. They are to be added later.
- newCacheUpdates := make([]*cache.Update, 0, len(expandedReqUpdates))
-
- for _, u := range expandedReqUpdates {
- pathslice, err := utils.CompletePath(nil, u.GetPath())
- if err != nil {
- return nil, err
- }
-
- // since we already have the pathslice, we construct the cache.Update, but keep it for later
- // addition to the tree. First we need to mark the existing once for deletion
-
- // make sure typedValue is carrying the correct type
- err = d.validateUpdate(ctx, u)
- if err != nil {
- return nil, err
- }
-
- // convert value to []byte for cache insertion
- val, err := proto.Marshal(u.GetValue())
- if err != nil {
- return nil, err
- }
-
- // construct the cache.Update
- newCacheUpdates = append(newCacheUpdates, cache.NewUpdate(pathslice, val, priority, intentName, 0))
- }
- return newCacheUpdates, nil
-}
+const (
+ ConcurrentValidate = false
+)
// SdcpbTransactionIntentToInternalTI converts sdcpb.TransactionIntent to types.TransactionIntent
func (d *Datastore) SdcpbTransactionIntentToInternalTI(ctx context.Context, req *sdcpb.TransactionIntent) (*types.TransactionIntent, error) {
@@ -78,13 +41,13 @@ func (d *Datastore) SdcpbTransactionIntentToInternalTI(ctx context.Context, req
}
// convert the sdcpb.updates to tree.UpdateSlice
- cacheUpdates, err := d.expandAndConvertIntent(ctx, req.GetIntent(), req.GetPriority(), req.GetUpdate())
+ Updates, err := treetypes.ExpandAndConvertIntent(ctx, d.schemaClient, req.GetIntent(), req.GetPriority(), req.GetUpdate(), time.Now().Unix())
if err != nil {
return nil, err
}
// add the intent to the TransactionIntent
- ti.AddUpdates(cacheUpdates)
+ ti.AddUpdates(Updates)
return ti, nil
}
@@ -93,11 +56,8 @@ func (d *Datastore) SdcpbTransactionIntentToInternalTI(ctx context.Context, req
// returns the warnings as a []string and potential errors that happend during validation / from SBI Set()
func (d *Datastore) replaceIntent(ctx context.Context, transaction *types.Transaction) ([]string, error) {
- treeSCC := tree.NewTreeCacheClient(d.Name(), d.cacheClient)
// create a new TreeContext
- tc := tree.NewTreeContext(treeSCC, d.schemaClient, d.Name())
- // refresh the Cache content of the treeCacheSchemaClient
- tc.GetTreeSchemaCacheClient().RefreshCaches(ctx)
+ tc := tree.NewTreeContext(d.schemaClient, d.Name())
// create a new TreeRoot to collect validate and hand to SBI.Set()
root, err := tree.NewTreeRoot(ctx, tc)
@@ -109,25 +69,31 @@ func (d *Datastore) replaceIntent(ctx context.Context, transaction *types.Transa
tc.SetActualOwner(tree.ReplaceIntentName)
// store the actual / old running in the transaction
- runningUpds, err := tc.GetTreeSchemaCacheClient().ReadRunningFull(ctx)
- transaction.GetOldRunning().AddUpdates(runningUpds)
+ runningProto, err := d.cacheClient.IntentGet(ctx, tree.RunningIntentName)
+ err = root.ImportConfig(ctx, nil, treeproto.NewProtoTreeImporter(runningProto.GetRoot()), tree.RunningIntentName, tree.RunningValuesPrio, treetypes.NewUpdateInsertFlags())
+ if err != nil {
+ return nil, err
+ }
// creat a InsertFlags struct with the New flag set.
- flagNew := tree.NewUpdateInsertFlags()
+ flagNew := treetypes.NewUpdateInsertFlags()
flagNew.SetNewFlag()
// add all the replace transaction updates with the New flag set
- err = root.AddCacheUpdatesRecursive(ctx, transaction.GetReplace().GetUpdates(), flagNew)
+ err = root.AddUpdatesRecursive(ctx, transaction.GetReplace().GetUpdates(), flagNew)
if err != nil {
return nil, err
}
log.Debugf("Transaction Replace: %s - finish tree insertion phase", transaction.GetTransactionId())
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ return nil, err
+ }
log.Debug(root.String())
// perform validation
- validationResult := root.Validate(ctx, d.config.Validation)
+ validationResult := root.Validate(ctx, &config.Validation{DisableConcurrency: !ConcurrentValidate})
validationResult.ErrorsStr()
if validationResult.HasErrors() {
return nil, validationResult.JoinErrors()
@@ -149,36 +115,53 @@ func (d *Datastore) replaceIntent(ctx context.Context, transaction *types.Transa
// collect warnings
warnings = append(warnings, dataResp.GetWarnings()...)
- // query tree for deletes
- deletes, err := root.GetDeletes(true)
- if err != nil {
- return nil, err
- }
-
- // fast and optimistic writeback to the config store
- err = d.cacheClient.Modify(ctx, d.Name(), &cache.Opts{
- Store: cachepb.Store_CONFIG,
- }, deletes.PathSlices().ToStringSlice(), root.GetHighestPrecedence(false).ToCacheUpdateSlice())
- if err != nil {
- return nil, fmt.Errorf("failed updating the running config store for %s: %w", d.Name(), err)
- }
-
log.Infof("ds=%s transaction=%s applied", d.Name(), transaction.GetTransactionId()+" - replace")
return warnings, nil
}
+func (d *Datastore) LoadAllButRunningIntents(ctx context.Context, root *tree.RootEntry) ([]string, error) {
+
+ IntentNames := []string{}
+ IntentChan := make(chan *tree_persist.Intent, 0)
+ ErrChan := make(chan error, 1)
+
+ go d.cacheClient.IntentGetAll(ctx, []string{"running"}, IntentChan, ErrChan)
+
+ for {
+ select {
+ case err := <-ErrChan:
+ return nil, err
+ case <-ctx.Done():
+ return nil, fmt.Errorf("context closed while retrieving all intents")
+ case intent, ok := <-IntentChan:
+ if !ok {
+ // IntentChan closed due to finish
+ return nil, nil
+ }
+ IntentNames = append(IntentNames, intent.GetIntentName())
+ log.Debugf("adding intent %s to tree", intent.GetIntentName())
+ protoLoader := treeproto.NewProtoTreeImporter(intent.GetRoot())
+ log.Debugf(intent.String())
+ err := root.ImportConfig(ctx, nil, protoLoader, intent.GetIntentName(), intent.GetPriority(), treetypes.NewUpdateInsertFlags())
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+}
+
// lowlevelTransactionSet
func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *types.Transaction, dryRun bool) (*sdcpb.TransactionSetResponse, error) {
+ // create a new TreeRoot
+ d.syncTreeMutex.Lock()
+ root, err := d.syncTree.DeepCopy(ctx)
+ d.syncTreeMutex.Unlock()
+ if err != nil {
+ return nil, err
+ }
- treeSCC := tree.NewTreeCacheClient(d.Name(), d.cacheClient)
- // create a new TreeContext
- tc := tree.NewTreeContext(treeSCC, d.schemaClient, d.Name())
- // refresh the SchemaClientCache
- tc.GetTreeSchemaCacheClient().RefreshCaches(ctx)
-
- // creat a new TreeRoot
- root, err := tree.NewTreeRoot(ctx, tc)
+ _, err = d.LoadAllButRunningIntents(ctx, root)
if err != nil {
return nil, err
}
@@ -187,25 +170,22 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
// this is then used to load the IntendedStore highes prio into the tree, to decide if an update
// is to be applied or if a higher precedence update exists and is therefore not applicable. Also if the value got
// deleted and a previousely shadowed entry becomes active.
- involvedPaths := tree.NewPathSet()
+ involvedPaths := treetypes.NewPathSet()
// create a flags attribute
- flagNew := tree.NewUpdateInsertFlags()
+ flagNew := treetypes.NewUpdateInsertFlags()
// where the New flag is set
flagNew.SetNewFlag()
// iterate through all the intents
for _, intent := range transaction.GetNewIntents() {
// update the TreeContext to reflect the actual owner (intent name)
- tc.SetActualOwner(intent.GetName())
+ lvs := tree.LeafVariantSlice{}
+ lvs = root.GetByOwner(intent.GetName(), lvs)
- log.Debugf("Transaction: %s - adding intent %s to tree", transaction.GetTransactionId(), intent.GetName())
+ oldIntentContent := lvs.ToUpdateSlice()
- // load the old intent content into the tree and return it
- oldIntentContent, err := root.LoadIntendedStoreOwnerData(ctx, intent.GetName(), intent.GetOnlyIntended())
- if err != nil {
- return nil, err
- }
+ root.MarkOwnerDelete(intent.GetName(), intent.GetOnlyIntended())
// store the old intent content in the transaction as the old intent.
err = transaction.AddIntentContent(intent.GetName(), types.TransactionIntentOld, oldIntentContent.GetFirstPriorityValue(), oldIntentContent)
@@ -214,7 +194,7 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
}
// add the content to the Tree
- err = root.AddCacheUpdatesRecursive(ctx, intent.GetUpdates(), flagNew)
+ err = root.AddUpdatesRecursive(ctx, intent.GetUpdates(), flagNew)
if err != nil {
return nil, err
}
@@ -225,26 +205,22 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
involvedPaths.Join(intent.GetUpdates().ToPathSet())
}
- // load the alternatives for the involved paths into the tree
- err = loadIntendedStoreHighestPrio(ctx, treeSCC, root, involvedPaths, transaction.GetIntentNames())
- if err != nil {
- return nil, err
- }
+ les := tree.LeafVariantSlice{}
+ les = root.GetByOwner(tree.RunningIntentName, les)
- // add running to the tree
- err = populateTreeWithRunning(ctx, treeSCC, root)
- if err != nil {
- return nil, err
- }
+ transaction.GetOldRunning().AddUpdates(les.ToUpdateSlice())
log.Debugf("Transaction: %s - finish tree insertion phase", transaction.GetTransactionId())
// FinishInsertion Phase
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ return nil, err
+ }
log.Debug(root.String())
// perform validation
- validationResult := root.Validate(ctx, d.config.Validation)
+ validationResult := root.Validate(ctx, &config.Validation{DisableConcurrency: !ConcurrentValidate})
// prepare the response struct
result := &sdcpb.TransactionSetResponse{
@@ -271,7 +247,7 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
// convert updates from cache.Update to sdcpb.Update
// adding them to the response
- result.Update, err = cacheUpdateToSdcpbUpdate(updates)
+ result.Update, err = updateToSdcpbUpdate(updates)
if err != nil {
return nil, err
}
@@ -287,7 +263,7 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
// Error out if validation failed.
if validationResult.HasErrors() {
- return result, nil
+ return result, ErrValidationError
}
log.Infof("Transaction: %s - validation passed", transaction.GetTransactionId())
@@ -312,11 +288,8 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
/////////////////////////////////////
// logging
- strSl := tree.Map(updates.ToCacheUpdateSlice(), func(u *cache.Update) string { return u.String() })
+ strSl := treetypes.Map(updates.ToUpdateSlice(), func(u *treetypes.Update) string { return u.String() })
log.Debugf("Updates\n%s", strings.Join(strSl, "\n"))
-
- delSl := deletes.PathSlices()
-
log.Debugf("Deletes:\n%s", strings.Join(strSl, "\n"))
for _, intent := range transaction.GetNewIntents() {
@@ -325,30 +298,47 @@ func (d *Datastore) lowlevelTransactionSet(ctx context.Context, transaction *typ
deletesOwner := root.GetDeletesForOwner(intent.GetName())
// logging
- strSl := tree.Map(updatesOwner, func(u *cache.Update) string { return u.String() })
+ strSl := treetypes.Map(updatesOwner, func(u *treetypes.Update) string { return u.String() })
log.Debugf("Updates Owner: %s\n%s", intent.GetName(), strings.Join(strSl, "\n"))
delSl := deletesOwner.StringSlice()
- log.Debugf("Deletes Owner: %s \n%s", intent.GetName(), strings.Join(delSl, "\n"))
-
- // modify intended store per intent
- err = d.cacheClient.Modify(ctx, d.Name(), &cache.Opts{
- Store: cachepb.Store_INTENDED,
- Owner: intent.GetName(),
- Priority: intent.GetPriority(),
- }, deletesOwner.ToStringSlice(), updatesOwner)
-
+ log.Debugf("Deletes Owner: %s\n%s", intent.GetName(), strings.Join(delSl, "\n"))
+
+ protoIntent, err := root.TreeExport(intent.GetName(), intent.GetPriority())
+ switch {
+ case errors.Is(err, tree.ErrorIntentNotPresent):
+ err = d.cacheClient.IntentDelete(ctx, intent.GetName())
+ if err != nil {
+ return nil, fmt.Errorf("failed deleting intent from store for %s: %w", d.Name(), err)
+ }
+ continue
+ case err != nil:
+ return nil, err
+ }
+ err = d.cacheClient.IntentModify(ctx, protoIntent)
if err != nil {
return nil, fmt.Errorf("failed updating the intended store for %s: %w", d.Name(), err)
}
}
- // fast and optimistic writeback to the config store
- err = d.cacheClient.Modify(ctx, d.Name(), &cache.Opts{
- Store: cachepb.Store_CONFIG,
- }, delSl.ToStringSlice(), updates.ToCacheUpdateSlice())
+ // OPTIMISTIC WRITEBACK TO RUNNING
+ runningUpdates := updates.ToUpdateSlice().CopyWithNewOwnerAndPrio(tree.RunningIntentName, tree.RunningValuesPrio)
+
+ // add the calculated updates to the tree, as running with adjusted prio and owner
+ err = root.AddUpdatesRecursive(ctx, runningUpdates, treetypes.NewUpdateInsertFlags())
if err != nil {
- return nil, fmt.Errorf("failed updating the running config store for %s: %w", d.Name(), err)
+ return nil, err
+ }
+
+ // perform deletes
+ root.DeleteSubtreePaths(deletes, tree.RunningIntentName)
+
+ newRunningIntent, err := root.TreeExport(tree.RunningIntentName, tree.RunningValuesPrio)
+ if newRunningIntent != nil {
+ err = d.cacheClient.IntentModify(ctx, newRunningIntent)
+ if err != nil {
+ return nil, fmt.Errorf("failed updating the running store for %s: %w", d.Name(), err)
+ }
}
log.Infof("ds=%s transaction=%s: completed", d.Name(), transaction.GetTransactionId())
@@ -425,6 +415,13 @@ func (d *Datastore) TransactionSet(ctx context.Context, transactionId string, tr
}
response, err := d.lowlevelTransactionSet(ctx, transaction, dryRun)
+ // if it is a validation error, we need to send the response while not successing the transaction guard
+ // since validation errors are transported in the response itself, not in the seperate error
+ if errors.Is(err, ErrValidationError) {
+ log.Errorf("Transaction: %s - validation failed\n%s", transactionId, strings.Join(response.GetErrors(), "\n"))
+ return response, nil
+ }
+ // if it is any other error, return a regular error
if err != nil {
log.Errorf("error executing transaction: %v", err)
return nil, err
@@ -437,17 +434,14 @@ func (d *Datastore) TransactionSet(ctx context.Context, transactionId string, tr
return response, err
}
-func cacheUpdateToSdcpbUpdate(lvs tree.LeafVariantSlice) ([]*sdcpb.Update, error) {
+func updateToSdcpbUpdate(lvs tree.LeafVariantSlice) ([]*sdcpb.Update, error) {
result := make([]*sdcpb.Update, 0, len(lvs))
for _, lv := range lvs {
path, err := lv.GetEntry().SdcpbPath()
if err != nil {
return nil, err
}
- value, err := lv.Update.Value()
- if err != nil {
- return nil, err
- }
+ value := lv.Value()
upd := &sdcpb.Update{
Path: path,
Value: value,
@@ -478,78 +472,3 @@ func (d *Datastore) TransactionCancel(ctx context.Context, transactionId string)
return d.transactionManager.Cancel(ctx, transactionId)
}
-
-func loadIntendedStoreHighestPrio(ctx context.Context, tscc tree.TreeCacheClient, r *tree.RootEntry, pathKeySet *tree.PathSet, skipIntents []string) error {
-
- // Get all entries of the already existing intent
- cacheEntries := tscc.ReadCurrentUpdatesHighestPriorities(ctx, pathKeySet.GetPaths(), 2)
-
- flags := tree.NewUpdateInsertFlags()
-
- // add all the existing entries
- for _, entry := range cacheEntries {
- // we need to skip the actual owner entries
- if slices.Contains(skipIntents, entry.Owner()) {
- continue
- }
- _, err := r.AddCacheUpdateRecursive(ctx, entry, flags)
- if err != nil {
- return err
- }
- }
- return nil
-}
-
-func populateTreeWithRunning(ctx context.Context, tscc tree.TreeCacheClient, r *tree.RootEntry) error {
- upds, err := tscc.ReadRunningFull(ctx)
- if err != nil {
- return err
- }
-
- flags := tree.NewUpdateInsertFlags()
-
- for _, upd := range upds {
- newUpd := cache.NewUpdate(upd.GetPath(), upd.Bytes(), tree.RunningValuesPrio, tree.RunningIntentName, 0)
- _, err := r.AddCacheUpdateRecursive(ctx, newUpd, flags)
- if err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func pathIsKeyAsLeaf(p *sdcpb.Path) bool {
- numPElem := len(p.GetElem())
- if numPElem < 2 {
- return false
- }
-
- _, ok := p.GetElem()[numPElem-2].GetKey()[p.GetElem()[numPElem-1].GetName()]
- return ok
-}
-
-func (d *Datastore) readStoreKeysMeta(ctx context.Context, store cachepb.Store) (map[string]tree.UpdateSlice, error) {
- entryCh, err := d.cacheClient.GetKeys(ctx, d.config.Name, store)
- if err != nil {
- return nil, err
- }
-
- result := map[string]tree.UpdateSlice{}
- for {
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- case e, ok := <-entryCh:
- if !ok {
- return result, nil
- }
- key := strings.Join(e.GetPath(), tree.KeysIndexSep)
- _, exists := result[key]
- if !exists {
- result[key] = tree.UpdateSlice{}
- }
- result[key] = append(result[key], e)
- }
- }
-}
diff --git a/pkg/datastore/tree_operation_test.go b/pkg/datastore/tree_operation_test.go
index 43810b8b..212d62f2 100644
--- a/pkg/datastore/tree_operation_test.go
+++ b/pkg/datastore/tree_operation_test.go
@@ -16,37 +16,29 @@ package datastore
import (
"context"
+ "encoding/json"
"fmt"
"strings"
"testing"
"github.com/openconfig/ygot/ygot"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
- "github.com/sdcio/data-server/mocks/mocktarget"
- "github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/config"
schemaClient "github.com/sdcio/data-server/pkg/datastore/clients/schema"
"github.com/sdcio/data-server/pkg/tree"
- "github.com/sdcio/data-server/pkg/utils"
+ jsonImporter "github.com/sdcio/data-server/pkg/tree/importer/json"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils/testhelper"
sdcio_schema "github.com/sdcio/data-server/tests/sdcioygot"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"go.uber.org/mock/gomock"
- "google.golang.org/protobuf/proto"
)
var (
// TypedValue Bool True and false
- TypedValueTrue []byte
- TypedValueFalse []byte
+ TypedValueTrue = &sdcpb.TypedValue{Value: &sdcpb.TypedValue_BoolVal{BoolVal: true}}
+ TypedValueFalse = &sdcpb.TypedValue{Value: &sdcpb.TypedValue_BoolVal{BoolVal: false}}
)
-func init() {
- // Calculate the TypedValues for true and false
- TypedValueTrue, _ = proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_BoolVal{BoolVal: true}})
- TypedValueFalse, _ = proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_BoolVal{BoolVal: true}})
-}
-
func TestDatastore_populateTree(t *testing.T) {
prio15 := int32(15)
prio10 := int32(10)
@@ -65,23 +57,23 @@ func TestDatastore_populateTree(t *testing.T) {
tests := []struct {
name string
intentReqValue func() (string, error) // depending on the path, this should be *testhelper.TestConfig or any sub-value
- intentReqPath string
+ intentReqPath types.PathSlice
intentName string
intentPrio int32
intentDelete bool
- expectedModify []*cache.Update
+ expectedModify []*types.Update
expectedDeletes [][]string
expectedOwnerDeletes [][]string
- expectedOwnerUpdates []*cache.Update
- intendedStoreUpdates []*cache.Update
- runningStoreUpdates []*cache.Update
+ expectedOwnerUpdates []*types.Update
+ intendedStoreUpdates []*types.Update
+ runningStoreUpdates []*types.Update
NotOnlyNewOrUpdated bool // it negated when used in the call, usually we want it to be true
}{
{
name: "DoubleKey - Delete Single item",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
Doublekey: map[sdcio_schema.SdcioModel_Doublekey_Key]*sdcio_schema.SdcioModel_Doublekey{
@@ -116,33 +108,33 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- runningStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto(t, "k1.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
-
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto(t, "k1.3"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
-
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto(t, "k2.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto(t, "k2.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval2.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval2.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto("k1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto("k1.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto("k1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto("k1.3"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto("k2.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto("k2.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval2.1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval2.2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
},
expectedDeletes: [][]string{
{"doublekey", "k1.1", "k1.3"},
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValueOther"), prio10, owner2, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValueOther"), prio10, owner2, 0),
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValueOther"), prio10, owner2, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValueOther"), prio10, owner2, 0),
},
expectedOwnerDeletes: [][]string{
{"doublekey", "k1.1", "k1.3", "key1"},
@@ -151,31 +143,31 @@ func TestDatastore_populateTree(t *testing.T) {
{"doublekey", "k1.1", "k1.3", "cont", "value1"},
{"doublekey", "k1.1", "k1.3", "cont", "value2"},
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto(t, "k1.2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), prio10, owner2, 0),
-
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto(t, "k1.3"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), prio10, owner2, 0),
-
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto(t, "k2.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto(t, "k2.2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval2.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval2.2"), prio10, owner2, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto("k1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto("k1.2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), prio10, owner2, 0),
+
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto("k1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto("k1.3"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), prio10, owner2, 0),
+
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto("k2.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto("k2.2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval2.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval2.2"), prio10, owner2, 0),
},
},
{
name: "DoubleKey - New Data",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
Doublekey: map[sdcio_schema.SdcioModel_Doublekey_Key]*sdcio_schema.SdcioModel_Doublekey{
@@ -222,51 +214,51 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto(t, "k1.2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), prio10, owner2, 0),
-
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto(t, "k1.3"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), prio10, owner2, 0),
-
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto(t, "k2.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto(t, "k2.2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval2.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval2.2"), prio10, owner2, 0),
- },
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto(t, "k1.2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), prio10, owner2, 0),
-
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto(t, "k1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto(t, "k1.3"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval1.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval1.2"), prio10, owner2, 0),
-
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto(t, "k2.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto(t, "k2.2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto(t, "TheMandatoryValue2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto(t, "containerval2.1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto(t, "containerval2.2"), prio10, owner2, 0),
- },
- intendedStoreUpdates: []*cache.Update{},
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto("k1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto("k1.2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), prio10, owner2, 0),
+
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto("k1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto("k1.3"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), prio10, owner2, 0),
+
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto("k2.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto("k2.2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval2.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval2.2"), prio10, owner2, 0),
+ },
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key1"}, testhelper.GetStringTvProto("k1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "key2"}, testhelper.GetStringTvProto("k1.2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), prio10, owner2, 0),
+
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key1"}, testhelper.GetStringTvProto("k1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "key2"}, testhelper.GetStringTvProto("k1.3"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value1"}, testhelper.GetStringTvProto("containerval1.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "cont", "value2"}, testhelper.GetStringTvProto("containerval1.2"), prio10, owner2, 0),
+
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key1"}, testhelper.GetStringTvProto("k2.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "key2"}, testhelper.GetStringTvProto("k2.2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value1"}, testhelper.GetStringTvProto("containerval2.1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"doublekey", "k2.1", "k2.2", "cont", "value2"}, testhelper.GetStringTvProto("containerval2.2"), prio10, owner2, 0),
+ },
+ intendedStoreUpdates: []*types.Update{},
},
{
name: "Simple add to root path",
intentName: owner1,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
Interface: map[string]*sdcio_schema.SdcioModel_Interface{},
@@ -281,13 +273,13 @@ func TestDatastore_populateTree(t *testing.T) {
})
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
intendedStoreUpdates: nil,
},
@@ -295,7 +287,7 @@ func TestDatastore_populateTree(t *testing.T) {
name: "Simple add with a specific path",
intentName: owner1,
intentPrio: prio10,
- intentReqPath: "interface",
+ intentReqPath: types.PathSlice{"interface"},
intentReqValue: func() (string, error) {
i := &sdcio_schema.SdcioModel_Interface{
@@ -307,21 +299,21 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
intendedStoreUpdates: nil,
},
{
- name: "Add with existing better prio same intent / owner",
+ name: "Add with existing better prio same intent name",
intentName: owner1,
intentPrio: prio10,
- intentReqPath: "interface",
+ intentReqPath: types.PathSlice{"interface"},
intentReqValue: func() (string, error) {
i := &sdcio_schema.SdcioModel_Interface{
Name: ygot.String("ethernet-1/1"),
@@ -332,50 +324,50 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- expectedModify: []*cache.Update{
+ expectedModify: []*types.Update{
// Right now, although the value stays the same, but the priority changes, we'll receive an update for these values.
// This maybe needs to be mitigated, but is not considered harmfull atm.
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio5, owner1, 0),
},
},
{
name: "Delete the highes priority values, making shadowed values become active",
intentName: owner1,
intentPrio: prio5,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
return "{}", nil
},
intentDelete: true,
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
},
expectedOwnerDeletes: [][]string{
{"interface", "ethernet-1/1", "name"},
{"interface", "ethernet-1/1", "description"},
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
},
},
{
name: "Delete - aggregate branch via keys",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
return "{}", nil
},
@@ -388,17 +380,17 @@ func TestDatastore_populateTree(t *testing.T) {
{"interface", "ethernet-1/1", "description"},
{"interface", "ethernet-1/1", "admin-state"},
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
},
},
{
name: "Delete - aggregate branch via keys, multiple entries (different keys)",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
Interface: map[string]*sdcio_schema.SdcioModel_Interface{
@@ -414,16 +406,16 @@ func TestDatastore_populateTree(t *testing.T) {
})
},
intentDelete: true,
- runningStoreUpdates: []*cache.Update{
- // cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/1", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/2", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/3", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/3"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/3", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-1/3", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
+ runningStoreUpdates: []*types.Update{
+ // cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/1", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/2", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/3", "name"}, testhelper.GetStringTvProto("ethernet-1/3"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/3", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ // cache.NewUpdate([]string{"interface", "ethernet-1/3", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
},
expectedDeletes: [][]string{
{"interface", "ethernet-1/1", "admin-state"},
@@ -439,30 +431,30 @@ func TestDatastore_populateTree(t *testing.T) {
{"interface", "ethernet-1/3", "description"},
{"interface", "ethernet-1/3", "admin-state"},
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyNonappliedDescription"), prio10, owner2, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyNonappliedDescription"), prio10, owner2, 0),
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyNonappliedDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyNonappliedDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/3", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/3"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/3", "description"}, testhelper.GetStringTvProto(t, "MyDescriptionOwner2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/3", "admin-state"}, testhelper.GetStringTvProto(t, "enable"), prio10, owner2, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/3", "name"}, testhelper.GetStringTvProto("ethernet-1/3"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/3", "description"}, testhelper.GetStringTvProto("MyDescriptionOwner2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/3", "admin-state"}, testhelper.GetStringTvProto("enable"), prio10, owner2, 0),
},
},
{
name: "Add lower precedence intent, every value already shadowed",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "interface",
+ intentReqPath: types.PathSlice{"interface"},
intentReqValue: func() (string, error) {
i := &sdcio_schema.SdcioModel_Interface{
Name: ygot.String("ethernet-1/1"),
@@ -473,23 +465,22 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- runningStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
},
-
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyNonappliedDescription"), prio10, owner2, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyNonappliedDescription"), prio10, owner2, 0),
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio5, owner1, 0),
},
},
{
name: "choices delete",
- intentReqPath: "interface",
+ intentReqPath: types.PathSlice{"interface"},
intentReqValue: func() (string, error) {
i := &sdcio_schema.SdcioModel_Interface{
Name: ygot.String("ethernet-1/1"),
@@ -502,19 +493,19 @@ func TestDatastore_populateTree(t *testing.T) {
},
intentPrio: 10,
intentName: owner1,
- runningStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case1", "case-elem"}, testhelper.GetStringTvProto(t, "Foobar"), prio10, owner1, 0),
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case1", "case-elem"}, testhelper.GetStringTvProto("Foobar"), prio10, owner1, 0),
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case1", "case-elem"}, testhelper.GetStringTvProto(t, "Foobar"), prio10, owner1, 0),
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case1", "case-elem"}, testhelper.GetStringTvProto("Foobar"), prio10, owner1, 0),
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio10, owner1, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio10, owner1, 0),
},
expectedDeletes: [][]string{
{"choices"},
@@ -527,7 +518,7 @@ func TestDatastore_populateTree(t *testing.T) {
name: "Mixed, new entry, higher and lower precedence",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
@@ -559,46 +550,46 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- runningStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "Owner3 Description"), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(t, 1), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio15, owner3, 0),
- },
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "MyOtherDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- },
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyOtherDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "MyOtherDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- },
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "Owner3 Description"), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(t, 1), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio15, owner3, 0),
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("Owner3 Description"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(2), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ },
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("MyOtherDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ },
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyOtherDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("MyOtherDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ },
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("Owner3 Description"), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(2), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio15, owner3, 0),
},
},
{
name: "Mixed, new entry, higher and lower precedence. notOnlyUpdated set to TRUE",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
NotOnlyNewOrUpdated: true,
intentReqValue: func() (string, error) {
@@ -631,44 +622,50 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
-
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "MyOtherDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- // the next two are not part of the result, we might want to add the behaviour, such that one can query the entire intended.
- // cache.NewUpdate([]string{"interface", "ethernet-0/1", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(t, 1), prio15, owner3, 0),
- // cache.NewUpdate([]string{"interface", "ethernet-0/1", "subinterface", "2", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio15, owner3, 0),
- },
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyOtherDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "MyOtherDescription"), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(t, 1), prio10, owner2, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio10, owner2, 0),
- },
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto(t, "MyDescription"), prio5, owner1, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/2"), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto(t, "Owner3 Description"), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(t, 1), prio15, owner3, 0),
- cache.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto(t, "Subinterface Desc"), prio15, owner3, 0),
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("Owner3 Description"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(1), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ },
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("MyOtherDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(1), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio15, owner3, 0),
+ },
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyOtherDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("MyOtherDescription"), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio10, owner2, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "1", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio10, owner2, 0),
+ },
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio5, owner1, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "name"}, testhelper.GetStringTvProto("ethernet-1/2"), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "description"}, testhelper.GetStringTvProto("Owner3 Description"), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "index"}, testhelper.GetUIntTvProto(1), prio15, owner3, 0),
+ types.NewUpdate([]string{"interface", "ethernet-1/2", "subinterface", "2", "description"}, testhelper.GetStringTvProto("Subinterface Desc"), prio15, owner3, 0),
},
},
{
- name: "ChoiceCase - new highes case",
+ name: "ChoiceCase - new highest case",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
Choices: &sdcio_schema.SdcioModel_Choices{
@@ -682,25 +679,29 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- expectedModify: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
},
expectedDeletes: [][]string{
{"choices", "case1"},
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
+ },
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case1", "case-elem", "elem"}, testhelper.GetStringTvProto("case1-content"), prio15, owner1, 0),
+ types.NewUpdate([]string{"choices", "case1", "log"}, TypedValueFalse, prio15, owner1, 0),
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case1", "case-elem", "elem"}, testhelper.GetStringTvProto(t, "case1-content"), prio15, owner1, 0),
- cache.NewUpdate([]string{"choices", "case1", "log"}, TypedValueFalse, prio15, owner1, 0),
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case1", "case-elem", "elem"}, testhelper.GetStringTvProto("case1-content"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"choices", "case1", "log"}, TypedValueFalse, tree.RunningValuesPrio, tree.RunningIntentName, 0),
},
},
{
- name: "ChoiceCase - old highes case",
+ name: "ChoiceCase - old highest case",
intentName: owner2,
intentPrio: prio10,
- intentReqPath: "/",
+ intentReqPath: nil,
intentReqValue: func() (string, error) {
d := &sdcio_schema.Device{
Choices: &sdcio_schema.SdcioModel_Choices{
@@ -714,16 +715,47 @@ func TestDatastore_populateTree(t *testing.T) {
SkipValidation: false,
})
},
- expectedModify: []*cache.Update{
+ expectedModify: []*types.Update{
// no mods expected
},
- expectedOwnerUpdates: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
+ },
+ intendedStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case1", "case-elem", "elem"}, testhelper.GetStringTvProto("case1-content"), prio5, owner1, 0),
+ types.NewUpdate([]string{"choices", "case1", "log"}, TypedValueFalse, prio5, owner1, 0),
+ },
+ runningStoreUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case1", "case-elem", "elem"}, testhelper.GetStringTvProto("case1-content"), tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ types.NewUpdate([]string{"choices", "case1", "log"}, TypedValueFalse, tree.RunningValuesPrio, tree.RunningIntentName, 0),
+ },
+ },
+ {
+ name: "ChoiceCase - add first case",
+ intentName: owner2,
+ intentPrio: prio10,
+ intentReqPath: nil,
+ intentReqValue: func() (string, error) {
+ d := &sdcio_schema.Device{
+ Choices: &sdcio_schema.SdcioModel_Choices{
+ Case2: &sdcio_schema.SdcioModel_Choices_Case2{
+ Log: ygot.Bool(true),
+ },
+ },
+ }
+ return ygot.EmitJSON(d, &ygot.EmitJSONConfig{
+ Format: ygot.RFC7951,
+ SkipValidation: false,
+ })
+ },
+ expectedModify: []*types.Update{
+ types.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
},
- intendedStoreUpdates: []*cache.Update{
- cache.NewUpdate([]string{"choices", "case1", "case-elem", "elem"}, testhelper.GetStringTvProto(t, "case1-content"), prio5, owner1, 0),
- cache.NewUpdate([]string{"choices", "case1", "log"}, TypedValueFalse, prio5, owner1, 0),
+ expectedOwnerUpdates: []*types.Update{
+ types.NewUpdate([]string{"choices", "case2", "log"}, TypedValueTrue, prio10, owner2, 0),
},
+ intendedStoreUpdates: []*types.Update{},
+ runningStoreUpdates: []*types.Update{},
},
}
@@ -731,108 +763,70 @@ func TestDatastore_populateTree(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// create a gomock controller
controller := gomock.NewController(t)
+ defer controller.Finish()
- // create a cache client mock
- cacheClient := mockcacheclient.NewMockClient(controller)
- testhelper.ConfigureCacheClientMock(t, cacheClient, tt.intendedStoreUpdates, tt.runningStoreUpdates, tt.expectedModify, tt.expectedDeletes)
+ ctx := context.Background()
sc, schema, err := testhelper.InitSDCIOSchema()
if err != nil {
t.Fatal(err)
}
+ scb := schemaClient.NewSchemaClientBound(schema, sc)
+ tc := tree.NewTreeContext(scb, tt.intentName)
- dsName := "dev1"
- ctx := context.Background()
-
- // create a datastore
- d := &Datastore{
- config: &config.DatastoreConfig{
- Name: dsName,
- Schema: schema,
- Validation: &config.Validation{DisableConcurrency: true},
- },
-
- sbi: mocktarget.NewMockTarget(controller),
- cacheClient: cacheClient,
- schemaClient: schemaClient.NewSchemaClientBound(schema.GetSchema(), sc),
- }
-
- // marshall the intentReqValue into a byte slice
- jsonConf, err := tt.intentReqValue()
+ root, err := tree.NewTreeRoot(ctx, tc)
if err != nil {
t.Error(err)
}
- // parse the path under which the intent value is to be put
- path, err := utils.ParsePath(tt.intentReqPath)
+ jconfStr, err := tt.intentReqValue()
if err != nil {
t.Error(err)
}
- // prepare the SetintentRequest
- reqOne := &sdcpb.SetIntentRequest{
- Name: dsName,
- Intent: tt.intentName,
- Priority: tt.intentPrio,
- Update: []*sdcpb.Update{
- {
- Path: path,
- Value: &sdcpb.TypedValue{
- Value: &sdcpb.TypedValue_JsonVal{
- JsonVal: []byte(jsonConf)},
- },
- },
- },
- Delete: tt.intentDelete,
- }
-
- tcc := tree.NewTreeCacheClient(d.Name(), cacheClient)
- tc := tree.NewTreeContext(tcc, d.schemaClient, tt.intentName)
-
- root, err := tree.NewTreeRoot(ctx, tc)
+ var jsonConfAny any
+ err = json.Unmarshal([]byte(jconfStr), &jsonConfAny)
if err != nil {
t.Error(err)
}
- updSlice, err := d.expandAndConvertIntent(ctx, reqOne.GetIntent(), reqOne.GetPriority(), reqOne.GetUpdate())
+ // add intended content
+ err = root.AddUpdatesRecursive(ctx, tt.intendedStoreUpdates, types.NewUpdateInsertFlags())
if err != nil {
t.Error(err)
}
- oldIntentContent, err := root.LoadIntendedStoreOwnerData(ctx, reqOne.GetIntent(), false)
+ // add running content
+ err = root.AddUpdatesRecursive(ctx, tt.runningStoreUpdates, types.NewUpdateInsertFlags())
if err != nil {
t.Error(err)
}
- loadHighest := oldIntentContent.ToPathSet()
- loadHighest.Join(updSlice.ToPathSet())
+ root.MarkOwnerDelete(tt.intentName, false)
+
+ newFlag := types.NewUpdateInsertFlags().SetNewFlag()
- err = loadIntendedStoreHighestPrio(ctx, tcc, root, loadHighest, []string{reqOne.GetIntent()})
+ err = root.ImportConfig(ctx, tt.intentReqPath, jsonImporter.NewJsonTreeImporter(jsonConfAny), tt.intentName, tt.intentPrio, newFlag)
if err != nil {
t.Error(err)
}
- flags := tree.NewUpdateInsertFlags()
- flags.SetNewFlag()
- root.AddCacheUpdatesRecursive(ctx, updSlice, flags)
-
- // populate Tree with running
- err = populateTreeWithRunning(ctx, tcc, root)
+ fmt.Println(root.String())
+ err = root.FinishInsertionPhase(ctx)
if err != nil {
t.Error(err)
}
+ fmt.Println(root.String())
- root.FinishInsertionPhase(ctx)
-
- validationResult := root.Validate(ctx, d.config.Validation)
+ validationResult := root.Validate(ctx, &config.Validation{DisableConcurrency: true})
fmt.Printf("Validation Errors:\n%v\n", strings.Join(validationResult.ErrorsStr(), "\n"))
fmt.Printf("Tree:%s\n", root.String())
// get the updates that are meant to be send down towards the device
updates := root.GetHighestPrecedence(!tt.NotOnlyNewOrUpdated)
- if diff := testhelper.DiffCacheUpdates(tt.expectedModify, updates.ToCacheUpdateSlice()); diff != "" {
- t.Errorf("root.GetHighestPrecedence(true) mismatch (-want +got):\n%s", diff)
+ if diff := testhelper.DiffUpdates(tt.expectedModify, updates.ToUpdateSlice()); diff != "" {
+ t.Errorf("root.GetHighestPrecedence(%t) mismatch (-want +got):\n%s", !tt.NotOnlyNewOrUpdated, diff)
}
// get the deletes that are meant to be send down towards the device
@@ -841,7 +835,7 @@ func TestDatastore_populateTree(t *testing.T) {
t.Error(err)
}
- deletePathSlice := make(tree.PathSlices, 0, len(deletes))
+ deletePathSlice := make(types.PathSlices, 0, len(deletes))
for _, del := range deletes {
deletePathSlice = append(deletePathSlice, del.Path())
}
@@ -852,7 +846,7 @@ func TestDatastore_populateTree(t *testing.T) {
// get the updates that are meant to be send down towards the cache (INTENDED)
updatesOwner := root.GetUpdatesForOwner(tt.intentName)
- if diff := testhelper.DiffCacheUpdates(tt.expectedOwnerUpdates, updatesOwner); diff != "" {
+ if diff := testhelper.DiffUpdates(tt.expectedOwnerUpdates, updatesOwner); diff != "" {
t.Errorf("root.GetUpdatesForOwner mismatch (-want +got):\n%s", diff)
}
diff --git a/pkg/datastore/tree_operation_validation_test.go b/pkg/datastore/tree_operation_validation_test.go
index 740fa75a..78ec3566 100644
--- a/pkg/datastore/tree_operation_validation_test.go
+++ b/pkg/datastore/tree_operation_validation_test.go
@@ -16,22 +16,21 @@ package datastore
import (
"context"
+ "encoding/json"
"fmt"
"slices"
"testing"
"github.com/openconfig/ygot/ygot"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
- "github.com/sdcio/data-server/mocks/mocktarget"
"github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/config"
schemaClient "github.com/sdcio/data-server/pkg/datastore/clients/schema"
"github.com/sdcio/data-server/pkg/tree"
+ json_importer "github.com/sdcio/data-server/pkg/tree/importer/json"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils"
"github.com/sdcio/data-server/pkg/utils/testhelper"
sdcio_schema "github.com/sdcio/data-server/tests/sdcioygot"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "go.uber.org/mock/gomock"
)
func TestDatastore_validateTree(t *testing.T) {
@@ -160,37 +159,22 @@ func TestDatastore_validateTree(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- // create a gomock controller
- controller := gomock.NewController(t)
-
- // create a cache client mock
- cacheClient := mockcacheclient.NewMockClient(controller)
- testhelper.ConfigureCacheClientMock(t, cacheClient, tt.intendedStoreUpdates, nil, nil, nil)
sc, schema, err := testhelper.InitSDCIOSchema()
if err != nil {
- t.Fatal(err)
- }
-
- dsName := "dev1"
-
- // create a datastore
- d := &Datastore{
- config: &config.DatastoreConfig{
- Name: dsName,
- Schema: schema,
- Validation: &config.Validation{DisableConcurrency: true},
- },
-
- sbi: mocktarget.NewMockTarget(controller),
- cacheClient: cacheClient,
- schemaClient: schemaClient.NewSchemaClientBound(schema.GetSchema(), sc),
+ t.Error(err)
}
-
+ scb := schemaClient.NewSchemaClientBound(schema, sc)
ctx := context.Background()
// marshall the intentReqValue into a byte slice
- jsonConf, err := tt.intentReqValue()
+ jsonConfString, err := tt.intentReqValue()
+ if err != nil {
+ t.Error(err)
+ }
+
+ var jsonConf any
+ err = json.Unmarshal([]byte(jsonConfString), &jsonConf)
if err != nil {
t.Error(err)
}
@@ -201,35 +185,30 @@ func TestDatastore_validateTree(t *testing.T) {
t.Error(err)
}
- tcc := tree.NewTreeCacheClient(dsName, d.cacheClient)
- tc := tree.NewTreeContext(tcc, d.schemaClient, tt.intentName)
+ tc := tree.NewTreeContext(scb, tt.intentName)
root, err := tree.NewTreeRoot(ctx, tc)
if err != nil {
t.Error(err)
}
- insertUpdates := []*sdcpb.Update{
- {
- Path: path,
- Value: &sdcpb.TypedValue{
- Value: &sdcpb.TypedValue_JsonVal{
- JsonVal: []byte(jsonConf)},
- },
- },
- }
+ flagsNew := types.NewUpdateInsertFlags()
+ flagsNew.SetNewFlag()
+
+ importer := json_importer.NewJsonTreeImporter(jsonConf)
- updSlice, err := d.expandAndConvertIntent(ctx, tt.intentName, tt.intentPrio, insertUpdates)
+ err = root.ImportConfig(ctx, utils.ToStrings(path, false, false), importer, tt.intentName, tt.intentPrio, flagsNew)
if err != nil {
t.Error(err)
}
- flagsNew := tree.NewUpdateInsertFlags()
- flagsNew.SetNewFlag()
- root.AddCacheUpdatesRecursive(ctx, updSlice, flagsNew)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
- root.FinishInsertionPhase(ctx)
+ validationResult := root.Validate(ctx, &config.Validation{DisableConcurrency: true})
- validationResult := root.Validate(ctx, d.config.Validation)
+ t.Log(root.String())
for _, x := range tt.expectedWarnings {
if !slices.Contains(validationResult.WarningsStr(), x) {
diff --git a/pkg/datastore/types/transaction.go b/pkg/datastore/types/transaction.go
index d1a9c847..cbc26a92 100644
--- a/pkg/datastore/types/transaction.go
+++ b/pkg/datastore/types/transaction.go
@@ -6,6 +6,7 @@ import (
"time"
"github.com/sdcio/data-server/pkg/tree"
+ treetypes "github.com/sdcio/data-server/pkg/tree/types"
)
type Transaction struct {
@@ -26,7 +27,7 @@ func NewTransaction(id string, tm *TransactionManager) *Transaction {
transactionManager: tm,
newIntents: map[string]*TransactionIntent{},
oldIntents: map[string]*TransactionIntent{},
- oldRunning: NewTransactionIntent("oldrunning", 600),
+ oldRunning: NewTransactionIntent(tree.RunningIntentName, 600),
replace: NewTransactionIntent(tree.ReplaceIntentName, tree.ReplaceValuesPrio),
}
}
@@ -129,7 +130,7 @@ func (t *Transaction) AddTransactionIntent(ti *TransactionIntent, tit Transactio
}
// AddIntentContent add the content of an intent. If the intent did not exist, add the name of the intent and content == nil.
-func (t *Transaction) AddIntentContent(name string, tit TransactionIntentType, priority int32, content tree.UpdateSlice) error {
+func (t *Transaction) AddIntentContent(name string, tit TransactionIntentType, priority int32, content treetypes.UpdateSlice) error {
dstMap := t.getTransactionIntentTypeMap(tit)
_, exists := dstMap[name]
if exists {
@@ -142,9 +143,9 @@ func (t *Transaction) AddIntentContent(name string, tit TransactionIntentType, p
return nil
}
-func (t *Transaction) GetPathSet(tit TransactionIntentType) *tree.PathSet {
+func (t *Transaction) GetPathSet(tit TransactionIntentType) *treetypes.PathSet {
srcMap := t.getTransactionIntentTypeMap(tit)
- ps := tree.NewPathSet()
+ ps := treetypes.NewPathSet()
for _, intent := range srcMap {
ps.Join(intent.GetPathSet())
}
diff --git a/pkg/datastore/types/transaction_intent.go b/pkg/datastore/types/transaction_intent.go
index 4927dc24..2d5feb50 100644
--- a/pkg/datastore/types/transaction_intent.go
+++ b/pkg/datastore/types/transaction_intent.go
@@ -1,14 +1,13 @@
package types
import (
- "github.com/sdcio/data-server/pkg/cache"
- "github.com/sdcio/data-server/pkg/tree"
+ treetypes "github.com/sdcio/data-server/pkg/tree/types"
)
type TransactionIntent struct {
name string
// updates is nil if the intent did not exist.
- updates tree.UpdateSlice
+ updates treetypes.UpdateSlice
delete bool
onlyIntended bool
priority int32
@@ -16,7 +15,9 @@ type TransactionIntent struct {
func NewTransactionIntent(name string, priority int32) *TransactionIntent {
return &TransactionIntent{
- name: name,
+ name: name,
+ updates: make(treetypes.UpdateSlice, 0),
+ priority: priority,
}
}
@@ -28,11 +29,11 @@ func (ti *TransactionIntent) GetPriority() int32 {
return ti.priority
}
-func (ti *TransactionIntent) AddUpdates(u tree.UpdateSlice) {
+func (ti *TransactionIntent) AddUpdates(u treetypes.UpdateSlice) {
ti.updates = append(ti.updates, u...)
}
-func (ti *TransactionIntent) GetUpdates() tree.UpdateSlice {
+func (ti *TransactionIntent) GetUpdates() treetypes.UpdateSlice {
return ti.updates
}
@@ -48,10 +49,10 @@ func (ti *TransactionIntent) SetDeleteOnlyIntendedFlag() {
ti.onlyIntended = true
}
-func (ti *TransactionIntent) GetPathSet() *tree.PathSet {
+func (ti *TransactionIntent) GetPathSet() *treetypes.PathSet {
return ti.updates.ToPathSet()
}
-func (ti *TransactionIntent) AddUpdate(u *cache.Update) {
+func (ti *TransactionIntent) AddUpdate(u *treetypes.Update) {
ti.updates = append(ti.updates, u)
}
diff --git a/pkg/schema/remote.go b/pkg/schema/remote.go
index 91b9dd19..507e013f 100644
--- a/pkg/schema/remote.go
+++ b/pkg/schema/remote.go
@@ -56,7 +56,7 @@ func NewRemoteClient(cc *grpc.ClientConn, cacheConfig *config.RemoteSchemaCache)
}
// rc with cache
rc := &remoteClient{
- schemaCache: ttlcache.New[cacheKey, *sdcpb.GetSchemaResponse](
+ schemaCache: ttlcache.New(
ttlcache.WithTTL[cacheKey, *sdcpb.GetSchemaResponse](cacheConfig.TTL),
ttlcache.WithCapacity[cacheKey, *sdcpb.GetSchemaResponse](cacheConfig.Capacity),
),
diff --git a/pkg/server/cache.go b/pkg/server/cache.go
index 7209dbdb..f0d2face 100644
--- a/pkg/server/cache.go
+++ b/pkg/server/cache.go
@@ -41,14 +41,6 @@ START:
goto START
}
log.Infof("local cache created")
- // case "remote":
- // err = s.createRemoteCacheClient(ctx)
- // if err != nil {
- // log.Errorf("failed to initialize a remote cache client: %v", err)
- // time.Sleep(time.Second)
- // goto START
- // }
- // log.Infof("connected to remote cache: %s", s.config.Cache.Address)
}
}
@@ -56,16 +48,8 @@ func (s *Server) createLocalCacheClient(_ context.Context) error {
var err error
log.Infof("initializing local cache client")
s.cacheClient, err = cache.NewLocalCache(&cconfig.CacheConfig{
- MaxCaches: -1,
StoreType: s.config.Cache.StoreType,
Dir: s.config.Cache.Dir,
})
return err
}
-
-// func (s *Server) createRemoteCacheClient(ctx context.Context) error {
-// log.Infof("initializing remote cache client")
-// var err error
-// s.cacheClient, err = cache.NewRemoteCache(ctx, s.config.Cache.Address)
-// return err
-// }
diff --git a/pkg/server/data.go b/pkg/server/data.go
deleted file mode 100644
index 5a57a340..00000000
--- a/pkg/server/data.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 server
-
-import (
- "strings"
- "sync"
- "time"
-
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- log "github.com/sirupsen/logrus"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/peer"
- "google.golang.org/grpc/status"
-)
-
-// data
-func (s *Server) GetData(req *sdcpb.GetDataRequest, stream sdcpb.DataServer_GetDataServer) error {
- pr, _ := peer.FromContext(stream.Context())
- log.Debugf("received GetData request %v from peer %s", req, pr.Addr.String())
- name := req.GetName()
- if name == "" {
- return status.Error(codes.InvalidArgument, "missing datastore name")
- }
- switch req.GetDataType() {
- case sdcpb.DataType_STATE:
- if req.GetDatastore().GetType() == sdcpb.Type_CANDIDATE {
- return status.Error(codes.InvalidArgument, "a candidate datastore does not store state data")
- }
- }
- if len(req.GetPath()) == 0 {
- return status.Error(codes.InvalidArgument, "missing path attribute")
- }
-
- s.md.RLock()
- defer s.md.RUnlock()
- ds, ok := s.datastores[name]
- if !ok {
- return status.Errorf(codes.InvalidArgument, "unknown datastore %s", name)
- }
- wg := new(sync.WaitGroup)
- wg.Add(1)
- nCh := make(chan *sdcpb.GetDataResponse)
- go func() {
- defer wg.Done()
- for {
- select {
- case <-stream.Context().Done():
- return
- case rsp, ok := <-nCh:
- if !ok {
- return
- }
- err := stream.Send(rsp)
- if err != nil {
- if strings.Contains(err.Error(), "context canceled") || strings.Contains(err.Error(), "EOF") {
- return
- }
- log.Errorf("GetData stream send err :%v", err)
- }
- }
- }
- }()
- err := ds.Get(stream.Context(), req, nCh)
- if err != nil {
- return err
- }
- wg.Wait()
- return nil
-}
-
-func (s *Server) Subscribe(req *sdcpb.SubscribeRequest, stream sdcpb.DataServer_SubscribeServer) error {
- log.Infof("received SubscribeRequest: %v", req)
- name := req.GetName()
- if name == "" {
- return status.Errorf(codes.InvalidArgument, "missing datastore name")
- }
-
- if len(req.GetSubscription()) == 0 {
- return status.Errorf(codes.InvalidArgument, "missing subscription list in request")
- }
- // TODO: set subscribe request defaults
- for _, subsc := range req.GetSubscription() {
- if subsc.GetSampleInterval() < uint64(time.Second) {
- subsc.SampleInterval = uint64(time.Second)
- }
- }
-
- s.md.RLock()
- ds, ok := s.datastores[name]
- s.md.RUnlock()
- if !ok {
- return status.Errorf(codes.InvalidArgument, "unknown datastore %s", name)
- }
- return ds.Subscribe(req, stream)
-}
-
-func (s *Server) Watch(req *sdcpb.WatchRequest, stream sdcpb.DataServer_WatchServer) error {
- return nil
-}
diff --git a/pkg/server/datastore.go b/pkg/server/datastore.go
index 72b32add..f70c99ac 100644
--- a/pkg/server/datastore.go
+++ b/pkg/server/datastore.go
@@ -36,11 +36,9 @@ import (
func (s *Server) ListDataStore(ctx context.Context, req *sdcpb.ListDataStoreRequest) (*sdcpb.ListDataStoreResponse, error) {
log.Debug("Received ListDataStoreRequest")
- s.md.RLock()
- defer s.md.RUnlock()
- numDs := len(s.datastores)
- rs := make([]*sdcpb.GetDataStoreResponse, 0, numDs)
- for _, ds := range s.datastores {
+ datastores := s.datastores.GetDatastoreAll()
+ rs := make([]*sdcpb.GetDataStoreResponse, 0, len(datastores))
+ for _, ds := range datastores {
r, err := s.datastoreToRsp(ctx, ds)
if err != nil {
return nil, err
@@ -54,22 +52,20 @@ func (s *Server) ListDataStore(ctx context.Context, req *sdcpb.ListDataStoreRequ
func (s *Server) GetDataStore(ctx context.Context, req *sdcpb.GetDataStoreRequest) (*sdcpb.GetDataStoreResponse, error) {
log.Debugf("Received GetDataStoreRequest: %v", req)
- name := req.GetName()
+ name := req.GetDatastoreName()
if name == "" {
return nil, status.Error(codes.InvalidArgument, "missing datastore name attribute")
}
- s.md.RLock()
- defer s.md.RUnlock()
- ds, ok := s.datastores[name]
- if !ok {
- return nil, status.Errorf(codes.InvalidArgument, "unknown datastore %s", name)
+ ds, err := s.datastores.GetDataStore(req.GetDatastoreName())
+ if err != nil {
+ return nil, err
}
return s.datastoreToRsp(ctx, ds)
}
func (s *Server) CreateDataStore(ctx context.Context, req *sdcpb.CreateDataStoreRequest) (*sdcpb.CreateDataStoreResponse, error) {
log.Debugf("Received CreateDataStoreRequest: %v", req)
- name := req.GetName()
+ name := req.GetDatastoreName()
lName := len(name)
if lName == 0 {
return nil, status.Error(codes.InvalidArgument, "missing datastore name attribute")
@@ -77,149 +73,116 @@ func (s *Server) CreateDataStore(ctx context.Context, req *sdcpb.CreateDataStore
if lName > math.MaxUint16 {
return nil, status.Error(codes.InvalidArgument, "missing datastore name attribute")
}
- switch {
- // create candidate
- case req.GetSchema() == nil && req.GetDatastore() != nil:
- s.md.RLock()
- defer s.md.RUnlock()
- ds, ok := s.datastores[name]
- if !ok {
- return nil, status.Errorf(codes.InvalidArgument, "unknown datastore %s", name)
- }
- switch req.GetDatastore().GetType() {
- case sdcpb.Type_CANDIDATE:
- owner := req.GetDatastore().GetOwner()
- lOwner := len(owner)
- if lOwner == 0 {
- return nil, status.Error(codes.InvalidArgument, "missing owner name attribute")
- }
- if lOwner > math.MaxUint16 {
- return nil, status.Errorf(codes.InvalidArgument, "owner name too long(%d>%d)", lOwner, math.MaxUint16)
- }
- if strings.HasPrefix(owner, "__") && owner != datastore.DefaultOwner {
- return nil, status.Error(codes.InvalidArgument, "owner name cannot start with `__`")
- }
- err := ds.CreateCandidate(ctx, req.GetDatastore())
- if err != nil {
- return nil, status.Errorf(codes.Internal, "%v", err)
- }
- return &sdcpb.CreateDataStoreResponse{}, nil
- default:
- return nil, status.Errorf(codes.InvalidArgument, "schema required for MAIN datastore creation")
- }
- // create main
- case req.GetSchema() != nil:
- s.md.Lock()
- defer s.md.Unlock()
- if _, ok := s.datastores[name]; ok {
- return nil, status.Errorf(codes.InvalidArgument, "datastore %s already exists", name)
- }
- sbi := &config.SBI{
- Type: req.GetTarget().GetType(),
- Port: req.GetTarget().GetPort(),
- Address: req.GetTarget().GetAddress(),
- }
+ if _, err := s.datastores.GetDataStore(name); err == nil {
+ return nil, status.Errorf(codes.InvalidArgument, "datastore %s already exists", name)
+ }
- switch strings.ToLower(req.GetTarget().GetType()) {
- case "netconf":
- commitDatastore := "candidate"
- switch req.GetTarget().GetNetconfOpts().GetCommitCandidate() {
- case sdcpb.CommitCandidate_COMMIT_CANDIDATE:
- case sdcpb.CommitCandidate_COMMIT_RUNNING:
- commitDatastore = "running"
- default:
- return nil, fmt.Errorf("unknown commitDatastore: %v", req.GetTarget().GetNetconfOpts().GetCommitCandidate())
- }
- sbi.NetconfOptions = &config.SBINetconfOptions{
- IncludeNS: req.GetTarget().GetNetconfOpts().GetIncludeNs(),
- OperationWithNamespace: req.GetTarget().GetNetconfOpts().GetOperationWithNs(),
- UseOperationRemove: req.GetTarget().GetNetconfOpts().GetUseOperationRemove(),
- CommitDatastore: commitDatastore,
- }
+ sbi := &config.SBI{
+ Type: req.GetTarget().GetType(),
+ Port: req.GetTarget().GetPort(),
+ Address: req.GetTarget().GetAddress(),
+ }
- case "gnmi":
- sbi.GnmiOptions = &config.SBIGnmiOptions{
- Encoding: req.GetTarget().GetGnmiOpts().GetEncoding(),
- }
+ switch strings.ToLower(req.GetTarget().GetType()) {
+ case "netconf":
+ commitDatastore := "candidate"
+ switch req.GetTarget().GetNetconfOpts().GetCommitCandidate() {
+ case sdcpb.CommitCandidate_COMMIT_CANDIDATE:
+ case sdcpb.CommitCandidate_COMMIT_RUNNING:
+ commitDatastore = "running"
default:
- return nil, fmt.Errorf("unknowm protocol type %s", req.GetTarget().GetType())
+ return nil, fmt.Errorf("unknown commitDatastore: %v", req.GetTarget().GetNetconfOpts().GetCommitCandidate())
+ }
+ sbi.NetconfOptions = &config.SBINetconfOptions{
+ IncludeNS: req.GetTarget().GetNetconfOpts().GetIncludeNs(),
+ OperationWithNamespace: req.GetTarget().GetNetconfOpts().GetOperationWithNs(),
+ UseOperationRemove: req.GetTarget().GetNetconfOpts().GetUseOperationRemove(),
+ CommitDatastore: commitDatastore,
}
- if req.GetTarget().GetTls() != nil {
- sbi.TLS = &config.TLS{
- CA: req.GetTarget().GetTls().GetCa(),
- Cert: req.GetTarget().GetTls().GetCert(),
- Key: req.GetTarget().GetTls().GetKey(),
- SkipVerify: req.GetTarget().GetTls().GetSkipVerify(),
- }
+ case "gnmi":
+ sbi.GnmiOptions = &config.SBIGnmiOptions{
+ Encoding: req.GetTarget().GetGnmiOpts().GetEncoding(),
}
- if req.GetTarget().GetCredentials() != nil {
- sbi.Credentials = &config.Creds{
- Username: req.GetTarget().GetCredentials().GetUsername(),
- Password: req.GetTarget().GetCredentials().GetPassword(),
- Token: req.GetTarget().GetCredentials().GetToken(),
- }
+ default:
+ return nil, fmt.Errorf("unknowm protocol type %s", req.GetTarget().GetType())
+ }
+
+ if req.GetTarget().GetTls() != nil {
+ sbi.TLS = &config.TLS{
+ CA: req.GetTarget().GetTls().GetCa(),
+ Cert: req.GetTarget().GetTls().GetCert(),
+ Key: req.GetTarget().GetTls().GetKey(),
+ SkipVerify: req.GetTarget().GetTls().GetSkipVerify(),
+ }
+ }
+ if req.GetTarget().GetCredentials() != nil {
+ sbi.Credentials = &config.Creds{
+ Username: req.GetTarget().GetCredentials().GetUsername(),
+ Password: req.GetTarget().GetCredentials().GetPassword(),
+ Token: req.GetTarget().GetCredentials().GetToken(),
}
+ }
- dsConfig := &config.DatastoreConfig{
- Name: name,
- Schema: &config.SchemaConfig{
- Name: req.GetSchema().GetName(),
- Vendor: req.GetSchema().GetVendor(),
- Version: req.GetSchema().GetVersion(),
- },
- SBI: sbi,
- Validation: s.config.Validation,
+ dsConfig := &config.DatastoreConfig{
+ Name: name,
+ Schema: &config.SchemaConfig{
+ Name: req.GetSchema().GetName(),
+ Vendor: req.GetSchema().GetVendor(),
+ Version: req.GetSchema().GetVersion(),
+ },
+ SBI: sbi,
+ }
+ if req.GetSync() != nil {
+ dsConfig.Sync = &config.Sync{
+ Validate: req.GetSync().GetValidate(),
+ Buffer: req.GetSync().GetBuffer(),
+ WriteWorkers: req.GetSync().GetWriteWorkers(),
+ Config: make([]*config.SyncProtocol, 0, len(req.GetSync().GetConfig())),
}
- if req.GetSync() != nil {
- dsConfig.Sync = &config.Sync{
- Validate: req.GetSync().GetValidate(),
- Buffer: req.GetSync().GetBuffer(),
- WriteWorkers: req.GetSync().GetWriteWorkers(),
- Config: make([]*config.SyncProtocol, 0, len(req.GetSync().GetConfig())),
+ for _, pSync := range req.GetSync().GetConfig() {
+ gnSyncConfig := &config.SyncProtocol{
+ Protocol: pSync.GetTarget().GetType(),
+ Name: pSync.GetName(),
+ Paths: pSync.GetPath(),
+ Interval: time.Duration(pSync.GetInterval()),
}
- for _, pSync := range req.GetSync().GetConfig() {
- gnSyncConfig := &config.SyncProtocol{
- Protocol: pSync.GetTarget().GetType(),
- Name: pSync.GetName(),
- Paths: pSync.GetPath(),
- Interval: time.Duration(pSync.GetInterval()),
- }
- switch pSync.GetTarget().GetType() {
- case "gnmi":
- gnSyncConfig.Mode = "on-change"
- switch pSync.GetMode() {
- case sdcpb.SyncMode_SM_ON_CHANGE:
- case sdcpb.SyncMode_SM_SAMPLE:
- gnSyncConfig.Mode = "sample"
- case sdcpb.SyncMode_SM_ONCE:
- gnSyncConfig.Mode = "once"
- case sdcpb.SyncMode_SM_GET:
- gnSyncConfig.Mode = "get"
- }
- gnSyncConfig.Encoding = pSync.GetTarget().GetGnmiOpts().GetEncoding()
- case "netconf":
- default:
- return nil, status.Errorf(codes.InvalidArgument, "unknown sync protocol: %q", pSync.GetTarget().GetType())
+ switch strings.ToLower(pSync.GetTarget().GetType()) {
+ case "gnmi":
+ gnSyncConfig.Mode = "on-change"
+ switch pSync.GetMode() {
+ case sdcpb.SyncMode_SM_ON_CHANGE:
+ case sdcpb.SyncMode_SM_SAMPLE:
+ gnSyncConfig.Mode = "sample"
+ case sdcpb.SyncMode_SM_ONCE:
+ gnSyncConfig.Mode = "once"
+ case sdcpb.SyncMode_SM_GET:
+ gnSyncConfig.Mode = "get"
}
- dsConfig.Sync.Config = append(dsConfig.Sync.Config, gnSyncConfig)
+ gnSyncConfig.Encoding = pSync.GetTarget().GetGnmiOpts().GetEncoding()
+ case "netconf":
+ default:
+ return nil, status.Errorf(codes.InvalidArgument, "unknown sync protocol: %q", pSync.GetTarget().GetType())
}
+ dsConfig.Sync.Config = append(dsConfig.Sync.Config, gnSyncConfig)
}
- err := dsConfig.ValidateSetDefaults()
- if err != nil {
- return nil, status.Errorf(codes.InvalidArgument, "invalid datastore config: %v", err)
- }
- s.datastores[req.GetName()] = datastore.New(
- s.ctx,
- dsConfig,
- s.schemaClient,
- s.cacheClient,
- s.gnmiOpts...)
- return &sdcpb.CreateDataStoreResponse{}, nil
- default:
- return nil, status.Errorf(codes.InvalidArgument, "schema or datastore must be set")
}
+ err := dsConfig.ValidateSetDefaults()
+ if err != nil {
+ return nil, status.Errorf(codes.InvalidArgument, "invalid datastore config: %v", err)
+ }
+ ds, err := datastore.New(
+ s.ctx,
+ dsConfig,
+ s.schemaClient,
+ s.cacheClient,
+ s.gnmiOpts...)
+ if err != nil {
+ return nil, err
+ }
+ s.datastores.AddDatastore(ds)
+ return &sdcpb.CreateDataStoreResponse{}, nil
}
func (s *Server) DeleteDataStore(ctx context.Context, req *sdcpb.DeleteDataStoreRequest) (*sdcpb.DeleteDataStoreResponse, error) {
@@ -228,60 +191,20 @@ func (s *Server) DeleteDataStore(ctx context.Context, req *sdcpb.DeleteDataStore
if name == "" {
return nil, status.Error(codes.InvalidArgument, "missing datastore name attribute")
}
- s.md.Lock()
- defer s.md.Unlock()
- ds, ok := s.datastores[name]
- if !ok {
- return nil, status.Errorf(codes.InvalidArgument, "unknown datastore %s", name)
- }
- switch {
- case req.GetDatastore() == nil:
- err := ds.Stop()
- if err != nil {
- log.Errorf("failed to stop datastore %s: %v", name, err)
- }
- err = ds.DeleteCache(ctx)
- if err != nil {
- log.Errorf("failed to delete the datastore %s cache: %v", name, err)
- }
- delete(s.datastores, name)
- log.Infof("deleted datastore %s", name)
- return &sdcpb.DeleteDataStoreResponse{}, nil
- default:
- switch req.GetDatastore().GetType() {
- case *sdcpb.Type_CANDIDATE.Enum():
- ds.DeleteCandidate(ctx, req.GetDatastore().GetName())
- log.Infof("datastore %s deleted candidate %s", name, req.GetDatastore().GetName())
- case *sdcpb.Type_MAIN.Enum():
- err := ds.Stop()
- if err != nil {
- log.Errorf("failed to stop datastore %s: %v", name, err)
- }
- delete(s.datastores, name)
- log.Infof("deleted datastore %s", name)
- }
- return &sdcpb.DeleteDataStoreResponse{}, nil
+ ds, err := s.datastores.GetDataStore(name)
+ if err != nil {
+ return nil, err
}
-}
-func (s *Server) Discard(ctx context.Context, req *sdcpb.DiscardRequest) (*sdcpb.DiscardResponse, error) {
- log.Debugf("Received DiscardDataStoreRequest: %v", req)
- name := req.GetName()
- if name == "" {
- return nil, status.Error(codes.InvalidArgument, "missing name attribute")
- }
- s.md.RLock()
- defer s.md.RUnlock()
- ds, ok := s.datastores[name]
- if !ok {
- return nil, status.Errorf(codes.InvalidArgument, "unknown datastore %s", name)
- }
- err := ds.Discard(ctx, req)
+ err = ds.Stop()
if err != nil {
- return nil, status.Errorf(codes.Internal, "%v", err)
+ log.Errorf("failed to stop datastore %s: %v", name, err)
}
- return &sdcpb.DiscardResponse{}, nil
+ s.datastores.DeleteDatastore(ctx, name)
+ log.Infof("deleted datastore %s", name)
+
+ return &sdcpb.DeleteDataStoreResponse{}, nil
}
func (s *Server) WatchDeviations(req *sdcpb.WatchDeviationRequest, stream sdcpb.DataServer_WatchDeviationsServer) error {
@@ -294,38 +217,35 @@ func (s *Server) WatchDeviations(req *sdcpb.WatchDeviationRequest, stream sdcpb.
if req.GetName() == nil {
return status.Errorf(codes.InvalidArgument, "missing datastore name")
}
- s.md.RLock()
- ds, ok := s.datastores[req.GetName()[0]]
- s.md.RUnlock()
- if !ok {
- return status.Errorf(codes.InvalidArgument, "unknown datastore name: %s", req.GetName()[0])
+
+ ds, err := s.datastores.GetDataStore(req.GetName()[0])
+ if err != nil {
+ log.Error(err)
+ return status.Errorf(codes.NotFound, "unknown datastore")
+ }
+
+ err = ds.WatchDeviations(req, stream)
+ if err != nil {
+ log.Error(err)
}
- _ = ds.WatchDeviations(req, stream)
<-stream.Context().Done()
ds.StopDeviationsWatch(peerInfo.Addr.String())
return nil
}
func (s *Server) datastoreToRsp(ctx context.Context, ds *datastore.Datastore) (*sdcpb.GetDataStoreResponse, error) {
- cands, err := ds.Candidates(ctx)
- if err != nil {
- return nil, err
- }
+ var err error
rsp := &sdcpb.GetDataStoreResponse{
- Name: ds.Config().Name,
- Datastore: make([]*sdcpb.DataStore, 0, len(cands)+1),
+ DatastoreName: ds.Config().Name,
}
- rsp.Datastore = append(rsp.Datastore,
- &sdcpb.DataStore{
- Type: *sdcpb.Type_MAIN.Enum().Enum(),
- Name: ds.Config().Name,
- },
- )
- rsp.Datastore = append(rsp.Datastore, cands...)
rsp.Target = &sdcpb.Target{
Type: ds.Config().SBI.Type,
Address: ds.Config().SBI.Address,
}
+ rsp.Intents, err = ds.IntentsList(ctx)
+ if err != nil {
+ return nil, err
+ }
// map datastore sbi conn state to sdcpb.TargetStatus
switch ds.ConnectionState().Status {
case target.TargetStatusConnected:
diff --git a/pkg/server/intent.go b/pkg/server/intent.go
index 14d9b84c..bcef2b52 100644
--- a/pkg/server/intent.go
+++ b/pkg/server/intent.go
@@ -1,82 +1,119 @@
-// Copyright 2024 Nokia
-//
-// Licensed 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 server
import (
"context"
+ "encoding/json"
+ "fmt"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- log "github.com/sirupsen/logrus"
"google.golang.org/grpc/codes"
- "google.golang.org/grpc/peer"
"google.golang.org/grpc/status"
)
-func (s *Server) GetIntent(ctx context.Context, req *sdcpb.GetIntentRequest) (*sdcpb.GetIntentResponse, error) {
- pr, _ := peer.FromContext(ctx)
- log.Debugf("received GetIntent request %v from peer %s", req, pr.Addr.String())
-
- if req.GetName() == "" {
+func (s *Server) ListIntent(ctx context.Context, req *sdcpb.ListIntentRequest) (*sdcpb.ListIntentResponse, error) {
+ if req.GetDatastoreName() == "" {
return nil, status.Error(codes.InvalidArgument, "missing datastore name")
}
- if req.GetIntent() == "" {
- return nil, status.Error(codes.InvalidArgument, "missing intent name")
+
+ ds, err := s.datastores.getDataStore(req.GetDatastoreName())
+ if err != nil {
+ return nil, status.Error(codes.NotFound, err.Error())
}
- if req.GetPriority() == 0 {
- return nil, status.Error(codes.InvalidArgument, "missing intent priority")
+ resp := &sdcpb.ListIntentResponse{
+ DatastoreName: req.DatastoreName,
}
- ds, err := s.getDataStore(req.Name)
+
+ intentNames, err := ds.IntentsList(ctx)
if err != nil {
- return nil, status.Error(codes.NotFound, err.Error())
+ return nil, err
}
- return ds.GetIntent(ctx, req)
-}
-// func (s *Server) SetIntent(ctx context.Context, req *sdcpb.SetIntentRequest) (*sdcpb.SetIntentResponse, error) {
-// pr, _ := peer.FromContext(ctx)
-// log.Debugf("received SetIntent request %v from peer %s", req, pr.Addr.String())
-
-// if req.GetName() == "" {
-// return nil, status.Error(codes.InvalidArgument, "missing datastore name")
-// }
-// if req.GetIntent() == "" {
-// return nil, status.Error(codes.InvalidArgument, "missing intent name")
-// }
-// if len(req.GetUpdate()) == 0 && !req.GetDelete() {
-// return nil, status.Error(codes.InvalidArgument, "updates or a delete flag must be set")
-// }
-// if len(req.GetUpdate()) != 0 && req.GetDelete() {
-// return nil, status.Error(codes.InvalidArgument, "both updates and the delete flag cannot be set at the same time")
-// }
-// ds, err := s.getDataStore(req.Name)
-// if err != nil {
-// return nil, status.Error(codes.NotFound, err.Error())
-// }
-// return ds.SetIntent(ctx, req)
-// }
+ resp.Intent = intentNames
-func (s *Server) ListIntent(ctx context.Context, req *sdcpb.ListIntentRequest) (*sdcpb.ListIntentResponse, error) {
- pr, _ := peer.FromContext(ctx)
- log.Debugf("received ListIntent request %v from peer %s", req, pr.Addr.String())
+ return resp, nil
+
+}
- if req.GetName() == "" {
+func (s *Server) GetIntent(ctx context.Context, req *sdcpb.GetIntentRequest) (*sdcpb.GetIntentResponse, error) {
+ if req.GetDatastoreName() == "" {
return nil, status.Error(codes.InvalidArgument, "missing datastore name")
}
- ds, err := s.getDataStore(req.Name)
+
+ if req.GetIntent() == "" {
+ return nil, status.Error(codes.InvalidArgument, "missing intent name")
+ }
+
+ // retrieve the referenced datastore
+ ds, err := s.datastores.getDataStore(req.GetDatastoreName())
if err != nil {
return nil, status.Error(codes.NotFound, err.Error())
}
- return ds.ListIntent(ctx, req)
+
+ rsp, err := ds.GetIntent(ctx, req.GetIntent())
+ if err != nil {
+ return nil, err
+ }
+
+ switch req.GetFormat() {
+ case sdcpb.Format_Intent_Format_JSON, sdcpb.Format_Intent_Format_JSON_IETF:
+ var j any
+ switch req.GetFormat() {
+ case sdcpb.Format_Intent_Format_JSON:
+ j, err = rsp.ToJson()
+ if err != nil {
+ return nil, err
+ }
+ case sdcpb.Format_Intent_Format_JSON_IETF:
+ j, err = rsp.ToJsonIETF()
+ if err != nil {
+ return nil, err
+ }
+ }
+ b, err := json.Marshal(j)
+ if err != nil {
+ return nil, err
+ }
+ return &sdcpb.GetIntentResponse{
+ DatastoreName: req.GetIntent(),
+ Format: req.GetFormat(),
+ Intent: &sdcpb.GetIntentResponse_Blob{
+ Blob: b,
+ },
+ }, nil
+
+ case sdcpb.Format_Intent_Format_XML:
+ doc, err := rsp.ToXML()
+ if err != nil {
+ return nil, err
+ }
+ xml, err := doc.WriteToBytes()
+ if err != nil {
+ return nil, err
+ }
+
+ return &sdcpb.GetIntentResponse{
+ DatastoreName: req.GetIntent(),
+ Format: req.GetFormat(),
+ Intent: &sdcpb.GetIntentResponse_Blob{
+ Blob: xml,
+ },
+ }, nil
+ case sdcpb.Format_Intent_Format_PROTO:
+ upds, err := rsp.ToProtoUpdates(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return &sdcpb.GetIntentResponse{
+ DatastoreName: req.GetIntent(),
+ Format: req.GetFormat(),
+ Intent: &sdcpb.GetIntentResponse_Proto{
+ Proto: &sdcpb.Intent{
+ Intent: req.GetIntent(),
+ Update: upds,
+ },
+ },
+ }, nil
+ }
+ return nil, fmt.Errorf("unknown format")
}
diff --git a/pkg/server/schema.go b/pkg/server/schema.go
index 67580c82..e2af82b0 100644
--- a/pkg/server/schema.go
+++ b/pkg/server/schema.go
@@ -49,10 +49,10 @@ func (s *Server) createLocalSchemaStore(ctx context.Context) {
var store schemaStore.Store
switch s.config.SchemaStore.Type {
case schemaConfig.StoreTypeMemory:
- store = schemaMemoryStore.New()
+ store = schemaMemoryStore.New(s.config.SchemaStore.UploadPath)
case schemaConfig.StoreTypePersistent:
var err error
- store, err = schemaPersistentStore.New(ctx, s.config.SchemaStore.Path, s.config.SchemaStore.Cache)
+ store, err = schemaPersistentStore.New(ctx, s.config.SchemaStore.UploadPath, s.config.SchemaStore.Path, s.config.SchemaStore.Cache)
if err != nil {
log.Errorf("failed to create a persistent schema store: %v", err)
os.Exit(1)
diff --git a/pkg/server/server.go b/pkg/server/server.go
index f884e13f..5fc07f3c 100644
--- a/pkg/server/server.go
+++ b/pkg/server/server.go
@@ -53,9 +53,6 @@ type Server struct {
ctx context.Context
cfn context.CancelFunc
- md *sync.RWMutex
- datastores map[string]*datastore.Datastore // datastore group with sbi
-
srv *grpc.Server
sdcpb.UnimplementedDataServerServer
sdcpb.UnimplementedSchemaServerServer
@@ -63,7 +60,7 @@ type Server struct {
router *mux.Router
reg *prometheus.Registry
- // remoteSchemaClient sdcpb.SchemaServerClient
+ datastores *DatastoreMap
schemaClient schema.Client
cacheClient cache.Client
@@ -71,6 +68,71 @@ type Server struct {
gnmiOpts []grpc.DialOption
}
+type DatastoreMap struct {
+ md *sync.RWMutex
+ datastores map[string]*datastore.Datastore // datastore group with sbi
+}
+
+func NewDatastoreMap() *DatastoreMap {
+ return &DatastoreMap{
+ md: &sync.RWMutex{},
+ datastores: map[string]*datastore.Datastore{},
+ }
+}
+func (d *DatastoreMap) StopAll() {
+ for _, ds := range d.datastores {
+ ds.Stop()
+ }
+}
+
+func (d *DatastoreMap) AddDatastore(ds *datastore.Datastore) error {
+ d.md.Lock()
+ defer d.md.Unlock()
+ if existingDs, _ := d.getDataStore(ds.Name()); existingDs != nil {
+ return fmt.Errorf("datastore %s already exists", ds.Name())
+ }
+
+ d.datastores[ds.Name()] = ds
+ return nil
+}
+
+func (d *DatastoreMap) DeleteDatastore(ctx context.Context, name string) error {
+ d.md.Lock()
+ defer d.md.Unlock()
+ ds, err := d.getDataStore(name)
+ if err != nil {
+ return err
+ }
+ ds.Delete(ctx)
+ delete(d.datastores, name)
+ return nil
+}
+
+func (d *DatastoreMap) GetDataStore(name string) (*datastore.Datastore, error) {
+ d.md.RLock()
+ defer d.md.RUnlock()
+ return d.getDataStore(name)
+}
+
+func (d *DatastoreMap) GetDatastoreAll() []*datastore.Datastore {
+ d.md.RLock()
+ defer d.md.RUnlock()
+ result := make([]*datastore.Datastore, 0, len(d.datastores))
+ for _, x := range d.datastores {
+ result = append(result, x)
+ }
+ return result
+}
+
+// getDataStore expects that the mutex d.md is already held
+func (d *DatastoreMap) getDataStore(name string) (*datastore.Datastore, error) {
+ ds, exists := d.datastores[name]
+ if !exists {
+ return nil, fmt.Errorf("unknown datastore %s", name)
+ }
+ return ds, nil
+}
+
func New(ctx context.Context, c *config.Config) (*Server, error) {
ctx, cancel := context.WithCancel(ctx)
var s = &Server{
@@ -78,8 +140,7 @@ func New(ctx context.Context, c *config.Config) (*Server, error) {
ctx: ctx,
cfn: cancel,
- md: &sync.RWMutex{},
- datastores: make(map[string]*datastore.Datastore),
+ datastores: NewDatastoreMap(),
router: mux.NewRouter(),
reg: prometheus.NewRegistry(),
@@ -159,16 +220,6 @@ func (s *Server) Serve(ctx context.Context) error {
return nil
}
-func (s *Server) getDataStore(name string) (*datastore.Datastore, error) {
- s.md.Lock()
- defer s.md.Unlock()
- ds, exists := s.datastores[name]
- if !exists {
- return nil, fmt.Errorf("unknown datastore %s", name)
- }
- return ds, nil
-}
-
func (s *Server) ServeHTTP() {
s.router.Handle("/metrics", promhttp.HandlerFor(s.reg, promhttp.HandlerOpts{}))
s.reg.MustRegister(collectors.NewGoCollector())
@@ -187,9 +238,7 @@ func (s *Server) ServeHTTP() {
func (s *Server) Stop() {
s.srv.Stop()
- for _, ds := range s.datastores {
- ds.Stop()
- }
+ s.datastores.StopAll()
s.cfn()
}
@@ -228,11 +277,9 @@ func (s *Server) createInitialDatastores(ctx context.Context) {
log.Debugf("creating datastore %s", dsCfg.Name)
go func(dsCfg *config.DatastoreConfig) {
defer wg.Done()
- dsCfg.Validation = s.config.Validation
- ds := datastore.New(ctx, dsCfg, s.schemaClient, s.cacheClient, s.gnmiOpts...)
- s.md.Lock()
- defer s.md.Unlock()
- s.datastores[dsCfg.Name] = ds
+ // TODO: handle error
+ ds, _ := datastore.New(ctx, dsCfg, s.schemaClient, s.cacheClient, s.gnmiOpts...)
+ s.datastores.AddDatastore(ds)
}(dsCfg)
}
wg.Wait()
diff --git a/pkg/server/transaction.go b/pkg/server/transaction.go
index 3ecef288..41a89307 100644
--- a/pkg/server/transaction.go
+++ b/pkg/server/transaction.go
@@ -32,7 +32,7 @@ func (s *Server) TransactionSet(ctx context.Context, req *sdcpb.TransactionSetRe
}
// retrieve the referenced datastore
- ds, err := s.getDataStore(req.DatastoreName)
+ ds, err := s.datastores.getDataStore(req.DatastoreName)
if err != nil {
return nil, status.Error(codes.NotFound, err.Error())
}
@@ -76,7 +76,7 @@ func (s *Server) TransactionConfirm(ctx context.Context, req *sdcpb.TransactionC
return nil, status.Error(codes.InvalidArgument, "missing datastore name")
}
- ds, err := s.getDataStore(req.DatastoreName)
+ ds, err := s.datastores.GetDataStore(req.DatastoreName)
if err != nil {
return nil, status.Error(codes.NotFound, err.Error())
}
@@ -93,7 +93,7 @@ func (s *Server) TransactionCancel(ctx context.Context, req *sdcpb.TransactionCa
return nil, status.Error(codes.InvalidArgument, "missing datastore name")
}
- ds, err := s.getDataStore(req.DatastoreName)
+ ds, err := s.datastores.GetDataStore(req.DatastoreName)
if err != nil {
return nil, status.Error(codes.NotFound, err.Error())
}
diff --git a/pkg/tree/cache_update_filter.go b/pkg/tree/cache_update_filter.go
deleted file mode 100644
index 393f2da4..00000000
--- a/pkg/tree/cache_update_filter.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package tree
-
-import "github.com/sdcio/data-server/pkg/cache"
-
-type CacheUpdateFilter func(u *cache.Update) bool
-
-func CacheUpdateFilterExcludeOwner(owner string) func(u *cache.Update) bool {
- return func(u *cache.Update) bool {
- return u.Owner() != owner
- }
-}
-
-// ApplyCacheUpdateFilters takes a bunch of CacheUpdateFilters applies them in an AND fashion
-// and returns the result.
-func ApplyCacheUpdateFilters(u *cache.Update, fs []CacheUpdateFilter) bool {
- for _, f := range fs {
- b := f(u)
- if !b {
- return false
- }
- }
- return true
-}
diff --git a/pkg/tree/childMap.go b/pkg/tree/childMap.go
new file mode 100644
index 00000000..841636da
--- /dev/null
+++ b/pkg/tree/childMap.go
@@ -0,0 +1,102 @@
+package tree
+
+import (
+ "iter"
+ "slices"
+ "sync"
+)
+
+type childMap struct {
+ c map[string]Entry
+ mu sync.RWMutex
+}
+
+func newChildMap() *childMap {
+ return &childMap{
+ c: map[string]Entry{},
+ }
+}
+
+func (c *childMap) Items() iter.Seq2[string, Entry] {
+ return func(yield func(string, Entry) bool) {
+ for i, v := range c.c {
+ if !yield(i, v) {
+ return
+ }
+ }
+ }
+}
+
+func (c *childMap) DeleteChilds(names []string) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ for _, name := range names {
+ delete(c.c, name)
+ }
+}
+
+func (c *childMap) DeleteChild(name string) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ delete(c.c, name)
+}
+
+func (c *childMap) Add(e Entry) {
+ c.mu.Lock()
+ defer c.mu.Unlock()
+ c.c[e.PathName()] = e
+}
+
+func (c *childMap) GetEntry(s string) (e Entry, exists bool) {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ e, exists = c.c[s]
+ return e, exists
+}
+
+func (c *childMap) GetAllSorted() []Entry {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ childNames := make([]string, 0, len(c.c))
+ for name := range c.c {
+ childNames = append(childNames, name)
+ }
+ slices.Sort(childNames)
+
+ result := make([]Entry, 0, len(c.c))
+ // range over children
+ for _, childName := range childNames {
+ result = append(result, c.c[childName])
+ }
+
+ return result
+}
+
+func (c *childMap) GetAll() map[string]Entry {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ result := map[string]Entry{}
+ for k, v := range c.c {
+ result[k] = v
+ }
+ return result
+}
+
+func (c *childMap) GetKeys() []string {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+
+ result := make([]string, 0, c.Length())
+ for k := range c.c {
+ result = append(result, k)
+ }
+ return result
+}
+
+func (c *childMap) Length() int {
+ c.mu.RLock()
+ defer c.mu.RUnlock()
+ return len(c.c)
+}
diff --git a/pkg/tree/choice_case_resolver.go b/pkg/tree/choice_case_resolver.go
index 7f990cf8..98054327 100644
--- a/pkg/tree/choice_case_resolver.go
+++ b/pkg/tree/choice_case_resolver.go
@@ -2,20 +2,28 @@ package tree
import (
"math"
- "slices"
)
-type choiceCasesResolvers map[string]*choiceCasesResolver
+type choiceResolvers map[string]*choiceResolver
// AddChoice adds / registers a new Choice to the choiceCasesResolver
-func (c choiceCasesResolvers) AddChoice(name string) *choiceCasesResolver {
- r := newChoiceCasesResolver()
+func (c choiceResolvers) AddChoice(name string) *choiceResolver {
+ r := newChoiceResolver()
c[name] = r
return r
}
-func (c choiceCasesResolvers) deepCopy() choiceCasesResolvers {
- result := choiceCasesResolvers{}
+// GetDeletes returns the names of the elements that need to be deleted.
+func (c choiceResolvers) GetDeletes() []string {
+ result := []string{}
+ for _, cases := range c {
+ result = append(result, cases.GetDeletes()...)
+ }
+ return result
+}
+
+func (c choiceResolvers) deepCopy() choiceResolvers {
+ result := choiceResolvers{}
for k, v := range c {
result[k] = v.deepCopy()
@@ -27,7 +35,7 @@ func (c choiceCasesResolvers) deepCopy() choiceCasesResolvers {
// GetSkipElements returns the list of all choices elements that are not highes priority.
// The resulting slice is used to skip these elements.
-func (c choiceCasesResolvers) GetSkipElements() []string {
+func (c choiceResolvers) GetSkipElements() []string {
result := []string{}
for _, x := range c {
result = append(result, x.GetSkipElements()...)
@@ -35,72 +43,129 @@ func (c choiceCasesResolvers) GetSkipElements() []string {
return result
}
-func (c choiceCasesResolvers) shouldDelete() bool {
- if len(c) == 0 {
- return false
- }
- return !c.remainsToExist()
+// choiceResolver is a helper used to efficiently store the priority values of certain branches and their association to the cases is a choice.
+// All with the goal of composing a list of elements that do not belong to the prioritised case, for exclusion on tree traversal time.
+type choiceResolver struct {
+ cases map[string]*choicesCase
+ elementToCaseMapping map[string]*choicesCase
+ elements map[string]*caseElement
}
-func (c choiceCasesResolvers) remainsToExist() bool {
- for _, x := range c {
- if x.getBestCaseName() != "" {
- return true
+func (c *choiceResolver) deepCopy() *choiceResolver {
+ result := &choiceResolver{
+ cases: map[string]*choicesCase{},
+ elementToCaseMapping: map[string]*choicesCase{},
+ elements: map[string]*caseElement{},
+ }
+
+ for k, v := range c.cases {
+ result.cases[k] = v.deepCopy()
+ }
+
+ for _, cas := range result.cases {
+ for _, elem := range cas.elements {
+ result.elementToCaseMapping[elem.name] = cas
+ result.elements[elem.name] = elem
}
}
- return false
-}
-
-// GetChoiceElements returns a list of elements that belong to the same choice
-// as the given element. This is used to query the cache for all elements of all cases for the
-// choice.
-func (c choiceCasesResolvers) GetChoiceElementNeighbors(elemName string) []string {
- var result []string
- // iterate through the different choices that might exist
- for _, choice := range c {
- // get all the elements references in a certain contains
- sl := choice.GetElementNames()
- // check for the given element, if it belongs to the actual choice
- var idx int
- if idx = slices.Index(sl, elemName); idx == -1 {
- // if not continue with next choice
+
+ return result
+}
+
+// newChoiceResolver returns a ready to use choiceCasesResolver.
+func newChoiceResolver() *choiceResolver {
+ return &choiceResolver{
+ cases: map[string]*choicesCase{}, // case name -> case data
+ elementToCaseMapping: map[string]*choicesCase{}, // element name -> case name
+ elements: map[string]*caseElement{}, //element name -> element data
+ }
+}
+
+// AddCase adds / registers a case with its name and the element names that belong to the case
+func (c *choiceResolver) AddCase(name string, elements []string) *choicesCase {
+ cse := newChoicesCase(name)
+ c.cases[name] = cse
+
+ for _, e := range elements {
+ cce := newCaseElement(e)
+ c.elementToCaseMapping[e] = cse
+ cse.elements[e] = cce
+ c.elements[e] = cce
+ }
+ return cse
+}
+
+// SetValue Sets the priority value that the given elements with its entire branch has calculated
+func (c *choiceResolver) SetValue(elemName string, highestWODel int32, highestDelete int32, highestWONew int32, isDeleted bool) {
+ elem := c.elements[elemName]
+ elem.highestWODeleted = highestWODel
+ elem.highestWONew = highestWONew
+}
+
+// GetSkipElements returns the names of all the elements that belong to
+// cases that have not the best priority
+func (c *choiceResolver) GetSkipElements() []string {
+ result := make([]string, 0, len(c.elementToCaseMapping))
+
+ bestCase := c.GetBestCaseNow()
+ for elem, cas := range c.elementToCaseMapping {
+ if cas == bestCase {
continue
}
- // if it belongs to it, return the list of all elements belonging to the
- // choice without the provided element itself.
- return append(sl[:idx], sl[idx+1:]...)
-
+ result = append(result, elem)
}
return result
}
-// choiceCasesResolver is a helper used to efficiently store the priority values of certain branches and their association to the cases is a choice.
-// All with the goal of composing a list of elements that do not belong to the prioritised case, for exclusion on tree traversal time.
-type choiceCasesResolver struct {
- cases map[string]*choicesCase
- elementToCaseMapping map[string]string
-}
+func (c *choiceResolver) GetBestCaseNow() *choicesCase {
+ // best case now
+ var highestCaseWODeleted *choicesCase
+ highesPrecedenceWODeletedValue := int32(math.MaxInt32)
-func (c *choiceCasesResolver) deepCopy() *choiceCasesResolver {
- result := &choiceCasesResolver{
- cases: map[string]*choicesCase{},
- elementToCaseMapping: map[string]string{},
+ for _, cas := range c.cases {
+ actualCaseWODeletedValue := cas.getHighestPrecedenceWODeleted()
+ if actualCaseWODeletedValue < highesPrecedenceWODeletedValue {
+ highesPrecedenceWODeletedValue = actualCaseWODeletedValue
+ highestCaseWODeleted = cas
+ }
}
+ return highestCaseWODeleted
+}
- for k, v := range c.cases {
- result.cases[k] = v.deepCopy()
+func (c *choiceResolver) GetBestCaseBefore() *choicesCase {
+ // best case before
+ var highestCaseWONew *choicesCase
+ highesPrecedenceWONewValue := int32(math.MaxInt32)
+
+ for _, cas := range c.cases {
+ actualCaseWONewValue := cas.getHighestPrecedenceWONew()
+ if actualCaseWONewValue < highesPrecedenceWONewValue {
+ highesPrecedenceWONewValue = actualCaseWONewValue
+ highestCaseWONew = cas
+ }
}
+ return highestCaseWONew
+}
- for k, v := range c.elementToCaseMapping {
- result.elementToCaseMapping[k] = v
+func (c *choiceResolver) GetDeletes() []string {
+ result := []string{}
+ // best case now
+ highestCaseNow := c.GetBestCaseNow()
+ // best case before
+ highestCaseBefore := c.GetBestCaseBefore()
+
+ // if best case before (highestCaseWONew) != best case now (highestCaseWODeleted)
+ if highestCaseBefore != nil && highestCaseBefore != highestCaseNow {
+ // remove best case before
+ result = append(result, highestCaseBefore.GetElementNames()...)
}
return result
}
// GetElementNames retrieve all the Element names involved in the Choice
-func (c *choiceCasesResolver) GetElementNames() []string {
- result := make([]string, 0, len(c.cases))
+func (c *choiceResolver) GetElementNames() []string {
+ result := make([]string, 0, len(c.elementToCaseMapping))
for elemName := range c.elementToCaseMapping {
result = append(result, elemName)
}
@@ -110,127 +175,70 @@ func (c *choiceCasesResolver) GetElementNames() []string {
// choicesCase is the representation of a case in the choiceCasesResolver.
type choicesCase struct {
name string
- elements map[string]*choicesCaseElement
+ elements map[string]*caseElement
}
-func (c *choicesCase) deepCopy() *choicesCase {
- result := &choicesCase{
- name: c.name,
+func newChoicesCase(name string) *choicesCase {
+ return &choicesCase{
+ name: name,
+ elements: map[string]*caseElement{},
}
- for k, v := range c.elements {
- result.elements[k] = v.deepCopy()
+}
+
+func (c *choicesCase) GetElementNames() []string {
+ result := make([]string, 0, len(c.elements))
+ for name := range c.elements {
+ result = append(result, name)
}
return result
}
-func (c *choicesCase) GetLowestPriorityValue() int32 {
+func (c *choicesCase) getHighestPrecedenceWONew() int32 {
result := int32(math.MaxInt32)
- for _, cas := range c.elements {
- if cas.value < result {
- result = cas.value
+ for _, elem := range c.elements {
+ if elem.highestWONew < result {
+ result = elem.highestWONew
}
}
return result
}
-func (c *choicesCase) GetLowestPriorityValueOld() int32 {
+func (c *choicesCase) getHighestPrecedenceWODeleted() int32 {
result := int32(math.MaxInt32)
- for _, cas := range c.elements {
- if !cas.new && cas.value < result {
- result = cas.value
+ for _, elem := range c.elements {
+ if elem.highestWODeleted < result {
+ result = elem.highestWODeleted
}
}
return result
}
-type choicesCaseElement struct {
- name string
- value int32
- new bool
-}
-
-func (c *choicesCaseElement) deepCopy() *choicesCaseElement {
- return &choicesCaseElement{
- name: c.name,
- value: c.value,
- new: c.new,
- }
-}
-
-// newChoiceCasesResolver returns a ready to use choiceCasesResolver.
-func newChoiceCasesResolver() *choiceCasesResolver {
- return &choiceCasesResolver{
- cases: map[string]*choicesCase{}, // case name -> case data
- elementToCaseMapping: map[string]string{}, // element name -> case name
- }
-}
-
-// AddCase adds / registers a case with its name and the element names that belong to the case
-func (c *choiceCasesResolver) AddCase(name string, elements []string) *choicesCase {
- c.cases[name] = &choicesCase{
- name: name,
- elements: map[string]*choicesCaseElement{},
+func (c *choicesCase) deepCopy() *choicesCase {
+ result := &choicesCase{
+ name: c.name,
}
- for _, e := range elements {
- c.elementToCaseMapping[e] = name
- c.cases[name].elements[e] = &choicesCaseElement{
- name: e,
- value: int32(math.MaxInt32),
- }
+ for k, v := range c.elements {
+ result.elements[k] = v.deepCopy()
}
- return c.cases[name]
+ return result
}
-// SetValue Sets the priority value that the given elements with its entire branch has calculated
-func (c *choiceCasesResolver) SetValue(elemName string, v int32, new bool) {
- // math.MaxInt32 indicates that the branch is not populated,
- // so we skip adding it
- if v == math.MaxInt32 {
- return
- }
- actualCase := c.elementToCaseMapping[elemName]
- c.cases[actualCase].elements[elemName].value = v
- c.cases[actualCase].elements[elemName].new = new
-}
-
-// GetBestCaseName returns the name of the case, that has the highes priority
-func (c *choiceCasesResolver) getBestCaseName() string {
- var bestCaseName string
- bestCasePrio := int32(math.MaxInt32)
- for caseName, cas := range c.cases {
- if cas.GetLowestPriorityValue() <= bestCasePrio {
- bestCaseName = caseName
- bestCasePrio = cas.GetLowestPriorityValue()
- }
- }
- return bestCaseName
+type caseElement struct {
+ name string
+ highestWODeleted int32
+ highestWONew int32
}
-func (c *choiceCasesResolver) getOldBestCaseName() string {
- var bestCaseName string
- bestCasePrio := int32(math.MaxInt32)
- for caseName, cas := range c.cases {
- lowestPrioOld := cas.GetLowestPriorityValueOld()
- if lowestPrioOld < bestCasePrio {
- bestCaseName = caseName
- bestCasePrio = lowestPrioOld
- }
+func newCaseElement(name string) *caseElement {
+ return &caseElement{
+ name: name,
}
- return bestCaseName
}
-// GetSkipElements returns the names of all the elements that belong to
-// cases that have not the best priority
-func (c *choiceCasesResolver) GetSkipElements() []string {
- result := make([]string, 0, len(c.elementToCaseMapping))
-
- bestCase := c.getBestCaseName()
-
- for elem, cas := range c.elementToCaseMapping {
- if cas == bestCase {
- continue
- }
- result = append(result, elem)
+func (c *caseElement) deepCopy() *caseElement {
+ return &caseElement{
+ name: c.name,
+ highestWODeleted: c.highestWODeleted,
+ highestWONew: c.highestWONew,
}
- return result
}
diff --git a/pkg/utils/default_value.go b/pkg/tree/default_value.go
similarity index 78%
rename from pkg/utils/default_value.go
rename to pkg/tree/default_value.go
index eacacc4c..4fdb6330 100644
--- a/pkg/utils/default_value.go
+++ b/pkg/tree/default_value.go
@@ -1,12 +1,12 @@
-package utils
+package tree
import (
"fmt"
"strings"
- "github.com/sdcio/data-server/pkg/cache"
+ "github.com/sdcio/data-server/pkg/tree/types"
+ "github.com/sdcio/data-server/pkg/utils"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "google.golang.org/protobuf/proto"
)
func DefaultValueExists(schema *sdcpb.SchemaElem) bool {
@@ -19,7 +19,7 @@ func DefaultValueExists(schema *sdcpb.SchemaElem) bool {
return false
}
-func DefaultValueRetrieve(schema *sdcpb.SchemaElem, path []string, prio int32, intent string) (*cache.Update, error) {
+func DefaultValueRetrieve(schema *sdcpb.SchemaElem, path []string, prio int32, intent string) (*types.Update, error) {
var tv *sdcpb.TypedValue
var err error
switch schem := schema.GetSchema().(type) {
@@ -28,7 +28,7 @@ func DefaultValueRetrieve(schema *sdcpb.SchemaElem, path []string, prio int32, i
if defaultVal == "" {
return nil, fmt.Errorf("no defaults defined for schema path: %s", strings.Join(path, "->"))
}
- tv, err = Convert(defaultVal, schem.Field.GetType())
+ tv, err = utils.Convert(defaultVal, schem.Field.GetType())
if err != nil {
return nil, err
}
@@ -39,7 +39,7 @@ func DefaultValueRetrieve(schema *sdcpb.SchemaElem, path []string, prio int32, i
}
tvlist := make([]*sdcpb.TypedValue, 0, len(listDefaults))
for _, dv := range schem.Leaflist.GetDefaults() {
- tvelem, err := Convert(dv, schem.Leaflist.GetType())
+ tvelem, err := utils.Convert(dv, schem.Leaflist.GetType())
if err != nil {
return nil, fmt.Errorf("error converting default to typed value for %s, type: %s ; value: %s; err: %v", strings.Join(path, " -> "), schem.Leaflist.GetType().GetTypeName(), dv, err)
}
@@ -56,11 +56,5 @@ func DefaultValueRetrieve(schema *sdcpb.SchemaElem, path []string, prio int32, i
return nil, fmt.Errorf("no defaults defined for schema path: %s", strings.Join(path, "->"))
}
- // convert value to []byte for cache insertion
- val, err := proto.Marshal(tv)
- if err != nil {
- return nil, err
- }
-
- return cache.NewUpdate(path, val, prio, intent, 0), nil
+ return types.NewUpdate(path, tv, prio, intent, 0), nil
}
diff --git a/pkg/tree/entry.go b/pkg/tree/entry.go
index 42bf6752..fb7f994f 100644
--- a/pkg/tree/entry.go
+++ b/pkg/tree/entry.go
@@ -5,10 +5,10 @@ import (
"math"
"github.com/beevik/etree"
- "github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/config"
"github.com/sdcio/data-server/pkg/tree/importer"
- "github.com/sdcio/data-server/pkg/types"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
+ "github.com/sdcio/data-server/pkg/tree/types"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
)
@@ -46,28 +46,34 @@ func newEntry(ctx context.Context, parent Entry, pathElemName string, tc *TreeCo
// Entry is the primary Element of the Tree.
type Entry interface {
// Path returns the Path as PathSlice
- Path() PathSlice
+ Path() types.PathSlice
// PathName returns the last Path element, the name of the Entry
PathName() string
+ // GetLevel returns the depth of the Entry in the tree
+ GetLevel() int
// addChild Add a child entry
addChild(context.Context, Entry) error
- // AddCacheUpdateRecursive Add the given cache.Update to the tree
- AddCacheUpdateRecursive(ctx context.Context, u *cache.Update, flags *UpdateInsertFlags) (Entry, error)
+ // getOrCreateChilds retrieves the sub-child pointed at by the path.
+ // if the path does not exist in its full extend, the entries will be added along the way
+ // if the path does not point to a schema defined path an error will be raise
+ getOrCreateChilds(ctx context.Context, path types.PathSlice) (Entry, error)
+ // AddUpdateRecursive Add the given cache.Update to the tree
+ AddUpdateRecursive(ctx context.Context, u *types.Update, flags *types.UpdateInsertFlags) (Entry, error)
// StringIndent debug tree struct as indented string slice
StringIndent(result []string) []string
// GetHighesPrio return the new cache.Update entried from the tree that are the highes priority.
// If the onlyNewOrUpdated option is set to true, only the New or Updated entries will be returned
// It will append to the given list and provide a new pointer to the slice
- GetHighestPrecedence(result LeafVariantSlice, onlyNewOrUpdated bool) LeafVariantSlice
+ GetHighestPrecedence(result LeafVariantSlice, onlyNewOrUpdated bool, includeDefaults bool) LeafVariantSlice
// getHighestPrecedenceLeafValue returns the highest LeafValue of the Entry at hand
// will return an error if the Entry is not a Leaf
getHighestPrecedenceLeafValue(context.Context) (*LeafEntry, error)
// GetByOwner returns the branches Updates by owner
- GetByOwner(owner string, result []*LeafEntry) []*LeafEntry
+ GetByOwner(owner string, result []*LeafEntry) LeafVariantSlice
// markOwnerDelete Sets the delete flag on all the LeafEntries belonging to the given owner.
- markOwnerDelete(o string, onlyIntended bool)
+ MarkOwnerDelete(o string, onlyIntended bool)
// GetDeletes returns the cache-updates that are not updated, have no lower priority value left and hence should be deleted completely
- GetDeletes(entries []DeleteEntry, aggregatePaths bool) ([]DeleteEntry, error)
+ GetDeletes(entries []types.DeleteEntry, aggregatePaths bool) ([]types.DeleteEntry, error)
// Walk takes the EntryVisitor and applies it to every Entry in the tree
Walk(f EntryVisitor) error
// Validate kicks off validation
@@ -76,20 +82,20 @@ type Entry interface {
validateMandatory(ctx context.Context, resultChan chan<- *types.ValidationResultEntry)
// validateMandatoryWithKeys is an internally used function that us called by validateMandatory in case
// the container has keys defined that need to be skipped before the mandatory attributes can be checked
- validateMandatoryWithKeys(ctx context.Context, level int, attribute string, resultChan chan<- *types.ValidationResultEntry)
+ validateMandatoryWithKeys(ctx context.Context, level int, attributes []string, choiceName string, resultChan chan<- *types.ValidationResultEntry)
// getHighestPrecedenceValueOfBranch returns the highes Precedence Value (lowest Priority value) of the brach that starts at this Entry
- getHighestPrecedenceValueOfBranch() int32
+ getHighestPrecedenceValueOfBranch(filter HighestPrecedenceFilter) int32
// GetSchema returns the *sdcpb.SchemaElem of the Entry
GetSchema() *sdcpb.SchemaElem
// IsRoot returns true if the Entry is the root of the tree
IsRoot() bool
// FinishInsertionPhase indicates, that the insertion of Entries into the tree is over
// Hence calculations for e.g. choice/case can be performed.
- FinishInsertionPhase(ctx context.Context)
+ FinishInsertionPhase(ctx context.Context) error
// GetParent returns the parent entry
GetParent() Entry
// Navigate navigates the tree according to the given path and returns the referenced entry or nil if it does not exist.
- Navigate(ctx context.Context, path []string, isRootPath bool) (Entry, error)
+ Navigate(ctx context.Context, path []string, isRootPath bool, dotdotSkipKeys bool) (Entry, error)
NavigateSdcpbPath(ctx context.Context, path []*sdcpb.PathElem, isRootPath bool) (Entry, error)
// NavigateLeafRef follows the leafref and returns the referenced entry
NavigateLeafRef(ctx context.Context) ([]Entry, error)
@@ -138,7 +144,14 @@ type Entry interface {
ToXML(onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool) (*etree.Document, error)
toXmlInternal(parent *etree.Element, onlyNewOrUpdated bool, honorNamespace bool, operationWithNamespace bool, useOperationRemove bool) (doAdd bool, err error)
// ImportConfig allows importing config data received from e.g. the device in different formats (json, xml) to be imported into the tree.
- ImportConfig(ctx context.Context, t importer.ImportConfigAdapter, intentName string, intentPrio int32) error
+ ImportConfig(ctx context.Context, importer importer.ImportConfigAdapter, intentName string, intentPrio int32, flags *types.UpdateInsertFlags) error
+ TreeExport(owner string) ([]*tree_persist.TreeElement, error)
+ DeleteSubtree(relativePath types.PathSlice, owner string) (remainsToExist bool, err error)
+ GetDeviations(ch chan<- *types.DeviationEntry, activeCase bool)
+ // getListChilds collects all the childs of the list. In the tree we store them seperated into their key branches.
+ // this is collecting all the last level key entries.
+ GetListChilds() ([]Entry, error)
+ BreadthSearch(ctx context.Context, path string) ([]Entry, error)
}
type EntryVisitor func(s *sharedEntryAttributes) error
diff --git a/pkg/tree/entry_test.go b/pkg/tree/entry_test.go
index df105e0d..ce3ba82c 100644
--- a/pkg/tree/entry_test.go
+++ b/pkg/tree/entry_test.go
@@ -8,37 +8,32 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/config"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils/testhelper"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"go.uber.org/mock/gomock"
- "google.golang.org/protobuf/proto"
)
var (
- flagsNew *UpdateInsertFlags
- flagsExisting *UpdateInsertFlags
- validationConfig *config.Validation
+ flagsNew *types.UpdateInsertFlags
+ flagsExisting *types.UpdateInsertFlags
+ validationConfig = &config.Validation{DisableConcurrency: true}
)
func init() {
- flagsNew = NewUpdateInsertFlags()
+ flagsNew = types.NewUpdateInsertFlags()
flagsNew.SetNewFlag()
- flagsExisting = NewUpdateInsertFlags()
- validationConfig = &config.Validation{DisableConcurrency: true}
+ flagsExisting = types.NewUpdateInsertFlags()
}
func Test_Entry(t *testing.T) {
- desc, err := proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_StringVal{StringVal: "MyDescription"}})
- if err != nil {
- t.Error(err)
- }
+ desc := testhelper.GetStringTvProto("MyDescription")
- u1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "9", "description"}, desc, int32(100), "me", int64(9999999))
- u2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc, int32(99), "me", int64(444))
- u3 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc, int32(98), "me", int64(88))
+ u1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "9", "description"}, desc, int32(100), "me", int64(9999999))
+ u2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc, int32(99), "me", int64(444))
+ u3 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc, int32(98), "me", int64(88))
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
@@ -50,21 +45,24 @@ func Test_Entry(t *testing.T) {
ctx := context.TODO()
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Error(err)
}
- for _, u := range []*cache.Update{u1, u2, u3} {
- _, err = root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{u1, u2, u3} {
+ _, err = root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
r := []string{}
r = root.StringIndent(r)
@@ -72,9 +70,9 @@ func Test_Entry(t *testing.T) {
}
func Test_Entry_One(t *testing.T) {
- desc1 := testhelper.GetStringTvProto(t, "DescriptionOne")
- desc2 := testhelper.GetStringTvProto(t, "DescriptionTwo")
- desc3 := testhelper.GetStringTvProto(t, "DescriptionThree")
+ desc1 := testhelper.GetStringTvProto("DescriptionOne")
+ desc2 := testhelper.GetStringTvProto("DescriptionTwo")
+ desc3 := testhelper.GetStringTvProto("DescriptionThree")
prio100 := int32(100)
prio50 := int32(50)
@@ -84,9 +82,14 @@ func Test_Entry_One(t *testing.T) {
ts1 := int64(9999999)
- u1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "9", "description"}, desc1, prio100, owner1, ts1)
- u2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc2, prio100, owner1, ts1)
- u3 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc3, prio50, owner2, ts1)
+ u0o1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio100, owner1, ts1)
+ u0o2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio50, owner2, ts1)
+ u1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "9", "description"}, desc1, prio100, owner1, ts1)
+ u1_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "9", "index"}, testhelper.GetUIntTvProto(9), prio100, owner1, ts1)
+ u2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc2, prio100, owner1, ts1)
+ u2_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetUIntTvProto(10), prio100, owner1, ts1)
+ u3 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc3, prio50, owner2, ts1)
+ u3_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetUIntTvProto(10), prio50, owner2, ts1)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
@@ -98,7 +101,7 @@ func Test_Entry_One(t *testing.T) {
ctx := context.TODO()
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -106,34 +109,37 @@ func Test_Entry_One(t *testing.T) {
}
// start test
- for _, u := range []*cache.Update{u1, u2, u3} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{u0o1, u1, u1_1, u2, u2_1, u3, u3_1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
// log the tree
t.Log(root.String())
- t.Run("Test 1 - expect 2 entry for owner1", func(t *testing.T) {
+ t.Run("Test 1 - expected entries for owner1", func(t *testing.T) {
o1Le := []*LeafEntry{}
o1Le = root.GetByOwner(owner1, o1Le)
- o1 := LeafEntriesToCacheUpdates(o1Le)
+ o1 := LeafEntriesToUpdates(o1Le)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{u2, u1}, o1); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{u0o1, u2, u2_1, u1, u1_1}, o1); diff != "" {
t.Errorf("root.GetByOwner(owner1) mismatch (-want +got):\n%s", diff)
}
})
- t.Run("Test 2 - expect 1 entry for owner2", func(t *testing.T) {
+ t.Run("Test 2 - expected entries for owner2", func(t *testing.T) {
o2Le := []*LeafEntry{}
o2Le = root.GetByOwner(owner2, o2Le)
- o2 := LeafEntriesToCacheUpdates(o2Le)
+ o2 := LeafEntriesToUpdates(o2Le)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{u3}, o2); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{u0o2, u3_1, u3}, o2); diff != "" {
t.Errorf("root.GetByOwner(owner2) mismatch (-want +got):\n%s", diff)
}
})
@@ -142,7 +148,7 @@ func Test_Entry_One(t *testing.T) {
highprec := root.GetHighestPrecedence(true)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{u1, u3}, highprec.ToCacheUpdateSlice()); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{u0o2, u1, u1_1, u3, u3_1}, highprec.ToUpdateSlice()); diff != "" {
t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
}
})
@@ -151,11 +157,13 @@ func Test_Entry_One(t *testing.T) {
// Test_Entry_Two adding a new Update with same owner and priority but updating the value
func Test_Entry_Two(t *testing.T) {
- desc3 := testhelper.GetStringTvProto(t, "DescriptionThree")
+ desc3 := testhelper.GetStringTvProto("DescriptionThree")
prio50 := int32(50)
owner1 := "OwnerOne"
ts1 := int64(9999999)
- u1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc3, prio50, owner1, ts1)
+ u0 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc3, prio50, owner1, ts1)
+ u1_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetUIntTvProto(10), prio50, owner1, ts1)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
@@ -167,7 +175,7 @@ func Test_Entry_Two(t *testing.T) {
ctx := context.TODO()
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -175,53 +183,61 @@ func Test_Entry_Two(t *testing.T) {
}
// start test add "existing" data
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Error(err)
}
}
// add incomming set intent reques data
- overwriteDesc := testhelper.GetStringTvProto(t, "Owerwrite Description")
+ overwriteDesc := testhelper.GetStringTvProto("Owerwrite Description")
// adding a new Update with same owner and priority with different value
- n1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, overwriteDesc, prio50, owner1, ts1)
+ n1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, overwriteDesc, prio50, owner1, ts1)
- for _, u := range []*cache.Update{n1} {
- _, err = root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{n1} {
+ _, err = root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
// log the tree
t.Log(root.String())
highprec := root.GetHighestPrecedence(true)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{n1}, highprec.ToCacheUpdateSlice()); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{n1, u0, u1_1}, highprec.ToUpdateSlice()); diff != "" {
t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
}
}
// Test_Entry_Three Checks that an Intent update is processed properly
func Test_Entry_Three(t *testing.T) {
- desc3 := testhelper.GetStringTvProto(t, "DescriptionThree")
+ desc3 := testhelper.GetStringTvProto("DescriptionThree")
prio50 := int32(50)
owner1 := "OwnerOne"
ts1 := int64(9999999)
- u1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc3, prio50, owner1, ts1)
- u2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "11", "description"}, desc3, prio50, owner1, ts1)
- u3 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "12", "description"}, desc3, prio50, owner1, ts1)
- u4 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "13", "description"}, desc3, prio50, owner1, ts1)
-
- u1r := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
- u2r := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "11", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
- u3r := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "12", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
- u4r := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "13", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
+ u0 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc3, prio50, owner1, ts1)
+ u1_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetUIntTvProto(10), prio50, owner1, ts1)
+ u2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "description"}, desc3, prio50, owner1, ts1)
+ u2_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "index"}, testhelper.GetUIntTvProto(11), prio50, owner1, ts1)
+ u3 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "12", "description"}, desc3, prio50, owner1, ts1)
+ u3_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "12", "index"}, testhelper.GetUIntTvProto(12), prio50, owner1, ts1)
+ u4 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "13", "description"}, desc3, prio50, owner1, ts1)
+ u4_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "13", "index"}, testhelper.GetUIntTvProto(13), prio50, owner1, ts1)
+
+ u1r := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
+ u2r := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
+ u3r := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "12", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
+ u4r := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "13", "description"}, desc3, RunningValuesPrio, RunningIntentName, ts1)
mockCtrl := gomock.NewController(t)
defer mockCtrl.Finish()
@@ -233,7 +249,7 @@ func Test_Entry_Three(t *testing.T) {
ctx := context.TODO()
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -241,22 +257,25 @@ func Test_Entry_Three(t *testing.T) {
}
// start test add "existing" data
- for _, u := range []*cache.Update{u1, u2, u3, u4} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1, u2, u3, u4} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Error(err)
}
}
// start test add "existing" data as running
- for _, u := range []*cache.Update{u1r, u2r, u3r, u4r} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1r, u2r, u3r, u4r} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
t.Run("Check the data is present", func(t *testing.T) {
@@ -266,7 +285,7 @@ func Test_Entry_Three(t *testing.T) {
highpri := root.GetHighestPrecedence(false)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{u1, u2, u3, u4}, highpri.ToCacheUpdateSlice()); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{u0, u1, u1_1, u2, u2_1, u3, u3_1, u4, u4_1}, highpri.ToUpdateSlice()); diff != "" {
t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
}
})
@@ -279,30 +298,33 @@ func Test_Entry_Three(t *testing.T) {
highpri := root.GetHighestPrecedence(true)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{}, highpri.ToCacheUpdateSlice()); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{}, highpri.ToUpdateSlice()); diff != "" {
t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
}
})
// indicate that the intent is receiving an update
// therefor invalidate all the present entries of the owner / intent
- root.markOwnerDelete(owner1, false)
+ root.MarkOwnerDelete(owner1, false)
// add incomming set intent reques data
- overwriteDesc := testhelper.GetStringTvProto(t, "Owerwrite Description")
+ overwriteDesc := testhelper.GetStringTvProto("Owerwrite Description")
// adding a new Update with same owner and priority with different value
- n1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, overwriteDesc, prio50, owner1, ts1)
- n2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "11", "description"}, overwriteDesc, prio50, owner1, ts1)
+ n1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, overwriteDesc, prio50, owner1, ts1)
+ n2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "description"}, overwriteDesc, prio50, owner1, ts1)
- for _, u := range []*cache.Update{n1, n2} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{n1, n2} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
// log the tree
t.Log(root.String())
@@ -314,10 +336,10 @@ func Test_Entry_Three(t *testing.T) {
highPriLe := root.getByOwnerFiltered(owner1, FilterNonDeleted)
- highPri := LeafEntriesToCacheUpdates(highPriLe)
+ highPri := LeafEntriesToUpdates(highPriLe)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{n1, n2}, highPri); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{n1, n2}, highPri); diff != "" {
t.Errorf("root.GetByOwner() mismatch (-want +got):\n%s", diff)
}
})
@@ -325,7 +347,7 @@ func Test_Entry_Three(t *testing.T) {
t.Run("Check the old entries are gone", func(t *testing.T) {
highpri := root.GetHighestPrecedence(true)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{n1, n2}, highpri.ToCacheUpdateSlice()); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{n1, n2}, highpri.ToUpdateSlice()); diff != "" {
t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
}
})
@@ -334,20 +356,28 @@ func Test_Entry_Three(t *testing.T) {
// Test_Entry_Four Checks that an Intent update is processed properly with an intent that is shadowed initially.
func Test_Entry_Four(t *testing.T) {
- desc3 := testhelper.GetStringTvProto(t, "DescriptionThree")
+ desc3 := testhelper.GetStringTvProto("DescriptionThree")
prio50 := int32(50)
prio55 := int32(55)
owner1 := "OwnerOne"
owner2 := "OwnerTwo"
ts1 := int64(9999999)
- u1o1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc3, prio50, owner1, ts1)
- u2o1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "11", "description"}, desc3, prio50, owner1, ts1)
- u3 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "12", "description"}, desc3, prio50, owner1, ts1)
- u4 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "13", "description"}, desc3, prio50, owner1, ts1)
-
- u1o2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "10", "description"}, desc3, prio55, owner2, ts1)
- u2o2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "11", "description"}, desc3, prio55, owner2, ts1)
+ u1o1_0 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio50, owner1, ts1)
+ u1o1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc3, prio50, owner1, ts1)
+ u1o1_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetUIntTvProto(10), prio50, owner1, ts1)
+ u2o1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "description"}, desc3, prio50, owner1, ts1)
+ u2o1_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "index"}, testhelper.GetUIntTvProto(11), prio50, owner1, ts1)
+ u3 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "12", "description"}, desc3, prio50, owner1, ts1)
+ u3_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "12", "index"}, testhelper.GetUIntTvProto(12), prio50, owner1, ts1)
+ u4 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "13", "description"}, desc3, prio50, owner1, ts1)
+ u4_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "13", "index"}, testhelper.GetUIntTvProto(13), prio50, owner1, ts1)
+
+ u1o2_0 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio55, owner2, ts1)
+ u1o2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, desc3, prio55, owner2, ts1)
+ u1o2_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetUIntTvProto(10), prio55, owner2, ts1)
+ u2o2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "description"}, desc3, prio55, owner2, ts1)
+ u2o2_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "index"}, testhelper.GetUIntTvProto(11), prio55, owner2, ts1)
ctx := context.TODO()
@@ -359,7 +389,7 @@ func Test_Entry_Four(t *testing.T) {
t.Fatal(err)
}
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -367,14 +397,17 @@ func Test_Entry_Four(t *testing.T) {
}
// start test add "existing" data
- for _, u := range []*cache.Update{u1o1, u2o1, u3, u4, u1o2, u2o2} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1o1, u2o1, u1o1_1, u2o1_1, u3, u4, u3_1, u4_1, u1o2, u2o2} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
t.Run("Check the data is present", func(t *testing.T) {
@@ -384,29 +417,35 @@ func Test_Entry_Four(t *testing.T) {
highprec := root.GetHighestPrecedence(false)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{u1o1, u2o1, u3, u4}, highprec.ToCacheUpdateSlice()); diff != "" {
- t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
+ if diff := testhelper.DiffUpdates([]*types.Update{u1o1_0, u1o1, u2o1, u3, u4, u1o1_1, u2o1_1, u3_1, u4_1}, highprec.ToUpdateSlice()); diff != "" {
+ t.Errorf("root.GetHighestPrecedence() mismatch (-want +got):\n%s", diff)
}
})
// indicate that the intent is receiving an update
// therefor invalidate all the present entries of the owner / intent
- root.markOwnerDelete(owner1, false)
+ root.MarkOwnerDelete(owner1, false)
// add incomming set intent reques data
- overwriteDesc := testhelper.GetStringTvProto(t, "Owerwrite Description")
+ overwriteDesc := testhelper.GetStringTvProto("Owerwrite Description")
// adding a new Update with same owner and priority with different value
- n1 := cache.NewUpdate([]string{"interface", "ethernet-0/1", "subinterface", "10", "description"}, overwriteDesc, prio50, owner1, ts1)
- n2 := cache.NewUpdate([]string{"interface", "ethernet-0/1", "subinterface", "11", "description"}, overwriteDesc, prio50, owner1, ts1)
-
- for _, u := range []*cache.Update{n1, n2} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ //n0 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-1/1"), prio50, owner1, ts1)
+ // n1_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "index"}, testhelper.GetIntTvProto(t, 10), prio50, owner1, ts1)
+ n1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "10", "description"}, overwriteDesc, prio50, owner1, ts1)
+ // n2_1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "index"}, testhelper.GetIntTvProto(t, 11), prio50, owner1, ts1)
+ n2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "11", "description"}, overwriteDesc, prio50, owner1, ts1)
+
+ for _, u := range []*types.Update{n1, n2} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Error(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
// log the tree
t.Log(root.String())
@@ -418,27 +457,27 @@ func Test_Entry_Four(t *testing.T) {
highPriLe := root.getByOwnerFiltered(owner1, FilterNonDeleted)
- highPri := LeafEntriesToCacheUpdates(highPriLe)
+ highPri := LeafEntriesToUpdates(highPriLe)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{n1, n2}, highPri); diff != "" {
+ if diff := testhelper.DiffUpdates([]*types.Update{n1, n2}, highPri); diff != "" {
t.Errorf("root.GetByOwner() mismatch (-want +got):\n%s", diff)
}
})
t.Run("Check the old entries are gone from highest", func(t *testing.T) {
- highpri := root.GetHighestPrecedence(true)
+ highpri := root.GetHighestPrecedence(false)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{n1, n2, u1o2, u2o2}, highpri.ToCacheUpdateSlice()); diff != "" {
- t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
+ if diff := testhelper.DiffUpdates([]*types.Update{u1o1_0, n1, n2, u2o1_1, u1o1_1, u3, u3_1, u4, u4_1}, highpri.ToUpdateSlice()); diff != "" {
+ t.Errorf("root.GetHighestPrecedence() mismatch (-want +got):\n%s", diff)
}
})
- t.Run("Check the old entries are gone from highest (only New Or Updated)", func(t *testing.T) {
+ t.Run("Check the old entries are gone from highest (Only New Or Updated)", func(t *testing.T) {
highpri := root.GetHighestPrecedence(true)
// diff the result with the expected
- if diff := testhelper.DiffCacheUpdates([]*cache.Update{u1o2, u2o2, n1, n2}, highpri.ToCacheUpdateSlice()); diff != "" {
- t.Errorf("root.GetHighesPrio() mismatch (-want +got):\n%s", diff)
+ if diff := testhelper.DiffUpdates([]*types.Update{u1o2_0, n1, n2, u2o2_1, u1o2_1}, highpri.ToUpdateSlice()); diff != "" {
+ t.Errorf("root.GetHighestPrecedence() mismatch (-want +got):\n%s", diff)
}
})
}
@@ -460,13 +499,13 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
t.Run("Test Leaflist min- & max- elements - One",
func(t *testing.T) {
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, owner1)
+ tc := NewTreeContext(scb, owner1)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
}
- leaflistval := testhelper.GetLeafListTvProto(t,
+ leaflistval := testhelper.GetLeafListTvProto(
[]*sdcpb.TypedValue{
{
Value: &sdcpb.TypedValue_StringVal{StringVal: "data"},
@@ -474,17 +513,20 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
},
)
- u1 := cache.NewUpdate([]string{"leaflist", "entry"}, leaflistval, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"leaflist", "entry"}, leaflistval, prio50, owner1, ts1)
// start test add "existing" data
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
t.Log(root.String())
@@ -501,13 +543,13 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
t.Run("Test Leaflist min- & max- elements - Two",
func(t *testing.T) {
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, owner1)
+ tc := NewTreeContext(scb, owner1)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
}
- leaflistval := testhelper.GetLeafListTvProto(t,
+ leaflistval := testhelper.GetLeafListTvProto(
[]*sdcpb.TypedValue{
{
Value: &sdcpb.TypedValue_StringVal{StringVal: "data1"},
@@ -518,11 +560,11 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
},
)
- u1 := cache.NewUpdate([]string{"leaflist", "entry"}, leaflistval, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"leaflist", "entry"}, leaflistval, prio50, owner1, ts1)
// start test add "existing" data
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Fatal(err)
}
@@ -541,13 +583,13 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
t.Run("Test Leaflist min- & max- elements - Four",
func(t *testing.T) {
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, owner1)
+ tc := NewTreeContext(scb, owner1)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
}
- leaflistval := testhelper.GetLeafListTvProto(t,
+ leaflistval := testhelper.GetLeafListTvProto(
[]*sdcpb.TypedValue{
{
Value: &sdcpb.TypedValue_StringVal{StringVal: "data1"},
@@ -564,11 +606,11 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
},
)
- u1 := cache.NewUpdate([]string{"leaflist", "entry"}, leaflistval, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"leaflist", "entry"}, leaflistval, prio50, owner1, ts1)
// start test add "existing" data
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Fatal(err)
}
@@ -587,17 +629,17 @@ func Test_Validation_Leaflist_Min_Max(t *testing.T) {
}
func Test_Entry_Delete_Aggregation(t *testing.T) {
- desc3 := testhelper.GetStringTvProto(t, "DescriptionThree")
+ desc3 := testhelper.GetStringTvProto("DescriptionThree")
prio50 := int32(50)
owner1 := "OwnerOne"
ts1 := int64(9999999)
- u1 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "description"}, desc3, prio50, owner1, ts1)
- u2 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "name"}, testhelper.GetStringTvProto(t, "ethernet-0/0"), prio50, owner1, ts1)
- u3 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "0", "index"}, testhelper.GetStringTvProto(t, "0"), prio50, owner1, ts1)
- u4 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "0", "description"}, desc3, prio50, owner1, ts1)
- u5 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "1", "index"}, testhelper.GetStringTvProto(t, "1"), prio50, owner1, ts1)
- u6 := cache.NewUpdate([]string{"interface", "ethernet-0/0", "subinterface", "1", "description"}, desc3, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, desc3, prio50, owner1, ts1)
+ u2 := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio50, owner1, ts1)
+ u3 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "0", "index"}, testhelper.GetUIntTvProto(0), prio50, owner1, ts1)
+ u4 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "0", "description"}, desc3, prio50, owner1, ts1)
+ u5 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "index"}, testhelper.GetUIntTvProto(1), prio50, owner1, ts1)
+ u6 := types.NewUpdate([]string{"interface", "ethernet-1/1", "subinterface", "1", "description"}, desc3, prio50, owner1, ts1)
ctx := context.TODO()
mockCtrl := gomock.NewController(t)
@@ -608,7 +650,7 @@ func Test_Entry_Delete_Aggregation(t *testing.T) {
t.Fatal(err)
}
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -616,28 +658,33 @@ func Test_Entry_Delete_Aggregation(t *testing.T) {
}
// start test add "existing" data
- for _, u := range []*cache.Update{u1, u2, u3, u4, u5, u6} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsExisting)
+ for _, u := range []*types.Update{u1, u2, u3, u4, u5, u6} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsExisting)
if err != nil {
t.Fatal(err)
}
}
// get ready to add the new intent data
- root.markOwnerDelete(owner1, false)
+ root.MarkOwnerDelete(owner1, false)
- u1n := cache.NewUpdate([]string{"interface", "ethernet-0/1", "description"}, desc3, prio50, owner1, ts1)
- u2n := cache.NewUpdate([]string{"interface", "ethernet-0/1", "name"}, testhelper.GetStringTvProto(t, "ethernet-0/1"), prio50, owner1, ts1)
+ u1n := types.NewUpdate([]string{"interface", "ethernet-1/1", "description"}, desc3, prio50, owner1, ts1)
+ u2n := types.NewUpdate([]string{"interface", "ethernet-1/1", "name"}, testhelper.GetStringTvProto("ethernet-1/1"), prio50, owner1, ts1)
// start test add "new" / request data
- for _, u := range []*cache.Update{u1n, u2n} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{u1n, u2n} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
+
+ t.Log(root.String())
// retrieve the Deletes
deletesSlices, err := root.GetDeletes(true)
@@ -653,7 +700,8 @@ func Test_Entry_Delete_Aggregation(t *testing.T) {
// define the expected result
expects := []string{
- "interface/ethernet-0/0",
+ "interface/ethernet-1/1/subinterface/0",
+ "interface/ethernet-1/1/subinterface/1",
}
// sort both slices for equality check
slices.Sort(deletes)
@@ -678,8 +726,8 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 2, owner1, ts), flagsExisting, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 1, owner2, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 2, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 1, owner2, ts), flagsExisting, nil))
lv.les[1].MarkDelete(false)
le := lv.GetHighestPrecedence(true, false)
@@ -696,7 +744,7 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
t.Run("Single entry thats also marked for deletion",
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 1, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 1, owner1, ts), flagsExisting, nil))
lv.les[0].MarkDelete(false)
le := lv.GetHighestPrecedence(true, false)
@@ -712,9 +760,9 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
t.Run("New Low Prio IsUpdate OnlyChanged True",
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, RunningValuesPrio, RunningIntentName, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, RunningValuesPrio, RunningIntentName, ts), flagsExisting, nil))
le := lv.GetHighestPrecedence(true, false)
@@ -729,8 +777,8 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
t.Run("New Low Prio IsUpdate OnlyChanged False",
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 6, owner1, ts), flagsNew, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 6, owner1, ts), flagsNew, nil))
le := lv.GetHighestPrecedence(false, false)
@@ -746,9 +794,9 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, RunningValuesPrio, RunningIntentName, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, RunningValuesPrio, RunningIntentName, ts), flagsExisting, nil))
le := lv.GetHighestPrecedence(true, false)
@@ -764,8 +812,8 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
le := lv.GetHighestPrecedence(true, false)
@@ -778,8 +826,8 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
t.Run("New Low Prio IsNew OnlyChanged == False",
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 5, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 6, owner2, ts), flagsNew, nil))
le := lv.GetHighestPrecedence(false, false)
@@ -806,9 +854,9 @@ func TestLeafVariants_GetHighesPrio(t *testing.T) {
t.Run("secondhighes populated if highes was first",
func(t *testing.T) {
lv := newLeafVariants(&TreeContext{})
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 1, owner1, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 1, owner1, ts), flagsExisting, nil))
lv.les[0].MarkDelete(false)
- lv.Add(NewLeafEntry(cache.NewUpdate(path, nil, 2, owner2, ts), flagsExisting, nil))
+ lv.Add(NewLeafEntry(types.NewUpdate(path, nil, 2, owner2, ts), flagsExisting, nil))
le := lv.GetHighestPrecedence(true, false)
@@ -863,7 +911,7 @@ func Test_Schema_Population(t *testing.T) {
t.Fatal(err)
}
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -876,11 +924,11 @@ func Test_Schema_Population(t *testing.T) {
}
expectNotNil(t, interf.schema, "/interface schema")
- e00, err := newSharedEntryAttributes(ctx, interf, "ethernet-0/0", tc)
+ e00, err := newSharedEntryAttributes(ctx, interf, "ethernet-1/1", tc)
if err != nil {
t.Error(err)
}
- expectNil(t, e00.schema, "/interface/ethernet-0/0 schema")
+ expectNil(t, e00.schema, "/interface/ethernet-1/1 schema")
dk, err := newSharedEntryAttributes(ctx, root.sharedEntryAttributes, "doublekey", tc)
if err != nil {
@@ -918,7 +966,7 @@ func Test_sharedEntryAttributes_SdcpbPath(t *testing.T) {
t.Fatal(err)
}
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -930,7 +978,7 @@ func Test_sharedEntryAttributes_SdcpbPath(t *testing.T) {
t.Error(err)
}
- e00, err := newSharedEntryAttributes(ctx, interf, "ethernet-0/0", tc)
+ e00, err := newSharedEntryAttributes(ctx, interf, "ethernet-1/1", tc)
if err != nil {
t.Error(err)
}
@@ -971,7 +1019,7 @@ func Test_sharedEntryAttributes_SdcpbPath(t *testing.T) {
{
Name: "interface",
Key: map[string]string{
- "name": "ethernet-0/0",
+ "name": "ethernet-1/1",
},
},
},
@@ -992,7 +1040,7 @@ func Test_sharedEntryAttributes_SdcpbPath(t *testing.T) {
{
Name: "interface",
Key: map[string]string{
- "name": "ethernet-0/0",
+ "name": "ethernet-1/1",
},
},
{
@@ -1045,7 +1093,7 @@ func Test_sharedEntryAttributes_getKeyName(t *testing.T) {
t.Fatal(err)
}
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, "foo")
+ tc := NewTreeContext(scb, "foo")
root, err := NewTreeRoot(ctx, tc)
if err != nil {
@@ -1057,7 +1105,7 @@ func Test_sharedEntryAttributes_getKeyName(t *testing.T) {
t.Error(err)
}
- e00, err := newSharedEntryAttributes(ctx, interf, "ethernet-0/0", tc)
+ e00, err := newSharedEntryAttributes(ctx, interf, "ethernet-1/1", tc)
if err != nil {
t.Error(err)
}
@@ -1142,24 +1190,27 @@ func Test_Validation_String_Pattern(t *testing.T) {
t.Run("Test_Validation_String_Pattern - One",
func(t *testing.T) {
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, owner1)
+ tc := NewTreeContext(scb, owner1)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
}
- leafval := testhelper.GetStringTvProto(t, "data123")
+ leafval := testhelper.GetStringTvProto("data123")
- u1 := cache.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
validationResult := root.Validate(context.TODO(), validationConfig)
@@ -1171,29 +1222,32 @@ func Test_Validation_String_Pattern(t *testing.T) {
}
},
)
- flagsNew := NewUpdateInsertFlags()
+ flagsNew := types.NewUpdateInsertFlags()
flagsNew.SetNewFlag()
t.Run("Test_Validation_String_Pattern - Two",
func(t *testing.T) {
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, owner1)
+ tc := NewTreeContext(scb, owner1)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
}
- leafval := testhelper.GetStringTvProto(t, "hallo F")
+ leafval := testhelper.GetStringTvProto("hallo F")
- u1 := cache.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
validationResult := root.Validate(context.TODO(), validationConfig)
@@ -1216,10 +1270,10 @@ func Test_Validation_String_Pattern(t *testing.T) {
// leafval := testhelper.GetStringTvProto(t, "hallo DU")
- // u1 := cache.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
+ // u1 := types.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
- // for _, u := range []*cache.Update{u1} {
- // err := root.AddCacheUpdateRecursive(ctx, u, true)
+ // for _, u := range []*types.Update{u1} {
+ // err := root.AddUpdateRecursive(ctx, u, true)
// if err != nil {
// t.Fatal(err)
// }
@@ -1264,29 +1318,32 @@ func Test_Validation_Deref(t *testing.T) {
t.Fatal(err)
}
- flagsNew := NewUpdateInsertFlags()
+ flagsNew := types.NewUpdateInsertFlags()
flagsNew.SetNewFlag()
t.Run("Test_Validation_String_Pattern - One",
func(t *testing.T) {
- tc := NewTreeContext(NewTreeCacheClient("dev1", nil), scb, owner1)
+ tc := NewTreeContext(scb, owner1)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
}
- leafval := testhelper.GetStringTvProto(t, "data123")
+ leafval := testhelper.GetStringTvProto("data123")
- u1 := cache.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
+ u1 := types.NewUpdate([]string{"patterntest"}, leafval, prio50, owner1, ts1)
- for _, u := range []*cache.Update{u1} {
- _, err := root.AddCacheUpdateRecursive(ctx, u, flagsNew)
+ for _, u := range []*types.Update{u1} {
+ _, err := root.AddUpdateRecursive(ctx, u, flagsNew)
if err != nil {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
validationResult := root.Validate(context.TODO(), validationConfig)
diff --git a/pkg/tree/importer/json/json_tree_importer.go b/pkg/tree/importer/json/json_tree_importer.go
index a11969f6..61aaf254 100644
--- a/pkg/tree/importer/json/json_tree_importer.go
+++ b/pkg/tree/importer/json/json_tree_importer.go
@@ -82,3 +82,6 @@ func (j *JsonTreeImporter) GetTVValue(slt *sdcpb.SchemaLeafType) (*sdcpb.TypedVa
func (j *JsonTreeImporter) GetName() string {
return j.name
}
+
+// Function to ensure JsonTreeImporter implements ImportConfigAdapter (optional)
+var _ importer.ImportConfigAdapter = (*JsonTreeImporter)(nil)
diff --git a/pkg/tree/importer/json/json_tree_importer_test.go b/pkg/tree/importer/json/json_tree_importer_test.go
index d5686ded..16a36b07 100644
--- a/pkg/tree/importer/json/json_tree_importer_test.go
+++ b/pkg/tree/importer/json/json_tree_importer_test.go
@@ -6,8 +6,8 @@ import (
"testing"
"github.com/google/go-cmp/cmp"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
"github.com/sdcio/data-server/pkg/tree"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils/testhelper"
"go.uber.org/mock/gomock"
)
@@ -22,101 +22,108 @@ func TestJsonTreeImporter(t *testing.T) {
{
name: "JSON",
input: `
- {
- "choices": {
- "case1": {
- "case-elem": {
- "elem": "foocaseval"
- }
- }
- },
- "interface": [
- {
- "admin-state": "enable",
- "description": "Foo",
- "name": "ethernet-1/2",
- "subinterface": [
- {
- "description": "Subinterface 5",
- "index": 5,
- "type": "routed"
- }
- ]
- }
- ],
- "leaflist": {
- "entry": [
- "foo",
- "bar"
- ]
- },
- "network-instance": [
- {
- "admin-state": "enable",
- "description": "Other NI",
- "name": "other",
- "type": "ip-vrf",
- "protocol":{
- "bgp": {}
- }
- }
- ],
- "patterntest": "hallo DU",
- "emptyconf": {}
- }`,
+ {
+ "choices": {
+ "case1": {
+ "case-elem": {
+ "elem": "foocaseval"
+ }
+ }
+ },
+ "interface": [
+ {
+ "admin-state": "enable",
+ "description": "Foo",
+ "name": "ethernet-1/2",
+ "subinterface": [
+ {
+ "description": "Subinterface 5",
+ "index": 5,
+ "type": "routed"
+ }
+ ]
+ },
+ {
+ "admin-state": "disable",
+ "description": "Bar",
+ "name": "ethernet-1/3",
+ "subinterface": [
+ {
+ "description": "Subinterface 7",
+ "index": 7,
+ "type": "routed"
+ }
+ ]
+ }
+ ],
+ "leaflist": {
+ "entry": [
+ "foo",
+ "bar"
+ ]
+ },
+ "network-instance": [
+ {
+ "admin-state": "enable",
+ "description": "Other NI",
+ "name": "other",
+ "type": "ip-vrf",
+ "protocol":{
+ "bgp": {}
+ }
+ }
+ ],
+ "patterntest": "hallo DU",
+ "emptyconf": {}
+ }`,
},
{
name: "JSON_IETF",
ietf: true,
input: `{
- "sdcio_model:patterntest": "foo",
- "sdcio_model_choice:choices": {
- "case1": {
- "case-elem": {
- "elem": "foocaseval"
- }
- }
- },
- "sdcio_model_if:interface": [
- {
- "admin-state": "enable",
- "description": "Foo",
- "name": "ethernet-1/1",
- "subinterface": [
- {
- "description": "Subinterface 0",
- "index": 0,
- "type": "sdcio_model_common:routed"
- }
- ]
- }
- ],
- "sdcio_model_leaflist:leaflist": {
- "entry": [
- "foo",
- "bar"
- ]
- },
- "sdcio_model_ni:network-instance": [
- {
- "admin-state": "disable",
- "description": "Default NI",
- "name": "default",
- "type": "sdcio_model_ni:default"
- }
- ]
- }`,
+ "sdcio_model:patterntest": "foo",
+ "sdcio_model_choice:choices": {
+ "case1": {
+ "case-elem": {
+ "elem": "foocaseval"
+ }
+ }
+ },
+ "sdcio_model_if:interface": [
+ {
+ "admin-state": "enable",
+ "description": "Foo",
+ "name": "ethernet-1/1",
+ "subinterface": [
+ {
+ "description": "Subinterface 0",
+ "index": 0,
+ "type": "sdcio_model_common:routed"
+ }
+ ]
+ }
+ ],
+ "sdcio_model_leaflist:leaflist": {
+ "entry": [
+ "foo",
+ "bar"
+ ]
+ },
+ "sdcio_model_ni:network-instance": [
+ {
+ "admin-state": "disable",
+ "description": "Default NI",
+ "name": "default",
+ "type": "sdcio_model_ni:default"
+ }
+ ]
+ }`,
},
}
// create a gomock controller
controller := gomock.NewController(t)
- // create a cache client mock
- cacheClient := mockcacheclient.NewMockClient(controller)
- testhelper.ConfigureCacheClientMock(t, cacheClient, nil, nil, nil, nil)
-
- dsName := "dev1"
scb, err := testhelper.GetSchemaClientBound(t, controller)
if err != nil {
t.Error(err)
@@ -125,7 +132,7 @@ func TestJsonTreeImporter(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
- tc := tree.NewTreeContext(tree.NewTreeCacheClient(dsName, cacheClient), scb, "test")
+ tc := tree.NewTreeContext(scb, "intent1")
root, err := tree.NewTreeRoot(ctx, tc)
if err != nil {
t.Error(err)
@@ -139,12 +146,15 @@ func TestJsonTreeImporter(t *testing.T) {
t.Fatalf("error parsing json document: %v", err)
}
jti := NewJsonTreeImporter(j)
- err = root.ImportConfig(ctx, jti, tree.RunningIntentName, tree.RunningValuesPrio)
+ err = root.ImportConfig(ctx, nil, jti, "owner1", 5, types.NewUpdateInsertFlags())
if err != nil {
t.Fatal(err)
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
t.Log(root.String())
var result any
diff --git a/pkg/tree/importer/proto/proto_tree_importer.go b/pkg/tree/importer/proto/proto_tree_importer.go
new file mode 100644
index 00000000..e5412737
--- /dev/null
+++ b/pkg/tree/importer/proto/proto_tree_importer.go
@@ -0,0 +1,75 @@
+package proto
+
+import (
+ "github.com/sdcio/data-server/pkg/tree/importer"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
+ "github.com/sdcio/data-server/pkg/utils"
+ sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+ log "github.com/sirupsen/logrus"
+ "google.golang.org/protobuf/proto"
+)
+
+type ProtoTreeImporter struct {
+ data *tree_persist.TreeElement
+}
+
+func NewProtoTreeImporter(data *tree_persist.TreeElement) *ProtoTreeImporter {
+ return &ProtoTreeImporter{
+ data: data,
+ }
+}
+
+func (p *ProtoTreeImporter) GetElements() []importer.ImportConfigAdapter {
+ if len(p.data.Childs) == 0 {
+ return nil
+ }
+ result := []importer.ImportConfigAdapter{}
+ for _, c := range p.data.Childs {
+ result = append(result, NewProtoTreeImporter(c))
+ }
+ return result
+}
+
+// func (p *ProtoTreeImporter) getListElements(elems []*tree_persist.TreeElement) []*tree_persist.TreeElement {
+// result := make([]*tree_persist.TreeElement, 0, len(elems))
+// for _, elem := range elems {
+// if elem.Name == "" {
+// result = append(result, &tree_persist.TreeElement{Name: p.data.Name, Childs: p.getListElements(elem.GetChilds())})
+// } else {
+// result = append(result, p.getListElements(elem.GetChilds())...)
+// }
+// }
+// return result
+// }
+
+func (p *ProtoTreeImporter) GetElement(key string) importer.ImportConfigAdapter {
+ for _, c := range p.data.Childs {
+ if c.Name == key {
+ return NewProtoTreeImporter(c)
+ }
+ }
+ return nil
+}
+
+func (p *ProtoTreeImporter) GetKeyValue() string {
+ tv, err := p.GetTVValue(nil)
+ if err != nil {
+ log.Errorf("failed GetTVValue for %s", p.data.Name)
+ }
+ return utils.TypedValueToString(tv)
+}
+
+func (p *ProtoTreeImporter) GetTVValue(slt *sdcpb.SchemaLeafType) (*sdcpb.TypedValue, error) {
+ result := &sdcpb.TypedValue{}
+ err := proto.Unmarshal(p.data.LeafVariant, result)
+ if err != nil {
+ return nil, err
+ }
+ return result, nil
+}
+func (p *ProtoTreeImporter) GetName() string {
+ return p.data.Name
+}
+
+// Function to ensure ProtoTreeImporter implements ImportConfigAdapter (optional)
+var _ importer.ImportConfigAdapter = (*ProtoTreeImporter)(nil)
diff --git a/pkg/tree/importer/proto/proto_tree_importer_test.go b/pkg/tree/importer/proto/proto_tree_importer_test.go
new file mode 100644
index 00000000..d16f4b71
--- /dev/null
+++ b/pkg/tree/importer/proto/proto_tree_importer_test.go
@@ -0,0 +1,171 @@
+package proto
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "testing"
+
+ "github.com/google/go-cmp/cmp"
+
+ "github.com/sdcio/data-server/pkg/tree"
+ jimport "github.com/sdcio/data-server/pkg/tree/importer/json"
+ "github.com/sdcio/data-server/pkg/tree/types"
+ "github.com/sdcio/data-server/pkg/utils/testhelper"
+ "go.uber.org/mock/gomock"
+)
+
+func TestProtoTreeImporter(t *testing.T) {
+
+ tests := []struct {
+ name string
+ input string
+ }{
+ {
+ name: "One",
+ input: `
+ {
+ "choices": {
+ "case1": {
+ "case-elem": {
+ "elem": "foocaseval"
+ }
+ }
+ },
+ "interface": [
+ {
+ "admin-state": "enable",
+ "description": "Foo",
+ "name": "ethernet-1/2",
+ "subinterface": [
+ {
+ "description": "Subinterface 5",
+ "index": 5,
+ "type": "routed"
+ }
+ ]
+ },
+ {
+ "admin-state": "enable",
+ "description": "Bar",
+ "name": "ethernet-1/3",
+ "subinterface": [
+ {
+ "description": "Subinterface 5",
+ "index": 5,
+ "type": "routed"
+ }
+ ]
+ }
+ , {
+ "admin-state": "enable",
+ "description": "FooBar",
+ "name": "ethernet-1/4",
+ "subinterface": [
+ {
+ "description": "Subinterface 5",
+ "index": 5,
+ "type": "routed"
+ }, {
+ "description": "Subinterface 6",
+ "index": 6,
+ "type": "routed"
+ }, {
+ "description": "Subinterface 7",
+ "index": 7,
+ "type": "routed"
+ }
+ ]
+ }
+ ],
+ "leaflist": {
+ "entry": [
+ "foo",
+ "bar"
+ ]
+ },
+ "network-instance": [
+ {
+ "admin-state": "enable",
+ "description": "Other NI",
+ "name": "other",
+ "type": "ip-vrf",
+ "protocol":{
+ "bgp": {}
+ }
+ }
+ ],
+ "patterntest": "hallo DU",
+ "emptyconf": {}
+ }`,
+ },
+ }
+
+ // create a gomock controller
+ controller := gomock.NewController(t)
+
+ scb, err := testhelper.GetSchemaClientBound(t, controller)
+ if err != nil {
+ t.Error(err)
+ }
+ ctx := context.Background()
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ tc := tree.NewTreeContext(scb, "test")
+ root, err := tree.NewTreeRoot(ctx, tc)
+ if err != nil {
+ t.Error(err)
+ }
+
+ jsonBytes := []byte(tt.input)
+
+ var j any
+ err = json.Unmarshal(jsonBytes, &j)
+ if err != nil {
+ t.Fatalf("error parsing json document: %v", err)
+ }
+
+ jti := jimport.NewJsonTreeImporter(j)
+ err = root.ImportConfig(ctx, nil, jti, "owner1", 5, types.NewUpdateInsertFlags())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
+ t.Log(root.String())
+
+ protoIntent, err := root.TreeExport("owner1", 5)
+ if err != nil {
+ t.Error(err)
+ }
+
+ fmt.Println(protoIntent.PrettyString(" "))
+
+ tcNew := tree.NewTreeContext(scb, "test")
+ rootNew, err := tree.NewTreeRoot(ctx, tcNew)
+ if err != nil {
+ t.Error(err)
+ }
+
+ protoAdapter := NewProtoTreeImporter(protoIntent.GetRoot())
+
+ err = rootNew.ImportConfig(ctx, nil, protoAdapter, protoIntent.GetIntentName(), protoIntent.GetPriority(), types.NewUpdateInsertFlags())
+ if err != nil {
+ t.Error(err)
+ }
+ err = rootNew.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
+ t.Log(rootNew.String())
+
+ if diff := cmp.Diff(root.String(), rootNew.String()); diff != "" {
+ t.Errorf("Error imported data differs:%s", diff)
+ }
+ })
+ }
+}
diff --git a/pkg/tree/importer/xml/xml_tree_importer.go b/pkg/tree/importer/xml/xml_tree_importer.go
index a2d5444c..9ec64106 100644
--- a/pkg/tree/importer/xml/xml_tree_importer.go
+++ b/pkg/tree/importer/xml/xml_tree_importer.go
@@ -51,3 +51,6 @@ func (x *XmlTreeImporter) GetTVValue(slt *sdcpb.SchemaLeafType) (*sdcpb.TypedVal
func (x *XmlTreeImporter) GetName() string {
return x.elem.Tag
}
+
+// Function to ensure JsonTreeImporter implements ImportConfigAdapter (optional)
+var _ importer.ImportConfigAdapter = (*XmlTreeImporter)(nil)
diff --git a/pkg/tree/importer/xml/xml_tree_importer_test.go b/pkg/tree/importer/xml/xml_tree_importer_test.go
index 2e196229..4ace5325 100644
--- a/pkg/tree/importer/xml/xml_tree_importer_test.go
+++ b/pkg/tree/importer/xml/xml_tree_importer_test.go
@@ -7,8 +7,8 @@ import (
"github.com/beevik/etree"
"github.com/google/go-cmp/cmp"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
"github.com/sdcio/data-server/pkg/tree"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils"
"github.com/sdcio/data-server/pkg/utils/testhelper"
"go.uber.org/mock/gomock"
@@ -71,18 +71,13 @@ func TestXmlTreeImporter(t *testing.T) {
// create a gomock controller
controller := gomock.NewController(t)
- // create a cache client mock
- cacheClient := mockcacheclient.NewMockClient(controller)
- testhelper.ConfigureCacheClientMock(t, cacheClient, nil, nil, nil, nil)
-
- dsName := "dev1"
scb, err := testhelper.GetSchemaClientBound(t, controller)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
- tc := tree.NewTreeContext(tree.NewTreeCacheClient(dsName, cacheClient), scb, "test")
+ tc := tree.NewTreeContext(scb, "test")
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -97,14 +92,17 @@ func TestXmlTreeImporter(t *testing.T) {
t.Fatal(err)
}
- err = root.ImportConfig(ctx, NewXmlTreeImporter(&inputDoc.Element), tree.RunningIntentName, tree.RunningValuesPrio)
+ err = root.ImportConfig(ctx, nil, NewXmlTreeImporter(&inputDoc.Element), "owner1", 5, types.NewUpdateInsertFlags())
if err != nil {
t.Fatal(err)
}
t.Log(root.String())
fmt.Println(root.String())
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
result, err := root.ToXML(false, false, false, false)
if err != nil {
diff --git a/pkg/tree/json.go b/pkg/tree/json.go
index cd0a03ee..4ef3d4a6 100644
--- a/pkg/tree/json.go
+++ b/pkg/tree/json.go
@@ -125,11 +125,7 @@ func (s *sharedEntryAttributes) toJsonInternal(onlyNewOrUpdated bool, ietf bool)
if le == nil {
return nil, nil
}
- v, err := le.Update.Value()
- if err != nil {
- return nil, err
- }
- return utils.GetJsonValue(v, ietf)
+ return utils.GetJsonValue(le.Value(), ietf)
}
return nil, fmt.Errorf("unable to convert to json (%s)", s.Path())
}
diff --git a/pkg/tree/json_test.go b/pkg/tree/json_test.go
index e4ea3346..c6adb217 100644
--- a/pkg/tree/json_test.go
+++ b/pkg/tree/json_test.go
@@ -8,14 +8,12 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/openconfig/ygot/ygot"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
- "github.com/sdcio/data-server/pkg/cache"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils"
"github.com/sdcio/data-server/pkg/utils/testhelper"
sdcio_schema "github.com/sdcio/data-server/tests/sdcioygot"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"go.uber.org/mock/gomock"
- "google.golang.org/protobuf/proto"
)
func TestToJsonTable(t *testing.T) {
@@ -361,10 +359,10 @@ func TestToJsonTable(t *testing.T) {
},
}
- flagsNew := NewUpdateInsertFlags()
+ flagsNew := types.NewUpdateInsertFlags()
flagsNew.SetNewFlag()
- flagsOld := NewUpdateInsertFlags()
+ flagsOld := types.NewUpdateInsertFlags()
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
@@ -380,11 +378,7 @@ func TestToJsonTable(t *testing.T) {
ctx := context.Background()
- // create a cache client mock
- cacheClient := mockcacheclient.NewMockClient(mockCtrl)
- testhelper.ConfigureCacheClientMock(t, cacheClient, []*cache.Update{}, []*cache.Update{}, []*cache.Update{}, [][]string{})
-
- tc := NewTreeContext(NewTreeCacheClient("dev1", cacheClient), scb, owner)
+ tc := NewTreeContext(scb, owner)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
@@ -423,7 +417,10 @@ func TestToJsonTable(t *testing.T) {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
fmt.Println(root.String())
@@ -550,19 +547,14 @@ func expandUpdateFromConfig(ctx context.Context, conf *sdcio_schema.Device, conv
Elem: []*sdcpb.PathElem{},
},
Value: &sdcpb.TypedValue{Value: &sdcpb.TypedValue_JsonVal{JsonVal: []byte(strJson)}},
- },
- true)
+ })
}
-func addToRoot(ctx context.Context, root *RootEntry, updates []*sdcpb.Update, flags *UpdateInsertFlags, owner string, prio int32) error {
+func addToRoot(ctx context.Context, root *RootEntry, updates []*sdcpb.Update, flags *types.UpdateInsertFlags, owner string, prio int32) error {
for _, upd := range updates {
- b, err := proto.Marshal(upd.Value)
- if err != nil {
- return err
- }
- cacheUpd := cache.NewUpdate(utils.ToStrings(upd.GetPath(), false, false), b, prio, owner, 0)
+ cacheUpd := types.NewUpdate(utils.ToStrings(upd.GetPath(), false, false), upd.Value, prio, owner, 0)
- _, err = root.AddCacheUpdateRecursive(ctx, cacheUpd, flags)
+ _, err := root.AddUpdateRecursive(ctx, cacheUpd, flags)
if err != nil {
return err
}
diff --git a/pkg/tree/leaf_entry.go b/pkg/tree/leaf_entry.go
index 5e7623b9..961bf215 100644
--- a/pkg/tree/leaf_entry.go
+++ b/pkg/tree/leaf_entry.go
@@ -4,13 +4,16 @@ import (
"fmt"
"sync"
- "github.com/sdcio/data-server/pkg/cache"
+ "github.com/sdcio/data-server/pkg/tree/types"
+ "github.com/sdcio/data-server/pkg/utils"
)
// LeafEntry stores the *cache.Update along with additional attributes.
// These Attributes indicate if the entry is to be deleted / added (new) or updated.
type LeafEntry struct {
- *cache.Update
+ *types.Update
+
+ // helper values
parentEntry Entry
IsNew bool
Delete bool
@@ -20,12 +23,24 @@ type LeafEntry struct {
mu sync.RWMutex
}
+func (l *LeafEntry) DeepCopy() *LeafEntry {
+ return &LeafEntry{
+ Update: l.Update.DeepCopy(),
+ parentEntry: l.parentEntry,
+ IsNew: l.IsNew,
+ Delete: l.Delete,
+ DeleteOnlyIntended: l.DeleteOnlyIntended,
+ IsUpdated: l.IsUpdated,
+ mu: sync.RWMutex{},
+ }
+}
+
func (l *LeafEntry) GetEntry() Entry {
return l.parentEntry
}
// MarkUpdate indicate that the entry is an Updated value
-func (l *LeafEntry) MarkUpdate(u *cache.Update) {
+func (l *LeafEntry) MarkUpdate(u *types.Update) {
l.mu.Lock()
defer l.mu.Unlock()
// set the new value
@@ -97,23 +112,15 @@ func (l *LeafEntry) GetRootBasedEntryChain() []Entry {
// String returns a string representation of the LeafEntry
func (l *LeafEntry) String() string {
- tv, err := l.Value()
- var v string
- if err != nil {
- v = err.Error()
- } else {
- v = tv.String()
- }
- return fmt.Sprintf("Owner: %s, Priority: %d, Value: %s, New: %t, Delete: %t, Update: %t, DeleteIntendedOnly: %t", l.Owner(), l.Priority(), v, l.GetNewFlag(), l.GetDeleteFlag(), l.GetUpdateFlag(), l.GetDeleteOnlyIntendedFlag())
+ return fmt.Sprintf("Owner: %s, Priority: %d, Value: %s, New: %t, Delete: %t, Update: %t, DeleteIntendedOnly: %t", l.Owner(), l.Priority(), utils.TypedValueToString(l.Value()), l.GetNewFlag(), l.GetDeleteFlag(), l.GetUpdateFlag(), l.GetDeleteOnlyIntendedFlag())
}
// NewLeafEntry constructor for a new LeafEntry
-func NewLeafEntry(c *cache.Update, flags *UpdateInsertFlags, parent Entry) *LeafEntry {
+func NewLeafEntry(c *types.Update, flags *types.UpdateInsertFlags, parent Entry) *LeafEntry {
le := &LeafEntry{
parentEntry: parent,
Update: c,
}
flags.Apply(le)
return le
-
}
diff --git a/pkg/tree/leaf_entry_filter.go b/pkg/tree/leaf_entry_filter.go
index ddc6b477..0eda6ac1 100644
--- a/pkg/tree/leaf_entry_filter.go
+++ b/pkg/tree/leaf_entry_filter.go
@@ -1,6 +1,6 @@
package tree
-import "github.com/sdcio/data-server/pkg/cache"
+import "github.com/sdcio/data-server/pkg/tree/types"
type LeafEntryFilter func(*LeafEntry) bool
@@ -35,8 +35,8 @@ func Unfiltered(l *LeafEntry) bool {
}
// LeafEntriesToCacheUpdates
-func LeafEntriesToCacheUpdates(l []*LeafEntry) []*cache.Update {
- result := make([]*cache.Update, 0, len(l))
+func LeafEntriesToUpdates(l []*LeafEntry) []*types.Update {
+ result := make([]*types.Update, 0, len(l))
for _, e := range l {
result = append(result, e.Update)
}
diff --git a/pkg/tree/leaf_variant_slice.go b/pkg/tree/leaf_variant_slice.go
index adf6eccf..a9d22741 100644
--- a/pkg/tree/leaf_variant_slice.go
+++ b/pkg/tree/leaf_variant_slice.go
@@ -1,11 +1,11 @@
package tree
-import "github.com/sdcio/data-server/pkg/cache"
+import "github.com/sdcio/data-server/pkg/tree/types"
type LeafVariantSlice []*LeafEntry
-func (lvs LeafVariantSlice) ToCacheUpdateSlice() []*cache.Update {
- result := make([]*cache.Update, 0, len(lvs))
+func (lvs LeafVariantSlice) ToUpdateSlice() types.UpdateSlice {
+ result := make([]*types.Update, 0, len(lvs))
for _, x := range lvs {
result = append(result, x.Update)
}
diff --git a/pkg/tree/leaf_variants.go b/pkg/tree/leaf_variants.go
index 8bbc1224..29daba6a 100644
--- a/pkg/tree/leaf_variants.go
+++ b/pkg/tree/leaf_variants.go
@@ -5,7 +5,9 @@ import (
"math"
"sync"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils"
+ log "github.com/sirupsen/logrus"
)
type LeafVariants struct {
@@ -23,7 +25,7 @@ func newLeafVariants(tc *TreeContext) *LeafVariants {
func (lv *LeafVariants) Add(le *LeafEntry) {
if leafVariant := lv.GetByOwner(le.Owner()); leafVariant != nil {
- if leafVariant.EqualSkipPath(le.Update) {
+ if leafVariant.Equal(le.Update) {
// it seems like the element was not deleted, so drop the delete flag
leafVariant.DropDeleteFlag()
} else {
@@ -57,19 +59,6 @@ func (lv *LeafVariants) Length() int {
return len(lv.les)
}
-// containsOtherOwnerThenDefaultOrRunning returns true if there is any other leafentry then default or running
-func (lv *LeafVariants) containsOtherOwnerThenDefaultOrRunning() bool {
- foundOther := false
- for _, le := range lv.les {
- foundOther = le.Owner() != RunningIntentName && le.Owner() != DefaultsIntentName
- if foundOther {
- break
- }
- }
-
- return foundOther
-}
-
// canDelete returns true if leafValues exist that are not owned by default or running that do not have the DeleteFlag set [or if delete is set, also the DeleteOnlyIntendedFlag set]
func (lv *LeafVariants) canDelete() bool {
lv.lesMutex.RLock()
@@ -150,12 +139,12 @@ func (lv *LeafVariants) remainsToExist() bool {
return false
}
-func (lv *LeafVariants) GetHighestPrecedenceValue() int32 {
+func (lv *LeafVariants) GetHighestPrecedenceValue(filter HighestPrecedenceFilter) int32 {
lv.lesMutex.RLock()
defer lv.lesMutex.RUnlock()
result := int32(math.MaxInt32)
for _, e := range lv.les {
- if !e.GetDeleteFlag() && e.Owner() != DefaultsIntentName && e.Update.Priority() < result {
+ if filter(e) && e.Owner() != DefaultsIntentName && e.Update.Priority() < result {
result = e.Update.Priority()
}
}
@@ -253,8 +242,8 @@ func (lv *LeafVariants) highestIsUnequalRunning(highest *LeafEntry) bool {
}
// ignore errors, they should not happen :-P I know... should...
- rval, _ := runVal.Value()
- hval, _ := highest.Value()
+ rval := runVal.Value()
+ hval := highest.Value()
return !utils.EqualTypedValues(rval, hval)
}
@@ -271,3 +260,114 @@ func (lv *LeafVariants) GetByOwner(owner string) *LeafEntry {
}
return nil
}
+
+// MarkOwnerForDeletion searches for a LefVariant of given owner, if it exists
+// the entry is marked for deletion
+func (lv *LeafVariants) MarkOwnerForDeletion(owner string, onlyIntended bool) {
+ le := lv.GetByOwner(owner)
+ if le != nil {
+ le.MarkDelete(onlyIntended)
+ }
+}
+
+func (lv *LeafVariants) DeleteByOwner(owner string) (remainsToExist bool) {
+ foundOwner := false
+ for i, l := range lv.les {
+ // early exit if condition is met
+ if foundOwner && remainsToExist {
+ return remainsToExist
+ }
+ if l.Owner() == owner {
+ // Remove element from slice
+ lv.les = append(lv.les[:i], lv.les[i+1:]...)
+ foundOwner = true
+ continue
+ }
+ if l.Owner() == DefaultsIntentName {
+ continue
+ }
+ remainsToExist = true
+
+ }
+ return remainsToExist
+}
+
+func (lv *LeafVariants) GetDeviations(ch chan<- *types.DeviationEntry, isActiveCase bool) {
+ if len(lv.les) == 0 {
+ return
+ }
+
+ // get the path via the first LeafEntry
+ // is valida for all entries
+ sdcpbPath, err := lv.les[0].parentEntry.SdcpbPath()
+ if err != nil {
+ log.Error(err)
+ }
+
+ // we are part of an inactive case of a choice
+ if !isActiveCase {
+ for _, le := range lv.les {
+ ch <- types.NewDeviationEntry(le.Owner(), types.DeviationReasonOverruled, sdcpbPath).SetExpectedValue(le.Value())
+ }
+ return
+ }
+
+ var running *LeafEntry
+ var highest *LeafEntry
+
+ overruled := make([]*types.DeviationEntry, 0, len(lv.les))
+ for _, le := range lv.les {
+ // Defaults should be skipped
+ if le.Owner() == DefaultsIntentName {
+ continue
+ }
+ // running is stored in running var
+ if le.Owner() == RunningIntentName {
+ running = le
+ continue
+ }
+ // if no highest exists yet, set it
+ if highest == nil {
+ highest = le
+ continue
+ }
+ // if precedence of actual (le) is higher then highest
+ // replace highest with it
+ if le.Priority() < highest.Priority() {
+ de := types.NewDeviationEntry(highest.Owner(), types.DeviationReasonOverruled, sdcpbPath).SetExpectedValue(highest.Value())
+ overruled = append(overruled, de)
+ highest = le
+ }
+ // if precedence of actual (le) is lower then le needs to be adeded to overruled
+ if le.Priority() >= highest.Priority() {
+ de := types.NewDeviationEntry(le.Owner(), types.DeviationReasonOverruled, sdcpbPath).SetExpectedValue(le.Value())
+ overruled = append(overruled, de)
+ }
+ }
+
+ // send all the overruleds
+ for _, de := range overruled {
+ ch <- de.SetCurrentValue(highest.Value())
+ }
+
+ // if there is no running and no highest (probably a default), skip
+ if running == nil && highest == nil {
+ return
+ }
+
+ // unhandled -> running but no intent data
+ if running != nil && highest == nil {
+ ch <- types.NewDeviationEntry(running.Owner(), types.DeviationReasonUnhandled, sdcpbPath).SetCurrentValue(running.Value())
+ return
+ }
+
+ // if higeste exists but not running OR running != highest
+ if (running == nil && highest != nil) || running.Value().Cmp(highest.Value()) != 0 {
+ de := types.NewDeviationEntry(highest.Owner(), types.DeviationReasonNotApplied, sdcpbPath).SetExpectedValue(highest.Value())
+ if running != nil {
+ de.SetCurrentValue(running.Value())
+ }
+ ch <- de
+ }
+
+}
diff --git a/pkg/tree/proto.go b/pkg/tree/proto.go
index 6cfb2819..2b0e89e0 100644
--- a/pkg/tree/proto.go
+++ b/pkg/tree/proto.go
@@ -7,17 +7,13 @@ import (
)
func (r *RootEntry) ToProtoUpdates(ctx context.Context, onlyNewOrUpdated bool) ([]*sdcpb.Update, error) {
-
cacheUpdates := r.GetHighestPrecedence(onlyNewOrUpdated)
upds := make([]*sdcpb.Update, 0, len(cacheUpdates))
// updates
for _, cachUpdate := range cacheUpdates {
- val, err := cachUpdate.Value()
- if err != nil {
- return nil, err
- }
+ val := cachUpdate.Value()
path, err := cachUpdate.parentEntry.SdcpbPath()
if err != nil {
return nil, err
@@ -30,7 +26,6 @@ func (r *RootEntry) ToProtoUpdates(ctx context.Context, onlyNewOrUpdated bool) (
}
func (r *RootEntry) ToProtoDeletes(ctx context.Context) ([]*sdcpb.Path, error) {
-
cacheDeletes, err := r.GetDeletes(true)
if err != nil {
return nil, err
diff --git a/pkg/tree/root_entry.go b/pkg/tree/root_entry.go
index 96b1b465..3d789223 100644
--- a/pkg/tree/root_entry.go
+++ b/pkg/tree/root_entry.go
@@ -2,10 +2,14 @@ package tree
import (
"context"
+ "fmt"
+ "os"
"strings"
"github.com/sdcio/data-server/pkg/config"
- "github.com/sdcio/data-server/pkg/types"
+ "github.com/sdcio/data-server/pkg/tree/importer"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
+ "github.com/sdcio/data-server/pkg/tree/types"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
)
@@ -14,6 +18,10 @@ type RootEntry struct {
*sharedEntryAttributes
}
+var (
+ ErrorIntentNotPresent = fmt.Errorf("intent not present")
+)
+
// NewTreeRoot Instantiate a new Tree Root element.
func NewTreeRoot(ctx context.Context, tc *TreeContext) (*RootEntry, error) {
sea, err := newSharedEntryAttributes(ctx, nil, "", tc)
@@ -33,6 +41,12 @@ func NewTreeRoot(ctx context.Context, tc *TreeContext) (*RootEntry, error) {
return root, nil
}
+// stringToDisk just for debugging purpose
+func (r *RootEntry) stringToDisk(filename string) error {
+ err := os.WriteFile(filename, []byte(r.String()), 0755)
+ return err
+}
+
func (r *RootEntry) DeepCopy(ctx context.Context) (*RootEntry, error) {
tc := r.treeContext.deepCopy()
se, err := r.sharedEntryAttributes.deepCopy(tc, nil)
@@ -48,10 +62,10 @@ func (r *RootEntry) DeepCopy(ctx context.Context) (*RootEntry, error) {
return result, nil
}
-func (r *RootEntry) AddCacheUpdatesRecursive(ctx context.Context, us UpdateSlice, flags *UpdateInsertFlags) error {
+func (r *RootEntry) AddUpdatesRecursive(ctx context.Context, us types.UpdateSlice, flags *types.UpdateInsertFlags) error {
var err error
for _, u := range us {
- _, err = r.sharedEntryAttributes.AddCacheUpdateRecursive(ctx, u, flags)
+ _, err = r.sharedEntryAttributes.AddUpdateRecursive(ctx, u, flags)
if err != nil {
return err
}
@@ -59,26 +73,15 @@ func (r *RootEntry) AddCacheUpdatesRecursive(ctx context.Context, us UpdateSlice
return nil
}
-func (r *RootEntry) LoadIntendedStoreOwnerData(ctx context.Context, owner string, deleteOnlyIntended bool) (UpdateSlice, error) {
- tc := r.getTreeContext()
+func (r *RootEntry) ImportConfig(ctx context.Context, path types.PathSlice, importer importer.ImportConfigAdapter, intentName string, intentPrio int32, flags *types.UpdateInsertFlags) error {
+ r.treeContext.SetActualOwner(intentName)
- // Get all entries of the already existing intent
- ownerCacheEntries := tc.GetTreeSchemaCacheClient().ReadUpdatesOwner(ctx, owner)
-
- flags := NewUpdateInsertFlags()
-
- // add all the existing entries
- for _, entry := range ownerCacheEntries {
- _, err := r.AddCacheUpdateRecursive(ctx, entry, flags)
- if err != nil {
- return nil, err
- }
+ e, err := r.sharedEntryAttributes.getOrCreateChilds(ctx, path)
+ if err != nil {
+ return err
}
- // Mark all the entries that belong to the owner / intent as deleted.
- // This is to allow for intent updates. We mark all existing entries for deletion up front.
- r.markOwnerDelete(owner, deleteOnlyIntended)
- return ownerCacheEntries, nil
+ return e.ImportConfig(ctx, importer, intentName, intentPrio, flags)
}
func (r *RootEntry) Validate(ctx context.Context, vCfg *config.Validation) types.ValidationResults {
@@ -111,25 +114,25 @@ func (r *RootEntry) String() string {
}
// GetUpdatesForOwner returns the updates that have been calculated for the given intent / owner
-func (r *RootEntry) GetUpdatesForOwner(owner string) UpdateSlice {
+func (r *RootEntry) GetUpdatesForOwner(owner string) types.UpdateSlice {
// retrieve all the entries from the tree that belong to the given
// Owner / Intent, skipping the once marked for deletion
// this is to insert / update entries in the cache.
- return LeafEntriesToCacheUpdates(r.getByOwnerFiltered(owner, FilterNonDeletedButNewOrUpdated))
+ return LeafEntriesToUpdates(r.getByOwnerFiltered(owner, FilterNonDeletedButNewOrUpdated))
}
// GetDeletesForOwner returns the deletes that have been calculated for the given intent / owner
-func (r *RootEntry) GetDeletesForOwner(owner string) PathSlices {
+func (r *RootEntry) GetDeletesForOwner(owner string) types.PathSlices {
// retrieve all entries from the tree that belong to the given user
// and that are marked for deletion.
// This is to cover all the cases where an intent was changed and certain
// part of the config got deleted.
- deletesOwnerUpdates := LeafEntriesToCacheUpdates(r.getByOwnerFiltered(owner, FilterDeleted))
+ deletesOwnerUpdates := LeafEntriesToUpdates(r.getByOwnerFiltered(owner, FilterDeleted))
// they are retrieved as cache.update, we just need the path for deletion from cache
- deletesOwner := make(PathSlices, 0, len(deletesOwnerUpdates))
+ deletesOwner := make(types.PathSlices, 0, len(deletesOwnerUpdates))
// so collect the paths
for _, d := range deletesOwnerUpdates {
- deletesOwner = append(deletesOwner, d.GetPath())
+ deletesOwner = append(deletesOwner, d.GetPathSlice())
}
return deletesOwner
}
@@ -138,24 +141,38 @@ func (r *RootEntry) GetDeletesForOwner(owner string) PathSlices {
// If the onlyNewOrUpdated option is set to true, only the New or Updated entries will be returned
// It will append to the given list and provide a new pointer to the slice
func (r *RootEntry) GetHighestPrecedence(onlyNewOrUpdated bool) LeafVariantSlice {
- return r.sharedEntryAttributes.GetHighestPrecedence(make(LeafVariantSlice, 0), onlyNewOrUpdated)
+ return r.sharedEntryAttributes.GetHighestPrecedence(make(LeafVariantSlice, 0), onlyNewOrUpdated, false)
}
// GetDeletes returns the paths that due to the Tree content are to be deleted from the southbound device.
-func (r *RootEntry) GetDeletes(aggregatePaths bool) (DeleteEntriesList, error) {
- deletes := []DeleteEntry{}
+func (r *RootEntry) GetDeletes(aggregatePaths bool) (types.DeleteEntriesList, error) {
+ deletes := []types.DeleteEntry{}
return r.sharedEntryAttributes.GetDeletes(deletes, aggregatePaths)
}
-// getTreeContext returns the handle to the TreeContext
-func (r *RootEntry) getTreeContext() *TreeContext {
- return r.treeContext
-}
-
func (r *RootEntry) GetAncestorSchema() (*sdcpb.SchemaElem, int) {
return nil, 0
}
+func (r *RootEntry) GetDeviations(ch chan<- *types.DeviationEntry) {
+ r.sharedEntryAttributes.GetDeviations(ch, true)
+}
+
+func (r *RootEntry) TreeExport(owner string, priority int32) (*tree_persist.Intent, error) {
+ te, err := r.sharedEntryAttributes.TreeExport(owner)
+ if err != nil {
+ return nil, err
+ }
+ if te != nil {
+ return &tree_persist.Intent{
+ IntentName: owner,
+ Root: te[0],
+ Priority: priority,
+ }, nil
+ }
+ return nil, ErrorIntentNotPresent
+}
+
// getByOwnerFiltered returns the Tree content filtered by owner, whilst allowing to filter further
// via providing additional LeafEntryFilter
func (r *RootEntry) getByOwnerFiltered(owner string, f ...LeafEntryFilter) []*LeafEntry {
@@ -177,37 +194,8 @@ NEXTELEMENT:
return result
}
-type DeleteEntry interface {
- SdcpbPath() (*sdcpb.Path, error)
- Path() PathSlice
-}
-
-// DeleteEntryImpl is a crutch to flag oldbestcases if on a choice, the active case changed
-type DeleteEntryImpl struct {
- sdcpbPath *sdcpb.Path
- pathslice PathSlice
-}
-
-func NewDeleteEntryImpl(sdcpbPath *sdcpb.Path, pathslice PathSlice) *DeleteEntryImpl {
- return &DeleteEntryImpl{
- sdcpbPath: sdcpbPath,
- pathslice: pathslice,
+func (r *RootEntry) DeleteSubtreePaths(deletes types.DeleteEntriesList, intentName string) {
+ for _, del := range deletes {
+ r.DeleteSubtree(del.Path(), intentName)
}
}
-
-func (d *DeleteEntryImpl) SdcpbPath() (*sdcpb.Path, error) {
- return d.sdcpbPath, nil
-}
-func (d *DeleteEntryImpl) Path() PathSlice {
- return d.pathslice
-}
-
-type DeleteEntriesList []DeleteEntry
-
-func (d DeleteEntriesList) PathSlices() PathSlices {
- result := make(PathSlices, 0, len(d))
- for _, del := range d {
- result = append(result, del.Path())
- }
- return result
-}
diff --git a/pkg/tree/sharedEntryAttributes.go b/pkg/tree/sharedEntryAttributes.go
index ea8d1af2..eab9ade6 100644
--- a/pkg/tree/sharedEntryAttributes.go
+++ b/pkg/tree/sharedEntryAttributes.go
@@ -11,13 +11,13 @@ import (
"sync"
"unicode/utf8"
- "github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/config"
"github.com/sdcio/data-server/pkg/tree/importer"
- "github.com/sdcio/data-server/pkg/types"
+ "github.com/sdcio/data-server/pkg/tree/tree_persist"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "google.golang.org/protobuf/proto"
+ log "github.com/sirupsen/logrus"
"google.golang.org/protobuf/types/known/emptypb"
)
@@ -37,15 +37,16 @@ type sharedEntryAttributes struct {
schema *sdcpb.SchemaElem
schemaMutex sync.RWMutex
- choicesResolvers choiceCasesResolvers
+ choicesResolvers choiceResolvers
treeContext *TreeContext
// state cache
+ cacheMutex sync.Mutex
cacheShouldDelete *bool
cacheCanDelete *bool
cacheRemains *bool
- cacheMutex sync.Mutex
+ level *int
}
func (s *sharedEntryAttributes) deepCopy(tc *TreeContext, parent Entry) (*sharedEntryAttributes, error) {
@@ -57,60 +58,13 @@ func (s *sharedEntryAttributes) deepCopy(tc *TreeContext, parent Entry) (*shared
schema: s.schema,
treeContext: tc,
choicesResolvers: s.choicesResolvers.deepCopy(),
+ childsMutex: sync.RWMutex{},
+ schemaMutex: sync.RWMutex{},
+ cacheMutex: sync.Mutex{},
+ level: s.level,
}
- return result, nil
-}
-
-type childMap struct {
- c map[string]Entry
- mu sync.RWMutex
-}
-
-func newChildMap() *childMap {
- return &childMap{
- c: map[string]Entry{},
- }
-}
-
-func (c *childMap) Add(e Entry) {
- c.mu.Lock()
- defer c.mu.Unlock()
- c.c[e.PathName()] = e
-}
-
-func (c *childMap) GetEntry(s string) (Entry, bool) {
- c.mu.RLock()
- defer c.mu.RUnlock()
- e, exists := c.c[s]
- return e, exists
-}
-
-func (c *childMap) GetAll() map[string]Entry {
- c.mu.RLock()
- defer c.mu.RUnlock()
-
- result := map[string]Entry{}
- for k, v := range c.c {
- result[k] = v
- }
- return result
-}
-
-func (c *childMap) GetKeys() []string {
- c.mu.RLock()
- defer c.mu.RUnlock()
-
- result := make([]string, 0, c.Length())
- for k := range c.c {
- result = append(result, k)
- }
- return result
-}
-func (c *childMap) Length() int {
- c.mu.RLock()
- defer c.mu.RUnlock()
- return len(c.c)
+ return result, nil
}
func newSharedEntryAttributes(ctx context.Context, parent Entry, pathElemName string, tc *TreeContext) (*sharedEntryAttributes, error) {
@@ -150,7 +104,7 @@ func (s *sharedEntryAttributes) GetRoot() Entry {
// loadDefaults helper to populate defaults on the initializiation of the sharedEntryAttribute
func (s *sharedEntryAttributes) loadDefaults(ctx context.Context) error {
- // if it is a container wihtout keys (not a list) then load the defaults
+ // if it is a container without keys (not a list) then load the defaults
if s.schema.GetContainer() != nil && len(s.schema.GetContainer().GetKeys()) == 0 {
for _, childname := range s.schema.GetContainer().ChildsWithDefaults {
// tryLoadingDefaults is using the pathslice, that contains keys as well,
@@ -198,6 +152,85 @@ func (s *sharedEntryAttributes) loadDefaults(ctx context.Context) error {
return nil
}
+func (s *sharedEntryAttributes) GetDeviations(ch chan<- *types.DeviationEntry, activeCase bool) {
+ s.leafVariants.GetDeviations(ch, activeCase)
+
+ // get all active childs
+ activeChilds := s.filterActiveChoiceCaseChilds()
+
+ // iterate through all childs
+ for cName, c := range s.getChildren() {
+ // check if c is a active child (choice / case)
+ _, isActiveChild := activeChilds[cName]
+ // recurse the call
+ c.GetDeviations(ch, isActiveChild)
+ }
+}
+
+func (s *sharedEntryAttributes) checkAndCreateKeysAsLeafs(ctx context.Context, intentName string, prio int32) error {
+ // keys themselfes do not have a schema attached.
+ // keys must be added to the last keys level, since that is carrying the list elements data
+ // hence if the entry has a schema attached, there is nothing to be done, return.
+ if s.schema != nil {
+ return nil
+ }
+
+ // get the first ancestor with a schema and how many levels up that is
+ ancestor, levelsUp := s.GetFirstAncestorWithSchema()
+
+ // retrieve the container schema
+ ancestorContainerSchema := ancestor.GetSchema().GetContainer()
+ // if it is not a container, return
+ if ancestorContainerSchema == nil {
+ return nil
+ }
+
+ // if we're in the last level of keys, then we need to add the defaults
+ if len(ancestorContainerSchema.Keys) == levelsUp {
+ // iterate through the keys
+ for idx, k := range ancestor.GetSchemaKeys() {
+ child, entryExists := s.childs.GetEntry(k)
+ // if the key Leaf exists continue with next key
+ if entryExists {
+ // if it exists, we need to check that the entry for the owner exists.
+ var result []*LeafEntry
+ lvs := child.GetByOwner(intentName, result)
+ if len(lvs) > 0 {
+ continue
+ }
+ }
+ // construct the key path
+ keyPath := append(s.Path(), k)
+
+ schem, err := s.treeContext.schemaClient.GetSchemaSlicePath(ctx, keyPath)
+ if err != nil {
+ return err
+ }
+ // convert the key value to the schema defined Typed_Value
+ tv, err := utils.Convert(keyPath[len(keyPath)-levelsUp-1+idx], schem.Schema.GetField().Type)
+ if err != nil {
+ return err
+ }
+ if !entryExists {
+ // create a new entry
+ child, err = newEntry(ctx, s, k, s.treeContext)
+ if err != nil {
+ return err
+ }
+ // add the new child entry to s
+ err = s.addChild(ctx, child)
+ if err != nil {
+ return err
+ }
+ }
+ _, err = child.AddUpdateRecursive(ctx, types.NewUpdate(keyPath, tv, prio, intentName, 0), types.NewUpdateInsertFlags())
+ return err
+
+ }
+ }
+ return nil
+}
+
func (s *sharedEntryAttributes) populateSchema(ctx context.Context) error {
s.schemaMutex.Lock()
defer s.schemaMutex.Unlock()
@@ -252,6 +285,36 @@ func (s *sharedEntryAttributes) getChildren() map[string]Entry {
return s.childs.GetAll()
}
+// getListChilds collects all the childs of the list. In the tree we store them seperated into their key branches.
+// this is collecting all the last level key entries.
+func (s *sharedEntryAttributes) GetListChilds() ([]Entry, error) {
+ if s.schema == nil {
+ return nil, fmt.Errorf("error GetListChilds() non schema level %s", s.Path().String())
+ }
+ if s.schema.GetContainer() == nil {
+ return nil, fmt.Errorf("error GetListChilds() not a Container %s", s.Path().String())
+ }
+ keys := s.schema.GetContainer().GetKeys()
+ if len(keys) == 0 {
+ return nil, fmt.Errorf("error GetListChilds() not a List Container %s", s.Path().String())
+ }
+ actualEntries := []Entry{s}
+ var newEntries []Entry
+
+ for level := 0; level < len(keys); level++ {
+ for _, e := range actualEntries {
+ // add all children
+ for _, c := range e.getChildren() {
+ newEntries = append(newEntries, c)
+ }
+ }
+ actualEntries = newEntries
+ newEntries = []Entry{}
+ }
+ return actualEntries, nil
+
+}
+
// FilterChilds returns the child entries (skipping the key entries in the tree) that
// match the given keys. The keys do not need to match all levels of keys, in which case the
// key level is considered a wildcard match (*)
@@ -314,7 +377,19 @@ func (s *sharedEntryAttributes) IsRoot() bool {
// GetLevel returns the level / depth position of this element in the tree
func (s *sharedEntryAttributes) GetLevel() int {
- return len(s.Path())
+ // if level is cached, return level
+ if s.level != nil {
+ return *s.level
+ }
+ // if we're at the root level, return 0
+ if s.parent == nil {
+ return 0
+ }
+ // Get parent level and add 1
+ l := s.parent.GetLevel() + 1
+ // cache level value
+ s.level = &l
+ return l
}
// Walk takes the EntryVisitor and applies it to every Entry in the tree
@@ -358,7 +433,7 @@ func (s *sharedEntryAttributes) GetSchemaKeys() []string {
// getAggregatedDeletes is called on levels that have no schema attached, meaning key schemas.
// here we might delete the whole branch of the tree, if all key elements are being deleted
// if not, we continue with regular deltes
-func (s *sharedEntryAttributes) getAggregatedDeletes(deletes []DeleteEntry, aggregatePaths bool) ([]DeleteEntry, error) {
+func (s *sharedEntryAttributes) getAggregatedDeletes(deletes []types.DeleteEntry, aggregatePaths bool) ([]types.DeleteEntry, error) {
var err error
// we take a look into the level(s) up
// trying to get the schema
@@ -446,8 +521,15 @@ func (s *sharedEntryAttributes) shouldDelete() bool {
// but a real delete should only be added if there is at least one shouldDelete() == true
shouldDelete := false
+ activeChilds := s.filterActiveChoiceCaseChilds()
+ // if we have no active childs, we can and should delete.
+ if len(s.choicesResolvers) > 0 && len(activeChilds) == 0 {
+ canDelete = true
+ shouldDelete = true
+ }
+
// iterate through the active childs
- for _, c := range s.filterActiveChoiceCaseChilds() {
+ for _, c := range activeChilds {
// check if the child can be deleted
canDelete = c.canDelete()
// if it can explicitly not be deleted, then the result is clear, we should not delete
@@ -492,56 +574,65 @@ func (s *sharedEntryAttributes) remainsToExist() bool {
break
}
}
- activeChoiceCase := false
- // only needs to be checked if it still looks like there
- // it is to be deleted
- if !childsRemain {
- activeChoiceCase = s.choicesResolvers.remainsToExist()
- }
// assumption is, that if the entry exists, there is at least a running value available.
- remains := leafVariantResult || childsRemain || activeChoiceCase
+ remains := leafVariantResult || childsRemain
s.cacheRemains = &remains
return remains
}
// getRegularDeletes performs deletion calculation on elements that have a schema attached.
-func (s *sharedEntryAttributes) getRegularDeletes(deletes []DeleteEntry, aggregate bool) ([]DeleteEntry, error) {
+func (s *sharedEntryAttributes) getRegularDeletes(deletes []types.DeleteEntry, aggregate bool) ([]types.DeleteEntry, error) {
var err error
// if entry is a container type, check the keys, to be able to
// issue a delte for the whole branch at once via keys
- switch s.schema.GetSchema().(type) {
- case *sdcpb.SchemaElem_Container:
-
- // deletes for child elements (choice cases) that newly became inactive.
- for _, v := range s.choicesResolvers {
- oldBestCaseName := v.getOldBestCaseName()
- newBestCaseName := v.getBestCaseName()
- // so if we have an old and a new best cases (not "") and the names are different,
- // all the old to the deletion list
- if oldBestCaseName != "" && newBestCaseName != "" && oldBestCaseName != newBestCaseName {
- // try fetching the case from the childs
- oldBestCaseEntry, exists := s.childs.GetEntry(oldBestCaseName)
- if exists {
- deletes = append(deletes, oldBestCaseEntry)
- } else {
- // it might be that the child is not loaded into the tree, but just considered from the treecontext cache for the choice/case resolution
- // if so, we create and return the DeleteEntryImpl struct
- path, err := s.SdcpbPath()
- if err != nil {
- return nil, err
- }
- deletes = append(deletes, NewDeleteEntryImpl(path, append(s.Path(), oldBestCaseName)))
- }
- }
- }
- }
+ // switch s.schema.GetSchema().(type) {
+ // case *sdcpb.SchemaElem_Container:
+ // // deletes for child elements (choice cases) that newly became inactive.
+ // for _, v := range s.choicesResolvers {
+ // // oldBestCaseName := v.getOldBestCaseName()
+ // // newBestCaseName := v.getBestCaseName()
+ // // // so if we have an old and a new best cases (not "") and the names are different,
+ // // // all the old to the deletion list
+ // // if oldBestCaseName != "" && newBestCaseName != "" && oldBestCaseName != newBestCaseName {
+ // // // try fetching the case from the childs
+ // // oldBestCaseEntry, exists := s.childs.GetEntry(oldBestCaseName)
+ // // if exists {
+ // // deletes = append(deletes, oldBestCaseEntry)
+ // // } else {
+ // // // it might be that the child is not loaded into the tree, but just considered from the treecontext cache for the choice/case resolution
+ // // // if so, we create and return the DeleteEntryImpl struct
+ // // path, err := s.SdcpbPath()
+ // // if err != nil {
+ // // return nil, err
+ // // }
+ // // deletes = append(deletes, types.NewDeleteEntryImpl(path, append(s.Path(), oldBestCaseName)))
+ // // }
+ // // }
+ // path, err := s.SdcpbPath()
+ // if err != nil {
+ // return nil, err
+ // }
+ // deleteElements := v.GetDeletes()
+ // for _, de := range deleteElements {
+ // deletes = append(deletes, types.NewDeleteEntryImpl(path, append(s.Path(), de)))
+ // }
+ // }
+ // }
if s.shouldDelete() && !s.IsRoot() && len(s.GetSchemaKeys()) == 0 {
return append(deletes, s), nil
}
+ for _, elem := range s.choicesResolvers.GetDeletes() {
+ path, err := s.SdcpbPath()
+ if err != nil {
+ return nil, err
+ }
+ deletes = append(deletes, types.NewDeleteEntryImpl(path, append(s.Path(), elem)))
+ }
+
for _, e := range s.childs.GetAll() {
deletes, err = e.GetDeletes(deletes, aggregate)
if err != nil {
@@ -552,7 +643,7 @@ func (s *sharedEntryAttributes) getRegularDeletes(deletes []DeleteEntry, aggrega
}
// GetDeletes calculate the deletes that need to be send to the device.
-func (s *sharedEntryAttributes) GetDeletes(deletes []DeleteEntry, aggregatePaths bool) ([]DeleteEntry, error) {
+func (s *sharedEntryAttributes) GetDeletes(deletes []types.DeleteEntry, aggregatePaths bool) ([]types.DeleteEntry, error) {
// if the actual level has no schema assigned we're on a key level
// element. Hence we try deletion via aggregation
@@ -585,7 +676,7 @@ func (s *sharedEntryAttributes) GetFirstAncestorWithSchema() (Entry, int) {
}
// GetByOwner returns all the LeafEntries that belong to a certain owner.
-func (s *sharedEntryAttributes) GetByOwner(owner string, result []*LeafEntry) []*LeafEntry {
+func (s *sharedEntryAttributes) GetByOwner(owner string, result []*LeafEntry) LeafVariantSlice {
lv := s.leafVariants.GetByOwner(owner)
if lv != nil {
result = append(result, lv)
@@ -599,10 +690,10 @@ func (s *sharedEntryAttributes) GetByOwner(owner string, result []*LeafEntry) []
}
// Path returns the root based path of the Entry
-func (s *sharedEntryAttributes) Path() PathSlice {
+func (s *sharedEntryAttributes) Path() types.PathSlice {
// special handling for root node
if s.parent == nil {
- return PathSlice{}
+ return types.PathSlice{}
}
return append(s.parent.Path(), s.pathElemName)
}
@@ -662,16 +753,6 @@ func (s *sharedEntryAttributes) NavigateSdcpbPath(ctx context.Context, pathElems
return entry.NavigateSdcpbPath(ctx, pathElems[1:], false)
default:
e, exists := s.filterActiveChoiceCaseChilds()[pathElems[0].Name]
- if !exists {
- e, err = s.tryLoading(ctx, []string{pathElems[0].Name})
- if err != nil {
- return nil, err
- }
- if e != nil {
- exists = true
- }
- }
-
if !exists {
pth := &sdcpb.Path{Elem: pathElems}
e, err = s.tryLoadingDefault(ctx, utils.ToStrings(pth, false, false))
@@ -683,7 +764,7 @@ func (s *sharedEntryAttributes) NavigateSdcpbPath(ctx context.Context, pathElems
}
for _, v := range pathElems[0].Key {
- e, err = e.Navigate(ctx, []string{v}, false)
+ e, err = e.Navigate(ctx, []string{v}, false, false)
if err != nil {
return nil, err
}
@@ -702,14 +783,14 @@ func (s *sharedEntryAttributes) tryLoadingDefault(ctx context.Context, path []st
return nil, fmt.Errorf("error trying to load defaults for %s: %v", strings.Join(path, "->"), err)
}
- upd, err := utils.DefaultValueRetrieve(schema.GetSchema(), path, DefaultValuesPrio, DefaultsIntentName)
+ upd, err := DefaultValueRetrieve(schema.GetSchema(), path, DefaultValuesPrio, DefaultsIntentName)
if err != nil {
return nil, err
}
- flags := NewUpdateInsertFlags()
+ flags := types.NewUpdateInsertFlags()
- result, err := s.AddCacheUpdateRecursive(ctx, upd, flags)
+ result, err := s.AddUpdateRecursive(ctx, upd, flags)
if err != nil {
return nil, fmt.Errorf("failed adding default value for %s to tree; %v", strings.Join(path, "/"), err)
}
@@ -718,28 +799,33 @@ func (s *sharedEntryAttributes) tryLoadingDefault(ctx context.Context, path []st
}
// Navigate move through the tree, returns the Entry that is present under the given path
-func (s *sharedEntryAttributes) Navigate(ctx context.Context, path []string, isRootPath bool) (Entry, error) {
+func (s *sharedEntryAttributes) Navigate(ctx context.Context, path []string, isRootPath bool, dotdotSkipKeys bool) (Entry, error) {
if len(path) == 0 {
return s, nil
}
if isRootPath {
- return s.GetRoot().Navigate(ctx, path, false)
+ return s.treeContext.root.Navigate(ctx, path, false, dotdotSkipKeys)
}
var err error
switch path[0] {
case ".":
- return s.Navigate(ctx, path[1:], false)
+ return s.Navigate(ctx, path[1:], false, dotdotSkipKeys)
case "..":
- return s.parent.Navigate(ctx, path[1:], false)
- default:
- e, exists := s.filterActiveChoiceCaseChilds()[path[0]]
- if !exists {
- e, _ = s.tryLoading(ctx, append(s.Path(), path...))
- if e != nil {
- exists = true
+ parent := s.parent
+ if dotdotSkipKeys {
+ // if dotdotSkipKeys is set, we need to advance to the next schema level above
+ // the issue is, that if there is a list, with keys, the last element even without a schema defined
+ // is the element to stop at.
+ // so here we need to check is the parent schema is nil and that we still want to move further up.
+ // if thats the case, move up to the next schema carrying element.
+ if parent.GetSchema() == nil && len(path) > 0 && path[1] == ".." {
+ parent, _ = parent.GetFirstAncestorWithSchema()
}
}
+ return parent.Navigate(ctx, path[1:], false, dotdotSkipKeys)
+ default:
+ e, exists := s.filterActiveChoiceCaseChilds()[path[0]]
if !exists {
e, err = s.tryLoadingDefault(ctx, append(s.Path(), path...))
if err != nil {
@@ -747,41 +833,55 @@ func (s *sharedEntryAttributes) Navigate(ctx context.Context, path []string, isR
}
return e, nil
}
- return e.Navigate(ctx, path[1:], false)
+ return e.Navigate(ctx, path[1:], false, dotdotSkipKeys)
}
}
-func (s *sharedEntryAttributes) tryLoading(ctx context.Context, path []string) (Entry, error) {
- upd, err := s.treeContext.GetTreeSchemaCacheClient().ReadRunningPath(ctx, append(s.Path(), path...))
- if err != nil {
- return nil, err
- }
- if upd == nil {
- return nil, fmt.Errorf("reached %v but child %s does not exist", s.Path(), path[0])
+func (s *sharedEntryAttributes) DeleteSubtree(relativePath types.PathSlice, owner string) (bool, error) {
+ if len(relativePath) > 0 {
+ child, exists := s.childs.GetEntry(relativePath[0])
+ if !exists {
+ path := make([]string, 0, len(s.Path())+len(relativePath))
+ path = append(path, s.Path()...)
+ path = append(path, relativePath...)
+ return false, fmt.Errorf("trying to delete subtree %q but unable to find child %s at %s", path, relativePath[0], s.Path())
+ }
+ remainingPath := relativePath[1:]
+ return child.DeleteSubtree(remainingPath, owner)
}
- flags := NewUpdateInsertFlags()
+ remainsToExist := false
+ // delete possibly existing leafvariants for the owner
+ remainsToExist = s.leafVariants.DeleteByOwner(owner)
- _, err = s.treeContext.root.AddCacheUpdateRecursive(ctx, upd, flags)
- if err != nil {
- return nil, err
+ deleteKeys := []string{}
+ // recurse the call
+ for childName, child := range s.childs.Items() {
+ childRemains, err := child.DeleteSubtree(nil, owner)
+ if err != nil {
+ return false, err
+ }
+ if !childRemains {
+ deleteKeys = append(deleteKeys, childName)
+ }
+ remainsToExist = remainsToExist || childRemains
}
-
- e, _ := s.childs.GetEntry(path[0])
- return e, nil
+ // finally delete the childs
+ s.childs.DeleteChilds(deleteKeys)
+ return remainsToExist, nil
}
// GetHighestPrecedence goes through the whole branch and returns the new and updated cache.Updates.
// These are the updated that will be send to the device.
-func (s *sharedEntryAttributes) GetHighestPrecedence(result LeafVariantSlice, onlyNewOrUpdated bool) LeafVariantSlice {
+func (s *sharedEntryAttributes) GetHighestPrecedence(result LeafVariantSlice, onlyNewOrUpdated bool, includeDefaults bool) LeafVariantSlice {
// get the highes precedence LeafeVariant and add it to the list
- lv := s.leafVariants.GetHighestPrecedence(onlyNewOrUpdated, false)
+ lv := s.leafVariants.GetHighestPrecedence(onlyNewOrUpdated, includeDefaults)
if lv != nil {
result = append(result, lv)
}
// continue with childs. Childs are part of choices, process only the "active" (highes precedence) childs
for _, c := range s.filterActiveChoiceCaseChilds() {
- result = c.GetHighestPrecedence(result, onlyNewOrUpdated)
+ result = c.GetHighestPrecedence(result, onlyNewOrUpdated, includeDefaults)
}
return result
}
@@ -803,22 +903,35 @@ func (s *sharedEntryAttributes) getHighestPrecedenceLeafValue(ctx context.Contex
}
func (s *sharedEntryAttributes) GetRootBasedEntryChain() []Entry {
+ s.GetLevel()
if s.IsRoot() {
return []Entry{}
}
return append(s.parent.GetRootBasedEntryChain(), s)
}
+type HighestPrecedenceFilter func(le *LeafEntry) bool
+
+func HighestPrecedenceFilterAll(le *LeafEntry) bool {
+ return true
+}
+func HighestPrecedenceFilterWithoutNew(le *LeafEntry) bool {
+ return !le.IsNew
+}
+func HighestPrecedenceFilterWithoutDeleted(le *LeafEntry) bool {
+ return !le.Delete
+}
+
// getHighestPrecedenceValueOfBranch goes through all the child branches to find the highest
// precedence value (lowest priority value) for the entire branch and returns it.
-func (s *sharedEntryAttributes) getHighestPrecedenceValueOfBranch() int32 {
+func (s *sharedEntryAttributes) getHighestPrecedenceValueOfBranch(filter HighestPrecedenceFilter) int32 {
result := int32(math.MaxInt32)
for _, e := range s.childs.GetAll() {
- if val := e.getHighestPrecedenceValueOfBranch(); val < result {
+ if val := e.getHighestPrecedenceValueOfBranch(filter); val < result {
result = val
}
}
- if val := s.leafVariants.GetHighestPrecedenceValue(); val < result {
+ if val := s.leafVariants.GetHighestPrecedenceValue(filter); val < result {
result = val
}
@@ -888,11 +1001,7 @@ func (s *sharedEntryAttributes) validateRange(resultChan chan<- *types.Validatio
return
}
- tv, err := lv.Update.Value()
- if err != nil {
- resultChan <- types.NewValidationResultEntry(lv.Owner(), fmt.Errorf("path %s, error validating ranges: %w", s.Path(), err), types.ValidationResultEntryTypeError)
- return
- }
+ tv := lv.Update.Value()
var tvs []*sdcpb.TypedValue
var typeSchema *sdcpb.SchemaLeafType
@@ -960,10 +1069,8 @@ func (s *sharedEntryAttributes) validateLeafListMinMaxAttributes(resultChan chan
if schema := s.schema.GetLeaflist(); schema != nil {
if schema.MinElements > 0 {
if lv := s.leafVariants.GetHighestPrecedence(false, true); lv != nil {
- tv, err := lv.Update.Value()
- if err != nil {
- resultChan <- types.NewValidationResultEntry(lv.Owner(), fmt.Errorf("validating LeafList Min Attribute: %v", err), types.ValidationResultEntryTypeError)
- }
+ tv := lv.Update.Value()
+
if val := tv.GetLeaflistVal(); val != nil {
// check minelements if set
if schema.MinElements > 0 && len(val.GetElement()) < int(schema.GetMinElements()) {
@@ -990,13 +1097,7 @@ func (s *sharedEntryAttributes) validateLength(resultChan chan<- *types.Validati
if lv == nil {
return
}
-
- tv, err := lv.Value()
- if err != nil {
- resultChan <- types.NewValidationResultEntry(lv.Owner(), fmt.Errorf("failed reading value from %s LeafVariant %v: %w", s.Path(), lv, err), types.ValidationResultEntryTypeError)
- return
- }
- value := tv.GetStringVal()
+ value := lv.Value().GetStringVal()
actualLength := utf8.RuneCountInString(value)
for _, lengthDef := range schema.GetType().Length {
@@ -1018,12 +1119,7 @@ func (s *sharedEntryAttributes) validatePattern(resultChan chan<- *types.Validat
return
}
lv := s.leafVariants.GetHighestPrecedence(false, true)
- tv, err := lv.Update.Value()
- if err != nil {
- resultChan <- types.NewValidationResultEntry(lv.Owner(), fmt.Errorf("failed reading value from %s LeafVariant %v: %w", s.Path(), lv, err), types.ValidationResultEntryTypeError)
- return
- }
- value := tv.GetStringVal()
+ value := lv.Value().GetStringVal()
for _, pattern := range schema.Type.Patterns {
if p := pattern.GetPattern(); p != "" {
matched, err := regexp.MatchString(p, value)
@@ -1039,14 +1135,9 @@ func (s *sharedEntryAttributes) validatePattern(resultChan chan<- *types.Validat
}
}
-func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.ImportConfigAdapter, intentName string, intentPrio int32) error {
+func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.ImportConfigAdapter, intentName string, intentPrio int32, insertFlags *types.UpdateInsertFlags) error {
var err error
- updateInsertFlags := NewUpdateInsertFlags()
- if intentName != RunningIntentName {
- updateInsertFlags.SetNewFlag()
- }
-
switch x := s.schema.GetSchema().(type) {
case *sdcpb.SchemaElem_Container, nil:
switch {
@@ -1073,7 +1164,7 @@ func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.Imp
}
actualEntry = keyChild
}
- err = actualEntry.ImportConfig(ctx, t, intentName, intentPrio)
+ err = actualEntry.ImportConfig(ctx, t, intentName, intentPrio, insertFlags)
if err != nil {
return err
}
@@ -1086,12 +1177,8 @@ func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.Imp
}
if schem.IsPresence {
tv := &sdcpb.TypedValue{Value: &sdcpb.TypedValue_EmptyVal{EmptyVal: &emptypb.Empty{}}}
- tvVal, err := proto.Marshal(tv)
- if err != nil {
- return err
- }
- upd := cache.NewUpdate(s.Path(), tvVal, intentPrio, intentName, 0)
- s.leafVariants.Add(NewLeafEntry(upd, updateInsertFlags, s))
+ upd := types.NewUpdate(s.Path(), tv, intentPrio, intentName, 0)
+ s.leafVariants.Add(NewLeafEntry(upd, insertFlags, s))
}
}
@@ -1110,7 +1197,7 @@ func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.Imp
return err
}
}
- err = child.ImportConfig(ctx, elem, intentName, intentPrio)
+ err = child.ImportConfig(ctx, elem, intentName, intentPrio, insertFlags)
if err != nil {
return err
}
@@ -1127,27 +1214,18 @@ func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.Imp
if err != nil {
return err
}
- tvVal, err := proto.Marshal(tv)
- if err != nil {
- return err
- }
- upd := cache.NewUpdate(s.Path(), tvVal, intentPrio, intentName, 0)
+ upd := types.NewUpdate(s.Path(), tv, intentPrio, intentName, 0)
- s.leafVariants.Add(NewLeafEntry(upd, updateInsertFlags, s))
+ s.leafVariants.Add(NewLeafEntry(upd, insertFlags, s))
case *sdcpb.SchemaElem_Leaflist:
var scalarArr *sdcpb.ScalarArray
mustAdd := false
le := s.leafVariants.GetByOwner(intentName)
if le != nil {
- llvTv, err := le.Update.Value()
- if err != nil {
- return err
- }
-
- scalarArr = llvTv.GetLeaflistVal()
+ scalarArr = le.Value().GetLeaflistVal()
} else {
- le = NewLeafEntry(nil, updateInsertFlags, s)
+ le = NewLeafEntry(nil, insertFlags, s)
mustAdd = true
scalarArr = &sdcpb.ScalarArray{Element: []*sdcpb.TypedValue{}}
}
@@ -1156,14 +1234,14 @@ func (s *sharedEntryAttributes) ImportConfig(ctx context.Context, t importer.Imp
if err != nil {
return err
}
- scalarArr.Element = append(scalarArr.Element, tv)
- tvVal, err := proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_LeaflistVal{LeaflistVal: scalarArr}})
- if err != nil {
- return err
+ // the proto implementation will return leaflist tvs
+ if tv.GetLeaflistVal() == nil {
+ scalarArr.Element = append(scalarArr.Element, tv)
+ tv = &sdcpb.TypedValue{Value: &sdcpb.TypedValue_LeaflistVal{LeaflistVal: scalarArr}}
}
- le.Update = cache.NewUpdate(s.Path(), tvVal, intentPrio, intentName, 0)
+ le.Update = types.NewUpdate(s.Path(), tv, intentPrio, intentName, 0)
if mustAdd {
s.leafVariants.Add(le)
}
@@ -1178,37 +1256,73 @@ func (s *sharedEntryAttributes) validateMandatory(ctx context.Context, resultCha
switch s.schema.GetSchema().(type) {
case *sdcpb.SchemaElem_Container:
for _, c := range s.schema.GetContainer().GetMandatoryChildrenConfig() {
- s.validateMandatoryWithKeys(ctx, len(s.GetSchema().GetContainer().GetKeys()), c.Name, resultChan)
+ attributes := []string{}
+ choiceName := ""
+ // check if it is a ChildContainer
+ if slices.Contains(s.schema.GetContainer().GetChildren(), c.Name) {
+ attributes = append(attributes, c.Name)
+ }
+
+ // check if it is a Field
+ if slices.ContainsFunc(s.schema.GetContainer().GetFields(), func(x *sdcpb.LeafSchema) bool {
+ return x.Name == c.Name
+ }) {
+ attributes = append(attributes, c.Name)
+ }
+
+ // otherwise it will probably be a choice
+ if len(attributes) == 0 {
+ choice := s.schema.GetContainer().GetChoiceInfo().GetChoiceByName(c.Name)
+ if choice != nil {
+ attributes = append(attributes, choice.GetAllAttributes()...)
+ choiceName = c.Name
+ }
+ }
+
+ if len(attributes) == 0 {
+ log.Errorf("error path: %s, validationg mandatory attribute %s could not be found as child, field or choice.", s.Path(), c.Name)
+ }
+
+ s.validateMandatoryWithKeys(ctx, len(s.GetSchema().GetContainer().GetKeys()), attributes, choiceName, resultChan)
}
}
}
}
-func (s *sharedEntryAttributes) validateMandatoryWithKeys(ctx context.Context, level int, attribute string, resultChan chan<- *types.ValidationResultEntry) {
+// validateMandatoryWithKeys steps down the tree, passing the key levels and checking the existence of the mandatory.
+// attributes is a string slice, it will be checked that at least of the the given attributes is defined
+// !Not checking all of these are defined (call multiple times with single entry in attributes for that matter)!
+func (s *sharedEntryAttributes) validateMandatoryWithKeys(ctx context.Context, level int, attributes []string, choiceName string, resultChan chan<- *types.ValidationResultEntry) {
if level == 0 {
- // first check if the mandatory value is set via the intent, e.g. part of the tree already
- v, existsInTree := s.filterActiveChoiceCaseChilds()[attribute]
-
+ success := false
+ existsInTree := false
+ var v Entry
+ // iterate over the attributes make sure any of these exists
+ for _, attr := range attributes {
+ // first check if the mandatory value is set via the intent, e.g. part of the tree already
+ v, existsInTree = s.filterActiveChoiceCaseChilds()[attr]
+ // if exists and remains to Exist
+ if existsInTree && v.remainsToExist() {
+ // set success to true and break the loop
+ success = true
+ break
+ }
+ }
// if not the path exists in the tree and is not to be deleted, then lookup in the paths index of the store
// and see if such path exists, if not raise the error
- if !(existsInTree && v.remainsToExist()) {
- exists, err := s.treeContext.cacheClient.IntendedPathExists(ctx, append(s.Path(), attribute))
- owner := "unknown"
- if s.leafVariants.Length() > 0 {
- s.leafVariants.GetHighestPrecedence(false, true).Owner()
- }
- if err != nil {
- resultChan <- types.NewValidationResultEntry(owner, fmt.Errorf("error validating mandatory childs %s: %v", s.Path(), err), types.ValidationResultEntryTypeError)
- }
- if !exists {
- resultChan <- types.NewValidationResultEntry(owner, fmt.Errorf("error mandatory child %s does not exist, path: %s", attribute, s.Path()), types.ValidationResultEntryTypeError)
+ if !success {
+ // if it is not a choice
+ if choiceName == "" {
+ resultChan <- types.NewValidationResultEntry("unknown", fmt.Errorf("error mandatory child %s does not exist, path: %s", attributes, s.Path()), types.ValidationResultEntryTypeError)
}
+ // if it is a mandatory choice
+ resultChan <- types.NewValidationResultEntry("unknown", fmt.Errorf("error mandatory choice %s [attributes: %s] does not exist, path: %s", choiceName, attributes, s.Path()), types.ValidationResultEntryTypeError)
}
return
}
for _, c := range s.filterActiveChoiceCaseChilds() {
- c.validateMandatoryWithKeys(ctx, level-1, attribute, resultChan)
+ c.validateMandatoryWithKeys(ctx, level-1, attributes, choiceName, resultChan)
}
}
@@ -1232,7 +1346,7 @@ func (s *sharedEntryAttributes) initChoiceCasesResolvers() {
}
// create a new choiceCasesResolvers struct
- choicesResolvers := choiceCasesResolvers{}
+ choicesResolvers := choiceResolvers{}
// iterate through choices defined in schema
for choiceName, choice := range ci.GetChoice() {
@@ -1251,15 +1365,21 @@ func (s *sharedEntryAttributes) initChoiceCasesResolvers() {
// FinishInsertionPhase certain values that are costly to calculate but used multiple times
// will be calculated and stored for later use. However therefore the insertion phase into the
// tree needs to be over. Calling this function indicated the end of the phase and thereby triggers the calculation
-func (s *sharedEntryAttributes) FinishInsertionPhase(ctx context.Context) {
+func (s *sharedEntryAttributes) FinishInsertionPhase(ctx context.Context) error {
// populate the ChoiceCaseResolvers to determine the active case
- s.populateChoiceCaseResolvers(ctx)
+ err := s.populateChoiceCaseResolvers(ctx)
+ if err != nil {
+ return err
+ }
// recurse the call to all (active) entries within the tree.
// Thereby already using the choiceCaseResolver via filterActiveChoiceCaseChilds()
for _, child := range s.filterActiveChoiceCaseChilds() {
- child.FinishInsertionPhase(ctx)
+ err = child.FinishInsertionPhase(ctx)
+ if err != nil {
+ return err
+ }
}
// reset state
@@ -1268,6 +1388,8 @@ func (s *sharedEntryAttributes) FinishInsertionPhase(ctx context.Context) {
s.cacheRemains = nil
s.cacheShouldDelete = nil
s.cacheCanDelete = nil
+
+ return nil
}
// populateChoiceCaseResolvers iterates through the ChoiceCaseResolvers,
@@ -1276,32 +1398,43 @@ func (s *sharedEntryAttributes) FinishInsertionPhase(ctx context.Context) {
// caches index (old intent content) as well as from the tree (new intent content).
// the choiceResolver is fed with the resulting values and thereby ready to be queried
// in a later stage (filterActiveChoiceCaseChilds()).
-func (s *sharedEntryAttributes) populateChoiceCaseResolvers(ctx context.Context) {
+func (s *sharedEntryAttributes) populateChoiceCaseResolvers(_ context.Context) error {
if s.schema == nil {
- return
+ return nil
}
// if choice/cases exist, process it
for _, choiceResolver := range s.choicesResolvers {
for _, elem := range choiceResolver.GetElementNames() {
- isNew := false
- var val2 *int32
- // Query the Index, stored in the treeContext for the per branch highes precedence
- v := s.treeContext.GetTreeSchemaCacheClient().GetBranchesHighesPrecedence(ctx, append(s.Path(), elem), CacheUpdateFilterExcludeOwner(s.treeContext.GetActualOwner()))
+ isDeleted := false
+ highestWDeleted := int32(math.MaxInt32)
+ highestWODeleted := int32(math.MaxInt32)
+ highestWONew := int32(math.MaxInt32)
child, childExists := s.childs.GetEntry(elem)
// set the value from the tree as well
if childExists {
- x := child.getHighestPrecedenceValueOfBranch()
- val2 = &x
- }
+ valWDeleted := child.getHighestPrecedenceValueOfBranch(HighestPrecedenceFilterAll)
+ if valWDeleted <= highestWDeleted {
+ highestWDeleted = valWDeleted
+ if child.canDelete() {
+ isDeleted = true
+ }
+ }
+
+ valWODeleted := child.getHighestPrecedenceValueOfBranch(HighestPrecedenceFilterWithoutDeleted)
+ if valWODeleted <= highestWODeleted {
+ highestWODeleted = valWODeleted
+ }
+ valWONew := child.getHighestPrecedenceValueOfBranch(HighestPrecedenceFilterWithoutNew)
+ if valWONew <= highestWONew {
+ highestWONew = valWONew
+ }
- if val2 != nil && v >= *val2 {
- v = *val2
- isNew = true
}
- choiceResolver.SetValue(elem, v, isNew)
+ choiceResolver.SetValue(elem, highestWODeleted, highestWDeleted, highestWONew, isDeleted)
}
}
+ return nil
}
// filterActiveChoiceCaseChilds returns the list of child elements. In case the Entry is
@@ -1336,10 +1469,9 @@ func (s *sharedEntryAttributes) StringIndent(result []string) []string {
// ranging over children and LeafVariants
// then should be mutual exclusive, either a node has children or LeafVariants
-
// range over children
- for _, c := range s.childs.GetAll() {
- result = c.StringIndent(result)
+ for _, child := range s.childs.GetAllSorted() {
+ result = child.StringIndent(result)
}
// range over LeafVariants
for l := range s.leafVariants.Items() {
@@ -1349,15 +1481,11 @@ func (s *sharedEntryAttributes) StringIndent(result []string) []string {
}
// markOwnerDelete Sets the delete flag on all the LeafEntries belonging to the given owner.
-func (s *sharedEntryAttributes) markOwnerDelete(o string, onlyIntended bool) {
- lvEntry := s.leafVariants.GetByOwner(o)
- // if an entry for the given user exists, mark it for deletion
- if lvEntry != nil {
- lvEntry.MarkDelete(onlyIntended)
- }
+func (s *sharedEntryAttributes) MarkOwnerDelete(o string, onlyIntended bool) {
+ s.leafVariants.MarkOwnerForDeletion(o, onlyIntended)
// recurse into childs
for _, child := range s.childs.GetAll() {
- child.markOwnerDelete(o, onlyIntended)
+ child.MarkOwnerDelete(o, onlyIntended)
}
}
@@ -1407,6 +1535,70 @@ func (s *sharedEntryAttributes) SdcpbPathInternal(spath []string) (*sdcpb.Path,
return p, err
}
+func (s *sharedEntryAttributes) TreeExport(owner string) ([]*tree_persist.TreeElement, error) {
+ var lvResult []byte
+ var childResults []*tree_persist.TreeElement
+ var err error
+
+ le := s.leafVariants.GetByOwner(owner)
+
+ if le != nil && !le.Delete {
+ lvResult, err = le.ValueAsBytes()
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if len(s.GetSchemaKeys()) > 0 {
+ children, err := s.FilterChilds(nil)
+ if err != nil {
+ return nil, err
+ }
+ result := []*tree_persist.TreeElement{}
+ for _, c := range children {
+ childexport, err := c.TreeExport(owner)
+ if err != nil {
+ return nil, err
+ }
+ if len(childexport) == 0 {
+ // no childs belonging to the given owner
+ continue
+ }
+ if len(childexport) > 1 {
+ return nil, fmt.Errorf("unexpected value")
+ }
+ childexport[0].Name = s.pathElemName
+
+ result = append(result, childexport...)
+ }
+ if len(result) > 0 {
+ return result, nil
+ }
+ } else {
+ for _, c := range s.getChildren() {
+ childExport, err := c.TreeExport(owner)
+ if err != nil {
+ return nil, err
+ }
+ if len(childExport) > 0 {
+ childResults = append(childResults, childExport...)
+ }
+
+ }
+ if lvResult != nil || len(childResults) > 0 {
+ return []*tree_persist.TreeElement{
+ {
+ Name: s.pathElemName,
+ Childs: childResults,
+ LeafVariant: lvResult,
+ },
+ }, nil
+ }
+ }
+
+ return nil, nil
+}
+
// getKeyName checks if s is a key level element in the tree, if not an error is throw
// if it is a key level element, the name of the key is determined via the ancestor schemas
func (s *sharedEntryAttributes) getKeyName() (string, error) {
@@ -1429,33 +1621,54 @@ func (s *sharedEntryAttributes) getKeyName() (string, error) {
return "", fmt.Errorf("error LeafList and Field should not have keys %s", strings.Join(s.Path(), " "))
}
+func (s *sharedEntryAttributes) getOrCreateChilds(ctx context.Context, path types.PathSlice) (Entry, error) {
+ var err error
+ if len(path) == 0 {
+ return s, nil
+ }
+
+ e, exists := s.childs.GetEntry(path[0])
+ if !exists {
+ e, err = newEntry(ctx, s, path[0], s.treeContext)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return e.getOrCreateChilds(ctx, path[1:])
+}
+
// AddCacheUpdateRecursive recursively adds the given cache.Update to the tree. Thereby creating all the entries along the path.
// if the entries along th path already exist, the existing entries are called to add the Update.
-func (s *sharedEntryAttributes) AddCacheUpdateRecursive(ctx context.Context, c *cache.Update, flags *UpdateInsertFlags) (Entry, error) {
- idx := 0
- // if it is the root node, index remains == 0
- if s.parent != nil {
- idx = s.GetLevel()
+func (s *sharedEntryAttributes) AddUpdateRecursive(ctx context.Context, u *types.Update, flags *types.UpdateInsertFlags) (Entry, error) {
+ idx := s.GetLevel()
+ var err error
+ // make sure all the keys are also present as leafs
+ err = s.checkAndCreateKeysAsLeafs(ctx, u.Owner(), u.Priority())
+ if err != nil {
+ return nil, err
}
+
// end of path reached, add LeafEntry
// continue with recursive add otherwise
- if idx == len(c.GetPath()) {
+ if idx == len(u.GetPathSlice()) {
// delegate update handling to leafVariants
- s.leafVariants.Add(NewLeafEntry(c, flags, s))
+ s.leafVariants.Add(NewLeafEntry(u, flags, s))
return s, nil
}
var e Entry
- var err error
+
var exists bool
// if child does not exist, create Entry
- if e, exists = s.childs.GetEntry(c.GetPath()[idx]); !exists {
- e, err = newEntry(ctx, s, c.GetPath()[idx], s.treeContext)
+ if e, exists = s.childs.GetEntry(u.GetPathSlice()[idx]); !exists {
+ e, err = newEntry(ctx, s, u.GetPathSlice()[idx], s.treeContext)
if err != nil {
return nil, err
}
+
}
- return e.AddCacheUpdateRecursive(ctx, c, flags)
+ return e.AddUpdateRecursive(ctx, u, flags)
}
// containsOnlyDefaults checks for presence containers, if only default values are present,
@@ -1493,55 +1706,3 @@ func (s *sharedEntryAttributes) containsOnlyDefaults() bool {
return true
}
-
-type UpdateInsertFlags struct {
- new bool
- delete bool
- onlyIntended bool
-}
-
-// NewUpdateInsertFlags returns a new *UpdateInsertFlags instance
-// with all values set to false, so not new, and not marked for deletion
-func NewUpdateInsertFlags() *UpdateInsertFlags {
- return &UpdateInsertFlags{}
-}
-
-func (f *UpdateInsertFlags) SetDeleteFlag() {
- f.delete = true
- f.new = false
-}
-
-func (f *UpdateInsertFlags) SetDeleteOnlyUpdatedFlag() {
- f.delete = true
- f.onlyIntended = true
- f.new = false
-}
-
-func (f *UpdateInsertFlags) SetNewFlag() {
- f.new = true
- f.delete = false
- f.onlyIntended = false
-}
-
-func (f *UpdateInsertFlags) GetDeleteFlag() bool {
- return f.delete
-}
-
-func (f *UpdateInsertFlags) GetDeleteOnlyIntendedFlag() bool {
- return f.onlyIntended
-}
-
-func (f *UpdateInsertFlags) GetNewFlag() bool {
- return f.new
-}
-
-func (f *UpdateInsertFlags) Apply(le *LeafEntry) {
- if f.delete {
- le.MarkDelete(f.onlyIntended)
- return
- }
- if f.new {
- le.MarkNew()
- return
- }
-}
diff --git a/pkg/tree/sharedEntryAttributes_test.go b/pkg/tree/sharedEntryAttributes_test.go
new file mode 100644
index 00000000..988d09f7
--- /dev/null
+++ b/pkg/tree/sharedEntryAttributes_test.go
@@ -0,0 +1,59 @@
+package tree
+
+import (
+ "context"
+ "fmt"
+ "testing"
+
+ schemaClient "github.com/sdcio/data-server/pkg/datastore/clients/schema"
+ "github.com/sdcio/data-server/pkg/tree/types"
+ "github.com/sdcio/data-server/pkg/utils/testhelper"
+ "go.uber.org/mock/gomock"
+)
+
+func Test_sharedEntryAttributes_checkAndCreateKeysAsLeafs(t *testing.T) {
+ controller := gomock.NewController(t)
+ defer controller.Finish()
+
+ sc, schema, err := testhelper.InitSDCIOSchema()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ctx := context.Background()
+ scb := schemaClient.NewSchemaClientBound(schema, sc)
+
+ tc := NewTreeContext(scb, "intent1")
+
+ root, err := NewTreeRoot(ctx, tc)
+ if err != nil {
+ t.Error(err)
+ }
+
+ flags := types.NewUpdateInsertFlags()
+ flags.SetNewFlag()
+
+ prio := int32(5)
+ intentName := "intent1"
+
+ _, err = root.AddUpdateRecursive(ctx, types.NewUpdate(types.PathSlice{"interface", "ethernet-1/1", "description"}, testhelper.GetStringTvProto("MyDescription"), prio, intentName, 0), flags)
+ if err != nil {
+ t.Error(err)
+ }
+
+ _, err = root.AddUpdateRecursive(ctx, types.NewUpdate([]string{"doublekey", "k1.1", "k1.3", "mandato"}, testhelper.GetStringTvProto("TheMandatoryValue1"), prio, intentName, 0), flags)
+ if err != nil {
+ t.Error(err)
+ }
+
+ t.Log(root.String())
+
+ fmt.Println(root.String())
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
+ fmt.Println(root.String())
+
+ // TODO: check the result
+}
diff --git a/pkg/tree/sorter.go b/pkg/tree/sorter.go
index 57c5f433..44a97259 100644
--- a/pkg/tree/sorter.go
+++ b/pkg/tree/sorter.go
@@ -6,16 +6,21 @@ func getListEntrySortFunc(parent Entry) func(a, b Entry) int {
keys := parent.GetSchemaKeys()
var cmpResult int
for _, v := range keys {
- aLvSlice := a.getChildren()[v].GetHighestPrecedence(LeafVariantSlice{}, false)
- bLvSlice := b.getChildren()[v].GetHighestPrecedence(LeafVariantSlice{}, false)
+ achild, exists := a.getChildren()[v]
+ if !exists {
+ return 0
+ }
+ bchild, exists := b.getChildren()[v]
+ if !exists {
+ return 0
+ }
+ aLvSlice := achild.GetHighestPrecedence(LeafVariantSlice{}, false, true)
+ bLvSlice := bchild.GetHighestPrecedence(LeafVariantSlice{}, false, true)
aEntry := aLvSlice[0]
bEntry := bLvSlice[0]
- aTv, _ := aEntry.Value()
- bTv, _ := bEntry.Value()
-
- cmpResult = aTv.Cmp(bTv)
+ cmpResult = aEntry.Value().Cmp(bEntry.Value())
if cmpResult != 0 {
return cmpResult
}
diff --git a/pkg/tree/tree_cache_client.go b/pkg/tree/tree_cache_client.go
deleted file mode 100644
index 3c722488..00000000
--- a/pkg/tree/tree_cache_client.go
+++ /dev/null
@@ -1,203 +0,0 @@
-package tree
-
-import (
- "context"
- "math"
- "strings"
- "sync"
- "time"
-
- "github.com/sdcio/cache/proto/cachepb"
- "github.com/sdcio/data-server/pkg/cache"
-)
-
-type TreeCacheClient interface {
- // RefreshCaches refresh the running and intended Index cache
- RefreshCaches(ctx context.Context) error
-
- // CACHE based Functions
- // ReadIntended retrieves the highes priority value from the intended store
- Read(ctx context.Context, opts *cache.Opts, paths [][]string) []*cache.Update
-
- ReadRunningPath(ctx context.Context, path PathSlice) (*cache.Update, error)
- ReadRunningFull(ctx context.Context) ([]*cache.Update, error)
- GetBranchesHighesPrecedence(ctx context.Context, path []string, filters ...CacheUpdateFilter) int32
- ReadCurrentUpdatesHighestPriorities(ctx context.Context, ccp PathSlices, count uint64) UpdateSlice
- IntendedPathExists(ctx context.Context, path []string) (bool, error)
- ReadUpdatesOwner(ctx context.Context, owner string) UpdateSlice
-}
-
-type TreeCacheClientImpl struct {
- cc cache.Client
- datastore string
-
- timeout time.Duration
-
- intendedStoreIndex map[string]UpdateSlice // contains the keys that the intended store holds in the cache
- intendedStoreIndexMutex sync.RWMutex
- runningStoreIndex map[string]UpdateSlice // contains the keys of the running config
- runningStoreIndexMutex sync.RWMutex
-}
-
-func NewTreeCacheClient(datastore string, cc cache.Client) *TreeCacheClientImpl {
- return &TreeCacheClientImpl{
- cc: cc,
- datastore: datastore,
- timeout: time.Second * 2,
- intendedStoreIndexMutex: sync.RWMutex{},
- runningStoreIndexMutex: sync.RWMutex{},
- }
-}
-
-func (t *TreeCacheClientImpl) IntendedPathExists(ctx context.Context, path []string) (bool, error) {
- t.intendedStoreIndexMutex.RLock()
- if t.intendedStoreIndex == nil {
- t.intendedStoreIndexMutex.RUnlock()
- t.RefreshCaches(ctx)
- t.intendedStoreIndexMutex.RLock()
- }
- defer t.intendedStoreIndexMutex.RUnlock()
- _, exists := t.intendedStoreIndex[strings.Join(path, KeysIndexSep)]
- return exists, nil
-}
-
-func (c *TreeCacheClientImpl) Read(ctx context.Context, opts *cache.Opts, paths [][]string) []*cache.Update {
- if opts == nil {
- opts = &cache.Opts{
- PriorityCount: 1,
- }
- }
-
- return c.cc.Read(ctx, c.datastore, opts, paths, c.timeout)
-}
-
-func (c *TreeCacheClientImpl) RefreshCaches(ctx context.Context) error {
-
- var err error
- c.runningStoreIndexMutex.Lock()
- c.runningStoreIndex, err = c.readStoreKeysMeta(ctx, cachepb.Store_CONFIG)
- c.runningStoreIndexMutex.Unlock()
- if err != nil {
- return err
- }
- c.intendedStoreIndexMutex.Lock()
- c.intendedStoreIndex, err = c.readStoreKeysMeta(ctx, cachepb.Store_INTENDED)
- c.intendedStoreIndexMutex.Unlock()
- if err != nil {
- return err
- }
- return nil
-}
-
-func (c *TreeCacheClientImpl) readStoreKeysMeta(ctx context.Context, store cachepb.Store) (map[string]UpdateSlice, error) {
- entryCh, err := c.cc.GetKeys(ctx, c.datastore, store)
- if err != nil {
- return nil, err
- }
-
- result := map[string]UpdateSlice{}
- for {
- select {
- case <-ctx.Done():
- return nil, ctx.Err()
- case e, ok := <-entryCh:
- if !ok {
- return result, nil
- }
- key := strings.Join(e.GetPath(), KeysIndexSep)
- _, exists := result[key]
- if !exists {
- result[key] = UpdateSlice{}
- }
- result[key] = append(result[key], e)
- }
- }
-}
-
-func (c *TreeCacheClientImpl) GetBranchesHighesPrecedence(ctx context.Context, path []string, filters ...CacheUpdateFilter) int32 {
- result := int32(math.MaxInt32)
- pathKey := strings.Join(path, KeysIndexSep)
- c.intendedStoreIndexMutex.RLock()
- if c.intendedStoreIndex == nil {
- c.intendedStoreIndexMutex.RUnlock()
- c.RefreshCaches(ctx)
- c.intendedStoreIndexMutex.RLock()
- }
- defer c.intendedStoreIndexMutex.RUnlock()
-
- // TODO: Improve this, since it is probably an expensive operation
- for key, entries := range c.intendedStoreIndex {
- if strings.HasPrefix(key, pathKey) {
- if prio := entries.GetLowestPriorityValue(filters); prio < result {
- result = prio
- }
- }
- }
- return result
-}
-
-func (c *TreeCacheClientImpl) ReadCurrentUpdatesHighestPriorities(ctx context.Context, ccp PathSlices, count uint64) UpdateSlice {
- return c.Read(ctx, &cache.Opts{
- Store: cachepb.Store_INTENDED,
- PriorityCount: count,
- }, ccp.ToStringSlice())
-}
-
-func (c *TreeCacheClientImpl) ReadUpdatesOwner(ctx context.Context, owner string) UpdateSlice {
-
- ownerPaths := c.getPathsOfOwner(ctx, owner)
-
- return c.Read(ctx, &cache.Opts{
- Store: cachepb.Store_INTENDED,
- Owner: owner,
- }, ownerPaths.paths.ToStringSlice())
-}
-
-func (c *TreeCacheClientImpl) getPathsOfOwner(ctx context.Context, owner string) *PathSet {
- if c.intendedStoreIndex == nil {
- c.RefreshCaches(ctx)
- }
-
- p := NewPathSet()
- for _, keyMeta := range c.intendedStoreIndex {
- for _, k := range keyMeta {
- if k.Owner() == owner {
- // if the key is not yet listed in the keys slice, add it otherwise skip
- p.AddPath(k.GetPath())
- }
- }
- }
- return p
-}
-
-// ReadRunning reads the value from running if the value does not exist, nil is returned
-func (c *TreeCacheClientImpl) ReadRunningPath(ctx context.Context, path PathSlice) (*cache.Update, error) {
- c.runningStoreIndexMutex.RLock()
- if c.runningStoreIndex == nil {
- c.runningStoreIndexMutex.RUnlock()
- c.RefreshCaches(ctx)
- c.runningStoreIndexMutex.RLock()
- }
- defer c.runningStoreIndexMutex.RUnlock()
- // check if the value exists in running
- _, exists := c.runningStoreIndex[strings.Join(path, KeysIndexSep)]
- if !exists {
- return nil, nil
- }
-
- updates := c.Read(ctx, &cache.Opts{
- Store: cachepb.Store_CONFIG,
- PriorityCount: 1,
- }, [][]string{path})
-
- return updates[0], nil
-}
-
-// ReadRunning reads the value from running if the value does not exist, nil is returned
-func (c *TreeCacheClientImpl) ReadRunningFull(ctx context.Context) ([]*cache.Update, error) {
- updates := c.Read(ctx, &cache.Opts{
- Store: cachepb.Store_CONFIG,
- }, [][]string{{}})
-
- return updates, nil
-}
diff --git a/pkg/tree/tree_context.go b/pkg/tree/tree_context.go
index a33153e7..8dc1d19c 100644
--- a/pkg/tree/tree_context.go
+++ b/pkg/tree/tree_context.go
@@ -8,14 +8,12 @@ import (
type TreeContext struct {
root Entry // the trees root element
- cacheClient TreeCacheClient
schemaClient schemaClient.SchemaClientBound
actualOwner string
}
-func NewTreeContext(cc TreeCacheClient, sc schemaClient.SchemaClientBound, actualOwner string) *TreeContext {
+func NewTreeContext(sc schemaClient.SchemaClientBound, actualOwner string) *TreeContext {
return &TreeContext{
- cacheClient: cc,
schemaClient: sc,
actualOwner: actualOwner,
}
@@ -24,14 +22,10 @@ func NewTreeContext(cc TreeCacheClient, sc schemaClient.SchemaClientBound, actua
// deepCopy root is required to be set manually
func (t *TreeContext) deepCopy() *TreeContext {
return &TreeContext{
- cacheClient: t.cacheClient,
+ schemaClient: t.schemaClient,
}
}
-func (t *TreeContext) GetTreeSchemaCacheClient() TreeCacheClient {
- return t.cacheClient
-}
-
func (t *TreeContext) SetRoot(e Entry) error {
if t.root != nil {
return fmt.Errorf("trying to set treecontexts root, although it is already set")
diff --git a/pkg/tree/tree_persist/tree_persist.pb.go b/pkg/tree/tree_persist/tree_persist.pb.go
new file mode 100644
index 00000000..989aba06
--- /dev/null
+++ b/pkg/tree/tree_persist/tree_persist.pb.go
@@ -0,0 +1,234 @@
+// Copyright 2025 Nokia
+//
+// Licensed 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.
+
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// protoc-gen-go v1.35.1
+// protoc v3.21.12
+// source: tree_persist.proto
+
+package tree_persist
+
+import (
+ protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+ protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+ reflect "reflect"
+ sync "sync"
+)
+
+const (
+ // Verify that this generated code is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+ // Verify that runtime/protoimpl is sufficiently up-to-date.
+ _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Intent struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ IntentName string `protobuf:"bytes,1,opt,name=intent_name,json=intentName,proto3" json:"intent_name,omitempty"`
+ Root *TreeElement `protobuf:"bytes,2,opt,name=root,proto3" json:"root,omitempty"`
+ Priority int32 `protobuf:"varint,3,opt,name=priority,proto3" json:"priority,omitempty"`
+}
+
+func (x *Intent) Reset() {
+ *x = Intent{}
+ mi := &file_tree_persist_proto_msgTypes[0]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *Intent) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Intent) ProtoMessage() {}
+
+func (x *Intent) ProtoReflect() protoreflect.Message {
+ mi := &file_tree_persist_proto_msgTypes[0]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use Intent.ProtoReflect.Descriptor instead.
+func (*Intent) Descriptor() ([]byte, []int) {
+ return file_tree_persist_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Intent) GetIntentName() string {
+ if x != nil {
+ return x.IntentName
+ }
+ return ""
+}
+
+func (x *Intent) GetRoot() *TreeElement {
+ if x != nil {
+ return x.Root
+ }
+ return nil
+}
+
+func (x *Intent) GetPriority() int32 {
+ if x != nil {
+ return x.Priority
+ }
+ return 0
+}
+
+type TreeElement struct {
+ state protoimpl.MessageState
+ sizeCache protoimpl.SizeCache
+ unknownFields protoimpl.UnknownFields
+
+ Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
+ Childs []*TreeElement `protobuf:"bytes,4,rep,name=childs,proto3" json:"childs,omitempty"`
+ LeafVariant []byte `protobuf:"bytes,5,opt,name=leaf_variant,json=leafVariant,proto3" json:"leaf_variant,omitempty"`
+}
+
+func (x *TreeElement) Reset() {
+ *x = TreeElement{}
+ mi := &file_tree_persist_proto_msgTypes[1]
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ ms.StoreMessageInfo(mi)
+}
+
+func (x *TreeElement) String() string {
+ return protoimpl.X.MessageStringOf(x)
+}
+
+func (*TreeElement) ProtoMessage() {}
+
+func (x *TreeElement) ProtoReflect() protoreflect.Message {
+ mi := &file_tree_persist_proto_msgTypes[1]
+ if x != nil {
+ ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+ if ms.LoadMessageInfo() == nil {
+ ms.StoreMessageInfo(mi)
+ }
+ return ms
+ }
+ return mi.MessageOf(x)
+}
+
+// Deprecated: Use TreeElement.ProtoReflect.Descriptor instead.
+func (*TreeElement) Descriptor() ([]byte, []int) {
+ return file_tree_persist_proto_rawDescGZIP(), []int{1}
+}
+
+func (x *TreeElement) GetName() string {
+ if x != nil {
+ return x.Name
+ }
+ return ""
+}
+
+func (x *TreeElement) GetChilds() []*TreeElement {
+ if x != nil {
+ return x.Childs
+ }
+ return nil
+}
+
+func (x *TreeElement) GetLeafVariant() []byte {
+ if x != nil {
+ return x.LeafVariant
+ }
+ return nil
+}
+
+var File_tree_persist_proto protoreflect.FileDescriptor
+
+var file_tree_persist_proto_rawDesc = []byte{
+ 0x0a, 0x12, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x2e, 0x70,
+ 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x12, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x69,
+ 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7a, 0x0a, 0x06, 0x49, 0x6e, 0x74, 0x65,
+ 0x6e, 0x74, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6e, 0x61, 0x6d,
+ 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4e,
+ 0x61, 0x6d, 0x65, 0x12, 0x33, 0x0a, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28,
+ 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x70, 0x65, 0x72, 0x73, 0x69, 0x73, 0x74,
+ 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x65, 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65,
+ 0x6e, 0x74, 0x52, 0x04, 0x72, 0x6f, 0x6f, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x72, 0x69, 0x6f,
+ 0x72, 0x69, 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x70, 0x72, 0x69, 0x6f,
+ 0x72, 0x69, 0x74, 0x79, 0x22, 0x7d, 0x0a, 0x0b, 0x54, 0x72, 0x65, 0x65, 0x45, 0x6c, 0x65, 0x6d,
+ 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
+ 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x68, 0x69, 0x6c, 0x64,
+ 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x70,
+ 0x65, 0x72, 0x73, 0x69, 0x73, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x72, 0x65,
+ 0x65, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x73,
+ 0x12, 0x21, 0x0a, 0x0c, 0x6c, 0x65, 0x61, 0x66, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x6e, 0x74,
+ 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x6c, 0x65, 0x61, 0x66, 0x56, 0x61, 0x72, 0x69,
+ 0x61, 0x6e, 0x74, 0x42, 0x10, 0x5a, 0x0e, 0x2e, 0x3b, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x70, 0x65,
+ 0x72, 0x73, 0x69, 0x73, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+ file_tree_persist_proto_rawDescOnce sync.Once
+ file_tree_persist_proto_rawDescData = file_tree_persist_proto_rawDesc
+)
+
+func file_tree_persist_proto_rawDescGZIP() []byte {
+ file_tree_persist_proto_rawDescOnce.Do(func() {
+ file_tree_persist_proto_rawDescData = protoimpl.X.CompressGZIP(file_tree_persist_proto_rawDescData)
+ })
+ return file_tree_persist_proto_rawDescData
+}
+
+var file_tree_persist_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
+var file_tree_persist_proto_goTypes = []any{
+ (*Intent)(nil), // 0: tree_persist.proto.Intent
+ (*TreeElement)(nil), // 1: tree_persist.proto.TreeElement
+}
+var file_tree_persist_proto_depIdxs = []int32{
+ 1, // 0: tree_persist.proto.Intent.root:type_name -> tree_persist.proto.TreeElement
+ 1, // 1: tree_persist.proto.TreeElement.childs:type_name -> tree_persist.proto.TreeElement
+ 2, // [2:2] is the sub-list for method output_type
+ 2, // [2:2] is the sub-list for method input_type
+ 2, // [2:2] is the sub-list for extension type_name
+ 2, // [2:2] is the sub-list for extension extendee
+ 0, // [0:2] is the sub-list for field type_name
+}
+
+func init() { file_tree_persist_proto_init() }
+func file_tree_persist_proto_init() {
+ if File_tree_persist_proto != nil {
+ return
+ }
+ type x struct{}
+ out := protoimpl.TypeBuilder{
+ File: protoimpl.DescBuilder{
+ GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+ RawDescriptor: file_tree_persist_proto_rawDesc,
+ NumEnums: 0,
+ NumMessages: 2,
+ NumExtensions: 0,
+ NumServices: 0,
+ },
+ GoTypes: file_tree_persist_proto_goTypes,
+ DependencyIndexes: file_tree_persist_proto_depIdxs,
+ MessageInfos: file_tree_persist_proto_msgTypes,
+ }.Build()
+ File_tree_persist_proto = out.File
+ file_tree_persist_proto_rawDesc = nil
+ file_tree_persist_proto_goTypes = nil
+ file_tree_persist_proto_depIdxs = nil
+}
diff --git a/pkg/tree/tree_persist/tree_persist_additions.go b/pkg/tree/tree_persist/tree_persist_additions.go
new file mode 100644
index 00000000..ddb80ee6
--- /dev/null
+++ b/pkg/tree/tree_persist/tree_persist_additions.go
@@ -0,0 +1,36 @@
+package tree_persist
+
+import (
+ "fmt"
+ "strings"
+
+ sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+ "google.golang.org/protobuf/proto"
+)
+
+func (x *Intent) PrettyString(indent string) string {
+ sb := &strings.Builder{}
+ sb.WriteString(fmt.Sprintf("Intent: %s\nPriority: %d\n", x.GetIntentName(), x.GetPriority()))
+ x.GetRoot().prettyString(indent, 0, sb)
+ return sb.String()
+}
+
+func (te *TreeElement) PrettyString(indent string) string {
+ sb := &strings.Builder{}
+ te.prettyString(indent, 0, sb)
+ return sb.String()
+}
+
+func (x *TreeElement) prettyString(indent string, level int, sb *strings.Builder) {
+ prefix := strings.Repeat(indent, level)
+ keylevel := ""
+ sb.WriteString(fmt.Sprintf("%s%s%s\n", prefix, x.GetName(), keylevel))
+ for _, c := range x.GetChilds() {
+ c.prettyString(indent, level+1, sb)
+ }
+ if len(x.LeafVariant) > 0 {
+ tv := &sdcpb.TypedValue{}
+ proto.Unmarshal(x.LeafVariant, tv)
+ sb.WriteString(prefix + indent + tv.String() + "\n")
+ }
+}
diff --git a/pkg/tree/types/cache_update_filter.go b/pkg/tree/types/cache_update_filter.go
new file mode 100644
index 00000000..e7e849a3
--- /dev/null
+++ b/pkg/tree/types/cache_update_filter.go
@@ -0,0 +1,21 @@
+package types
+
+type CacheUpdateFilter func(u *Update) bool
+
+func CacheUpdateFilterExcludeOwner(owner string) func(u *Update) bool {
+ return func(u *Update) bool {
+ return u.Owner() != owner
+ }
+}
+
+// ApplyCacheUpdateFilters takes a bunch of CacheUpdateFilters applies them in an AND fashion
+// and returns the result.
+func ApplyCacheUpdateFilters(u *Update, fs []CacheUpdateFilter) bool {
+ for _, f := range fs {
+ b := f(u)
+ if !b {
+ return false
+ }
+ }
+ return true
+}
diff --git a/pkg/tree/types/delete_entry.go b/pkg/tree/types/delete_entry.go
new file mode 100644
index 00000000..c9804acc
--- /dev/null
+++ b/pkg/tree/types/delete_entry.go
@@ -0,0 +1,40 @@
+package types
+
+import (
+ sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+)
+
+type DeleteEntry interface {
+ SdcpbPath() (*sdcpb.Path, error)
+ Path() PathSlice
+}
+
+// DeleteEntryImpl is a crutch to flag oldbestcases if on a choice, the active case changed
+type DeleteEntryImpl struct {
+ sdcpbPath *sdcpb.Path
+ pathslice PathSlice
+}
+
+func NewDeleteEntryImpl(sdcpbPath *sdcpb.Path, pathslice PathSlice) *DeleteEntryImpl {
+ return &DeleteEntryImpl{
+ sdcpbPath: sdcpbPath,
+ pathslice: pathslice,
+ }
+}
+
+func (d *DeleteEntryImpl) SdcpbPath() (*sdcpb.Path, error) {
+ return d.sdcpbPath, nil
+}
+func (d *DeleteEntryImpl) Path() PathSlice {
+ return d.pathslice
+}
+
+type DeleteEntriesList []DeleteEntry
+
+func (d DeleteEntriesList) PathSlices() PathSlices {
+ result := make(PathSlices, 0, len(d))
+ for _, del := range d {
+ result = append(result, del.Path())
+ }
+ return result
+}
diff --git a/pkg/tree/types/deviation_entry.go b/pkg/tree/types/deviation_entry.go
new file mode 100644
index 00000000..a37248d4
--- /dev/null
+++ b/pkg/tree/types/deviation_entry.go
@@ -0,0 +1,55 @@
+package types
+
+import (
+ sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+)
+
+type DeviationEntry struct {
+ intentName string
+ reason DeviationReason
+ path *sdcpb.Path
+ currentValue *sdcpb.TypedValue
+ expectedValue *sdcpb.TypedValue
+}
+
+func NewDeviationEntry(intentName string, reason DeviationReason, path *sdcpb.Path) *DeviationEntry {
+ return &DeviationEntry{
+ intentName: intentName,
+ reason: reason,
+ path: path,
+ }
+}
+
+func (d *DeviationEntry) IntentName() string {
+ return d.intentName
+}
+func (d *DeviationEntry) Reason() DeviationReason {
+ return d.reason
+}
+func (d *DeviationEntry) Path() *sdcpb.Path {
+ return d.path
+}
+func (d *DeviationEntry) CurrentValue() *sdcpb.TypedValue {
+ return d.currentValue
+}
+func (d *DeviationEntry) ExpectedValue() *sdcpb.TypedValue {
+ return d.expectedValue
+}
+func (d *DeviationEntry) SetCurrentValue(cv *sdcpb.TypedValue) *DeviationEntry {
+ d.currentValue = cv
+ return d
+}
+func (d *DeviationEntry) SetExpectedValue(ev *sdcpb.TypedValue) *DeviationEntry {
+ d.expectedValue = ev
+ return d
+}
+
+type DeviationReason int
+
+const (
+ DeviationReasonUndefined DeviationReason = iota
+ DeviationReasonUnhandled
+ DeviationReasonNotApplied
+ DeviationReasonOverruled
+ DeviationReasonIntentExists
+)
diff --git a/pkg/tree/key_set.go b/pkg/tree/types/path_set.go
similarity index 92%
rename from pkg/tree/key_set.go
rename to pkg/tree/types/path_set.go
index 9e0f1f36..60a5d238 100644
--- a/pkg/tree/key_set.go
+++ b/pkg/tree/types/path_set.go
@@ -1,7 +1,11 @@
-package tree
+package types
import "strings"
+const (
+ KeysIndexSep = "_"
+)
+
type PathSet struct {
index map[string]struct{}
paths PathSlices
diff --git a/pkg/tree/path_slices.go b/pkg/tree/types/path_slices.go
similarity index 78%
rename from pkg/tree/path_slices.go
rename to pkg/tree/types/path_slices.go
index 9bb52f81..47f15463 100644
--- a/pkg/tree/path_slices.go
+++ b/pkg/tree/types/path_slices.go
@@ -1,4 +1,4 @@
-package tree
+package types
import (
"strings"
@@ -11,8 +11,12 @@ func (p PathSlice) String() string {
return strings.Join(p, "/")
}
-func (p PathSlice) ToStringSlice() []string {
- return p
+func (p PathSlice) DeepCopy() PathSlice {
+ result := make(PathSlice, 0, len(p))
+ for _, entry := range p {
+ result = append(result, entry)
+ }
+ return result
}
// PathSlices is the slice collection of multiple PathSlice objects.
diff --git a/pkg/tree/types/update.go b/pkg/tree/types/update.go
new file mode 100644
index 00000000..5b262e44
--- /dev/null
+++ b/pkg/tree/types/update.go
@@ -0,0 +1,121 @@
+package types
+
+import (
+ "context"
+ "fmt"
+ "slices"
+
+ "github.com/sdcio/data-server/pkg/utils"
+ sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+ "google.golang.org/protobuf/proto"
+)
+
+type Update struct {
+ value *sdcpb.TypedValue
+ priority int32
+ intentName string
+ timestamp int64
+ path PathSlice
+}
+
+func NewUpdateFromSdcpbUpdate(u *sdcpb.Update, prio int32, intent string, ts int64) *Update {
+ return NewUpdate(utils.ToStrings(u.GetPath(), false, false), u.GetValue(), prio, intent, ts)
+}
+
+func NewUpdate(path PathSlice, val *sdcpb.TypedValue, prio int32, intent string, ts int64) *Update {
+ return &Update{
+ value: val,
+ priority: prio,
+ intentName: intent,
+ timestamp: ts,
+ path: path,
+ }
+}
+
+func (u *Update) DeepCopy() *Update {
+
+ clonedVal := proto.Clone(u.Value()).(*sdcpb.TypedValue)
+
+ return &Update{
+ value: clonedVal,
+ priority: u.Priority(),
+ intentName: u.intentName,
+ timestamp: u.timestamp,
+ path: u.path.DeepCopy(),
+ }
+}
+
+func (u *Update) Owner() string {
+ return u.intentName
+}
+
+func (u *Update) SetOwner(owner string) {
+ u.intentName = owner
+}
+
+func (u *Update) Priority() int32 {
+ return u.priority
+}
+
+func (u *Update) SetPriority(prio int32) {
+ u.priority = prio
+}
+
+func (u *Update) Timestamp() int64 {
+ return u.timestamp
+}
+
+func (u *Update) Value() *sdcpb.TypedValue {
+ return u.value
+}
+
+func (u *Update) ValueAsBytes() ([]byte, error) {
+ return proto.Marshal(u.value)
+}
+
+func (u *Update) String() string {
+ return fmt.Sprintf("path: %s, owner: %s, priority: %d, value: %s", u.path, u.intentName, u.priority, u.value.String())
+}
+
+// EqualSkipPath checks the equality of two updates.
+// It however skips comparing paths and timestamps.
+// This is a shortcut for performace, for cases in which it is already clear that the path is definately equal.
+func (u *Update) Equal(other *Update) bool {
+ if u.intentName != other.intentName || u.priority != other.priority {
+ return false
+ }
+
+ uVal, _ := u.ValueAsBytes()
+ oVal, _ := other.ValueAsBytes()
+ return slices.Equal(uVal, oVal)
+}
+
+func (u *Update) GetPathSlice() PathSlice {
+ return u.path
+}
+
+// ExpandAndConvertIntent takes a slice of Updates ([]*sdcpb.Update) and converts it into a tree.UpdateSlice, that contains *treetypes.Updates.
+func ExpandAndConvertIntent(ctx context.Context, scb utils.SchemaClientBound, intentName string, priority int32, upds []*sdcpb.Update, ts int64) (UpdateSlice, error) {
+ converter := utils.NewConverter(scb)
+
+ // list of updates to be added to the cache
+ // Expands the value, in case of json to single typed value updates
+ expandedReqUpdates, err := converter.ExpandUpdates(ctx, upds)
+ if err != nil {
+ return nil, err
+ }
+
+ // temp storage for cache.Update of the req. They are to be added later.
+ newCacheUpdates := make(UpdateSlice, 0, len(expandedReqUpdates))
+
+ for _, u := range expandedReqUpdates {
+ pathslice, err := utils.CompletePath(nil, u.GetPath())
+ if err != nil {
+ return nil, err
+ }
+
+ // construct the cache.Update
+ newCacheUpdates = append(newCacheUpdates, NewUpdate(pathslice, u.GetValue(), priority, intentName, ts))
+ }
+ return newCacheUpdates, nil
+}
diff --git a/pkg/tree/types/update_insert_flags.go b/pkg/tree/types/update_insert_flags.go
new file mode 100644
index 00000000..6eef64a9
--- /dev/null
+++ b/pkg/tree/types/update_insert_flags.go
@@ -0,0 +1,62 @@
+package types
+
+type LeafEntry interface {
+ MarkDelete(onlyIntended bool)
+ MarkNew()
+}
+
+type UpdateInsertFlags struct {
+ new bool
+ delete bool
+ onlyIntended bool
+}
+
+// NewUpdateInsertFlags returns a new *UpdateInsertFlags instance
+// with all values set to false, so not new, and not marked for deletion
+func NewUpdateInsertFlags() *UpdateInsertFlags {
+ return &UpdateInsertFlags{}
+}
+
+func (f *UpdateInsertFlags) SetDeleteFlag() *UpdateInsertFlags {
+ f.delete = true
+ f.new = false
+ return f
+}
+
+func (f *UpdateInsertFlags) SetDeleteOnlyUpdatedFlag() *UpdateInsertFlags {
+ f.delete = true
+ f.onlyIntended = true
+ f.new = false
+ return f
+}
+
+func (f *UpdateInsertFlags) SetNewFlag() *UpdateInsertFlags {
+ f.new = true
+ f.delete = false
+ f.onlyIntended = false
+ return f
+}
+
+func (f *UpdateInsertFlags) GetDeleteFlag() bool {
+ return f.delete
+}
+
+func (f *UpdateInsertFlags) GetDeleteOnlyIntendedFlag() bool {
+ return f.onlyIntended
+}
+
+func (f *UpdateInsertFlags) GetNewFlag() bool {
+ return f.new
+}
+
+func (f *UpdateInsertFlags) Apply(le LeafEntry) *UpdateInsertFlags {
+ if f.delete {
+ le.MarkDelete(f.onlyIntended)
+ return f
+ }
+ if f.new {
+ le.MarkNew()
+ return f
+ }
+ return f
+}
diff --git a/pkg/tree/update_slice.go b/pkg/tree/types/update_slice.go
similarity index 64%
rename from pkg/tree/update_slice.go
rename to pkg/tree/types/update_slice.go
index b24c8664..f42695b9 100644
--- a/pkg/tree/update_slice.go
+++ b/pkg/tree/types/update_slice.go
@@ -1,13 +1,28 @@
-package tree
+package types
import (
"math"
-
- "github.com/sdcio/data-server/pkg/cache"
)
// UpdateSlice A slice of *cache.Update, that defines additional helper functions.
-type UpdateSlice []*cache.Update
+type UpdateSlice []*Update
+
+func (u UpdateSlice) CopyWithNewOwnerAndPrio(owner string, prio int32) UpdateSlice {
+ result := u.DeepCopy()
+ for _, x := range result {
+ x.SetPriority(prio)
+ x.SetOwner(owner)
+ }
+ return result
+}
+
+func (u UpdateSlice) DeepCopy() UpdateSlice {
+ result := make(UpdateSlice, 0, len(u))
+ for _, x := range u {
+ result = append(result, x.DeepCopy())
+ }
+ return result
+}
// GetFirstPriorityValue returns the priority of the first element or math.MaxInt32 if len() is zero
func (u UpdateSlice) GetFirstPriorityValue() int32 {
@@ -32,12 +47,12 @@ func (u UpdateSlice) ToPathSet() *PathSet {
pathKeySet := NewPathSet()
for _, upd := range u {
- pathKeySet.AddPath(upd.GetPath())
+ pathKeySet.AddPath(upd.GetPathSlice())
}
return pathKeySet
}
-func Map[T any](u UpdateSlice, f func(*cache.Update) T) []T {
+func Map[T any](u UpdateSlice, f func(*Update) T) []T {
vsm := make([]T, len(u))
for i, v := range u {
vsm[i] = f(v)
diff --git a/pkg/types/validation_result.go b/pkg/tree/types/validation_result.go
similarity index 100%
rename from pkg/types/validation_result.go
rename to pkg/tree/types/validation_result.go
diff --git a/pkg/tree/validation_entry_leafref.go b/pkg/tree/validation_entry_leafref.go
index 3d4aac53..3bf6829b 100644
--- a/pkg/tree/validation_entry_leafref.go
+++ b/pkg/tree/validation_entry_leafref.go
@@ -5,60 +5,34 @@ import (
"fmt"
"strings"
- "github.com/sdcio/data-server/pkg/types"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
)
-// NavigateLeafRef
-func (s *sharedEntryAttributes) NavigateLeafRef(ctx context.Context) ([]Entry, error) {
-
- var lref string
- switch {
- case s.GetSchema().GetField().GetType().GetLeafref() != "":
- lref = s.schema.GetField().GetType().GetLeafref()
- case s.GetSchema().GetLeaflist().GetType().GetLeafref() != "":
- lref = s.GetSchema().GetLeaflist().GetType().GetLeafref()
- default:
- return nil, fmt.Errorf("error not a leafref %s", s.Path().String())
- }
-
- lv := s.leafVariants.GetHighestPrecedence(false, true)
+func (s *sharedEntryAttributes) BreadthSearch(ctx context.Context, path string) ([]Entry, error) {
+ var err error
+ var resultEntries []Entry
+ var processEntries []Entry
- lref, err := utils.StripPathElemPrefix(lref)
+ lref, err := utils.StripPathElemPrefix(path)
if err != nil {
- return nil, fmt.Errorf("failed stripping namespaces from leafref %s LeafVariant %v: %w", s.Path(), lv, err)
+ return nil, fmt.Errorf("failed stripping namespaces from leafref %s: %w", s.Path(), err)
}
- lrefSdcpbPath, err := utils.ParsePath(lref)
+ sdcpbPath, err := utils.ParsePath(lref)
if err != nil {
- return nil, fmt.Errorf("failed parsing leafref path %s LeafVariant %v: %w", s.Path(), lv, err)
+ return nil, fmt.Errorf("failed parsing leafref path %s: %w", s.Path(), err)
}
+ lrefPath := newLrefPath(sdcpbPath)
+
// if the lrefs first character is "/" then it is a root based path
isRootBasedPath := false
if string(lref[0]) == "/" {
isRootBasedPath = true
}
- tv, err := lv.Update.Value()
- if err != nil {
- return nil, fmt.Errorf("failed reading value from %s LeafVariant %v: %w", s.Path(), lv, err)
- }
- var values []*sdcpb.TypedValue
-
- switch ttv := tv.Value.(type) {
- case *sdcpb.TypedValue_LeaflistVal:
- values = append(values, ttv.LeaflistVal.GetElement()...)
- default:
- values = append(values, tv)
- }
-
- var resultEntries []Entry
-
- lrefPath := newLrefPath(lrefSdcpbPath)
-
- var processEntries []Entry
if isRootBasedPath {
processEntries = []Entry{s.GetRoot()}
} else {
@@ -96,7 +70,7 @@ func (s *sharedEntryAttributes) NavigateLeafRef(ctx context.Context) ([]Entry, e
// we need to do the forwarding for all the already lookedup paths
for _, entry := range processEntries {
- entry, err = entry.Navigate(ctx, []string{elem.Name}, false)
+ entry, err = entry.Navigate(ctx, []string{elem.Name}, false, false)
if err != nil {
return nil, err
}
@@ -129,19 +103,50 @@ func (s *sharedEntryAttributes) NavigateLeafRef(ctx context.Context) ([]Entry, e
processEntries = resultEntries
count++
}
+ return resultEntries, nil
+}
+
+// NavigateLeafRef
+func (s *sharedEntryAttributes) NavigateLeafRef(ctx context.Context) ([]Entry, error) {
+
+ var lref string
+ switch {
+ case s.GetSchema().GetField().GetType().GetLeafref() != "":
+ lref = s.schema.GetField().GetType().GetLeafref()
+ case s.GetSchema().GetLeaflist().GetType().GetLeafref() != "":
+ lref = s.GetSchema().GetLeaflist().GetType().GetLeafref()
+ default:
+ return nil, fmt.Errorf("error not a leafref %s", s.Path().String())
+ }
+
+ lv := s.leafVariants.GetHighestPrecedence(false, true)
+
+ tv := lv.Value()
+ var values []*sdcpb.TypedValue
+
+ switch ttv := tv.Value.(type) {
+ case *sdcpb.TypedValue_LeaflistVal:
+ values = append(values, ttv.LeaflistVal.GetElement()...)
+ default:
+ values = append(values, tv)
+ }
+
+ var resultEntries []Entry
+
+ foundEntries, err := s.BreadthSearch(ctx, lref)
+ if err != nil {
+ return nil, err
+ }
resultEntries = []Entry{}
- for _, e := range processEntries {
+ for _, e := range foundEntries {
r, err := e.getHighestPrecedenceLeafValue(ctx)
if err != nil {
return nil, err
}
- val, err := r.Update.Value()
- if err != nil {
- return nil, err
- }
+ val := r.Value()
for _, value := range values {
if utils.EqualTypedValues(val, value) {
resultEntries = append(resultEntries, e)
@@ -179,11 +184,8 @@ func (s *sharedEntryAttributes) resolve_leafref_key_path(ctx context.Context, ke
return err
}
- lvs := keyValue.GetHighestPrecedence(LeafVariantSlice{}, false)
- tv, err := lvs[0].Value()
- if err != nil {
- return err
- }
+ lvs := keyValue.GetHighestPrecedence(LeafVariantSlice{}, false, false)
+ tv := lvs[0].Value()
keys[k].value = tv.GetStringVal()
keys[k].doNotResolve = true
}
@@ -231,11 +233,7 @@ func generateOptionalWarning(ctx context.Context, s Entry, lref string, resultCh
resultChan <- types.NewValidationResultEntry(lrefval.Owner(), err, types.ValidationResultEntryTypeError)
return
}
- tvVal, err := lrefval.Update.Value()
- if err != nil {
- resultChan <- types.NewValidationResultEntry(lrefval.Owner(), err, types.ValidationResultEntryTypeError)
- return
- }
+ tvVal := lrefval.Value()
resultChan <- types.NewValidationResultEntry(lrefval.Owner(), fmt.Errorf("leafref %s value %s unable to resolve non-mandatory reference %s", s.Path().String(), utils.TypedValueToString(tvVal), lref), types.ValidationResultEntryTypeWarning)
}
diff --git a/pkg/tree/validation_entry_must.go b/pkg/tree/validation_entry_must.go
index ec914a2f..826d7fa5 100644
--- a/pkg/tree/validation_entry_must.go
+++ b/pkg/tree/validation_entry_must.go
@@ -5,7 +5,7 @@ import (
"fmt"
"strings"
- "github.com/sdcio/data-server/pkg/types"
+ "github.com/sdcio/data-server/pkg/tree/types"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"github.com/sdcio/yang-parser/xpath"
"github.com/sdcio/yang-parser/xpath/grammars/expr"
@@ -66,7 +66,6 @@ func (s *sharedEntryAttributes) validateMustStatements(ctx context.Context, resu
owner = s.leafVariants.GetHighestPrecedence(false, true).Owner()
}
resultChan <- types.NewValidationResultEntry(owner, err, types.ValidationResultEntryTypeError)
- return
}
}
}
diff --git a/pkg/tree/validation_range_test.go b/pkg/tree/validation_range_test.go
index a5136ed9..debe24f8 100644
--- a/pkg/tree/validation_range_test.go
+++ b/pkg/tree/validation_range_test.go
@@ -8,6 +8,7 @@ import (
"github.com/openconfig/ygot/ygot"
json_importer "github.com/sdcio/data-server/pkg/tree/importer/json"
+ "github.com/sdcio/data-server/pkg/tree/types"
"github.com/sdcio/data-server/pkg/utils/testhelper"
sdcio_schema "github.com/sdcio/data-server/tests/sdcioygot"
"go.uber.org/mock/gomock"
@@ -23,7 +24,7 @@ func TestValidate_Range_SDC_Schema(t *testing.T) {
t.Error(err)
}
- tc := NewTreeContext(nil, scb, "owner1")
+ tc := NewTreeContext(scb, "owner1")
root, err := NewTreeRoot(ctx, tc)
@@ -63,12 +64,15 @@ func TestValidate_Range_SDC_Schema(t *testing.T) {
jimporter := json_importer.NewJsonTreeImporter(jsonConfig)
- err = root.ImportConfig(ctx, jimporter, "owner1", 5)
+ err = root.ImportConfig(ctx, types.PathSlice{}, jimporter, "owner1", 5, types.NewUpdateInsertFlags())
if err != nil {
t.Error(err)
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
validationResult := root.Validate(ctx, validationConfig)
@@ -147,7 +151,7 @@ func TestValidate_RangesSigned(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// the tree context
- tc := NewTreeContext(nil, scb, "owner1")
+ tc := NewTreeContext(scb, "owner1")
// the tree root
root, err := NewTreeRoot(ctx, tc)
@@ -172,12 +176,15 @@ func TestValidate_RangesSigned(t *testing.T) {
jimporter := json_importer.NewJsonTreeImporter(jsonConfig)
// import via importer
- err = root.ImportConfig(ctx, jimporter, "owner1", 5)
+ err = root.ImportConfig(ctx, types.PathSlice{}, jimporter, "owner1", 5, types.NewUpdateInsertFlags())
if err != nil {
t.Error(err)
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
validationResult := root.Validate(ctx, validationConfig)
@@ -277,7 +284,7 @@ func TestValidate_RangesUnSigned(t *testing.T) {
t.Run(tt.name, func(t *testing.T) {
// the tree context
- tc := NewTreeContext(nil, scb, "owner1")
+ tc := NewTreeContext(scb, "owner1")
// the tree root
root, err := NewTreeRoot(ctx, tc)
@@ -302,12 +309,15 @@ func TestValidate_RangesUnSigned(t *testing.T) {
jimporter := json_importer.NewJsonTreeImporter(jsonConfig)
// import via importer
- err = root.ImportConfig(ctx, jimporter, "owner1", 5)
+ err = root.ImportConfig(ctx, types.PathSlice{}, jimporter, "owner1", 5, types.NewUpdateInsertFlags())
if err != nil {
t.Error(err)
}
- root.FinishInsertionPhase(ctx)
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
// run validation
validationResults := root.Validate(ctx, validationConfig)
diff --git a/pkg/tree/xml.go b/pkg/tree/xml.go
index 72a9bf51..ce94b519 100644
--- a/pkg/tree/xml.go
+++ b/pkg/tree/xml.go
@@ -213,17 +213,13 @@ func (s *sharedEntryAttributes) toXmlInternal(parent *etree.Element, onlyNewOrUp
if le == nil {
return false, nil
}
- v, err := le.Update.Value()
- if err != nil {
- return false, err
- }
ns := ""
// process the namespace attribute
if s.parent == nil || (honorNamespace && !namespaceIsEqual(s, s.parent)) {
ns = utils.GetNamespaceFromGetSchema(s.GetSchema())
}
// convert value to XML and add to parent
- utils.TypedValueToXML(parent, v, s.PathName(), ns, onlyNewOrUpdated, operationWithNamespace, useOperationRemove)
+ utils.TypedValueToXML(parent, le.Value(), s.PathName(), ns, onlyNewOrUpdated, operationWithNamespace, useOperationRemove)
return true, nil
}
return false, fmt.Errorf("unable to convert to xml (%s)", s.Path())
diff --git a/pkg/tree/xml_test.go b/pkg/tree/xml_test.go
index e60c1f8e..79a3383d 100644
--- a/pkg/tree/xml_test.go
+++ b/pkg/tree/xml_test.go
@@ -7,8 +7,6 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/openconfig/ygot/ygot"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
- "github.com/sdcio/data-server/pkg/cache"
"github.com/sdcio/data-server/pkg/utils"
"github.com/sdcio/data-server/pkg/utils/testhelper"
sdcio_schema "github.com/sdcio/data-server/tests/sdcioygot"
@@ -82,7 +80,7 @@ func TestToXMLTable(t *testing.T) {
{
name: "XML NewOrUpdated - some elements deleted, some updated",
onlyNewOrUpdated: true,
- skip: true,
+ skip: false,
existingConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
c := config1()
return expandUpdateFromConfig(ctx, c, converter)
@@ -119,7 +117,7 @@ func TestToXMLTable(t *testing.T) {
`,
},
{
- name: "XML - delete ethernet-1/1, honor namespace, operatin With namespace, remove",
+ name: "XML - delete ethernet-1_1, honor namespace, operatin With namespace, remove",
onlyNewOrUpdated: true,
existingConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
c := config1()
@@ -167,7 +165,7 @@ func TestToXMLTable(t *testing.T) {
},
},
{
- name: "XML - delete certain ethernet-1/1 attributes update another",
+ name: "XML - delete certain ethernet-1_1 attributes update another",
onlyNewOrUpdated: true,
existingConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
c := config1()
@@ -199,7 +197,7 @@ func TestToXMLTable(t *testing.T) {
},
},
{
- name: "XML - delete ethernet-1/1 add ethernet-1/2",
+ name: "XML - delete ethernet-1_1 add ethernet-1_2",
onlyNewOrUpdated: true,
existingConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
c := config1()
@@ -209,10 +207,8 @@ func TestToXMLTable(t *testing.T) {
c := config1()
return expandUpdateFromConfig(ctx, c, converter)
},
- skip: true,
- expected: `
-
-
+ skip: false,
+ expected: `
ethernet-1/1
@@ -369,6 +365,36 @@ func TestToXMLTable(t *testing.T) {
return upds, nil
},
},
+ {
+ name: "XML - replace choice",
+ onlyNewOrUpdated: true,
+ existingConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
+ c := config1()
+ return expandUpdateFromConfig(ctx, c, converter)
+ },
+ runningConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
+ c := config1()
+ return expandUpdateFromConfig(ctx, c, converter)
+ },
+ expected: `
+
+
+ true
+
+
+`,
+ honorNamespace: true,
+ operationWithNamespace: true,
+ useOperationRemove: true,
+ newConfig: func(ctx context.Context, converter *utils.Converter) ([]*sdcpb.Update, error) {
+ c := config1()
+ c.Choices.Case1 = nil
+ c.Choices.Case2 = &sdcio_schema.SdcioModel_Choices_Case2{
+ Log: ygot.Bool(true),
+ }
+ return expandUpdateFromConfig(ctx, c, converter)
+ },
+ },
}
for _, tt := range tests {
@@ -388,15 +414,35 @@ func TestToXMLTable(t *testing.T) {
}
owner := "owner1"
- // mock cache client
- ccMock := mockcacheclient.NewMockClient(mockCtrl)
- testhelper.ConfigureCacheClientMock(t, ccMock, []*cache.Update{}, []*cache.Update{}, []*cache.Update{}, [][]string{})
+ // var runningCacheUpds []*types.Update
+ // if tt.runningConfig != nil {
+ // runningSdcpbUpds, err := tt.runningConfig(context.Background(), utils.NewConverter(scb))
+ // if err != nil {
+ // t.Error(err)
+ // }
+ // runningCacheUpds, err = utils.SdcpbUpdatesToCacheUpdates(runningSdcpbUpds, RunningIntentName, RunningValuesPrio)
+ // if err != nil {
+ // t.Error(err)
+ // }
+ // }
+
+ // var intendedCacheUpds []*types.Update
+ // if tt.existingConfig != nil {
+ // intendedSdcpbUpds, err := tt.existingConfig(context.Background(), utils.NewConverter(scb))
+ // if err != nil {
+ // t.Error(err)
+ // }
+ // intendedCacheUpds, err = utils.SdcpbUpdatesToCacheUpdates(intendedSdcpbUpds, owner, 5)
+ // if err != nil {
+ // t.Error(err)
+ // }
+ // }
ctx := context.Background()
converter := utils.NewConverter(scb)
- tc := NewTreeContext(NewTreeCacheClient("dev1", ccMock), scb, owner)
+ tc := NewTreeContext(scb, owner)
root, err := NewTreeRoot(ctx, tc)
if err != nil {
t.Fatal(err)
@@ -411,9 +457,11 @@ func TestToXMLTable(t *testing.T) {
t.Fatal(err)
}
}
+ fmt.Println("AFTER EXISTING:")
+ fmt.Println(root.String())
if tt.newConfig != nil {
- root.markOwnerDelete(owner, false)
+ root.MarkOwnerDelete(owner, false)
newUpds, err := tt.newConfig(ctx, converter)
if err != nil {
@@ -424,6 +472,8 @@ func TestToXMLTable(t *testing.T) {
t.Fatal(err)
}
}
+ fmt.Println("AFTER NEW:")
+ fmt.Println(root.String())
if tt.runningConfig != nil {
runningUpds, err := tt.runningConfig(ctx, converter)
if err != nil {
@@ -434,11 +484,16 @@ func TestToXMLTable(t *testing.T) {
t.Fatal(err)
}
}
- root.FinishInsertionPhase(ctx)
+ fmt.Println("AFTER RUNNING:")
t.Log(root.String())
fmt.Println(root.String())
+ err = root.FinishInsertionPhase(ctx)
+ if err != nil {
+ t.Error(err)
+ }
+
xmlDoc, err := root.ToXML(tt.onlyNewOrUpdated, tt.honorNamespace, tt.operationWithNamespace, tt.useOperationRemove)
if err != nil {
t.Fatal(err)
diff --git a/pkg/tree/yang-parser-adapter.go b/pkg/tree/yang-parser-adapter.go
index e7a6aa9c..2d7dc11c 100644
--- a/pkg/tree/yang-parser-adapter.go
+++ b/pkg/tree/yang-parser-adapter.go
@@ -48,20 +48,50 @@ func (y *yangParserEntryAdapter) valueToDatum(tv *sdcpb.TypedValue) xpath.Datum
}
func (y *yangParserEntryAdapter) GetValue() (xpath.Datum, error) {
- if y.e.GetSchema() == nil || y.e.GetSchema().GetContainer() != nil {
+ if y.e.GetSchema() == nil {
return xpath.NewBoolDatum(true), nil
}
+ // if y.e is a container
+ if cs := y.e.GetSchema().GetContainer(); cs != nil {
+ // its a container
+ if len(cs.Keys) == 0 {
+ // regular container
+ return xpath.NewBoolDatum(true), nil
+ }
+ // list
+ childs, err := y.e.GetListChilds()
+ if err != nil {
+ return nil, err
+ }
+ datums := make([]xutils.XpathNode, 0, len(childs))
+ for x := 0; x < len(childs); x++ {
+ // this is a dirty fix, that will enable count() to evaluate the right value
+ datums = append(datums, nil)
+ }
+ return xpath.NewNodesetDatum(datums), nil
+ }
+
+ // if y.e is anything else then a container
lv, _ := y.e.getHighestPrecedenceLeafValue(y.ctx)
if lv == nil {
return xpath.NewNodesetDatum([]xutils.XpathNode{}), nil
}
- tv, err := lv.Update.Value()
+ return y.valueToDatum(lv.Value()), nil
+}
+
+func (y *yangParserEntryAdapter) BreadthSearch(ctx context.Context, path string) ([]xpath.Entry, error) {
+ entries, err := y.e.BreadthSearch(ctx, path)
if err != nil {
return nil, err
}
- return y.valueToDatum(tv), nil
+ result := make([]xpath.Entry, 0, len(entries))
+ for _, x := range entries {
+ result = append(result, newYangParserEntryAdapter(ctx, x))
+ }
+
+ return result, nil
}
func (y *yangParserEntryAdapter) FollowLeafRef() (xpath.Entry, error) {
@@ -95,22 +125,10 @@ func (y *yangParserEntryAdapter) Navigate(p []string) (xpath.Entry, error) {
rootPath = true
}
- lookedUpEntry := y.e
- for idx, pelem := range p {
- // if we move up, on a .. we should just go up, staying in the branch that represents the instance
- // if there is another .. then we need to forward to the element with the schema and just then forward
- // to the parent. Thereby skipping the key levels that sit inbetween
- if pelem == ".." && lookedUpEntry.GetSchema().GetSchema() == nil {
- lookedUpEntry, _ = lookedUpEntry.GetFirstAncestorWithSchema()
- }
-
- // rootPath && idx == 0 => means only allow true on first index, for sure false on all other
- lookedUpEntry, err = lookedUpEntry.Navigate(y.ctx, []string{pelem}, rootPath && idx == 0)
- if err != nil {
- return newYangParserValueEntry(xpath.NewNodesetDatum([]xutils.XpathNode{}), err), nil
- }
+ lookedUpEntry, err := y.e.Navigate(y.ctx, p, rootPath, true)
+ if err != nil {
+ return newYangParserValueEntry(xpath.NewNodesetDatum([]xutils.XpathNode{}), err), nil
}
-
return newYangParserEntryAdapter(y.ctx, lookedUpEntry), nil
}
@@ -145,3 +163,7 @@ func (y *yangParserValueEntry) GetValue() (xpath.Datum, error) {
func (y *yangParserValueEntry) GetPath() []string {
return nil
}
+
+func (y *yangParserValueEntry) BreadthSearch(ctx context.Context, path string) ([]xpath.Entry, error) {
+ return nil, nil
+}
diff --git a/pkg/utils/converter.go b/pkg/utils/converter.go
index 72b288cf..27e21c8b 100644
--- a/pkg/utils/converter.go
+++ b/pkg/utils/converter.go
@@ -34,10 +34,10 @@ func NewConverter(scb SchemaClientBound) *Converter {
}
}
-func (c *Converter) ExpandUpdates(ctx context.Context, updates []*sdcpb.Update, includeKeysAsLeaf bool) ([]*sdcpb.Update, error) {
+func (c *Converter) ExpandUpdates(ctx context.Context, updates []*sdcpb.Update) ([]*sdcpb.Update, error) {
outUpdates := make([]*sdcpb.Update, 0, len(updates))
for _, upd := range updates {
- expUpds, err := c.ExpandUpdate(ctx, upd, includeKeysAsLeaf)
+ expUpds, err := c.ExpandUpdate(ctx, upd)
if err != nil {
return nil, err
}
@@ -47,16 +47,8 @@ func (c *Converter) ExpandUpdates(ctx context.Context, updates []*sdcpb.Update,
}
// expandUpdate Expands the value, in case of json to single typed value updates
-func (c *Converter) ExpandUpdate(ctx context.Context, upd *sdcpb.Update, includeKeysAsLeaf bool) ([]*sdcpb.Update, error) {
+func (c *Converter) ExpandUpdate(ctx context.Context, upd *sdcpb.Update) ([]*sdcpb.Update, error) {
upds := make([]*sdcpb.Update, 0)
- if includeKeysAsLeaf {
- // expand update path if it contains keys
- intUpd, err := c.ExpandUpdateKeysAsLeaf(ctx, upd)
- if err != nil {
- return nil, err
- }
- upds = append(upds, intUpd...)
- }
rsp, err := c.schemaClientBound.GetSchemaSdcpbPath(ctx, upd.GetPath())
if err != nil {
return nil, err
@@ -64,8 +56,20 @@ func (c *Converter) ExpandUpdate(ctx context.Context, upd *sdcpb.Update, include
switch rsp := rsp.GetSchema().Schema.(type) {
case *sdcpb.SchemaElem_Container:
- log.Debugf("expanding update %v on container %q", upd, rsp.Container.Name)
- var v interface{}
+ // if it is not a presence container and the value is nil,
+ // return without doing anything
+ if !rsp.Container.GetIsPresence() && upd.Value == nil {
+ return nil, nil
+ }
+
+ // if it is a presence container and no value is set, set upd value to EmptyVal
+ if rsp.Container.GetIsPresence() && upd.Value == nil {
+ upd.Value = &sdcpb.TypedValue{
+ Value: &sdcpb.TypedValue_EmptyVal{},
+ }
+ }
+
+ var v any
var err error
var jsonDecoder *json.Decoder
switch upd.GetValue().Value.(type) {
@@ -83,13 +87,14 @@ func (c *Converter) ExpandUpdate(ctx context.Context, upd *sdcpb.Update, include
if err != nil {
return nil, err
}
- log.Debugf("update has jsonVal: %T, %v\n", v, v)
- rs, err := c.ExpandContainerValue(ctx, upd.GetPath(), v, rsp, includeKeysAsLeaf)
+ // log.Debugf("update has jsonVal: %T, %v\n", v, v)
+ rs, err := c.ExpandContainerValue(ctx, upd.GetPath(), v, rsp)
if err != nil {
return nil, err
}
upds := append(upds, rs...)
return upds, nil
+
case *sdcpb.SchemaElem_Field:
var v interface{}
var err error
@@ -114,11 +119,16 @@ func (c *Converter) ExpandUpdate(ctx context.Context, upd *sdcpb.Update, include
}
}
- // TODO: Check if value is json and convert to String ?
+ if rsp.Field.GetType().Type == "identityref" {
+ upd.Value, err = Convert(upd.GetValue().GetStringVal(), rsp.Field.GetType())
+ if err != nil {
+ return nil, err
+ }
+ }
+
upds = append(upds, upd)
return upds, nil
case *sdcpb.SchemaElem_Leaflist:
- // TODO: Check if value is json and convert to String ?
upds = append(upds, upd)
return upds, nil
}
@@ -127,6 +137,8 @@ func (c *Converter) ExpandUpdate(ctx context.Context, upd *sdcpb.Update, include
func (c *Converter) ExpandUpdateKeysAsLeaf(ctx context.Context, upd *sdcpb.Update) ([]*sdcpb.Update, error) {
upds := make([]*sdcpb.Update, 0)
+ var err error
+ var schemaRsp *sdcpb.GetSchemaResponse
// expand update path if it contains keys
for i, pe := range upd.GetPath().GetElem() {
if len(pe.GetKey()) == 0 {
@@ -149,22 +161,25 @@ func (c *Converter) ExpandUpdateKeysAsLeaf(ctx context.Context, upd *sdcpb.Updat
}
intUpd.Path.Elem = append(intUpd.Path.Elem, &sdcpb.PathElem{Name: k})
- schemaRsp, err := c.schemaClientBound.GetSchemaSdcpbPath(ctx, intUpd.Path)
+ schemaRsp, err = c.schemaClientBound.GetSchemaSdcpbPath(ctx, intUpd.Path)
if err != nil {
return nil, err
}
+
intUpd.Value, err = TypedValueToYANGType(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_StringVal{StringVal: v}}, schemaRsp.GetSchema())
if err != nil {
return nil, err
}
+
upds = append(upds, intUpd)
}
}
+
return upds, nil
}
-func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv any, cs *sdcpb.SchemaElem_Container, includeKeysAsLeaf bool) ([]*sdcpb.Update, error) {
- log.Debugf("expanding jsonVal %T | %v | %v", jv, jv, p)
+func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv any, cs *sdcpb.SchemaElem_Container) ([]*sdcpb.Update, error) {
+ // log.Debugf("expanding jsonVal %T | %v | %v", jv, jv, p)
switch jv := jv.(type) {
case string:
v := strings.Trim(jv, "\"")
@@ -184,8 +199,8 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
if numElems := len(p.GetElem()); numElems > 0 {
keysInPath = p.GetElem()[numElems-1].GetKey()
}
- // make sure all keys exist either in the JSON value or
- // in the path but NOT in both and build keySet
+ // // make sure all keys exist either in the JSON value or
+ // // in the path but NOT in both and build keySet
keySet := map[string]string{}
for _, k := range cs.Container.GetKeys() {
if v, ok := jv[k.Name]; ok {
@@ -203,8 +218,8 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
}
// handling keys in last element of the path or in the json value
for _, k := range cs.Container.GetKeys() {
- if v, ok := jv[k.Name]; ok {
- log.Debugf("handling key %s", k.Name)
+ if _, ok := jv[k.Name]; ok {
+ // log.Debugf("handling key %s", k.Name)
if _, ok := keysInPath[k.Name]; ok {
return nil, fmt.Errorf("key %q is present in both the path and JSON value", k.Name)
}
@@ -212,23 +227,6 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
p.GetElem()[len(p.GetElem())-1].Key = make(map[string]string)
}
p.GetElem()[len(p.GetElem())-1].Key = keySet
- if includeKeysAsLeaf {
- np := proto.Clone(p).(*sdcpb.Path)
- np.Elem = append(np.Elem, &sdcpb.PathElem{Name: k.Name})
- schemaRsp, err := c.schemaClientBound.GetSchemaSdcpbPath(ctx, np)
- if err != nil {
- return nil, err
- }
- updVal, err := TypedValueToYANGType(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_StringVal{StringVal: fmt.Sprintf("%v", v)}}, schemaRsp.GetSchema())
- if err != nil {
- return nil, err
- }
- upd := &sdcpb.Update{
- Path: np,
- Value: updVal,
- }
- upds = append(upds, upd)
- }
continue
}
// if key is not in the value it must be set in the path
@@ -237,7 +235,8 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
}
}
for k, v := range jv {
- if isKey(k, cs) {
+ // TODO remove the statement_annotate again ...
+ if k == "_annotate" {
continue
}
item, ok := getItem(ctx, k, cs, c.schemaClientBound)
@@ -246,7 +245,7 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
}
switch item := item.(type) {
case *sdcpb.LeafSchema: // field
- log.Debugf("handling field %s", item.Name)
+ // log.Debugf("handling field %s", item.Name)
np := proto.Clone(p).(*sdcpb.Path)
np.Elem = append(np.Elem, &sdcpb.PathElem{Name: item.Name})
upd := &sdcpb.Update{Path: np}
@@ -310,7 +309,7 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
upds = append(upds, upd)
case string: // child container
- log.Debugf("handling child container %s", item)
+ // log.Debugf("handling child container %s", item)
np := proto.Clone(p).(*sdcpb.Path)
np.Elem = append(np.Elem, &sdcpb.PathElem{Name: item})
rsp, err := c.schemaClientBound.GetSchemaSdcpbPath(ctx, np)
@@ -331,7 +330,7 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
},
}}
} else {
- rs, err = c.ExpandContainerValue(ctx, np, v, rsp, includeKeysAsLeaf)
+ rs, err = c.ExpandContainerValue(ctx, np, v, rsp)
if err != nil {
return nil, err
}
@@ -351,7 +350,7 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
upds := make([]*sdcpb.Update, 0)
for _, v := range jv {
np := proto.Clone(p).(*sdcpb.Path)
- r, err := c.ExpandContainerValue(ctx, np, v, cs, includeKeysAsLeaf)
+ r, err := c.ExpandContainerValue(ctx, np, v, cs)
if err != nil {
return nil, err
}
@@ -364,15 +363,6 @@ func (c *Converter) ExpandContainerValue(ctx context.Context, p *sdcpb.Path, jv
}
}
-func isKey(s string, cs *sdcpb.SchemaElem_Container) bool {
- for _, k := range cs.Container.GetKeys() {
- if k.Name == s {
- return true
- }
- }
- return false
-}
-
func TypedValueToYANGType(tv *sdcpb.TypedValue, schemaObject *sdcpb.SchemaElem) (*sdcpb.TypedValue, error) {
switch tv.Value.(type) {
case *sdcpb.TypedValue_AsciiVal:
@@ -530,6 +520,22 @@ func getItem(ctx context.Context, s string, cs *sdcpb.SchemaElem_Container, scb
if ok {
return c, true
}
+ k, ok := getKey(s, cs)
+ if ok {
+ return k, true
+ }
+ return nil, false
+}
+
+func getKey(s string, cs *sdcpb.SchemaElem_Container) (*sdcpb.LeafSchema, bool) {
+ for _, f := range cs.Container.GetKeys() {
+ if f.Name == s {
+ return f, true
+ }
+ if fmt.Sprintf("%s:%s", f.ModuleName, f.Name) == s {
+ return f, true
+ }
+ }
return nil, false
}
@@ -777,7 +783,7 @@ func (c *Converter) ConvertNotificationTypedValues(ctx context.Context, n *sdcpb
log.Debugf("converted update from: %v, to: %v", upd, nup)
// gNMI get() could return a Notification with a single path element containing a JSON/JSON_IETF blob, we need to expand this into several typed values.
if nup == nil && (upd.GetValue().GetJsonVal() != nil || upd.GetValue().GetJsonIetfVal() != nil) {
- expUpds, err := c.ExpandUpdate(ctx, upd, true)
+ expUpds, err := c.ExpandUpdate(ctx, upd)
if err != nil {
return nil, err
}
diff --git a/pkg/utils/notification.go b/pkg/utils/notification.go
index 7198a27d..1edbd07e 100644
--- a/pkg/utils/notification.go
+++ b/pkg/utils/notification.go
@@ -67,11 +67,11 @@ func FromGNMIPath(pre, p *gnmi.Path) *sdcpb.Path {
}
func FromGNMITypedValue(v *gnmi.TypedValue) *sdcpb.TypedValue {
- log.Tracef("FromGNMITypedValue: %T : %v", v, v)
+ // log.Tracef("FromGNMITypedValue: %T : %v", v, v)
if v == nil {
return nil
}
- log.Tracef("FromGNMITypedValue - Value: %T : %v", v.GetValue(), v.GetValue())
+ // log.Tracef("FromGNMITypedValue - Value: %T : %v", v.GetValue(), v.GetValue())
switch v.GetValue().(type) {
// case *gnmi.TypedValue:
case *gnmi.TypedValue_AnyVal:
diff --git a/pkg/utils/testhelper/cacheclient.go b/pkg/utils/testhelper/cacheclient.go
index 25bfdae9..5859a4d2 100644
--- a/pkg/utils/testhelper/cacheclient.go
+++ b/pkg/utils/testhelper/cacheclient.go
@@ -1,108 +1,62 @@
package testhelper
-import (
- "context"
- "strings"
- "testing"
- "time"
-
- "github.com/sdcio/cache/proto/cachepb"
- "github.com/sdcio/data-server/mocks/mockcacheclient"
- "github.com/sdcio/data-server/pkg/cache"
- "github.com/sdcio/data-server/pkg/utils"
- sdcpb "github.com/sdcio/sdc-protos/sdcpb"
- "go.uber.org/mock/gomock"
- "google.golang.org/protobuf/proto"
-)
-
-func ConfigureCacheClientMock(t *testing.T, cacheClient *mockcacheclient.MockClient, updatesIntended []*cache.Update, updatesRunning []*cache.Update, expectedModify []*cache.Update, expectedDeletes [][]string) {
-
- // mock the .GetIntendedKeysMeta() call
- cacheClient.EXPECT().GetKeys(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
-
- func(_ context.Context, datastoreName string, store cachepb.Store) (chan *cache.Update, error) {
- rsCh := make(chan *cache.Update)
-
- // GetKeys might be called with different stores...
- // init with intended store, but if store is Config then use updatesRunning
- source := updatesIntended
- if store == cachepb.Store_CONFIG {
- source = updatesRunning
- }
-
- go func() {
- for _, u := range source {
- rsCh <- u
- }
- close(rsCh)
- }()
- return rsCh, nil
- },
- )
-
- // mock the .Read() call
- // prepare a map of the updates indexed by the path for quick lookup
- updatesMap := map[cachepb.Store]map[string][]*cache.Update{}
-
- updatesMap[cachepb.Store_CONFIG] = map[string][]*cache.Update{}
- updatesMap[cachepb.Store_INTENDED] = map[string][]*cache.Update{}
- // fill the map
- for _, u := range updatesIntended {
- key := strings.Join(u.GetPath(), pathSep)
- updatesMap[cachepb.Store_INTENDED][key] = append(updatesMap[cachepb.Store_INTENDED][key], u)
- }
- for _, u := range updatesRunning {
- key := strings.Join(u.GetPath(), pathSep)
- updatesMap[cachepb.Store_CONFIG][key] = append(updatesMap[cachepb.Store_CONFIG][key], u)
- }
- cacheClient.EXPECT().Read(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
- func(_ context.Context, datastoreName string, opts *cache.Opts, paths [][]string, period time.Duration) []*cache.Update {
- if len(paths) == 1 && len(paths[0]) == 0 {
- return updatesRunning
- }
- result := make([]*cache.Update, 0, len(paths))
- for _, p := range paths {
- if val, exists := updatesMap[opts.Store][strings.Join(p, pathSep)]; exists {
- result = append(result, val...)
- }
- }
- return result
- },
- )
-
- // mock the .HasCandidate() call
- cacheClient.EXPECT().HasCandidate(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
- func(_ context.Context, _ string, _ string) (bool, error) {
- return true, nil
- },
- )
-
- // mock the NewUpdate() call
- cacheClient.EXPECT().NewUpdate(gomock.Any()).AnyTimes().DoAndReturn(
-
- func(upd *sdcpb.Update) (*cache.Update, error) {
- b, err := proto.Marshal(upd.Value)
- if err != nil {
- return nil, err
- }
- return cache.NewUpdate(utils.ToStrings(upd.GetPath(), false, false), b, 0, "", 0), nil
-
- },
- )
-
- // mock the .Modify() call
- cacheClient.EXPECT().Modify(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
- func(ctx context.Context, name string, opts *cache.Opts, dels [][]string, upds []*cache.Update) error {
- if opts.Store == cachepb.Store_INTENDED {
- if diff := DiffCacheUpdates(expectedModify, upds); diff != "" {
- t.Errorf("cache.Modify() updates mismatch (-want +got):\n%s", diff)
- }
-
- if diff := DiffDoubleStringPathSlice(expectedDeletes, dels); diff != "" {
- t.Errorf("cache.Modify() deletes mismatch (-want +got):\n%s", diff)
- }
- }
- return nil
- },
- )
-}
+// func ConfigureCacheClientMock(t *testing.T, cacheClient *mockcacheclient.MockClient, updatesIntended []*cache.Update, updatesRunning []*cache.Update, expectedModify []*cache.Update, expectedDeletes [][]string) {
+
+// cacheClient.EXPECT().InstanceIntentGet(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
+// func (ctx context.Context, ) {
+
+// }
+
+// )
+
+// Read(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
+// func(_ context.Context, datastoreName string, opts *cache.Opts, paths [][]string, period time.Duration) []*cache.Update {
+// if len(paths) == 1 && len(paths[0]) == 0 {
+// return updatesRunning
+// }
+// result := make([]*cache.Update, 0, len(paths))
+// for _, p := range paths {
+// if val, exists := updatesMap[opts.Store][strings.Join(p, pathSep)]; exists {
+// result = append(result, val...)
+// }
+// }
+// return result
+// },
+// )
+
+// // mock the .HasCandidate() call
+// cacheClient.EXPECT().HasCandidate(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
+// func(_ context.Context, _ string, _ string) (bool, error) {
+// return true, nil
+// },
+// )
+
+// // mock the NewUpdate() call
+// cacheClient.EXPECT().NewUpdate(gomock.Any()).AnyTimes().DoAndReturn(
+
+// func(upd *sdcpb.Update) (*cache.Update, error) {
+// b, err := proto.Marshal(upd.Value)
+// if err != nil {
+// return nil, err
+// }
+// return cache.NewUpdate(utils.ToStrings(upd.GetPath(), false, false), b, 0, "", 0), nil
+
+// },
+// )
+
+// // mock the .Modify() call
+// cacheClient.EXPECT().Modify(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes().DoAndReturn(
+// func(ctx context.Context, name string, opts *cache.Opts, dels [][]string, upds []*cache.Update) error {
+// if opts.Store == cachepb.Store_INTENDED {
+// if diff := DiffCacheUpdates(expectedModify, upds); diff != "" {
+// t.Errorf("cache.Modify() updates mismatch (-want +got):\n%s", diff)
+// }
+
+// if diff := DiffDoubleStringPathSlice(expectedDeletes, dels); diff != "" {
+// t.Errorf("cache.Modify() deletes mismatch (-want +got):\n%s", diff)
+// }
+// }
+// return nil
+// },
+// )
+// }
diff --git a/pkg/utils/testhelper/utils.go b/pkg/utils/testhelper/utils.go
index 334684c6..dafbedfe 100644
--- a/pkg/utils/testhelper/utils.go
+++ b/pkg/utils/testhelper/utils.go
@@ -9,10 +9,9 @@ import (
"github.com/google/go-cmp/cmp"
"github.com/sdcio/data-server/mocks/mockschemaclientbound"
- "github.com/sdcio/data-server/pkg/cache"
+ "github.com/sdcio/data-server/pkg/tree/types"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
"go.uber.org/mock/gomock"
- "google.golang.org/protobuf/proto"
)
const (
@@ -20,12 +19,12 @@ const (
)
// diffCacheUpdates takes two []*cache.Update and compares the diff
-func DiffCacheUpdates(a, b []*cache.Update) string {
+func DiffUpdates(a, b []*types.Update) string {
return cmp.Diff(CacheUpdateSliceToStringSlice(a), CacheUpdateSliceToStringSlice(b))
}
// CacheUpdateSliceToStringSlice converts a []*cache.Update to []string
-func CacheUpdateSliceToStringSlice(s []*cache.Update) []string {
+func CacheUpdateSliceToStringSlice(s []*types.Update) []string {
result := make([]string, 0, len(s))
for _, e := range s {
result = append(result, fmt.Sprintf("%v", e))
@@ -36,29 +35,18 @@ func CacheUpdateSliceToStringSlice(s []*cache.Update) []string {
}
// GetStringTvProto takes a string and returns the sdcpb.TypedValue for it in proto encoding as []byte
-func GetStringTvProto(t *testing.T, s string) []byte {
- result, err := proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_StringVal{StringVal: s}})
- if err != nil {
- t.Error(err)
- }
- return result
+func GetStringTvProto(s string) *sdcpb.TypedValue {
+ return &sdcpb.TypedValue{Value: &sdcpb.TypedValue_StringVal{StringVal: s}}
}
-func GetLeafListTvProto(t *testing.T, tvs []*sdcpb.TypedValue) []byte {
- result, err := proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_LeaflistVal{LeaflistVal: &sdcpb.ScalarArray{Element: tvs}}})
- if err != nil {
- t.Error(err)
- }
+func GetLeafListTvProto(tvs []*sdcpb.TypedValue) *sdcpb.TypedValue {
+ result := &sdcpb.TypedValue{Value: &sdcpb.TypedValue_LeaflistVal{LeaflistVal: &sdcpb.ScalarArray{Element: tvs}}}
return result
}
// GetStringTvProto takes a string and returns the sdcpb.TypedValue for it in proto encoding as []byte
-func GetUIntTvProto(t *testing.T, i uint64) []byte {
- result, err := proto.Marshal(&sdcpb.TypedValue{Value: &sdcpb.TypedValue_UintVal{UintVal: uint64(i)}})
- if err != nil {
- t.Error(err)
- }
- return result
+func GetUIntTvProto(i uint64) *sdcpb.TypedValue {
+ return &sdcpb.TypedValue{Value: &sdcpb.TypedValue_UintVal{UintVal: uint64(i)}}
}
// PathMapIndex calculates a common map index for string slice based paths
diff --git a/pkg/utils/value.go b/pkg/utils/value.go
index 642b07c2..9e0db3a2 100644
--- a/pkg/utils/value.go
+++ b/pkg/utils/value.go
@@ -21,7 +21,10 @@ import (
"strings"
"github.com/openconfig/gnmi/proto/gnmi"
+ "github.com/sdcio/data-server/pkg/cache"
+ "github.com/sdcio/schema-server/pkg/utils"
sdcpb "github.com/sdcio/sdc-protos/sdcpb"
+ "google.golang.org/protobuf/proto"
)
func GetValue(updValue *gnmi.TypedValue) (interface{}, error) {
@@ -543,3 +546,24 @@ func ParseDecimal64(v string) (*sdcpb.Decimal64, error) {
func BoolPtr(b bool) *bool {
return &b
}
+
+func SdcpbUpdateToCacheUpdate(upd *sdcpb.Update, owner string, prio int32) (*cache.Update, error) {
+ b, err := proto.Marshal(upd.Value)
+ if err != nil {
+ return nil, err
+ }
+ return cache.NewUpdate(utils.ToStrings(upd.GetPath(), false, false), b, prio, owner, 0), nil
+}
+
+func SdcpbUpdatesToCacheUpdates(upds []*sdcpb.Update, owner string, prio int32) ([]*cache.Update, error) {
+ result := []*cache.Update{}
+ for _, upd := range upds {
+ cUpd, err := SdcpbUpdateToCacheUpdate(upd, owner, prio)
+ if err != nil {
+ return nil, err
+ }
+ result = append(result, cUpd)
+ }
+
+ return result, nil
+}
diff --git a/proto/clang-format.style b/proto/clang-format.style
new file mode 100644
index 00000000..cbced3b6
--- /dev/null
+++ b/proto/clang-format.style
@@ -0,0 +1,192 @@
+---
+Language: Proto
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
+AlignAfterOpenBracket: Align
+AlignArrayOfStructures: None
+AlignConsecutiveMacros: true
+AlignConsecutiveAssignments: AcrossEmptyLinesAndComments
+AlignConsecutiveBitFields: None
+AlignConsecutiveDeclarations: true
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: MultiLine
+AttributeMacros:
+ - __capability
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterControlStatement: Never
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ BeforeLambdaBody: false
+ BeforeWhile: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeConceptDeclarations: true
+BreakBeforeBraces: Attach
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeColon
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+QualifierAlignment: Leave
+CompactNamespaces: false
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: false
+DisableFormat: false
+EmptyLineAfterAccessModifier: Never
+EmptyLineBeforeAccessModifier: LogicalBlock
+ExperimentalAutoDetectBinPacking: false
+PackConstructorInitializers: BinPack
+BasedOnStyle: ''
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+AllowAllConstructorInitializersOnNextLine: true
+FixNamespaceComments: true
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IfMacros:
+ - KJ_IF_MAYBE
+IncludeBlocks: Preserve
+IncludeCategories:
+ - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
+ Priority: 2
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '^(<|"(gtest|gmock|isl|json)/)'
+ Priority: 3
+ SortPriority: 0
+ CaseSensitive: false
+ - Regex: '.*'
+ Priority: 1
+ SortPriority: 0
+ CaseSensitive: false
+IncludeIsMainRegex: '(Test)?$'
+IncludeIsMainSourceRegex: ''
+IndentAccessModifiers: false
+IndentCaseLabels: false
+IndentCaseBlocks: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentExternBlock: AfterExternBlock
+IndentRequires: false
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+InsertTrailingCommas: None
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: true
+LambdaBodyIndentation: Signature
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Auto
+ObjCBlockIndentWidth: 2
+ObjCBreakBeforeNestedBlockParam: true
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakOpenParenthesis: 0
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PenaltyIndentedWhitespace: 0
+PointerAlignment: Right
+PPIndentWidth: -1
+ReferenceAlignment: Pointer
+ReflowComments: true
+RemoveBracesLLVM: false
+SeparateDefinitionBlocks: Leave
+ShortNamespaceLines: 1
+SortIncludes: CaseSensitive
+SortJavaStaticImport: Before
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeParensOptions:
+ AfterControlStatements: true
+ AfterForeachMacros: true
+ AfterFunctionDefinitionName: false
+ AfterFunctionDeclarationName: false
+ AfterIfMacros: true
+ AfterOverloadedOperator: false
+ BeforeNonEmptyParentheses: false
+SpaceAroundPointerQualifiers: Default
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: Never
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInLineCommentPrefix:
+ Minimum: 1
+ Maximum: -1
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+BitFieldColonSpacing: Both
+Standard: Latest
+StatementAttributeLikeMacros:
+ - Q_EMIT
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 8
+UseCRLF: false
+UseTab: Never
+WhitespaceSensitiveMacros:
+ - STRINGIZE
+ - PP_STRINGIZE
+ - BOOST_PP_STRINGIZE
+ - NS_SWIFT_NAME
+ - CF_SWIFT_NAME
+...
+
diff --git a/proto/tree_persist.proto b/proto/tree_persist.proto
new file mode 100644
index 00000000..ce221fa8
--- /dev/null
+++ b/proto/tree_persist.proto
@@ -0,0 +1,31 @@
+// Copyright 2025 Nokia
+//
+// Licensed 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.
+
+syntax = "proto3";
+
+package tree_persist.proto;
+
+option go_package = ".;tree_persist";
+
+message Intent {
+ string intent_name = 1;
+ TreeElement root = 2;
+ int32 priority = 3;
+}
+
+message TreeElement {
+ string name = 1;
+ repeated TreeElement childs = 4;
+ bytes leaf_variant = 5;
+}
diff --git a/tests/schema/sdcio_model.yang b/tests/schema/sdcio_model.yang
index b3362403..86f6684d 100644
--- a/tests/schema/sdcio_model.yang
+++ b/tests/schema/sdcio_model.yang
@@ -72,7 +72,7 @@ module sdcio_model {
}
leaf-list rangetestLeaflist {
type uint32 {
- range "10..300 | 5000..5020 | 9999";
+ range "10..300 | 5000..5020 | 9999";
}
-}
+ }
}
diff --git a/tests/schema/sdcio_model_if.yang b/tests/schema/sdcio_model_if.yang
index f5f3136c..fb7e21d2 100644
--- a/tests/schema/sdcio_model_if.yang
+++ b/tests/schema/sdcio_model_if.yang
@@ -81,6 +81,15 @@ module sdcio_model_if {
description
"A user-entered description of this network instance.";
}
+ leaf admin-state {
+ type sdcio_model_common:admin-state;
+ default "enable";
+ description
+ "The configured, desired state of the subinterface";
+ must "((. = 'enable') and starts-with(../../name, 'system0')) or not(starts-with(../../name, 'system0'))" {
+ error-message "admin-state must be enable";
+ }
+ }
}
}
}
diff --git a/tests/sdcioygot/sdcio_schema.go b/tests/sdcioygot/sdcio_schema.go
index 9273d279..cb6af6a4 100644
--- a/tests/sdcioygot/sdcio_schema.go
+++ b/tests/sdcioygot/sdcio_schema.go
@@ -4,7 +4,7 @@ of structs which represent a YANG schema. The generated schema can be
compressed by a series of transformations (compression was false
in this case).
-This package was generated by /home/mava/go/pkg/mod/github.com/openconfig/ygot@v0.29.20/genutil/names.go
+This package was generated by /home/mava/go/pkg/mod/github.com/openconfig/ygot@v0.29.22/genutil/names.go
using the following YANG input files:
- ./tests/schema/sdcio_model.yang
- ./tests/schema/sdcio_model_choice.yang
@@ -592,6 +592,7 @@ func (*SdcioModel_Interface) ΛBelongingModule() string {
// SdcioModel_Interface_Subinterface represents the /sdcio_model/interface/subinterface YANG schema element.
type SdcioModel_Interface_Subinterface struct {
+ AdminState E_SdcioModelIf_AdminState `path:"admin-state" module:"sdcio_model"`
Description *string `path:"description" module:"sdcio_model"`
Index *uint32 `path:"index" module:"sdcio_model"`
Type E_SdcioModelCommon_SiType `path:"type" module:"sdcio_model"`
@@ -1364,334 +1365,341 @@ var (
// contents of a goyang yang.Entry struct, which defines the schema for the
// fields within the struct.
ySchema = []byte{
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x7b, 0x73, 0xda, 0xca,
- 0x7e, 0xff, 0xe7, 0x53, 0xec, 0x51, 0xdb, 0x31, 0xb4, 0x96, 0x11, 0x60, 0x48, 0x70, 0xc7, 0x93,
- 0xda, 0x39, 0x39, 0xa7, 0x9e, 0x1b, 0x9f, 0x9b, 0x49, 0xce, 0xbd, 0x7f, 0xd4, 0xa6, 0xae, 0x80,
- 0x05, 0xef, 0x44, 0x48, 0x54, 0x5a, 0x39, 0x71, 0x63, 0xf7, 0xb3, 0xdf, 0xd1, 0x03, 0x21, 0x21,
- 0x69, 0xb5, 0xbb, 0x5a, 0x21, 0x01, 0x3b, 0x73, 0xc6, 0x87, 0xc0, 0x4a, 0xfb, 0xf8, 0xbd, 0x9f,
- 0xfb, 0xf3, 0x0d, 0x00, 0x00, 0x28, 0x7f, 0xe8, 0x4b, 0xa8, 0x5c, 0x00, 0x65, 0x06, 0x9f, 0xd0,
- 0x14, 0x2a, 0xa7, 0xc1, 0xb7, 0x7f, 0x41, 0xe6, 0x4c, 0xb9, 0x00, 0xdd, 0xf0, 0x9f, 0x1f, 0x2c,
- 0x73, 0x8e, 0x16, 0xca, 0x05, 0xd0, 0xc2, 0x2f, 0x7e, 0x45, 0xb6, 0x72, 0x01, 0x82, 0x57, 0xf8,
- 0x5f, 0x4c, 0x1f, 0x2d, 0x34, 0x85, 0x4e, 0xe2, 0xcb, 0xc4, 0xfb, 0xd7, 0x03, 0x4e, 0x93, 0x3f,
- 0x27, 0x27, 0x8a, 0xbe, 0xde, 0x9e, 0x30, 0xfa, 0xe1, 0xb3, 0x0d, 0xe7, 0xe8, 0x47, 0x6a, 0x9a,
- 0xc4, 0x54, 0xce, 0x6c, 0x8a, 0xac, 0x87, 0xa5, 0x35, 0x83, 0xc6, 0x43, 0x30, 0xed, 0xd6, 0xac,
- 0xfe, 0xe8, 0xaf, 0x96, 0x6b, 0x4f, 0x61, 0xe6, 0x9b, 0x82, 0x95, 0xc1, 0xe7, 0xef, 0x96, 0xed,
- 0x2d, 0x4e, 0x59, 0x05, 0x93, 0x9e, 0x66, 0x0f, 0xfc, 0x4f, 0xdd, 0xb9, 0xb2, 0x17, 0xee, 0x12,
- 0x9a, 0x58, 0xb9, 0x00, 0xd8, 0x76, 0x61, 0xce, 0xc0, 0xd8, 0xa8, 0xac, 0x35, 0xa6, 0x1e, 0x7a,
- 0x4d, 0x7c, 0xf3, 0xba, 0x75, 0x12, 0xdb, 0x20, 0xd8, 0x02, 0xc5, 0x54, 0x77, 0x08, 0x9b, 0x4b,
- 0x42, 0xc5, 0x1f, 0x9b, 0xb3, 0xe8, 0x10, 0x40, 0x83, 0x9c, 0x9f, 0xf3, 0x00, 0x45, 0x03, 0x30,
- 0x3e, 0xc0, 0xd1, 0x02, 0x90, 0x19, 0x90, 0xcc, 0x00, 0xe5, 0x06, 0x6c, 0x36, 0x80, 0x73, 0x00,
- 0x5d, 0x08, 0xf0, 0x0d, 0xe0, 0x75, 0x07, 0x76, 0x8b, 0xcf, 0x23, 0x82, 0xbd, 0x3f, 0xbc, 0x60,
- 0x6b, 0x21, 0xf8, 0xcf, 0x0b, 0x86, 0x15, 0xa1, 0x01, 0x0b, 0x3a, 0x94, 0x43, 0x0b, 0x56, 0xf4,
- 0xe0, 0x46, 0x13, 0x6e, 0x74, 0x29, 0x8d, 0x36, 0x64, 0xf4, 0x29, 0x40, 0x23, 0x6a, 0x74, 0x62,
- 0x44, 0x2b, 0x2e, 0xf4, 0x2a, 0x10, 0x03, 0xa5, 0xd1, 0x8d, 0x07, 0xed, 0xc4, 0xa0, 0x1f, 0x2f,
- 0x1a, 0x96, 0x46, 0xc7, 0xd2, 0x68, 0x29, 0x0c, 0x3d, 0xe9, 0xd0, 0x94, 0x12, 0x5d, 0x99, 0xd1,
- 0x36, 0x81, 0xbe, 0x2a, 0x34, 0xe0, 0x92, 0x1d, 0x06, 0x71, 0x54, 0x0e, 0x5e, 0xc1, 0x78, 0x84,
- 0x6c, 0x68, 0xcd, 0x8d, 0xde, 0x65, 0xd0, 0x5c, 0x2c, 0xba, 0x97, 0x45, 0x7b, 0x61, 0xe8, 0x2f,
- 0x8c, 0x0c, 0x84, 0x93, 0x03, 0x1b, 0x59, 0x30, 0x92, 0x07, 0x37, 0x99, 0x44, 0x0f, 0x72, 0x51,
- 0x4a, 0x0a, 0x89, 0x38, 0x88, 0x65, 0x9b, 0x68, 0x34, 0xce, 0xc7, 0x79, 0x89, 0x47, 0x04, 0x11,
- 0x55, 0x43, 0x4c, 0xa2, 0x88, 0x4a, 0x38, 0x71, 0x09, 0x27, 0xb2, 0xca, 0x88, 0x8d, 0x8f, 0xe8,
- 0x38, 0x89, 0x2f, 0xda, 0xc5, 0x9f, 0xcf, 0x2b, 0x28, 0x08, 0x8f, 0xb0, 0x8d, 0xcc, 0x45, 0x19,
- 0xdc, 0x59, 0x8b, 0xa2, 0x77, 0x6f, 0x76, 0x73, 0x6e, 0xd5, 0xb2, 0xb7, 0x2b, 0xd3, 0xb4, 0xb0,
- 0x8e, 0x91, 0x65, 0xf2, 0x71, 0x39, 0x67, 0xfa, 0x08, 0x97, 0xfa, 0x4a, 0xc7, 0x8f, 0xde, 0xe9,
- 0x76, 0x62, 0x28, 0xd6, 0x09, 0x1d, 0x15, 0x9d, 0x8d, 0x69, 0xdc, 0xf1, 0x55, 0xd9, 0xd8, 0x5f,
- 0x95, 0x93, 0xbd, 0x79, 0x60, 0x74, 0xa7, 0xd8, 0x0c, 0x81, 0xfa, 0xd5, 0x9b, 0xf5, 0xd6, 0xc7,
- 0xeb, 0x0f, 0xc1, 0xa4, 0x0f, 0x1f, 0xbc, 0x39, 0xfc, 0xbf, 0x1f, 0xbd, 0x29, 0xde, 0x54, 0x73,
- 0xe2, 0x0c, 0xa7, 0xad, 0x18, 0xd6, 0x82, 0x5f, 0x71, 0xf2, 0x1e, 0x66, 0x15, 0x5c, 0x70, 0xae,
- 0xbb, 0x86, 0x47, 0xf8, 0x77, 0xec, 0xe7, 0x3b, 0xd7, 0x0d, 0x87, 0x91, 0x3b, 0x8c, 0xf9, 0x54,
- 0x3a, 0x4d, 0xaa, 0x74, 0x52, 0xa5, 0xdb, 0x2d, 0xcf, 0xe3, 0x96, 0x26, 0x11, 0x1e, 0x4c, 0x2c,
- 0xcb, 0x80, 0xba, 0xc9, 0x03, 0xfc, 0xb5, 0xf8, 0xe8, 0x56, 0xc5, 0x92, 0x84, 0x1a, 0x89, 0xf0,
- 0x07, 0xb6, 0x75, 0xd5, 0x35, 0x1d, 0xac, 0x4f, 0x0c, 0xb6, 0x43, 0xf3, 0x70, 0xd3, 0x81, 0xa6,
- 0x8f, 0xe8, 0x6c, 0x1c, 0xa8, 0x04, 0x60, 0x7c, 0xd1, 0x02, 0x90, 0x03, 0xf4, 0x29, 0x46, 0x4f,
- 0x0d, 0xa0, 0xce, 0xe0, 0x04, 0x9a, 0x44, 0x9f, 0xdb, 0x47, 0x54, 0x35, 0x71, 0x52, 0x8f, 0x1e,
- 0x0b, 0xc5, 0x5c, 0x4e, 0xc5, 0x86, 0x5f, 0xa1, 0x61, 0xf1, 0x65, 0xd1, 0xa9, 0x2f, 0x74, 0xa0,
- 0x79, 0xad, 0xd8, 0xbd, 0xc9, 0x78, 0x90, 0x3c, 0x07, 0x48, 0xde, 0x68, 0xfe, 0xf2, 0x09, 0x4b,
- 0xf7, 0xd1, 0xbc, 0xc7, 0xe6, 0xc3, 0xef, 0x49, 0x1f, 0x7e, 0x59, 0x15, 0xe3, 0x28, 0x7c, 0xf8,
- 0x3d, 0x3e, 0x1f, 0x7e, 0x4f, 0xfa, 0xf0, 0xa5, 0x0f, 0xbf, 0x66, 0x1f, 0xbe, 0x34, 0x42, 0xa5,
- 0x11, 0x2a, 0x8d, 0x50, 0x69, 0x84, 0x4a, 0x23, 0x54, 0x1a, 0xa1, 0xd2, 0x08, 0x3d, 0x20, 0x23,
- 0xb4, 0xd7, 0x61, 0x51, 0x31, 0xe9, 0x8d, 0xd0, 0xde, 0xb1, 0x18, 0xa1, 0x3d, 0x6e, 0x23, 0x94,
- 0x29, 0xf7, 0x8c, 0x72, 0x23, 0x6c, 0x1b, 0xc8, 0x5e, 0xfa, 0x2b, 0x63, 0x1e, 0x64, 0xc1, 0xd2,
- 0x28, 0x96, 0x94, 0x95, 0x1d, 0x5a, 0x84, 0x65, 0xc9, 0xb5, 0x6f, 0x56, 0x18, 0x5b, 0x9d, 0x32,
- 0xb3, 0xdc, 0x89, 0x01, 0xbf, 0xc1, 0xe7, 0xfc, 0xac, 0xd8, 0xcd, 0x90, 0x1d, 0xe7, 0xc5, 0xe6,
- 0x4d, 0x0c, 0x9a, 0x95, 0x1a, 0xbb, 0x59, 0xa6, 0xb0, 0xec, 0x58, 0xcb, 0x9f, 0xa5, 0x28, 0x2f,
- 0xd6, 0x1b, 0x45, 0xce, 0x88, 0xed, 0xee, 0x3a, 0x23, 0x96, 0x04, 0x32, 0x56, 0x09, 0x5c, 0x63,
- 0x52, 0x2c, 0x01, 0xa4, 0x7c, 0xbc, 0xa9, 0x30, 0x2f, 0xf6, 0x49, 0x37, 0x5c, 0x96, 0xc4, 0xd8,
- 0x70, 0x3c, 0x9d, 0x57, 0x4d, 0x6b, 0x8a, 0x57, 0x8d, 0x06, 0x3d, 0x0e, 0xc0, 0xb1, 0x46, 0x81,
- 0x3e, 0x62, 0x64, 0x37, 0xb5, 0xa5, 0xc3, 0x9e, 0xa4, 0x41, 0x99, 0x8c, 0xc1, 0xe7, 0x41, 0xf6,
- 0xb1, 0xb7, 0xc7, 0x88, 0xed, 0x3d, 0x89, 0xed, 0x12, 0xdb, 0x1b, 0x8b, 0xed, 0xbb, 0x56, 0x55,
- 0xa3, 0x53, 0xef, 0x10, 0xf4, 0x00, 0xb2, 0x9a, 0xf8, 0xeb, 0xfa, 0x15, 0x0f, 0x1f, 0xbc, 0x57,
- 0xd0, 0x6a, 0xba, 0x19, 0xca, 0xd8, 0x37, 0xf8, 0xdc, 0x2d, 0x56, 0x58, 0xfc, 0x51, 0x64, 0x85,
- 0x45, 0x93, 0x0a, 0x4b, 0x33, 0x14, 0x96, 0x42, 0x5a, 0xa3, 0xa7, 0xb1, 0x02, 0xda, 0xa2, 0xc6,
- 0xb0, 0x1e, 0x15, 0x86, 0xf5, 0x24, 0x86, 0x49, 0x0c, 0xe3, 0xc1, 0xb0, 0xa5, 0x6e, 0xce, 0x74,
- 0x6c, 0x15, 0x23, 0xd9, 0x7a, 0xa0, 0xc4, 0xb3, 0xbd, 0xc0, 0xb3, 0xdb, 0x00, 0x5c, 0xf6, 0x33,
- 0xc1, 0x1e, 0xae, 0x15, 0x17, 0x89, 0x3e, 0x82, 0xbf, 0xf8, 0x9e, 0x19, 0x5f, 0x74, 0x82, 0x0c,
- 0xee, 0xa6, 0x7c, 0x42, 0x0e, 0xbe, 0xc2, 0x38, 0xc7, 0x91, 0x70, 0x8b, 0xcc, 0x8f, 0x06, 0xf4,
- 0x8e, 0xd9, 0xc9, 0xc6, 0x38, 0xe5, 0x56, 0xff, 0x11, 0x1b, 0xd1, 0x7d, 0x77, 0x7e, 0x3e, 0x7c,
- 0x7b, 0x7e, 0xae, 0xbd, 0xed, 0xbf, 0xd5, 0x46, 0x83, 0x41, 0x77, 0xd8, 0xcd, 0x28, 0xaa, 0x55,
- 0xfe, 0x6a, 0xcf, 0xa0, 0x0d, 0x67, 0xd7, 0xde, 0xd2, 0x4c, 0xd7, 0x30, 0x48, 0x43, 0xfe, 0xe6,
- 0x40, 0x6f, 0x71, 0x7e, 0xc0, 0xb1, 0x2a, 0x1f, 0x19, 0xd1, 0x51, 0x54, 0xac, 0xfe, 0xd0, 0xf8,
- 0xc9, 0xe0, 0x72, 0x85, 0x9f, 0xa7, 0x96, 0x39, 0xcf, 0xf7, 0x93, 0x6d, 0x86, 0x64, 0xfb, 0xc9,
- 0xb4, 0x8a, 0xfc, 0x64, 0x8d, 0xf6, 0x8e, 0xb1, 0xfa, 0xc4, 0x72, 0x29, 0x31, 0x79, 0xcc, 0x59,
- 0x7b, 0x5e, 0x13, 0x5e, 0x9f, 0x02, 0x9c, 0x68, 0x06, 0x4d, 0x8c, 0xf0, 0xb3, 0x0d, 0x09, 0x00,
- 0x8d, 0x0f, 0xda, 0x99, 0xeb, 0x73, 0x3d, 0x69, 0x53, 0xa1, 0x1a, 0xad, 0x4f, 0x98, 0xb3, 0xd3,
- 0x7e, 0x5e, 0x61, 0xeb, 0x8a, 0xc2, 0xdf, 0x19, 0x0e, 0x6c, 0x8c, 0xdc, 0x25, 0x80, 0x6a, 0x2f,
- 0x04, 0x6e, 0x3e, 0x28, 0xab, 0xd6, 0xe8, 0xf2, 0x29, 0x2b, 0x93, 0xca, 0x06, 0x84, 0x31, 0x37,
- 0xe1, 0xab, 0xae, 0x49, 0xbd, 0x24, 0x72, 0x70, 0x49, 0xd5, 0x8d, 0x22, 0xe7, 0x80, 0xf2, 0x77,
- 0xdd, 0x70, 0xfd, 0x9e, 0x21, 0xc5, 0x31, 0x6e, 0xc6, 0xc4, 0xb5, 0xd9, 0x76, 0x84, 0x86, 0x33,
- 0x1c, 0xca, 0x3e, 0x6d, 0xbf, 0x8e, 0x79, 0x2d, 0xfc, 0x08, 0xed, 0x2b, 0x63, 0x61, 0xd5, 0x31,
- 0xb9, 0xed, 0xe8, 0x65, 0xbd, 0x53, 0x63, 0x56, 0x2a, 0xa1, 0xb2, 0x3a, 0x02, 0x44, 0xbc, 0xa6,
- 0xe5, 0x7e, 0xd7, 0x92, 0xfb, 0x49, 0xee, 0x27, 0xb9, 0x9f, 0xe4, 0x7e, 0x7b, 0xc8, 0xfd, 0xaa,
- 0xb2, 0xfe, 0xc8, 0xe4, 0x94, 0x6f, 0xff, 0xdd, 0xc4, 0x9e, 0xa3, 0x31, 0x19, 0x4c, 0x0c, 0xed,
- 0xb9, 0x9e, 0xc1, 0xce, 0x36, 0x84, 0x1d, 0x0d, 0xd9, 0x71, 0xa6, 0x04, 0x9a, 0x37, 0x3b, 0x45,
- 0x02, 0xcd, 0x85, 0x99, 0x0b, 0xfa, 0x6c, 0x89, 0x4c, 0xd5, 0xc1, 0x3a, 0xa6, 0x68, 0x1d, 0x16,
- 0x1f, 0x9c, 0x17, 0x99, 0xa7, 0x48, 0xa3, 0x56, 0xa0, 0xe9, 0xa7, 0x47, 0x66, 0x0e, 0x18, 0x37,
- 0xcc, 0x0f, 0x88, 0xe6, 0xfb, 0xed, 0x00, 0xcc, 0xc2, 0x95, 0xaa, 0x25, 0x72, 0x31, 0x9e, 0x24,
- 0xc8, 0x98, 0x50, 0xa5, 0xa4, 0x7c, 0x34, 0xdd, 0xe2, 0xde, 0x24, 0xca, 0x9f, 0xd6, 0xd7, 0xc0,
- 0x91, 0x48, 0x15, 0xce, 0xec, 0xfa, 0x7e, 0x8f, 0x00, 0x07, 0x29, 0x62, 0x99, 0x3d, 0x5f, 0xd0,
- 0x21, 0x27, 0x1f, 0x67, 0xa9, 0x23, 0xae, 0xd6, 0x0d, 0x21, 0x13, 0x29, 0x31, 0x74, 0x3d, 0xdf,
- 0x05, 0xe8, 0x51, 0x2c, 0x31, 0xdc, 0xcc, 0x05, 0xe8, 0xee, 0x24, 0xde, 0xca, 0x90, 0xe6, 0xac,
- 0x2c, 0x5d, 0xa7, 0xb8, 0xa8, 0x82, 0x21, 0x06, 0xdd, 0x6a, 0x9d, 0x81, 0x4b, 0x70, 0x12, 0xec,
- 0xf8, 0xa4, 0x0d, 0x74, 0x73, 0x06, 0x1c, 0xac, 0xdb, 0xd8, 0x51, 0xbf, 0x23, 0xfc, 0xd8, 0x3a,
- 0x3b, 0xeb, 0x78, 0xc2, 0xe9, 0x14, 0x9c, 0x38, 0xcf, 0x0e, 0x86, 0x4b, 0xed, 0xa4, 0xdd, 0x06,
- 0x96, 0x0d, 0x4c, 0x0b, 0xb7, 0x8a, 0xc6, 0xd1, 0x60, 0xc3, 0x47, 0xdb, 0xb6, 0xec, 0x5b, 0xe8,
- 0x38, 0xfa, 0x02, 0xb2, 0x57, 0x57, 0xc5, 0x28, 0x03, 0x78, 0x27, 0x03, 0x26, 0x10, 0x50, 0x63,
- 0x22, 0xe0, 0xcc, 0xb7, 0x8e, 0x73, 0x1f, 0xe8, 0x2d, 0x5f, 0x5d, 0x86, 0xeb, 0x67, 0xc8, 0xc1,
- 0x2d, 0x93, 0x5c, 0x9d, 0x60, 0x4e, 0x84, 0x23, 0xd8, 0x4d, 0x02, 0x6f, 0xee, 0xaf, 0x84, 0x92,
- 0x1c, 0xc5, 0x86, 0x73, 0x68, 0x53, 0xa5, 0xe7, 0x33, 0xe0, 0xf2, 0x97, 0xdf, 0x3e, 0x80, 0xde,
- 0xbb, 0x61, 0xff, 0x02, 0xfc, 0xf9, 0x08, 0xc1, 0xcd, 0x5a, 0xdd, 0x71, 0xc0, 0xef, 0xb6, 0xe5,
- 0xae, 0xc0, 0xed, 0xcd, 0x35, 0x50, 0x01, 0x9a, 0x5f, 0x79, 0x27, 0xf6, 0x15, 0xeb, 0xd8, 0x75,
- 0x2a, 0x4e, 0x7d, 0xd9, 0xec, 0x72, 0x97, 0xd9, 0x2f, 0x1c, 0xc7, 0x50, 0x1d, 0x0e, 0x94, 0x70,
- 0x3e, 0xcc, 0xa0, 0x33, 0xb5, 0xd1, 0x8a, 0x98, 0x87, 0x12, 0xb7, 0x9c, 0xa2, 0xc1, 0x52, 0xe5,
- 0xd9, 0x7b, 0x95, 0xa7, 0x18, 0x9c, 0xc9, 0x68, 0x26, 0x61, 0xcc, 0x27, 0x68, 0x2e, 0x7c, 0xbb,
- 0xac, 0x34, 0x9f, 0xb9, 0x45, 0xf4, 0xd5, 0x1c, 0x81, 0x6f, 0x82, 0xa1, 0x98, 0xf7, 0x37, 0x5b,
- 0x9f, 0x7a, 0xdb, 0xfd, 0x15, 0x2d, 0x50, 0x5e, 0x3c, 0x34, 0xfb, 0xc8, 0xe0, 0x42, 0xf7, 0x4b,
- 0x69, 0xb2, 0xc2, 0x98, 0x9c, 0x16, 0xbc, 0x72, 0xab, 0xff, 0x60, 0xdf, 0x6a, 0x6f, 0x30, 0x68,
- 0xde, 0x66, 0x6b, 0x60, 0x5c, 0x91, 0xa1, 0xad, 0x62, 0x12, 0xc2, 0xa7, 0x0d, 0xf3, 0x60, 0xbc,
- 0x64, 0x5f, 0x7b, 0xcf, 0xbe, 0x76, 0x94, 0x13, 0x84, 0x5d, 0x8a, 0x7c, 0x20, 0xec, 0x4a, 0x8c,
- 0xda, 0x7f, 0x8c, 0x72, 0x91, 0x89, 0xbb, 0x43, 0x0a, 0x8c, 0x1a, 0x12, 0x86, 0x7c, 0xd1, 0xcd,
- 0x05, 0xac, 0x4d, 0x12, 0x6a, 0xc7, 0x23, 0x09, 0x87, 0x83, 0x41, 0x5f, 0xca, 0x42, 0x6f, 0x91,
- 0xa1, 0x67, 0xbb, 0x80, 0x49, 0xf9, 0xa3, 0x24, 0x97, 0xda, 0x7b, 0x2e, 0xb5, 0xd1, 0x64, 0x08,
- 0x10, 0xdd, 0x17, 0xcd, 0xbd, 0x7f, 0x44, 0x9a, 0xbb, 0x76, 0x38, 0xcc, 0x8a, 0x80, 0x50, 0x9f,
- 0x75, 0x8c, 0xa1, 0x6d, 0x16, 0x62, 0x94, 0xd2, 0x5a, 0x2e, 0x96, 0x58, 0x7b, 0x09, 0x5d, 0x99,
- 0x2f, 0x86, 0xd5, 0xd2, 0x5e, 0xba, 0x77, 0x9a, 0x3a, 0x1a, 0xfb, 0x7f, 0x5e, 0x7a, 0xad, 0x3b,
- 0x4d, 0x3d, 0x0f, 0xff, 0x31, 0xb8, 0xd3, 0xd4, 0xc1, 0xb8, 0xfd, 0x72, 0xd7, 0x8d, 0x7e, 0xf7,
- 0x3f, 0xb6, 0x5f, 0x20, 0x7e, 0x84, 0xb6, 0x09, 0xb1, 0xda, 0xf2, 0xbf, 0x68, 0xdd, 0xdf, 0xcf,
- 0xda, 0x3f, 0xb5, 0xd3, 0xee, 0x6b, 0xab, 0x73, 0xa7, 0x4f, 0xa6, 0xb3, 0x71, 0xfb, 0x7d, 0xab,
- 0xb3, 0xf5, 0x53, 0xfb, 0x7d, 0xa7, 0xb5, 0x3d, 0xbc, 0xfd, 0xd2, 0xf2, 0x66, 0xef, 0x8e, 0xbd,
- 0x6f, 0x5e, 0x5a, 0xdd, 0xde, 0x9d, 0xa6, 0xbe, 0x1b, 0xb7, 0xdb, 0xed, 0x17, 0x64, 0x4f, 0xf8,
- 0x96, 0x66, 0xe8, 0x8b, 0xad, 0x69, 0x7a, 0xfe, 0x34, 0x9a, 0xa6, 0xb5, 0xdb, 0x6d, 0xa5, 0x12,
- 0x59, 0xe0, 0xb8, 0x93, 0xfc, 0x30, 0x65, 0x9a, 0x17, 0xc7, 0x47, 0x37, 0xac, 0x90, 0x58, 0xca,
- 0x86, 0xf5, 0x0c, 0x85, 0xa5, 0xc3, 0x34, 0x5e, 0x3c, 0x4e, 0xf7, 0x0f, 0x68, 0x62, 0x59, 0x25,
- 0x11, 0x35, 0x44, 0x38, 0x95, 0x6b, 0xae, 0xa7, 0x24, 0xa1, 0x0e, 0x25, 0xef, 0x16, 0x5e, 0x48,
- 0x49, 0x8f, 0x2e, 0xb4, 0xba, 0x07, 0xab, 0x0e, 0x42, 0xaf, 0x8b, 0x70, 0xe9, 0x24, 0xbc, 0x5e,
- 0xc5, 0xd2, 0x72, 0x9b, 0x5f, 0x7e, 0x33, 0xe8, 0x2c, 0x5c, 0xba, 0x0b, 0xbf, 0xf7, 0xb1, 0x09,
- 0x87, 0x22, 0x28, 0x34, 0x37, 0xae, 0xa0, 0xfa, 0x1d, 0x99, 0x33, 0xf8, 0x83, 0x9e, 0x55, 0x07,
- 0xc3, 0x25, 0x93, 0x96, 0x4c, 0x9a, 0xc2, 0x83, 0xd5, 0xef, 0x31, 0xf0, 0xe7, 0xb7, 0x14, 0x43,
- 0xe9, 0x3c, 0x5a, 0xbb, 0xe6, 0xce, 0x9a, 0xe4, 0xce, 0xdb, 0x47, 0x32, 0x1a, 0x8d, 0x46, 0x92,
- 0x3d, 0x33, 0x91, 0x18, 0x47, 0xf7, 0x43, 0xba, 0xf4, 0x20, 0x0e, 0x72, 0x48, 0xa6, 0x0b, 0x69,
- 0x99, 0x79, 0x42, 0x0c, 0xa9, 0x42, 0x9c, 0xd9, 0x42, 0xd1, 0x72, 0xb8, 0xb2, 0x86, 0x88, 0x16,
- 0x26, 0xf0, 0xe5, 0x58, 0x94, 0x41, 0xa3, 0x81, 0xb9, 0x65, 0x83, 0x70, 0x71, 0xa0, 0xc8, 0x0e,
- 0x15, 0x25, 0x41, 0xf2, 0xa4, 0x09, 0x6f, 0x96, 0x51, 0x69, 0x01, 0x93, 0x2f, 0x6c, 0xd8, 0x8f,
- 0xae, 0xde, 0x8e, 0xa3, 0xb5, 0xa8, 0x52, 0x98, 0x46, 0x48, 0x46, 0xe8, 0x48, 0x08, 0xfe, 0x4a,
- 0x45, 0x4a, 0x2a, 0x52, 0x8c, 0x05, 0x3a, 0x29, 0x6b, 0x97, 0xc2, 0x3a, 0x62, 0x2b, 0xd8, 0x49,
- 0x23, 0x06, 0x52, 0x29, 0x70, 0x38, 0xa9, 0x1a, 0x38, 0x4c, 0xfd, 0x79, 0x39, 0x19, 0xfd, 0xc4,
- 0x46, 0xb3, 0x05, 0x9c, 0x29, 0x55, 0xa8, 0x45, 0x9c, 0x4b, 0xb2, 0x2d, 0x17, 0x33, 0xad, 0x88,
- 0x6a, 0xe4, 0xb8, 0x62, 0x64, 0x6d, 0xa4, 0x4a, 0x92, 0xab, 0x5b, 0x20, 0x7b, 0x72, 0xe2, 0x6b,
- 0x20, 0xb9, 0x23, 0xd6, 0x0e, 0xfa, 0x82, 0x61, 0x86, 0xbe, 0x28, 0x1a, 0x81, 0xe6, 0x45, 0x53,
- 0x99, 0xab, 0x82, 0x11, 0x4f, 0x8f, 0x66, 0x2d, 0x6a, 0x90, 0x47, 0xb3, 0x9e, 0x92, 0x06, 0x1c,
- 0x77, 0xb5, 0xb2, 0x6c, 0x0c, 0x67, 0xc0, 0x32, 0x01, 0x7e, 0x44, 0x8e, 0x54, 0x7c, 0x52, 0xc2,
- 0x81, 0xea, 0xb0, 0xf6, 0xa1, 0xb9, 0x3a, 0x0f, 0xa5, 0x9d, 0x81, 0x5f, 0x2e, 0xc1, 0x89, 0x61,
- 0x4d, 0x75, 0x43, 0x5d, 0x22, 0x1f, 0x36, 0x33, 0xe8, 0x84, 0xd4, 0xd3, 0x12, 0x42, 0x65, 0x35,
- 0xe0, 0x7f, 0x6a, 0x3f, 0x00, 0x39, 0x92, 0x1e, 0x28, 0xe9, 0x81, 0xeb, 0xf0, 0x0e, 0xd5, 0x14,
- 0x60, 0x8a, 0x9c, 0x85, 0xbd, 0x93, 0x48, 0xfe, 0x53, 0x72, 0xff, 0xa4, 0xb8, 0xaf, 0x8a, 0xdc,
- 0x47, 0x29, 0xee, 0xc2, 0x89, 0x8d, 0x3c, 0xd7, 0x46, 0xa4, 0xea, 0xed, 0xe2, 0x3e, 0x4a, 0xe9,
- 0xa1, 0xb9, 0xfd, 0x94, 0x8a, 0x4e, 0x43, 0x40, 0xcf, 0xc9, 0x08, 0xbf, 0x3a, 0x14, 0xa1, 0x63,
- 0x40, 0x2e, 0xbe, 0x5d, 0x3f, 0xfd, 0xf0, 0x35, 0xfe, 0x2a, 0x91, 0x3d, 0xb3, 0x32, 0x12, 0x64,
- 0x64, 0xbb, 0xac, 0x04, 0x18, 0xd9, 0xca, 0xa5, 0xb3, 0x81, 0x94, 0x5d, 0x2c, 0x6d, 0x40, 0x7d,
- 0x6e, 0x20, 0x07, 0xe7, 0xd7, 0x4a, 0x47, 0x23, 0x76, 0x5c, 0x2a, 0x9d, 0x33, 0x2f, 0x68, 0x56,
- 0xc1, 0x74, 0xb4, 0x4a, 0x51, 0x65, 0xd3, 0xd0, 0xc4, 0xf6, 0x73, 0x71, 0x4a, 0x48, 0x30, 0xac,
- 0x61, 0x79, 0x82, 0x04, 0x90, 0xb1, 0x8a, 0xff, 0x1a, 0x33, 0x42, 0xf2, 0x41, 0xca, 0x27, 0xdd,
- 0x76, 0x98, 0x2b, 0x2f, 0x50, 0x76, 0xf6, 0xa8, 0x65, 0x67, 0x7f, 0xe7, 0x82, 0x73, 0x77, 0x2d,
- 0x2b, 0x48, 0x4c, 0x28, 0x97, 0x01, 0x7f, 0xca, 0x44, 0xa0, 0x7c, 0xfe, 0x6b, 0xc3, 0xb9, 0x6a,
- 0xf9, 0x29, 0x1b, 0xba, 0x41, 0xe6, 0xc3, 0x89, 0x91, 0xbb, 0x6d, 0x5e, 0xf8, 0x10, 0xce, 0xdf,
- 0x7c, 0x76, 0x9c, 0x6a, 0x13, 0x02, 0x04, 0x34, 0x33, 0x24, 0xec, 0x7e, 0x4d, 0x93, 0x6f, 0xb3,
- 0xd4, 0x85, 0x10, 0x58, 0x37, 0xa6, 0x83, 0xf5, 0xa0, 0xc6, 0x37, 0x7b, 0x57, 0xca, 0xe7, 0x35,
- 0xfa, 0x6d, 0x74, 0x37, 0x1f, 0xb5, 0x68, 0x70, 0x08, 0x39, 0x58, 0x75, 0x4d, 0xf4, 0xbf, 0x2e,
- 0xa1, 0xe5, 0x49, 0x7c, 0xd0, 0xae, 0x25, 0x39, 0x72, 0xf0, 0x43, 0xe6, 0xd4, 0x4d, 0xc3, 0x9e,
- 0xd8, 0x42, 0x45, 0xc9, 0x73, 0x07, 0xda, 0x4f, 0xd0, 0xa6, 0xc8, 0xf1, 0x0c, 0xc6, 0x35, 0x2c,
- 0xbb, 0x93, 0x0c, 0xba, 0x7d, 0x12, 0xea, 0x24, 0xd0, 0xf2, 0xc9, 0xf5, 0xc2, 0x7c, 0x4f, 0xb4,
- 0x62, 0xc8, 0x1d, 0x5a, 0xed, 0x5b, 0xbc, 0x8b, 0x0e, 0x35, 0x0e, 0x20, 0xf0, 0x45, 0x85, 0x3a,
- 0x75, 0x45, 0xc0, 0x9a, 0x71, 0x4d, 0x0c, 0xb1, 0xb4, 0x29, 0xb5, 0xe6, 0x82, 0x82, 0x18, 0x89,
- 0xed, 0x12, 0xdb, 0x1b, 0x8d, 0xed, 0x2b, 0xcb, 0xc6, 0xf4, 0xd8, 0xee, 0x8f, 0x96, 0xd8, 0x2e,
- 0xb1, 0x9d, 0x2b, 0x4d, 0x94, 0x58, 0xe8, 0xbc, 0x8d, 0x3f, 0x43, 0x99, 0x26, 0x4a, 0x1d, 0xf1,
- 0x6a, 0x7c, 0x9a, 0x28, 0x43, 0xe1, 0x74, 0x13, 0x8e, 0x65, 0x1f, 0x03, 0x4e, 0xa4, 0x5a, 0xeb,
- 0x6a, 0xe3, 0x4d, 0x74, 0x01, 0x89, 0x7a, 0xe2, 0x4f, 0x2c, 0x3d, 0xf8, 0x22, 0xaf, 0x83, 0xb0,
- 0xce, 0x65, 0x68, 0x05, 0x28, 0x24, 0x66, 0x59, 0xb1, 0x43, 0x2d, 0xdb, 0xc4, 0x89, 0x9d, 0xf5,
- 0xc6, 0x76, 0xdd, 0x9b, 0xa0, 0xba, 0x28, 0x63, 0xcc, 0xa5, 0xd4, 0x21, 0xba, 0x2f, 0x0a, 0xdc,
- 0xa5, 0xc8, 0xc1, 0x7f, 0xf3, 0xdf, 0xf2, 0xf0, 0x35, 0x78, 0x4b, 0xed, 0x5e, 0xdf, 0x5c, 0x5f,
- 0x19, 0xed, 0x4e, 0x68, 0xdc, 0x76, 0xcb, 0xc5, 0x12, 0xab, 0x14, 0xcd, 0x8a, 0xb7, 0xc6, 0xed,
- 0xfa, 0x6e, 0x67, 0xd8, 0x78, 0xa7, 0x6f, 0xb0, 0x44, 0x51, 0x0e, 0xbb, 0xfd, 0x6d, 0xd3, 0x91,
- 0x07, 0xaa, 0x3d, 0x72, 0xd3, 0xe5, 0x80, 0xb2, 0xea, 0xc0, 0x5b, 0xbe, 0x77, 0x9f, 0xc6, 0xcb,
- 0xcf, 0xe6, 0xc3, 0x27, 0xf0, 0xb3, 0x0c, 0x2a, 0xa3, 0x6b, 0x9b, 0xd6, 0xc4, 0x66, 0x69, 0x12,
- 0x1b, 0x1b, 0x87, 0x8d, 0x77, 0x1e, 0x36, 0x5e, 0x4e, 0x5d, 0xdb, 0x86, 0x26, 0x6e, 0xb5, 0xd7,
- 0x09, 0x87, 0xe3, 0xce, 0x56, 0xdb, 0xbd, 0xbd, 0x69, 0xd9, 0xec, 0x03, 0xa8, 0x75, 0xe6, 0xef,
- 0x24, 0xde, 0xfd, 0xf7, 0x12, 0xdc, 0x87, 0x9d, 0xab, 0xef, 0x95, 0xea, 0x5b, 0x2f, 0xff, 0xf9,
- 0x08, 0xc1, 0x52, 0x37, 0xf5, 0x85, 0xaf, 0xde, 0x6f, 0x92, 0xfb, 0xc0, 0x54, 0xf7, 0x74, 0x10,
- 0x30, 0x81, 0x20, 0x6c, 0xba, 0x3d, 0x3b, 0x3b, 0x9a, 0x66, 0xcc, 0x4c, 0x87, 0x52, 0x77, 0x7b,
- 0xe6, 0xba, 0x15, 0x4e, 0xa2, 0x8a, 0x47, 0xd6, 0x39, 0x6f, 0x17, 0x4b, 0xcc, 0x94, 0xf1, 0x65,
- 0x42, 0xfc, 0xdd, 0xb2, 0xbf, 0xa9, 0x68, 0x13, 0x92, 0xce, 0x51, 0x3c, 0x53, 0x23, 0x77, 0xac,
- 0x7a, 0x9a, 0xa8, 0xd9, 0x7a, 0xa7, 0x89, 0xe4, 0x65, 0x19, 0xbb, 0xd2, 0x26, 0x32, 0x71, 0x61,
- 0x8f, 0x54, 0x89, 0x2c, 0x5c, 0xa9, 0x5a, 0x8f, 0x90, 0x97, 0x65, 0xe4, 0x2d, 0x73, 0xcf, 0x2e,
- 0xcb, 0x38, 0xaa, 0x1e, 0xf1, 0x92, 0xd2, 0xd9, 0x29, 0x5d, 0xf6, 0x88, 0x97, 0x3d, 0xe2, 0xc5,
- 0x6c, 0xb6, 0xce, 0x1e, 0xf1, 0x0c, 0xed, 0xe1, 0x9b, 0x96, 0x27, 0x27, 0x99, 0x56, 0x91, 0x8a,
- 0x9b, 0x06, 0xb7, 0x9a, 0x75, 0xa7, 0x77, 0x31, 0xe8, 0xd5, 0xe2, 0x62, 0xff, 0x02, 0x34, 0xa0,
- 0x46, 0x07, 0x16, 0xb4, 0xe0, 0x47, 0x0f, 0x11, 0xf1, 0xac, 0x9a, 0xd3, 0x28, 0x48, 0xe8, 0x43,
- 0xc9, 0x5a, 0x0a, 0x20, 0x50, 0x84, 0x56, 0x0c, 0xdc, 0x84, 0x9b, 0xbb, 0x30, 0xaa, 0x48, 0xdc,
- 0xe8, 0xc6, 0x83, 0x76, 0xe5, 0xd1, 0xaf, 0x8c, 0xeb, 0xa9, 0x14, 0x3a, 0x0a, 0xf1, 0x3d, 0x95,
- 0x46, 0x4f, 0x7a, 0x2f, 0x13, 0xa0, 0xcf, 0x02, 0xa1, 0x4f, 0xfa, 0xe1, 0x70, 0x02, 0xf3, 0x38,
- 0x85, 0xcb, 0x85, 0x2c, 0x78, 0x4f, 0x81, 0xa3, 0x57, 0x06, 0x9b, 0xcb, 0x98, 0x5d, 0x3b, 0xcd,
- 0x3d, 0xf7, 0xb3, 0xb3, 0x44, 0xcd, 0x2c, 0xb8, 0x77, 0x35, 0xad, 0x0f, 0x2f, 0x81, 0xc6, 0x53,
- 0x63, 0x5e, 0xaa, 0x2a, 0x3f, 0x4d, 0xd2, 0xf1, 0x75, 0xad, 0x7b, 0x4c, 0x4d, 0x7d, 0xa6, 0xe2,
- 0xda, 0x70, 0x06, 0xbe, 0x3f, 0x42, 0x33, 0xe6, 0x68, 0x45, 0x0e, 0x70, 0x20, 0xe6, 0x58, 0x36,
- 0x28, 0x59, 0xa6, 0x2f, 0xd2, 0x21, 0x2d, 0x9c, 0x49, 0xe4, 0x33, 0x0c, 0xae, 0xd3, 0xe5, 0x9a,
- 0xfb, 0xf5, 0x4d, 0xb5, 0x4f, 0xbc, 0x9e, 0xee, 0x8a, 0x5a, 0x52, 0x0d, 0xed, 0x4e, 0x4f, 0x0c,
- 0x2b, 0xbc, 0x3b, 0x33, 0xe8, 0x68, 0x71, 0x76, 0xd6, 0xf1, 0x1b, 0x85, 0x5c, 0x82, 0x93, 0x38,
- 0x4b, 0x9e, 0x5a, 0xcb, 0xa5, 0x65, 0x5e, 0x2c, 0xf5, 0xa9, 0xfa, 0x64, 0xcf, 0x4f, 0xda, 0xf5,
- 0x53, 0xd7, 0x27, 0xcb, 0x5a, 0x4d, 0xf4, 0xe9, 0xb7, 0x0d, 0x8c, 0x9d, 0x58, 0xac, 0x22, 0x86,
- 0x08, 0x96, 0x09, 0xb6, 0x3d, 0xe3, 0xc0, 0x9a, 0x03, 0x7f, 0x97, 0xe1, 0x7e, 0x24, 0xd1, 0x51,
- 0x12, 0x9d, 0xd0, 0x43, 0x97, 0xb4, 0xb8, 0x4d, 0x8b, 0x41, 0xeb, 0xc1, 0x4c, 0x7a, 0xfc, 0x25,
- 0x9b, 0x20, 0x67, 0x41, 0xe0, 0xa0, 0x09, 0x04, 0xf9, 0xd5, 0x5f, 0xfc, 0x16, 0x66, 0x00, 0xcb,
- 0x34, 0x9e, 0x19, 0x70, 0x23, 0xdc, 0x8f, 0x24, 0x48, 0x4a, 0x82, 0x14, 0x7a, 0xe8, 0x47, 0x4e,
- 0x90, 0xb9, 0x89, 0x17, 0xe3, 0x84, 0x8a, 0x79, 0xe7, 0xf7, 0xbd, 0x49, 0xa6, 0x65, 0xc4, 0x7f,
- 0x1f, 0x6f, 0x08, 0x36, 0xdd, 0x6f, 0xaa, 0x61, 0x5a, 0xa9, 0xc7, 0x78, 0x02, 0x1c, 0x48, 0x77,
- 0x43, 0xa2, 0xe5, 0xeb, 0x92, 0x56, 0x79, 0x34, 0x56, 0x21, 0x27, 0xdf, 0x4c, 0x82, 0xa5, 0x1e,
- 0x3d, 0x16, 0x95, 0x47, 0x42, 0xe1, 0xac, 0xa3, 0xba, 0xc1, 0x87, 0x8a, 0x68, 0xa4, 0xb7, 0x49,
- 0x7a, 0x9b, 0x8e, 0xd6, 0xdb, 0x94, 0x91, 0x92, 0x18, 0x13, 0x7c, 0x71, 0x32, 0xe9, 0x04, 0xed,
- 0xe1, 0x8e, 0xd9, 0x31, 0xc5, 0xdb, 0x73, 0xb1, 0x02, 0xa9, 0x5f, 0xec, 0x2a, 0x49, 0xf6, 0x45,
- 0x97, 0xbe, 0x28, 0x16, 0x76, 0xc2, 0x77, 0xba, 0x52, 0x7a, 0x53, 0x8c, 0x28, 0x0a, 0x34, 0x51,
- 0xd6, 0x45, 0x6d, 0xf4, 0x80, 0xfc, 0xac, 0xce, 0x6d, 0xf5, 0xaa, 0x13, 0xe7, 0x65, 0xf4, 0xd1,
- 0x4c, 0x40, 0xcc, 0xff, 0xfc, 0x23, 0x98, 0x64, 0xdd, 0x60, 0x28, 0xd6, 0xaf, 0x31, 0xfa, 0xf4,
- 0x05, 0x16, 0xf8, 0x46, 0x64, 0xd3, 0x07, 0x19, 0xb6, 0xad, 0x86, 0x9a, 0xd8, 0x8b, 0xde, 0xb7,
- 0x89, 0x46, 0x0d, 0x38, 0xdd, 0x5c, 0xa5, 0x40, 0x20, 0x20, 0xaf, 0xb4, 0x93, 0x57, 0xda, 0x35,
- 0xe0, 0x50, 0xe4, 0x9d, 0x49, 0x14, 0x3a, 0xac, 0x27, 0xf9, 0x36, 0xff, 0xca, 0xbc, 0x1d, 0x29,
- 0x15, 0x4c, 0xca, 0x8a, 0x24, 0x99, 0x88, 0x2b, 0x8a, 0x24, 0xa8, 0x63, 0x7a, 0x8d, 0x51, 0xa3,
- 0xc3, 0xed, 0xa4, 0x5e, 0x5f, 0x54, 0x68, 0x7f, 0x6e, 0x20, 0x60, 0x26, 0xa5, 0x8c, 0x58, 0x50,
- 0x66, 0x20, 0xc8, 0x44, 0x5c, 0x41, 0x20, 0x41, 0xf4, 0x54, 0x63, 0xd0, 0xe7, 0x70, 0xe9, 0xa9,
- 0xbe, 0xa0, 0xce, 0xa1, 0xd0, 0xd3, 0xb6, 0xc3, 0xca, 0x71, 0x27, 0x41, 0x2f, 0x32, 0x75, 0x02,
- 0xe7, 0x96, 0x0d, 0x5b, 0x91, 0x07, 0xeb, 0x14, 0x9c, 0x9c, 0x9d, 0x64, 0x47, 0x78, 0x36, 0x0f,
- 0xe9, 0x73, 0x0c, 0xed, 0xf4, 0x33, 0x62, 0xe2, 0x3c, 0x55, 0x5c, 0x09, 0x58, 0x43, 0x5c, 0xe7,
- 0x48, 0x6e, 0x0c, 0xdc, 0x7d, 0xdc, 0xe6, 0x55, 0x36, 0x75, 0x92, 0x4d, 0x9d, 0x76, 0x59, 0xa5,
- 0x4f, 0xd0, 0x34, 0x1e, 0x2d, 0x3a, 0xde, 0x56, 0xb2, 0x42, 0xff, 0x26, 0x4b, 0x8f, 0xd4, 0x67,
- 0x33, 0x38, 0x03, 0xd8, 0x02, 0xfa, 0x9a, 0xa0, 0x40, 0x4a, 0xe8, 0x79, 0xeb, 0x3b, 0x9a, 0x92,
- 0xfd, 0x72, 0xa7, 0xd4, 0xcc, 0x1a, 0xfe, 0xea, 0xba, 0x5f, 0xe5, 0x7b, 0x77, 0xb9, 0xba, 0x60,
- 0xe5, 0xfa, 0x71, 0xcb, 0x74, 0x8f, 0xd9, 0xdf, 0x5e, 0x46, 0xb2, 0xa0, 0x8a, 0xda, 0x85, 0xba,
- 0xb9, 0x48, 0x13, 0x7a, 0xea, 0xe5, 0x14, 0xc3, 0x59, 0x91, 0xb3, 0x54, 0x56, 0x82, 0x36, 0xab,
- 0x12, 0xf4, 0xfc, 0xed, 0xe1, 0x54, 0x82, 0x92, 0x3b, 0x12, 0x61, 0x68, 0x9b, 0x85, 0x28, 0xa5,
- 0xdc, 0x5d, 0xa9, 0xff, 0xa5, 0xab, 0xff, 0xa7, 0xa9, 0xa3, 0x5f, 0xfe, 0xe3, 0x9f, 0xfe, 0xf9,
- 0x5f, 0xfe, 0xfb, 0xde, 0xd5, 0xb4, 0xde, 0xb0, 0xd5, 0x7e, 0xf9, 0xb7, 0xcb, 0xff, 0xf9, 0xff,
- 0xb3, 0xd3, 0x93, 0x87, 0x8b, 0x7f, 0x7f, 0xaf, 0x8e, 0x37, 0xa3, 0x00, 0x69, 0xd8, 0xbf, 0x2a,
- 0x95, 0x94, 0xad, 0xae, 0x6c, 0x0b, 0x5b, 0x53, 0xcb, 0x28, 0xe6, 0xaf, 0xd1, 0x48, 0x59, 0xb4,
- 0xba, 0xaf, 0x45, 0xab, 0x93, 0x05, 0xc3, 0x5d, 0x0e, 0xde, 0x60, 0x59, 0xa0, 0x2a, 0x0b, 0x54,
- 0xb3, 0x07, 0xd2, 0xb4, 0xfa, 0xc9, 0x85, 0x19, 0x5d, 0x4b, 0x97, 0xe4, 0xc2, 0x28, 0x5a, 0x01,
- 0xa5, 0xcd, 0x45, 0xb3, 0xb8, 0xcd, 0x0a, 0x05, 0xc7, 0x67, 0x50, 0x25, 0xb9, 0x71, 0x9f, 0x87,
- 0x06, 0xca, 0xd3, 0x42, 0x59, 0x2f, 0x95, 0xcc, 0x5f, 0xe4, 0x51, 0x75, 0x05, 0xd2, 0x05, 0xa0,
- 0x6c, 0x7d, 0x94, 0xf6, 0x44, 0xd0, 0xb4, 0x42, 0x4a, 0x6f, 0x8d, 0xa5, 0x35, 0x52, 0xea, 0x69,
- 0xb6, 0x56, 0x49, 0xa9, 0xc7, 0xe9, 0x5b, 0x27, 0x71, 0x42, 0x2e, 0xb6, 0x4d, 0xda, 0xd6, 0x4a,
- 0xa9, 0x47, 0x99, 0x5a, 0x2d, 0xe5, 0x31, 0xac, 0xa2, 0xd6, 0x4b, 0x0d, 0x89, 0x4f, 0xec, 0x55,
- 0xe2, 0x29, 0x68, 0x9d, 0x81, 0x4b, 0x70, 0x12, 0xc2, 0xc7, 0xbf, 0xb9, 0xfc, 0xde, 0x04, 0xad,
- 0xb3, 0xb3, 0x8e, 0x3e, 0x47, 0xaa, 0xa3, 0xcf, 0xd1, 0xdd, 0xfa, 0x83, 0x6f, 0x77, 0x5e, 0x9e,
- 0xa0, 0xd5, 0xd3, 0xb9, 0xea, 0x9a, 0x68, 0xaa, 0x3b, 0xf8, 0x64, 0xbc, 0xd5, 0x99, 0xf3, 0x24,
- 0x00, 0x15, 0xe5, 0x7b, 0x86, 0x22, 0xde, 0x03, 0x9f, 0x56, 0x66, 0xc9, 0x75, 0x9c, 0xab, 0x86,
- 0x3e, 0x81, 0x06, 0x9c, 0x09, 0xdb, 0x97, 0xc0, 0xf7, 0x19, 0xfd, 0xa7, 0x95, 0xa9, 0x8a, 0x3a,
- 0xf5, 0xe8, 0x6d, 0x42, 0xce, 0xde, 0xb6, 0x5c, 0x0c, 0x55, 0xac, 0xdb, 0x0b, 0x48, 0x78, 0x4f,
- 0xfd, 0x09, 0xcd, 0x7f, 0x35, 0x03, 0x7f, 0xe6, 0xa3, 0xef, 0xf2, 0xb4, 0xa1, 0xe3, 0x80, 0xb9,
- 0xbe, 0x44, 0x06, 0x82, 0x4e, 0x94, 0x84, 0x1b, 0xac, 0x96, 0xba, 0x89, 0xab, 0xc8, 0x88, 0x56,
- 0x15, 0x91, 0x2d, 0xa1, 0x11, 0xae, 0x4c, 0xb5, 0x82, 0xe9, 0x50, 0x65, 0xfa, 0x32, 0xb5, 0x97,
- 0x69, 0x4d, 0x63, 0x1c, 0x06, 0xc4, 0xfa, 0x49, 0x36, 0xa5, 0xbd, 0x2b, 0x95, 0x76, 0xa9, 0xb4,
- 0x97, 0x33, 0x7c, 0x4b, 0x19, 0xc0, 0x82, 0x14, 0x7e, 0x6e, 0x83, 0x38, 0xa5, 0xa5, 0x32, 0x3d,
- 0x39, 0x66, 0x5c, 0x21, 0x9b, 0xa5, 0xcc, 0x4d, 0x7c, 0x65, 0x88, 0x50, 0x1c, 0x31, 0x8a, 0x92,
- 0x8e, 0xa5, 0x89, 0x53, 0xb8, 0x38, 0x14, 0x42, 0xac, 0x9c, 0x62, 0x8b, 0xd5, 0x6e, 0x63, 0xb5,
- 0xbc, 0x05, 0x12, 0x24, 0xaf, 0x25, 0x5e, 0xce, 0x22, 0x17, 0x63, 0x99, 0x0b, 0xb2, 0xd0, 0x05,
- 0x58, 0xea, 0x9c, 0x90, 0x17, 0x60, 0xb9, 0x8b, 0xb1, 0xe0, 0xcb, 0x5a, 0xf2, 0xcd, 0x53, 0x08,
- 0x59, 0x6a, 0x23, 0x12, 0x46, 0x53, 0x09, 0xa9, 0x98, 0x78, 0x8d, 0x94, 0x3a, 0x52, 0xea, 0x1c,
- 0xb8, 0xd4, 0x41, 0x33, 0x68, 0x62, 0x84, 0x9f, 0xd9, 0x6a, 0xd7, 0x53, 0x52, 0x67, 0xc0, 0xf1,
- 0xec, 0x4d, 0x38, 0xf5, 0xb5, 0xee, 0x08, 0x70, 0x3f, 0x4c, 0x16, 0x2b, 0x35, 0x34, 0x91, 0x55,
- 0xdf, 0x44, 0x7e, 0xe6, 0xc5, 0x23, 0x3f, 0xa9, 0xc0, 0xe1, 0xd2, 0x6e, 0xf9, 0x9d, 0x85, 0x99,
- 0x7b, 0x82, 0x4f, 0x2b, 0x53, 0xe1, 0x7e, 0xd5, 0xeb, 0x69, 0xdd, 0xeb, 0xcf, 0x72, 0xfb, 0xed,
- 0xfd, 0x7e, 0x0e, 0x63, 0x1f, 0xc3, 0x03, 0x83, 0xcb, 0xf0, 0x10, 0xf6, 0x91, 0x76, 0x43, 0x1f,
- 0xc4, 0x6e, 0x0e, 0x02, 0x36, 0x71, 0x37, 0x7c, 0x89, 0x7d, 0x70, 0x3d, 0x39, 0x6e, 0x98, 0xda,
- 0x51, 0x22, 0xf8, 0x16, 0xbd, 0x83, 0x2b, 0x08, 0x57, 0x1e, 0xa6, 0x89, 0x66, 0x8f, 0x7e, 0x58,
- 0xce, 0x8f, 0x6d, 0xb5, 0xfd, 0x1a, 0xa5, 0xed, 0x8c, 0x64, 0xbf, 0x54, 0x09, 0x5c, 0x82, 0x44,
- 0x77, 0x9d, 0xe8, 0xbf, 0xe0, 0xe6, 0xbf, 0x75, 0x45, 0xed, 0xba, 0xe4, 0xaf, 0x8c, 0xf1, 0x2a,
- 0x24, 0x20, 0x93, 0xda, 0xe9, 0xc7, 0xbf, 0x7f, 0xfe, 0x03, 0x20, 0x07, 0x98, 0x16, 0x06, 0x8e,
- 0xbb, 0x5a, 0x59, 0x36, 0x86, 0x33, 0x80, 0xcc, 0x54, 0x3a, 0xba, 0x03, 0x2c, 0xfc, 0x08, 0x6d,
- 0x80, 0x1f, 0x75, 0xb3, 0x64, 0xdf, 0x47, 0x51, 0xd6, 0x41, 0x9e, 0xa5, 0x20, 0x2a, 0x72, 0x23,
- 0xdc, 0x78, 0xc8, 0x35, 0x24, 0xca, 0x41, 0xa1, 0xd4, 0x5a, 0x5e, 0x77, 0xcc, 0xae, 0x38, 0x99,
- 0xb5, 0x48, 0xa2, 0x4e, 0x04, 0x4d, 0x0f, 0x99, 0xb8, 0xe3, 0x1b, 0x95, 0x44, 0x5e, 0x37, 0x91,
- 0x8b, 0x81, 0x86, 0x24, 0x76, 0x36, 0x62, 0xcf, 0xc8, 0xde, 0x68, 0x83, 0x03, 0xa6, 0xf9, 0x4f,
- 0x7d, 0x29, 0xd1, 0x1b, 0x40, 0xec, 0x25, 0xc1, 0x20, 0xa9, 0x9c, 0x93, 0xca, 0x87, 0x31, 0x2a,
- 0x97, 0x44, 0x2e, 0x89, 0x5c, 0x12, 0xf9, 0xe1, 0x10, 0x79, 0x66, 0xa2, 0xe8, 0x41, 0x93, 0xb9,
- 0xb7, 0x57, 0xf5, 0xe6, 0xf3, 0xd3, 0xb9, 0xa4, 0xf5, 0xda, 0x69, 0x5d, 0x00, 0x2c, 0x24, 0xc1,
- 0x33, 0x13, 0xfc, 0xf0, 0x38, 0x09, 0x7e, 0x28, 0x09, 0xbe, 0x31, 0x04, 0x3f, 0x3c, 0x16, 0x82,
- 0x7f, 0x53, 0x6d, 0xe8, 0xa1, 0xae, 0x6a, 0xa0, 0xb0, 0x73, 0x11, 0x4f, 0xf6, 0x0e, 0x5d, 0x4b,
- 0xa3, 0xd4, 0x53, 0xd4, 0x2d, 0x8e, 0xd2, 0x4f, 0x96, 0x68, 0x79, 0x94, 0x7a, 0x19, 0x7d, 0x0b,
- 0xa4, 0xfc, 0x47, 0x0b, 0x5b, 0x22, 0xf1, 0x42, 0x85, 0xb1, 0x13, 0x78, 0xf4, 0x1c, 0x4b, 0xcf,
- 0x98, 0x75, 0x6b, 0x80, 0xce, 0x64, 0xb1, 0xea, 0x30, 0xe6, 0xe6, 0x03, 0xa6, 0x7e, 0x32, 0x9f,
- 0xc3, 0x99, 0x1e, 0xae, 0x17, 0xab, 0x87, 0xab, 0x39, 0xfa, 0xea, 0x4d, 0xb4, 0xcb, 0x92, 0x05,
- 0x17, 0x5b, 0xa6, 0xb5, 0xb4, 0x5c, 0x47, 0x0d, 0x3a, 0x51, 0x72, 0xd4, 0x2e, 0xa4, 0x5e, 0x21,
- 0x2b, 0x8f, 0x65, 0x11, 0x83, 0x10, 0x5a, 0xbf, 0xd5, 0xcd, 0x99, 0x8e, 0x2d, 0xfb, 0x99, 0xa1,
- 0xd6, 0xa5, 0x44, 0xb5, 0xb2, 0xa3, 0x9a, 0xee, 0x72, 0x02, 0x6d, 0x8e, 0x5a, 0x65, 0x96, 0xeb,
- 0x56, 0xbe, 0xe8, 0xa6, 0xaf, 0xfb, 0x55, 0x5e, 0x2a, 0xca, 0xd3, 0xed, 0x3c, 0x7a, 0x98, 0xb3,
- 0xeb, 0x79, 0xf4, 0x7c, 0xd9, 0x46, 0xdf, 0x1b, 0xf0, 0xf0, 0x36, 0xfc, 0x2e, 0x61, 0x90, 0x70,
- 0x75, 0x45, 0x4f, 0x1d, 0xdd, 0x79, 0x6f, 0x74, 0x3e, 0x1a, 0xbe, 0xed, 0x8d, 0x06, 0xfb, 0x7f,
- 0x86, 0x07, 0x50, 0x9e, 0xe7, 0xc7, 0xd1, 0x6c, 0x15, 0xcd, 0xd8, 0x65, 0xdc, 0xe6, 0x51, 0x29,
- 0xdb, 0xa4, 0x6c, 0xdb, 0x43, 0xd9, 0x86, 0xa2, 0x3c, 0x66, 0x9e, 0x46, 0x1c, 0x23, 0x86, 0x67,
- 0xc2, 0x35, 0xee, 0xac, 0x0f, 0x82, 0xef, 0xdc, 0x65, 0xdf, 0x5b, 0x6a, 0x8f, 0xef, 0x38, 0x9e,
- 0xa5, 0xed, 0x9c, 0x96, 0xfb, 0x82, 0x56, 0xeb, 0x4e, 0x53, 0x47, 0xe3, 0x97, 0xbb, 0xae, 0x3a,
- 0x1a, 0x07, 0x1f, 0xbb, 0xfe, 0xff, 0x82, 0xcf, 0xbd, 0x3b, 0x4d, 0x3d, 0x5f, 0x7f, 0x1e, 0xdc,
- 0x69, 0xea, 0x60, 0xdc, 0xbe, 0xbf, 0x3f, 0x6b, 0xff, 0xec, 0xbf, 0xb2, 0x3f, 0xa8, 0x54, 0x6d,
- 0xa6, 0x9f, 0xee, 0x10, 0xe4, 0xc3, 0x3d, 0x06, 0xf9, 0xc5, 0x8b, 0x07, 0x18, 0x5d, 0x9d, 0x5f,
- 0xa9, 0xbf, 0x8d, 0x7f, 0x6a, 0xa7, 0xe7, 0xaf, 0xed, 0x8b, 0x76, 0x6b, 0xfb, 0xbb, 0x8b, 0xf6,
- 0x4f, 0xed, 0x74, 0xf0, 0xda, 0x6a, 0x65, 0xfc, 0xf2, 0x3e, 0xeb, 0x1d, 0xed, 0x97, 0x56, 0xab,
- 0x15, 0x02, 0x3b, 0x81, 0x00, 0x77, 0x5a, 0x77, 0xfc, 0xde, 0xff, 0x18, 0xfc, 0x8d, 0x50, 0x88,
- 0x6a, 0x70, 0xbb, 0x7a, 0xc4, 0xd9, 0xb3, 0xbb, 0xc8, 0x9a, 0x78, 0x85, 0x8b, 0x69, 0xe1, 0x16,
- 0xb5, 0x6f, 0x3b, 0xe1, 0xd5, 0xbe, 0x57, 0xc2, 0x2b, 0x39, 0xee, 0x95, 0x1a, 0x2e, 0x96, 0xb8,
- 0xfe, 0xfd, 0x73, 0xd4, 0x45, 0xdd, 0x77, 0xea, 0xac, 0x7d, 0xa6, 0x2b, 0xcb, 0x71, 0xd0, 0xc4,
- 0x80, 0x34, 0x97, 0x89, 0x00, 0xd9, 0xc3, 0x3e, 0x54, 0x6d, 0x04, 0x1d, 0xe7, 0xe1, 0x5e, 0x26,
- 0x51, 0x70, 0xcf, 0x3e, 0x6d, 0xe3, 0xf3, 0x0a, 0xa8, 0x20, 0x19, 0x28, 0xf0, 0xef, 0x1f, 0xc8,
- 0x05, 0x14, 0x43, 0xff, 0xf3, 0xe3, 0xc0, 0x79, 0xe6, 0xc3, 0x6b, 0xfa, 0xd5, 0x0c, 0x14, 0xe6,
- 0xec, 0xca, 0x86, 0x0e, 0x34, 0xa7, 0xb0, 0x4a, 0xb1, 0xf2, 0x61, 0x7d, 0xc1, 0x05, 0xb8, 0xfe,
- 0xfd, 0xf3, 0xee, 0x2d, 0xc5, 0x60, 0x7f, 0x75, 0xda, 0x8a, 0xc9, 0x03, 0xd8, 0xb3, 0xbb, 0xe6,
- 0xaa, 0xbc, 0x34, 0x35, 0x1e, 0x22, 0x11, 0x7a, 0x53, 0x6a, 0x3c, 0x22, 0xa2, 0xec, 0xe4, 0x86,
- 0x92, 0x2a, 0x6e, 0x1d, 0x28, 0x68, 0x2e, 0xcd, 0x77, 0x24, 0x65, 0xee, 0x1c, 0xc0, 0x24, 0xd7,
- 0x41, 0x44, 0xef, 0xfe, 0xa8, 0xbc, 0x6e, 0xcc, 0x14, 0x0d, 0x7a, 0x14, 0x62, 0x00, 0x7b, 0x2c,
- 0x6f, 0x33, 0xd8, 0xfb, 0xdb, 0x0c, 0xe8, 0x4a, 0xfb, 0x69, 0x4a, 0xf8, 0xd9, 0x4a, 0xf5, 0x37,
- 0x96, 0x0e, 0x52, 0x09, 0x58, 0x9a, 0xf4, 0xc1, 0xd3, 0xd5, 0xdb, 0x33, 0xfa, 0x82, 0xa9, 0x73,
- 0x34, 0x28, 0x14, 0x59, 0xc6, 0xa9, 0xe9, 0x54, 0x17, 0xf1, 0xf3, 0xa2, 0x15, 0xdd, 0x9d, 0x8d,
- 0xe2, 0x67, 0xa6, 0xbe, 0x2e, 0x92, 0x2c, 0x4b, 0xc7, 0xac, 0x74, 0xf2, 0x86, 0xfc, 0xcd, 0xd6,
- 0x46, 0x09, 0x97, 0x5c, 0x91, 0x33, 0x41, 0x8a, 0x33, 0x3e, 0xb8, 0x32, 0x3b, 0x28, 0x32, 0x38,
- 0x28, 0x32, 0x35, 0xb6, 0x37, 0x59, 0x20, 0x27, 0x59, 0xe4, 0x63, 0x06, 0xf5, 0x52, 0x8b, 0xc3,
- 0x24, 0x2e, 0x6c, 0xe0, 0x12, 0x5b, 0xae, 0xb2, 0x0a, 0xbc, 0x74, 0x18, 0x3a, 0xe9, 0xe6, 0x49,
- 0x9b, 0x0b, 0x20, 0x62, 0x83, 0xb6, 0xe1, 0x99, 0x29, 0x91, 0x72, 0x25, 0x11, 0x49, 0x02, 0x65,
- 0x49, 0x9e, 0xac, 0xed, 0x17, 0x88, 0x1b, 0x6a, 0x31, 0x43, 0x2d, 0x5e, 0xf2, 0xc4, 0x8a, 0xc2,
- 0x88, 0xfb, 0xb9, 0xb2, 0x63, 0xb3, 0xf3, 0xa0, 0x93, 0x57, 0xc6, 0xa6, 0x09, 0x9e, 0xd8, 0xa2,
- 0x8b, 0x6e, 0xc8, 0x37, 0xc5, 0x15, 0xcb, 0x93, 0x75, 0x90, 0xb6, 0x20, 0x72, 0xcf, 0x1c, 0x83,
- 0xa5, 0x8f, 0xb5, 0xbe, 0x92, 0xaf, 0xb0, 0xa3, 0xdf, 0x42, 0x57, 0xab, 0x6f, 0x0f, 0x94, 0xec,
- 0x33, 0x43, 0xf5, 0x2b, 0x74, 0xa5, 0x2b, 0x8f, 0xba, 0x61, 0x58, 0x20, 0xe6, 0xe8, 0xce, 0xb8,
- 0x33, 0x66, 0x4c, 0xc1, 0x0d, 0x6c, 0xdd, 0x5c, 0x40, 0x8f, 0xcc, 0x3f, 0x41, 0x7d, 0x6e, 0x20,
- 0x12, 0x4f, 0x48, 0x0f, 0x95, 0x9c, 0xa1, 0x42, 0xce, 0xe0, 0x22, 0x13, 0xf7, 0x7b, 0x04, 0xce,
- 0x90, 0x41, 0x9d, 0x05, 0xf9, 0x33, 0xa2, 0xf8, 0x42, 0x9d, 0x44, 0x25, 0x8a, 0x31, 0xf4, 0xb5,
- 0xc6, 0x71, 0x86, 0xd3, 0x4a, 0x81, 0x36, 0xd0, 0xb4, 0x03, 0x00, 0xdb, 0x40, 0xeb, 0x1d, 0x19,
- 0xdc, 0x46, 0xa3, 0xd1, 0x68, 0xff, 0xe1, 0x56, 0xef, 0x2e, 0x68, 0x25, 0x31, 0x91, 0x65, 0xef,
- 0xb1, 0xb5, 0x42, 0x16, 0xfd, 0x0e, 0x5a, 0x98, 0x70, 0x46, 0x21, 0xf8, 0xc3, 0x81, 0x52, 0xec,
- 0x57, 0x28, 0xf6, 0x8b, 0xa4, 0x7e, 0xbf, 0x36, 0xa9, 0xdf, 0xaf, 0x56, 0x80, 0x78, 0x87, 0x5f,
- 0x3d, 0x1f, 0x1a, 0xd6, 0xb7, 0x85, 0x7a, 0x84, 0xfe, 0xde, 0x43, 0x6c, 0x70, 0x5c, 0x10, 0xeb,
- 0xf7, 0xf6, 0x1e, 0x62, 0xdd, 0xa3, 0x02, 0x98, 0x34, 0x86, 0x6a, 0x51, 0xce, 0xc8, 0x2a, 0x8d,
- 0x6b, 0x52, 0x2b, 0x35, 0xd1, 0x50, 0xa9, 0xd6, 0x48, 0x6f, 0x86, 0x24, 0x60, 0xe9, 0xcd, 0x90,
- 0xde, 0x0c, 0xe9, 0xcd, 0x38, 0x40, 0x6f, 0xc6, 0x9b, 0xe4, 0xa7, 0xf0, 0x2c, 0xf2, 0x22, 0x97,
- 0x0a, 0x72, 0x7e, 0xd3, 0xbf, 0xc1, 0x2f, 0x96, 0x95, 0x96, 0x20, 0xdb, 0xd1, 0x4c, 0x25, 0xfe,
- 0x53, 0x22, 0x52, 0xf9, 0x2b, 0x7c, 0x42, 0xeb, 0xa8, 0xe4, 0xeb, 0x9b, 0xd7, 0x7f, 0x00, 0x00,
- 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0xd9, 0x32, 0x70, 0x53, 0x74, 0x73, 0x01, 0x00,
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x3d, 0x6b, 0x73, 0xda, 0xc8,
+ 0x96, 0xdf, 0xf3, 0x2b, 0x7a, 0xb4, 0xbb, 0x65, 0xd8, 0xb5, 0x8c, 0x00, 0x43, 0x82, 0xb7, 0x5c,
+ 0x59, 0x3b, 0x93, 0x99, 0x75, 0xdd, 0x78, 0x6e, 0x2a, 0x99, 0x7b, 0x3f, 0xac, 0xcd, 0x7a, 0x05,
+ 0x34, 0xb8, 0x2b, 0x20, 0xb1, 0x52, 0xcb, 0x89, 0x37, 0xf6, 0xfe, 0xf6, 0x5b, 0x7a, 0x20, 0x24,
+ 0x24, 0xb5, 0xba, 0x5b, 0x2d, 0x24, 0x41, 0x57, 0x4d, 0x79, 0x08, 0x1c, 0xa9, 0x1f, 0xe7, 0xfd,
+ 0xe8, 0xd3, 0x3f, 0xdf, 0x00, 0x00, 0x80, 0xf2, 0x87, 0xbe, 0x82, 0xca, 0x05, 0x50, 0x66, 0xf0,
+ 0x09, 0x4d, 0xa1, 0x72, 0xea, 0x7f, 0xfb, 0x17, 0x64, 0xcc, 0x94, 0x0b, 0xd0, 0x0d, 0xfe, 0xf9,
+ 0xc1, 0x34, 0xe6, 0x68, 0xa1, 0x5c, 0x00, 0x2d, 0xf8, 0xe2, 0x57, 0x64, 0x29, 0x17, 0xc0, 0x7f,
+ 0x85, 0xf7, 0xc5, 0xf4, 0xd1, 0x44, 0x53, 0x68, 0xc7, 0xbe, 0x8c, 0xbd, 0x7f, 0x03, 0x70, 0x1a,
+ 0xff, 0x39, 0x3e, 0x50, 0xf8, 0xf5, 0xee, 0x80, 0xe1, 0x0f, 0x9f, 0x2d, 0x38, 0x47, 0x3f, 0x12,
+ 0xc3, 0xc4, 0x86, 0xb2, 0x67, 0x53, 0x64, 0x3e, 0xac, 0xcc, 0x19, 0x5c, 0x3e, 0xf8, 0xc3, 0xee,
+ 0x8c, 0xea, 0x41, 0x7f, 0x35, 0x1d, 0x6b, 0x0a, 0x53, 0xdf, 0xe4, 0xcf, 0x0c, 0x3e, 0x7f, 0x37,
+ 0x2d, 0x77, 0x72, 0xca, 0xda, 0x1f, 0xf4, 0x34, 0x1d, 0xf0, 0x3f, 0x75, 0xfb, 0xca, 0x5a, 0x38,
+ 0x2b, 0x68, 0x60, 0xe5, 0x02, 0x60, 0xcb, 0x81, 0x19, 0x80, 0x11, 0xa8, 0xb4, 0x39, 0x26, 0x1e,
+ 0x7a, 0x8d, 0x7d, 0xf3, 0xba, 0xb3, 0x13, 0xbb, 0x28, 0xd8, 0x41, 0xc5, 0x54, 0xb7, 0x09, 0x8b,
+ 0x8b, 0x63, 0xc5, 0x83, 0xcd, 0x98, 0x74, 0x80, 0xa0, 0x41, 0xc6, 0xcf, 0x59, 0x88, 0xa2, 0x41,
+ 0x18, 0x1f, 0xe2, 0x68, 0x11, 0xc8, 0x8c, 0x48, 0x66, 0x84, 0x72, 0x23, 0x36, 0x1d, 0xc1, 0x19,
+ 0x88, 0xce, 0x45, 0xf8, 0x16, 0xf1, 0xba, 0x0d, 0xbb, 0xf9, 0xfb, 0x11, 0xe2, 0xde, 0x03, 0xcf,
+ 0x59, 0x5a, 0x80, 0xfe, 0xf3, 0x1c, 0xb0, 0x3c, 0x32, 0x60, 0x21, 0x87, 0x62, 0x64, 0xc1, 0x4a,
+ 0x1e, 0xdc, 0x64, 0xc2, 0x4d, 0x2e, 0x85, 0xc9, 0x86, 0x4c, 0x3e, 0x39, 0x64, 0x44, 0x4d, 0x4e,
+ 0x8c, 0x64, 0xc5, 0x45, 0x5e, 0x39, 0x6a, 0xa0, 0x30, 0xb9, 0xf1, 0x90, 0x9d, 0x18, 0xf2, 0xe3,
+ 0x25, 0xc3, 0xc2, 0xe4, 0x58, 0x98, 0x2c, 0x85, 0x91, 0x27, 0x1d, 0x99, 0x52, 0x92, 0x2b, 0x33,
+ 0xd9, 0xc6, 0xc8, 0x57, 0x85, 0x4b, 0xb8, 0x62, 0xc7, 0x41, 0x94, 0x94, 0xfd, 0x57, 0x30, 0x6e,
+ 0x21, 0x1b, 0x59, 0x73, 0x93, 0x77, 0x11, 0x32, 0x17, 0x4b, 0xee, 0x45, 0xc9, 0x5e, 0x18, 0xf9,
+ 0x0b, 0x63, 0x03, 0xe1, 0xec, 0xc0, 0xc6, 0x16, 0x8c, 0xec, 0xc1, 0xcd, 0x26, 0xe1, 0x83, 0x5c,
+ 0x9c, 0x92, 0x20, 0x22, 0x0e, 0x66, 0xd9, 0x65, 0x1a, 0x8d, 0xf3, 0x71, 0x5e, 0xe6, 0x11, 0xc1,
+ 0x44, 0xe5, 0x30, 0x93, 0x28, 0xa6, 0x12, 0xce, 0x5c, 0xc2, 0x99, 0xac, 0x34, 0x66, 0xe3, 0x63,
+ 0x3a, 0x4e, 0xe6, 0x0b, 0x57, 0xf1, 0xe7, 0xf3, 0x1a, 0x0a, 0xa2, 0x23, 0x6c, 0x21, 0x63, 0x51,
+ 0x84, 0x76, 0x36, 0xaa, 0xe8, 0xdd, 0x9b, 0xfd, 0xec, 0x5b, 0xb9, 0xe2, 0xed, 0xca, 0x30, 0x4c,
+ 0xac, 0x63, 0x64, 0x1a, 0x7c, 0x52, 0xce, 0x9e, 0x3e, 0xc2, 0x95, 0xbe, 0xd6, 0xf1, 0xa3, 0xbb,
+ 0xbb, 0x9d, 0x08, 0x89, 0x75, 0x82, 0x40, 0x45, 0x67, 0xeb, 0x1a, 0x77, 0x3c, 0x53, 0x36, 0xf2,
+ 0x57, 0xe5, 0x14, 0x6f, 0x2e, 0x1a, 0x9d, 0x29, 0x36, 0x02, 0xa4, 0x7e, 0x75, 0x47, 0xbd, 0xf5,
+ 0xe8, 0xfa, 0x83, 0x3f, 0xe8, 0xc3, 0x07, 0x77, 0x0c, 0xef, 0xef, 0x47, 0x77, 0x88, 0x37, 0xe5,
+ 0xec, 0x38, 0xc3, 0x6e, 0x2b, 0x4b, 0x73, 0xc1, 0x6f, 0x38, 0xb9, 0x0f, 0xb3, 0x2a, 0x2e, 0x38,
+ 0xd7, 0x9d, 0xa5, 0xcb, 0xf8, 0x77, 0xec, 0xfb, 0x3b, 0xd7, 0x97, 0x36, 0xa3, 0x74, 0x18, 0xf3,
+ 0x99, 0x74, 0x9a, 0x34, 0xe9, 0xa4, 0x49, 0xb7, 0x5f, 0x99, 0xc7, 0xad, 0x4d, 0x42, 0x3a, 0x98,
+ 0x98, 0xe6, 0x12, 0xea, 0x06, 0x0f, 0xf2, 0x37, 0xea, 0xa3, 0x5b, 0x96, 0x48, 0x12, 0xea, 0x24,
+ 0xc2, 0x1f, 0xd8, 0xd2, 0x55, 0xc7, 0xb0, 0xb1, 0x3e, 0x59, 0xb2, 0x6d, 0x9a, 0x4b, 0x9b, 0x36,
+ 0x34, 0x3c, 0x42, 0x67, 0x93, 0x40, 0x05, 0x10, 0xe3, 0xa9, 0x16, 0x80, 0x6c, 0xa0, 0x4f, 0x31,
+ 0x7a, 0xaa, 0x01, 0x77, 0xfa, 0x3b, 0x50, 0x27, 0xfe, 0xdc, 0xdd, 0xa2, 0xb2, 0x99, 0x93, 0x1a,
+ 0x7a, 0x2c, 0x94, 0x72, 0x39, 0x0d, 0x1b, 0x7e, 0x83, 0x86, 0x25, 0x96, 0x45, 0x67, 0xbe, 0xd0,
+ 0xa1, 0xe6, 0xb5, 0xe4, 0xf0, 0x26, 0xe3, 0x46, 0xf2, 0x6c, 0x20, 0x79, 0xa1, 0xd9, 0xd3, 0x27,
+ 0x4c, 0xdd, 0x23, 0xf3, 0x1e, 0x5b, 0x0c, 0xbf, 0x27, 0x63, 0xf8, 0x45, 0x4d, 0x8c, 0xa3, 0x88,
+ 0xe1, 0xf7, 0xf8, 0x62, 0xf8, 0x3d, 0x19, 0xc3, 0x97, 0x31, 0xfc, 0x8a, 0x63, 0xf8, 0xd2, 0x09,
+ 0x95, 0x4e, 0xa8, 0x74, 0x42, 0xa5, 0x13, 0x2a, 0x9d, 0x50, 0xe9, 0x84, 0x4a, 0x27, 0xf4, 0x80,
+ 0x9c, 0xd0, 0x5e, 0x87, 0xc5, 0xc4, 0xa4, 0x77, 0x42, 0x7b, 0xc7, 0xe2, 0x84, 0xf6, 0xb8, 0x9d,
+ 0x50, 0xa6, 0xda, 0x33, 0xca, 0x85, 0xb0, 0x2d, 0x20, 0x7d, 0xea, 0xaf, 0x8c, 0x75, 0x90, 0x39,
+ 0x53, 0xa3, 0x98, 0x52, 0x5a, 0x75, 0x68, 0x1e, 0x95, 0xc5, 0xe7, 0xbe, 0x9d, 0x61, 0x64, 0x76,
+ 0xca, 0xcc, 0x74, 0x26, 0x4b, 0xf8, 0x0d, 0x3e, 0x67, 0x57, 0xc5, 0x6e, 0x41, 0xf6, 0x5c, 0x17,
+ 0x9b, 0x35, 0x30, 0xa8, 0x57, 0x69, 0xec, 0x76, 0x9a, 0xc2, 0xaa, 0x63, 0x4d, 0x6f, 0x94, 0xbc,
+ 0xba, 0x58, 0x17, 0x8a, 0x5c, 0x11, 0xdb, 0xdd, 0x77, 0x45, 0x2c, 0x09, 0x65, 0xac, 0x1a, 0xb8,
+ 0xc2, 0xa2, 0x58, 0x02, 0x4a, 0xf9, 0x64, 0x53, 0x6e, 0x5d, 0xec, 0x93, 0xbe, 0x74, 0x58, 0x0a,
+ 0x63, 0x03, 0x78, 0xba, 0xa8, 0x9a, 0x56, 0x97, 0xa8, 0x1a, 0x0d, 0x79, 0x1c, 0x40, 0x60, 0x8d,
+ 0x82, 0x7c, 0xc4, 0xe8, 0x6e, 0x6a, 0x4f, 0x87, 0xbd, 0x48, 0x83, 0xb2, 0x18, 0x83, 0x2f, 0x82,
+ 0xec, 0x51, 0x6f, 0x8f, 0x91, 0xda, 0x7b, 0x92, 0xda, 0x25, 0xb5, 0xd7, 0x96, 0xda, 0xf7, 0x6d,
+ 0xaa, 0x86, 0xbb, 0xde, 0x21, 0xd8, 0x01, 0x64, 0x33, 0xf1, 0xd7, 0xcd, 0x2b, 0x1e, 0x3e, 0xb8,
+ 0xaf, 0xa0, 0xb5, 0x74, 0x53, 0x8c, 0xb1, 0x6f, 0xf0, 0xb9, 0x9b, 0x6f, 0xb0, 0x78, 0x50, 0x64,
+ 0x83, 0x45, 0x93, 0x06, 0x4b, 0x3d, 0x0c, 0x96, 0x5c, 0x5e, 0xa3, 0xe7, 0xb1, 0x1c, 0xde, 0xa2,
+ 0xa6, 0xb0, 0x1e, 0x15, 0x85, 0xf5, 0x24, 0x85, 0x49, 0x0a, 0xe3, 0xa1, 0xb0, 0x95, 0x6e, 0xcc,
+ 0x74, 0x6c, 0xe6, 0x13, 0xd9, 0x06, 0x50, 0xd2, 0x59, 0x23, 0xe8, 0xec, 0xd6, 0x47, 0x97, 0xf5,
+ 0x4c, 0xf0, 0x87, 0x2b, 0xa5, 0x45, 0x62, 0x8c, 0xe0, 0x2f, 0x5e, 0x64, 0xc6, 0x53, 0x9d, 0x20,
+ 0x45, 0xba, 0x29, 0x9f, 0x90, 0x8d, 0xaf, 0x30, 0xce, 0x08, 0x24, 0xdc, 0x22, 0xe3, 0xe3, 0x12,
+ 0xba, 0xdb, 0x6c, 0xa7, 0x53, 0x9c, 0x72, 0xab, 0xff, 0x88, 0x40, 0x74, 0xdf, 0x9d, 0x9f, 0x0f,
+ 0xdf, 0x9e, 0x9f, 0x6b, 0x6f, 0xfb, 0x6f, 0xb5, 0xd1, 0x60, 0xd0, 0x1d, 0x76, 0x53, 0x0e, 0xd5,
+ 0x2a, 0x7f, 0xb5, 0x66, 0xd0, 0x82, 0xb3, 0x6b, 0x77, 0x6a, 0x86, 0xb3, 0x5c, 0x92, 0x40, 0xfe,
+ 0x66, 0x43, 0x77, 0x72, 0x5e, 0xc2, 0xb1, 0xac, 0x18, 0x19, 0x31, 0x50, 0x94, 0x6f, 0xfe, 0xd0,
+ 0xc4, 0xc9, 0xe0, 0x6a, 0x8d, 0x9f, 0xa7, 0xa6, 0x31, 0xcf, 0x8e, 0x93, 0x6d, 0x41, 0xd2, 0xe3,
+ 0x64, 0x5a, 0x49, 0x71, 0xb2, 0x5a, 0x47, 0xc7, 0x58, 0x63, 0x62, 0x99, 0x9c, 0x18, 0xdf, 0xe6,
+ 0xb4, 0x35, 0x6f, 0x18, 0xaf, 0x4f, 0x81, 0x4e, 0x34, 0x83, 0x06, 0x46, 0xf8, 0xd9, 0x82, 0x04,
+ 0x84, 0x46, 0x81, 0xf6, 0x16, 0xfa, 0xdc, 0x0c, 0x5a, 0x57, 0xac, 0x86, 0xf3, 0x13, 0x16, 0xec,
+ 0xb4, 0x9e, 0xd7, 0xd8, 0xbc, 0xa2, 0x88, 0x77, 0x06, 0x80, 0xb5, 0xd1, 0xbb, 0x04, 0x54, 0x35,
+ 0x42, 0xe1, 0x66, 0xa3, 0xb2, 0x6c, 0x8b, 0x2e, 0x9b, 0xb3, 0x52, 0xb9, 0x6c, 0x40, 0x80, 0xb9,
+ 0x09, 0x5e, 0x75, 0x4d, 0xea, 0x25, 0x91, 0x41, 0x4b, 0xaa, 0xbe, 0xcc, 0x0b, 0x0e, 0x28, 0x7f,
+ 0xd7, 0x97, 0x8e, 0xd7, 0x33, 0x24, 0x3f, 0xc7, 0xcd, 0x58, 0xb8, 0x36, 0xdb, 0xcd, 0xd0, 0x70,
+ 0xa6, 0x43, 0xd9, 0x87, 0xed, 0x57, 0x31, 0xae, 0x89, 0x1f, 0xa1, 0x75, 0xb5, 0x5c, 0x98, 0x55,
+ 0x0c, 0x6e, 0xd9, 0x7a, 0xd1, 0xe8, 0xd4, 0x98, 0x95, 0x4b, 0xa8, 0xbc, 0x0e, 0x9f, 0x10, 0xaf,
+ 0x69, 0xa5, 0xdf, 0xb5, 0x94, 0x7e, 0x52, 0xfa, 0x49, 0xe9, 0x27, 0xa5, 0x5f, 0x03, 0xa5, 0x5f,
+ 0x59, 0xde, 0x1f, 0x99, 0x9d, 0xb2, 0xfd, 0xbf, 0x9b, 0xc8, 0x73, 0x34, 0x2e, 0x83, 0x81, 0xa1,
+ 0x35, 0xd7, 0x53, 0xc4, 0xd9, 0x96, 0xb1, 0x43, 0x90, 0x3d, 0x57, 0x4a, 0xa0, 0x79, 0xbd, 0x4b,
+ 0x24, 0xd0, 0x5c, 0x98, 0xbb, 0xa0, 0xcf, 0x56, 0xc8, 0x50, 0x6d, 0xac, 0x63, 0x8a, 0xd6, 0x61,
+ 0x51, 0xe0, 0xac, 0xcc, 0x3c, 0x45, 0x19, 0xb5, 0x02, 0x0d, 0xaf, 0x3c, 0x32, 0x15, 0x60, 0x5c,
+ 0xb3, 0x38, 0x20, 0x9a, 0x37, 0x3b, 0x00, 0x98, 0x46, 0x2b, 0x65, 0x6b, 0xe4, 0x7c, 0x3a, 0x89,
+ 0xb1, 0x31, 0xe1, 0x94, 0x92, 0xf2, 0xd1, 0x70, 0xf2, 0x7b, 0x93, 0x28, 0x7f, 0x9a, 0x5f, 0xfd,
+ 0x40, 0x22, 0x55, 0x3a, 0xb3, 0xeb, 0xc5, 0x3d, 0x7c, 0x1a, 0xa4, 0xc8, 0x65, 0xf6, 0x3c, 0x45,
+ 0x87, 0xec, 0x6c, 0x9a, 0xa5, 0xce, 0xb8, 0x9a, 0x37, 0x84, 0x4a, 0xa4, 0x18, 0xe8, 0x66, 0xbc,
+ 0x0b, 0xd0, 0xa3, 0x98, 0x62, 0xb0, 0x98, 0x0b, 0xd0, 0xdd, 0x4b, 0xbe, 0x95, 0xa1, 0xcc, 0x59,
+ 0x59, 0x39, 0x76, 0xfe, 0xa1, 0x0a, 0x86, 0x1c, 0x74, 0xab, 0x75, 0x06, 0x2e, 0xc1, 0x89, 0xbf,
+ 0xe2, 0x93, 0x36, 0xd0, 0x8d, 0x19, 0xb0, 0xb1, 0x6e, 0x61, 0x5b, 0xfd, 0x8e, 0xf0, 0x63, 0xeb,
+ 0xec, 0xac, 0xe3, 0x2a, 0xa7, 0x53, 0x70, 0x62, 0x3f, 0xdb, 0x18, 0xae, 0xb4, 0x93, 0x76, 0x1b,
+ 0x98, 0x16, 0x30, 0x4c, 0xdc, 0xca, 0x83, 0xa3, 0xa1, 0x86, 0x8f, 0x96, 0x65, 0x5a, 0xb7, 0xd0,
+ 0xb6, 0xf5, 0x05, 0x64, 0x3f, 0x5d, 0x15, 0xe1, 0x0c, 0xe0, 0xee, 0x0c, 0x98, 0x40, 0x40, 0x4d,
+ 0x89, 0x80, 0xb3, 0xde, 0x3a, 0x2a, 0x7d, 0xa0, 0x3b, 0x7d, 0x75, 0x15, 0xcc, 0x9f, 0xa1, 0x06,
+ 0xb7, 0x48, 0x71, 0x75, 0x4c, 0x38, 0x11, 0xb6, 0x60, 0x3f, 0x05, 0xbc, 0x99, 0xbf, 0x12, 0x8e,
+ 0xe4, 0x28, 0x16, 0x9c, 0x43, 0x8b, 0xaa, 0x3c, 0x9f, 0x81, 0x96, 0xbf, 0xfc, 0xf6, 0x01, 0xf4,
+ 0xde, 0x0d, 0xfb, 0x17, 0xe0, 0xcf, 0x47, 0x08, 0x6e, 0x36, 0xe6, 0x8e, 0x0d, 0x7e, 0xb7, 0x4c,
+ 0x67, 0x0d, 0x6e, 0x6f, 0xae, 0x81, 0x0a, 0xd0, 0xfc, 0xca, 0xdd, 0xb1, 0xaf, 0x58, 0xc7, 0x8e,
+ 0x5d, 0x72, 0xe9, 0xcb, 0x76, 0x95, 0xfb, 0xac, 0x7e, 0xe1, 0xd8, 0x86, 0xf2, 0x68, 0xa0, 0x40,
+ 0xf0, 0x61, 0x06, 0xed, 0xa9, 0x85, 0xd6, 0xc4, 0x3a, 0x94, 0xa8, 0xe7, 0x14, 0x02, 0x4b, 0x93,
+ 0xa7, 0xf1, 0x26, 0x4f, 0x3e, 0x3a, 0xe3, 0xd9, 0x4c, 0x02, 0xcc, 0x27, 0x68, 0x2c, 0x3c, 0xbf,
+ 0xac, 0xb0, 0x9c, 0xb9, 0x45, 0xf4, 0xa7, 0x39, 0xfc, 0xd8, 0x04, 0xc3, 0x61, 0xde, 0xdf, 0x2c,
+ 0x7d, 0xea, 0x2e, 0xf7, 0x57, 0xb4, 0x40, 0x59, 0xf9, 0xd0, 0xf4, 0x2d, 0x83, 0x0b, 0xdd, 0x3b,
+ 0x4a, 0x93, 0x96, 0xc6, 0xe4, 0xf4, 0xe0, 0x95, 0x5b, 0xfd, 0x07, 0xfb, 0x52, 0x7b, 0x83, 0x41,
+ 0xfd, 0x16, 0x5b, 0x81, 0xe0, 0x0a, 0x1d, 0x6d, 0x15, 0x93, 0x08, 0x3e, 0xe9, 0x98, 0xfb, 0xf0,
+ 0x52, 0x7c, 0x35, 0x5e, 0x7c, 0xed, 0xa9, 0x26, 0x08, 0x3b, 0x14, 0xf5, 0x40, 0xd8, 0x91, 0x14,
+ 0xd5, 0x7c, 0x8a, 0x72, 0x90, 0x81, 0xbb, 0x43, 0x0a, 0x8a, 0x1a, 0x12, 0x40, 0xbe, 0xe8, 0xc6,
+ 0x02, 0x56, 0xa6, 0x09, 0xb5, 0xe3, 0xd1, 0x84, 0xc3, 0xc1, 0xa0, 0x2f, 0x75, 0xa1, 0x3b, 0xc9,
+ 0x20, 0xb2, 0x9d, 0x23, 0xa4, 0x3c, 0x28, 0x29, 0xa5, 0x1a, 0x2f, 0xa5, 0xb6, 0x96, 0x0c, 0x01,
+ 0xa3, 0x4d, 0xb1, 0xdc, 0xfb, 0x47, 0x64, 0xb9, 0x6b, 0x87, 0x23, 0xac, 0x08, 0x04, 0xf5, 0x59,
+ 0xc7, 0x18, 0x5a, 0x46, 0x2e, 0x45, 0x29, 0xad, 0xd5, 0x62, 0x85, 0xb5, 0x97, 0x20, 0x94, 0xf9,
+ 0xb2, 0x34, 0x5b, 0xda, 0x4b, 0xf7, 0x4e, 0x53, 0x47, 0x63, 0xef, 0xcf, 0x4b, 0xaf, 0x75, 0xa7,
+ 0xa9, 0xe7, 0xc1, 0x3f, 0x06, 0x77, 0x9a, 0x3a, 0x18, 0xb7, 0x5f, 0xee, 0xba, 0xe1, 0xef, 0xde,
+ 0xc7, 0xf6, 0x0b, 0xc4, 0x8f, 0xd0, 0x32, 0x20, 0x56, 0x5b, 0xde, 0x17, 0xad, 0xfb, 0xfb, 0x59,
+ 0xfb, 0xa7, 0x76, 0xda, 0x7d, 0x6d, 0x75, 0xee, 0xf4, 0xc9, 0x74, 0x36, 0x6e, 0xbf, 0x6f, 0x75,
+ 0x76, 0x7e, 0x6a, 0xbf, 0xef, 0xb4, 0x76, 0xc1, 0xdb, 0x2f, 0x2d, 0x77, 0xf4, 0xee, 0xd8, 0xfd,
+ 0xe6, 0xa5, 0xd5, 0xed, 0xdd, 0x69, 0xea, 0xbb, 0x71, 0xbb, 0xdd, 0x7e, 0x41, 0xd6, 0x84, 0x6f,
+ 0x6a, 0x4b, 0x7d, 0xb1, 0x33, 0x4c, 0xcf, 0x1b, 0x46, 0xd3, 0xb4, 0x76, 0xbb, 0xad, 0x94, 0xa2,
+ 0x0b, 0x6c, 0x67, 0x92, 0x9d, 0xa6, 0x4c, 0xca, 0xe2, 0x28, 0x74, 0xcd, 0x0e, 0x12, 0x4b, 0xdd,
+ 0xb0, 0x19, 0x21, 0xf7, 0xe8, 0x30, 0x4d, 0x46, 0x94, 0x33, 0xe3, 0x05, 0x58, 0x1b, 0x4d, 0x29,
+ 0x34, 0x81, 0xf1, 0x71, 0xc3, 0xce, 0x71, 0x12, 0x69, 0x51, 0x44, 0x14, 0xbb, 0xe2, 0x03, 0x9c,
+ 0x24, 0x5a, 0xa5, 0x54, 0x16, 0xc2, 0x4f, 0x6e, 0xd2, 0xd3, 0x27, 0xa0, 0xcc, 0xcc, 0x6e, 0x13,
+ 0x62, 0x34, 0x19, 0xda, 0xed, 0xd4, 0x59, 0x32, 0xb5, 0xe1, 0x53, 0x6c, 0x19, 0xdb, 0xf0, 0x31,
+ 0xfa, 0xcc, 0x2d, 0x83, 0xc1, 0x02, 0xd8, 0x32, 0xb9, 0xdb, 0xec, 0x00, 0x4b, 0x46, 0x77, 0x57,
+ 0x00, 0xe4, 0x65, 0x76, 0x85, 0x25, 0xc7, 0x72, 0x28, 0x8f, 0xa3, 0xc1, 0x15, 0x5d, 0x06, 0x98,
+ 0xde, 0x36, 0x4e, 0xd0, 0x36, 0x45, 0x46, 0x98, 0x21, 0x29, 0xcc, 0x99, 0x17, 0xde, 0xb2, 0x03,
+ 0x4f, 0x7e, 0x98, 0xc4, 0xaf, 0x7c, 0x79, 0x62, 0x5e, 0x39, 0x9a, 0x25, 0x53, 0x79, 0xf3, 0xc6,
+ 0x85, 0xc5, 0x6c, 0xa6, 0xc8, 0x2d, 0x9a, 0x47, 0xa6, 0x67, 0x19, 0x36, 0xc8, 0x7c, 0xa8, 0x71,
+ 0x09, 0x2d, 0x20, 0x68, 0x72, 0x8f, 0x9c, 0x49, 0x2b, 0x69, 0x44, 0x48, 0x23, 0x82, 0x91, 0x5c,
+ 0x68, 0x23, 0x26, 0xac, 0x91, 0x13, 0x0e, 0x2d, 0xc1, 0x12, 0x49, 0x49, 0x84, 0x19, 0x58, 0x6f,
+ 0x71, 0xe3, 0x8d, 0x36, 0xf0, 0x47, 0x1d, 0x18, 0x0d, 0x17, 0xe6, 0x88, 0x4b, 0x32, 0xf2, 0x42,
+ 0x9b, 0x33, 0xad, 0xc3, 0xa6, 0xd4, 0x58, 0x60, 0x23, 0x63, 0x06, 0x7f, 0xd0, 0x8b, 0x6a, 0x1f,
+ 0x5c, 0x0a, 0x69, 0x29, 0xa4, 0x73, 0xf6, 0xdf, 0x41, 0x06, 0xee, 0xf7, 0x18, 0xe4, 0xf3, 0x5b,
+ 0x0a, 0x50, 0xba, 0x3c, 0xdc, 0xbe, 0xa5, 0xb3, 0x26, 0xa5, 0xf3, 0xee, 0x96, 0x8c, 0x46, 0xa3,
+ 0x91, 0x14, 0xcf, 0x07, 0xe2, 0xd2, 0x6a, 0x87, 0xe1, 0xcb, 0x46, 0xe3, 0xe2, 0xc0, 0xd3, 0x63,
+ 0xa1, 0xbf, 0xa6, 0x81, 0xb9, 0x69, 0x81, 0x60, 0x72, 0x20, 0x2f, 0x7a, 0x7e, 0x7c, 0x3e, 0x2e,
+ 0xc7, 0xd6, 0x1d, 0xa1, 0xef, 0x8b, 0x69, 0x94, 0x64, 0x48, 0x8e, 0x84, 0x92, 0x35, 0x69, 0x48,
+ 0x49, 0x43, 0x8a, 0xf1, 0x58, 0x71, 0xc2, 0xdb, 0xa5, 0xf0, 0x8e, 0xd8, 0x8e, 0x19, 0x27, 0x09,
+ 0x03, 0xa9, 0x14, 0x34, 0x1c, 0x37, 0x0d, 0x6c, 0xa6, 0x5b, 0x05, 0x38, 0x05, 0xfd, 0xc4, 0x42,
+ 0xb3, 0x05, 0x9c, 0x29, 0x65, 0x98, 0x45, 0x9c, 0x53, 0xb2, 0x4c, 0x07, 0x33, 0xcd, 0x88, 0x0a,
+ 0x72, 0x7c, 0x8c, 0x51, 0xf6, 0x4c, 0xdb, 0x02, 0x59, 0x93, 0x13, 0xcf, 0x02, 0xc9, 0x84, 0xd8,
+ 0x94, 0x15, 0xe4, 0x80, 0x2d, 0xf5, 0x45, 0x1e, 0x04, 0x9a, 0xe7, 0x0d, 0x65, 0xac, 0x73, 0x20,
+ 0x9e, 0x1e, 0x8d, 0x4a, 0xcc, 0x20, 0x97, 0x67, 0x5d, 0x23, 0x0d, 0xd8, 0xce, 0x7a, 0x6d, 0x5a,
+ 0x18, 0xce, 0x80, 0x69, 0x00, 0xfc, 0x88, 0x6c, 0x69, 0xf8, 0x24, 0x94, 0x03, 0xd5, 0x66, 0x35,
+ 0xe1, 0x4a, 0x18, 0x1e, 0x4e, 0x3b, 0x03, 0xbf, 0x5c, 0x82, 0x93, 0xa5, 0x39, 0xd5, 0x97, 0xea,
+ 0x0a, 0x79, 0xb8, 0x99, 0x41, 0x3b, 0xe0, 0x9e, 0x96, 0x10, 0x2e, 0xab, 0x80, 0xfe, 0x13, 0xeb,
+ 0x01, 0xc8, 0x96, 0xfc, 0x40, 0xc9, 0x0f, 0x5c, 0x9b, 0x77, 0xa8, 0xae, 0x00, 0x53, 0xbd, 0x4f,
+ 0xd0, 0xf1, 0x91, 0x14, 0x3f, 0x25, 0x77, 0x7d, 0x8c, 0xc6, 0xaa, 0xc8, 0xdd, 0x1f, 0xa3, 0x21,
+ 0x9c, 0x08, 0xe4, 0xb9, 0x36, 0x22, 0xf5, 0x9c, 0xc9, 0xef, 0xfe, 0x98, 0x04, 0xcd, 0xec, 0x02,
+ 0x99, 0xb7, 0x1b, 0x02, 0x3a, 0x65, 0x87, 0xf4, 0xd5, 0xa1, 0x28, 0x78, 0x03, 0xe4, 0x96, 0x21,
+ 0x9b, 0xa7, 0x1f, 0xbe, 0x46, 0x5f, 0x25, 0xb2, 0xd3, 0x67, 0x4a, 0x59, 0xaf, 0x6c, 0xf2, 0x19,
+ 0x43, 0x23, 0x5b, 0x93, 0x97, 0x74, 0x24, 0xa5, 0xb7, 0x78, 0x59, 0x42, 0x7d, 0xbe, 0x44, 0x36,
+ 0xce, 0xee, 0xf0, 0x12, 0x42, 0xec, 0xb9, 0xc1, 0x4b, 0xc6, 0xb8, 0xa0, 0x5e, 0x6d, 0x5e, 0xc2,
+ 0x59, 0x8a, 0x6a, 0xf6, 0x02, 0x0d, 0x6c, 0x3d, 0xe7, 0x17, 0xb2, 0xfa, 0x60, 0x35, 0x3b, 0xdd,
+ 0x40, 0x40, 0x19, 0xab, 0xfa, 0xaf, 0xb0, 0x8e, 0x35, 0x1b, 0xa5, 0x7c, 0xda, 0x6d, 0x8f, 0x27,
+ 0xfc, 0x04, 0xea, 0xce, 0x1e, 0xb5, 0xee, 0xec, 0xef, 0x5d, 0x71, 0xee, 0xaf, 0xd1, 0x16, 0x49,
+ 0x08, 0x65, 0x0a, 0xe0, 0x4f, 0xa9, 0x04, 0x94, 0x2d, 0x7f, 0x2d, 0x38, 0x57, 0x4d, 0xaf, 0x64,
+ 0x43, 0x5f, 0x92, 0xe5, 0x70, 0x0c, 0x72, 0xbf, 0x2d, 0x97, 0x1f, 0x82, 0xf1, 0xeb, 0x2f, 0x8e,
+ 0x13, 0xcd, 0xcd, 0x80, 0x80, 0x16, 0xcc, 0x84, 0xd5, 0x6f, 0x78, 0xf2, 0x6d, 0x9a, 0xb9, 0x10,
+ 0x20, 0xeb, 0xc6, 0xb0, 0xb1, 0xee, 0x77, 0x26, 0x49, 0x5f, 0x95, 0xf2, 0x79, 0x43, 0x7e, 0x5b,
+ 0xdb, 0xcd, 0x23, 0x2d, 0x1a, 0x1a, 0x42, 0x36, 0x56, 0x1d, 0x03, 0xfd, 0xaf, 0x43, 0x68, 0xd4,
+ 0x16, 0x05, 0xda, 0xb7, 0x26, 0x47, 0x36, 0x7e, 0x48, 0x1d, 0xba, 0x6e, 0xd4, 0x13, 0x99, 0xa8,
+ 0x28, 0x7d, 0x6e, 0x43, 0xeb, 0x09, 0x5a, 0x14, 0x27, 0x53, 0x7c, 0xb8, 0x9a, 0x9d, 0x49, 0x21,
+ 0xa3, 0xae, 0x49, 0x4a, 0x9d, 0x84, 0x5a, 0x3e, 0xbd, 0x9e, 0x7b, 0x4a, 0x05, 0xad, 0x19, 0x6a,
+ 0x87, 0xd6, 0x4d, 0xcb, 0x77, 0xd1, 0x91, 0xc6, 0x01, 0x24, 0xbe, 0xa8, 0x48, 0xa7, 0xaa, 0x0c,
+ 0x58, 0x3d, 0x2e, 0xb7, 0x23, 0x1e, 0xc8, 0x4e, 0xcc, 0x39, 0xe7, 0x18, 0xaf, 0xa4, 0x76, 0x49,
+ 0xed, 0xb5, 0xa6, 0xf6, 0xb5, 0x69, 0x61, 0x7a, 0x6a, 0xf7, 0xa0, 0x25, 0xb5, 0x4b, 0x6a, 0xe7,
+ 0x2a, 0x13, 0x25, 0xb6, 0x67, 0xd9, 0xa5, 0x9f, 0xa1, 0x2c, 0x13, 0xa5, 0xce, 0x78, 0xd5, 0xbe,
+ 0x4c, 0x94, 0xa1, 0xdd, 0x4b, 0x1d, 0xb6, 0xa5, 0x89, 0x09, 0x27, 0x52, 0x87, 0x98, 0x72, 0xf3,
+ 0x4d, 0x74, 0x09, 0x89, 0x6a, 0xf2, 0x4f, 0x2c, 0x9d, 0x83, 0xc3, 0xa8, 0x83, 0xb0, 0x7e, 0xab,
+ 0x68, 0x0d, 0x28, 0x34, 0x66, 0x51, 0xb5, 0x43, 0xad, 0xdb, 0xc4, 0xa9, 0x9d, 0xcd, 0xc2, 0xf6,
+ 0xdd, 0x51, 0xa9, 0xbc, 0x2c, 0x63, 0x24, 0xa4, 0xd4, 0x21, 0x86, 0x2f, 0x72, 0xc2, 0xa5, 0xc8,
+ 0xc6, 0x7f, 0xf3, 0xde, 0xf2, 0xf0, 0xd5, 0x7f, 0x4b, 0xe5, 0x51, 0xdf, 0xcc, 0x58, 0x19, 0xed,
+ 0x4a, 0x68, 0xc2, 0x76, 0xab, 0xc5, 0x0a, 0xab, 0x14, 0x57, 0x2c, 0xec, 0xc0, 0xed, 0x39, 0x78,
+ 0xe7, 0x4a, 0x93, 0x9a, 0x07, 0x7d, 0xfd, 0x29, 0x8a, 0x0a, 0xd8, 0x35, 0xb7, 0xb9, 0x58, 0x16,
+ 0xaa, 0x1a, 0x14, 0xa6, 0xcb, 0x40, 0x65, 0xd9, 0x89, 0xb7, 0xec, 0xe8, 0x3e, 0x4d, 0x94, 0x9f,
+ 0x2d, 0x86, 0x4f, 0x90, 0x67, 0x29, 0x5c, 0x46, 0xd7, 0xec, 0xb5, 0x8e, 0x2d, 0x5e, 0x25, 0x35,
+ 0xd6, 0x8e, 0x1a, 0xef, 0x5c, 0x6a, 0xbc, 0x9c, 0x3a, 0x96, 0x05, 0x0d, 0xdc, 0x6a, 0x6f, 0x0a,
+ 0x0e, 0xc7, 0x9d, 0x9d, 0x66, 0xc1, 0x8d, 0xb9, 0x68, 0xc2, 0x43, 0x50, 0xeb, 0xcc, 0x5b, 0x49,
+ 0xb4, 0xd7, 0xc4, 0x25, 0xb8, 0x0f, 0xba, 0xb2, 0xdc, 0x2b, 0xe5, 0x5f, 0x18, 0xf1, 0xe7, 0x23,
+ 0x04, 0x2b, 0xdd, 0xd0, 0x17, 0x9e, 0x79, 0xbf, 0x2d, 0xee, 0x03, 0x53, 0xdd, 0xb5, 0x41, 0xc0,
+ 0x04, 0x82, 0xa0, 0xb1, 0xcc, 0xec, 0xec, 0x68, 0xae, 0x90, 0x60, 0xda, 0x94, 0xaa, 0x2f, 0x95,
+ 0xa8, 0xda, 0xe0, 0x24, 0x9a, 0x78, 0x64, 0x9b, 0xf3, 0x76, 0xb1, 0xc2, 0x4c, 0x15, 0x5f, 0x06,
+ 0xc4, 0xdf, 0x4d, 0xeb, 0x9b, 0x8a, 0xb6, 0x29, 0xe9, 0x0c, 0xc3, 0x33, 0x01, 0xb9, 0x67, 0xd3,
+ 0xd3, 0x40, 0xf5, 0xb6, 0x3b, 0x0d, 0x24, 0xaf, 0xf8, 0xda, 0x97, 0x35, 0x91, 0x4a, 0x0b, 0x0d,
+ 0x32, 0x25, 0xd2, 0x68, 0xa5, 0x6c, 0x3b, 0x42, 0x5e, 0xf1, 0x95, 0x35, 0xcd, 0x86, 0x5d, 0xf1,
+ 0x75, 0x54, 0x37, 0xdb, 0x48, 0x4e, 0x67, 0xe7, 0x74, 0x79, 0xb3, 0x8d, 0xbc, 0xd9, 0x46, 0xcc,
+ 0x62, 0xab, 0xbc, 0xd9, 0x86, 0xe1, 0x52, 0x9b, 0xba, 0xd5, 0xc9, 0x49, 0xa1, 0x95, 0x67, 0xe2,
+ 0x26, 0xd1, 0xad, 0x5a, 0x70, 0xce, 0xd2, 0x5c, 0x2b, 0xfa, 0x18, 0x5d, 0x3d, 0x45, 0xb7, 0x2e,
+ 0xf5, 0x14, 0x44, 0xf2, 0x10, 0x91, 0xcf, 0xaa, 0xb8, 0x8c, 0x82, 0x44, 0x3e, 0x94, 0xa2, 0x25,
+ 0xaf, 0x23, 0x77, 0x0e, 0x59, 0x31, 0x48, 0x13, 0x6e, 0xe9, 0xc2, 0x68, 0x22, 0x71, 0x93, 0x1b,
+ 0x0f, 0xd9, 0x15, 0x27, 0xbf, 0x22, 0xa1, 0xa7, 0x42, 0xe4, 0x28, 0x24, 0xf6, 0x54, 0x98, 0x3c,
+ 0xe9, 0xa3, 0x4c, 0x80, 0xa5, 0x07, 0x35, 0x6d, 0xd1, 0x0f, 0x47, 0x10, 0x98, 0x27, 0x28, 0x5c,
+ 0x2c, 0x65, 0xc1, 0xbb, 0x0b, 0x1c, 0xbd, 0x32, 0xd8, 0x42, 0xc6, 0xec, 0xd6, 0x69, 0xe6, 0xbe,
+ 0x9f, 0x9d, 0xc5, 0xce, 0xcc, 0x82, 0x7b, 0x47, 0xd3, 0xfa, 0xf0, 0x12, 0x68, 0x3c, 0x67, 0xcc,
+ 0x0b, 0x9d, 0xca, 0x4f, 0xb2, 0x74, 0x74, 0x5e, 0x9b, 0x1e, 0x53, 0x53, 0x4f, 0xa8, 0x38, 0x16,
+ 0x9c, 0x81, 0xef, 0x8f, 0xd0, 0x88, 0x04, 0x5a, 0x91, 0x0d, 0x6c, 0x88, 0x39, 0xa6, 0x0d, 0x0a,
+ 0x1e, 0xd3, 0x17, 0x19, 0x90, 0x16, 0x2e, 0x24, 0xb2, 0x05, 0x06, 0xd7, 0xee, 0x72, 0x8d, 0xfd,
+ 0xfa, 0xa6, 0xdc, 0x27, 0x5e, 0x4f, 0xf7, 0xc5, 0x2d, 0x89, 0x86, 0x76, 0xa7, 0x27, 0x4b, 0x33,
+ 0xe8, 0xef, 0xee, 0x77, 0xb4, 0x38, 0x3b, 0xeb, 0x78, 0x8d, 0x42, 0x2e, 0xc1, 0x49, 0x54, 0x24,
+ 0x4f, 0xcd, 0xd5, 0xca, 0x34, 0x2e, 0x56, 0xfa, 0x54, 0x7d, 0xb2, 0xe6, 0x27, 0xed, 0xea, 0xb9,
+ 0xeb, 0x93, 0x69, 0xae, 0x27, 0xfa, 0xf4, 0xdb, 0x16, 0xc7, 0x76, 0x24, 0x57, 0x11, 0x21, 0x04,
+ 0xd3, 0x00, 0xbb, 0x91, 0x71, 0x60, 0xce, 0x81, 0xb7, 0xca, 0x60, 0x3d, 0x92, 0xe9, 0x28, 0x99,
+ 0x4e, 0xe8, 0xa6, 0x4b, 0x5e, 0xdc, 0xe5, 0x45, 0xbf, 0xf5, 0x60, 0x2a, 0x3f, 0xfe, 0x92, 0xce,
+ 0x90, 0x33, 0x3f, 0x71, 0x50, 0x07, 0x86, 0xfc, 0xea, 0x4d, 0x7e, 0x87, 0x32, 0x80, 0x69, 0x2c,
+ 0x9f, 0x19, 0x68, 0x23, 0x58, 0x8f, 0x64, 0x48, 0x4a, 0x86, 0x14, 0xba, 0xe9, 0x47, 0xce, 0x90,
+ 0x99, 0x85, 0x17, 0xe3, 0x98, 0x89, 0x79, 0xe7, 0xf5, 0xbd, 0x89, 0x97, 0x65, 0x44, 0x7f, 0x1f,
+ 0x6f, 0x19, 0x36, 0xd9, 0x6f, 0xaa, 0x66, 0x56, 0xa9, 0x2b, 0x78, 0x7c, 0x1a, 0x48, 0x76, 0x43,
+ 0xa2, 0x95, 0xeb, 0x92, 0x57, 0x79, 0x2c, 0x56, 0x21, 0x3b, 0x5f, 0x4f, 0x86, 0xa5, 0x86, 0x1e,
+ 0x8b, 0xaa, 0x23, 0xa1, 0x08, 0xd6, 0x51, 0xdd, 0x3b, 0x48, 0xc5, 0x34, 0x32, 0xda, 0x24, 0xa3,
+ 0x4d, 0x47, 0x1b, 0x6d, 0x4a, 0x29, 0x49, 0x8c, 0x28, 0xbe, 0x28, 0x9b, 0x74, 0xfc, 0xf6, 0x70,
+ 0xc7, 0x1c, 0x98, 0xe2, 0xed, 0xb9, 0x58, 0x82, 0xd6, 0xcf, 0x0f, 0x95, 0xc4, 0xfb, 0xa2, 0xcb,
+ 0x58, 0x14, 0x8b, 0x38, 0xe1, 0xdb, 0x5d, 0xa9, 0xbd, 0x29, 0x20, 0xf2, 0x12, 0x4d, 0x94, 0xe7,
+ 0xa2, 0xb6, 0x76, 0x40, 0x76, 0x55, 0xe7, 0xae, 0x79, 0xd5, 0x89, 0xca, 0x32, 0xfa, 0x6c, 0x26,
+ 0x20, 0xd6, 0x7f, 0xfe, 0xe1, 0x0f, 0xb2, 0x69, 0x30, 0x14, 0xe9, 0xd7, 0x18, 0x7e, 0xfa, 0x02,
+ 0x73, 0x62, 0x23, 0xb2, 0xe9, 0x83, 0x4c, 0xdb, 0x96, 0xc3, 0x4d, 0xec, 0x87, 0xde, 0x77, 0x99,
+ 0x46, 0xf5, 0x25, 0xdd, 0x5c, 0xa5, 0x20, 0x20, 0x20, 0xaf, 0xb4, 0x93, 0x57, 0xda, 0xd5, 0x60,
+ 0x53, 0xe4, 0x9d, 0x49, 0x14, 0x36, 0xac, 0xab, 0xf9, 0xb6, 0xff, 0x4a, 0xbd, 0x1d, 0x29, 0x91,
+ 0x4c, 0x4a, 0xcb, 0x24, 0x19, 0x88, 0x2b, 0x8b, 0x24, 0xa8, 0x63, 0x7a, 0x85, 0x59, 0xa3, 0xc3,
+ 0xed, 0xa4, 0x5e, 0x5d, 0x56, 0xa8, 0x39, 0x37, 0x10, 0x30, 0xb3, 0x52, 0x4a, 0x2e, 0x28, 0x35,
+ 0x11, 0x64, 0x20, 0xae, 0x24, 0x90, 0x20, 0x7e, 0xaa, 0x30, 0xe9, 0x73, 0xb8, 0xfc, 0x54, 0x5d,
+ 0x52, 0xe7, 0x50, 0xf8, 0x69, 0x37, 0x60, 0x65, 0x3b, 0x13, 0xbf, 0x17, 0x99, 0x3a, 0x81, 0x73,
+ 0xd3, 0x82, 0xad, 0x30, 0x82, 0x75, 0x0a, 0x4e, 0xce, 0x4e, 0xd2, 0x33, 0x3c, 0xdb, 0x87, 0xf4,
+ 0x39, 0x86, 0x56, 0xf2, 0x19, 0x31, 0x79, 0x9e, 0x32, 0xae, 0x04, 0xac, 0x20, 0xaf, 0x73, 0x24,
+ 0x37, 0x06, 0xee, 0x3f, 0x6f, 0xf3, 0x2a, 0x9b, 0x3a, 0xc9, 0xa6, 0x4e, 0xfb, 0x3c, 0xa5, 0x4f,
+ 0xb0, 0x34, 0x1e, 0x4d, 0x3a, 0xd9, 0x56, 0xf0, 0x84, 0xfe, 0x4d, 0x9a, 0x1d, 0xa9, 0xcf, 0x66,
+ 0x70, 0x06, 0xb0, 0x09, 0xf4, 0x0d, 0x43, 0x81, 0x84, 0xd2, 0x73, 0xe7, 0x77, 0x34, 0x47, 0xf6,
+ 0x8b, 0xed, 0x52, 0x3d, 0xcf, 0xf0, 0x97, 0xd7, 0xfd, 0x2a, 0x3b, 0xba, 0xcb, 0xd5, 0x05, 0x2b,
+ 0x33, 0x8e, 0x5b, 0xa4, 0x7b, 0x4c, 0x73, 0x7b, 0x19, 0xc9, 0x03, 0x55, 0xd4, 0x21, 0xd4, 0xed,
+ 0x45, 0x9a, 0xd0, 0x35, 0x2f, 0xa7, 0x18, 0xce, 0xf2, 0x82, 0xa5, 0xf2, 0x24, 0x68, 0xbd, 0x4e,
+ 0x82, 0x9e, 0xbf, 0x3d, 0x9c, 0x93, 0xa0, 0xe4, 0x8e, 0x44, 0x18, 0x5a, 0x46, 0x2e, 0x49, 0x29,
+ 0x77, 0x57, 0xea, 0x7f, 0xe9, 0xea, 0xff, 0x69, 0xea, 0xe8, 0x97, 0xff, 0xf8, 0xa7, 0x7f, 0xfe,
+ 0x97, 0xff, 0xbe, 0x77, 0x34, 0xad, 0x37, 0x6c, 0xb5, 0x5f, 0xfe, 0xed, 0xf2, 0x7f, 0xfe, 0xff,
+ 0xec, 0xf4, 0xe4, 0xe1, 0xe2, 0xdf, 0xdf, 0xab, 0xe3, 0x2d, 0x14, 0x20, 0x81, 0xfd, 0xab, 0x52,
+ 0xca, 0xb1, 0xd5, 0xb5, 0x65, 0x62, 0x73, 0x6a, 0x2e, 0xf3, 0xe5, 0x6b, 0x08, 0x29, 0x0f, 0xad,
+ 0x36, 0xf5, 0xd0, 0xea, 0x64, 0xc1, 0x70, 0x97, 0x83, 0x0b, 0x2c, 0x0f, 0xa8, 0xca, 0x03, 0xaa,
+ 0xe9, 0x80, 0x34, 0xad, 0x7e, 0x32, 0x71, 0x46, 0xd7, 0xd2, 0x25, 0x3e, 0x31, 0x8a, 0x56, 0x40,
+ 0x49, 0x77, 0xd1, 0xc8, 0x6f, 0xb3, 0x42, 0x21, 0xf1, 0x19, 0x4c, 0x49, 0x6e, 0xda, 0xe7, 0xe1,
+ 0x81, 0xe2, 0xbc, 0x50, 0x34, 0x4a, 0x25, 0xeb, 0x17, 0x79, 0x4c, 0x5d, 0x81, 0x7c, 0x01, 0x28,
+ 0x5b, 0x1f, 0x25, 0x23, 0x11, 0x34, 0xad, 0x90, 0x92, 0x4b, 0x63, 0x69, 0x8d, 0x94, 0x78, 0x9a,
+ 0xad, 0x55, 0x52, 0xe2, 0x71, 0xfa, 0xd6, 0x49, 0x9c, 0x98, 0x8b, 0x2c, 0x93, 0xb6, 0xb5, 0x52,
+ 0xe2, 0x51, 0xa6, 0x56, 0x4b, 0x59, 0x02, 0x2b, 0xaf, 0xf5, 0x52, 0x4d, 0xf2, 0x13, 0x8d, 0x2a,
+ 0x3c, 0x05, 0xad, 0x33, 0x70, 0x09, 0x4e, 0x02, 0xfc, 0x78, 0x37, 0x97, 0xdf, 0x1b, 0xa0, 0x75,
+ 0x76, 0xd6, 0xd1, 0xe7, 0x48, 0xb5, 0xf5, 0x39, 0xba, 0xdb, 0x7c, 0xf0, 0xfc, 0xce, 0xcb, 0x13,
+ 0xb4, 0x7e, 0x3a, 0x57, 0x1d, 0x03, 0x4d, 0x75, 0x1b, 0x9f, 0x8c, 0x77, 0x3a, 0x73, 0x9e, 0xf8,
+ 0xa8, 0xa2, 0x7c, 0xcf, 0x50, 0xc4, 0x7b, 0xe0, 0xd3, 0xda, 0x28, 0x38, 0x8f, 0x73, 0x75, 0xa9,
+ 0x4f, 0xe0, 0x12, 0xce, 0x84, 0xad, 0x4b, 0xe0, 0xfb, 0x96, 0xfd, 0xa7, 0xb5, 0xa1, 0x8a, 0xda,
+ 0xf5, 0xf0, 0x6d, 0x42, 0xf6, 0xde, 0x32, 0x1d, 0x0c, 0x55, 0xac, 0x5b, 0x0b, 0x48, 0x78, 0x4f,
+ 0xf5, 0x05, 0xcd, 0x7f, 0x35, 0xfc, 0x78, 0xe6, 0xa3, 0x17, 0xf2, 0xb4, 0xa0, 0x6d, 0x83, 0xb9,
+ 0xbe, 0x42, 0x4b, 0x04, 0xed, 0xb0, 0x08, 0xd7, 0x9f, 0x2d, 0x75, 0x13, 0x57, 0x91, 0x19, 0xad,
+ 0x32, 0x32, 0x5b, 0x42, 0x33, 0x5c, 0xa9, 0x66, 0x05, 0xd3, 0xa6, 0xca, 0xf2, 0x65, 0xea, 0x28,
+ 0xd3, 0x86, 0xc7, 0x38, 0x1c, 0x88, 0xcd, 0x93, 0x6c, 0x46, 0x7b, 0x57, 0x1a, 0xed, 0xd2, 0x68,
+ 0x2f, 0xe6, 0xf8, 0x16, 0x72, 0x80, 0x05, 0x19, 0xfc, 0xdc, 0x0e, 0x71, 0xc2, 0x4a, 0x65, 0x7a,
+ 0x72, 0xcc, 0x38, 0x43, 0x36, 0x4f, 0x99, 0x9b, 0xf9, 0x8a, 0x30, 0xa1, 0x38, 0x66, 0x14, 0xa5,
+ 0x1d, 0x0b, 0x33, 0xa7, 0x70, 0x75, 0x28, 0x84, 0x59, 0x39, 0xd5, 0x16, 0xab, 0xdf, 0xc6, 0xea,
+ 0x79, 0x0b, 0x64, 0x48, 0x5e, 0x4f, 0xbc, 0x98, 0x47, 0x2e, 0xc6, 0x33, 0x17, 0xe4, 0xa1, 0x0b,
+ 0xf0, 0xd4, 0x39, 0x31, 0x2f, 0xc0, 0x73, 0x17, 0xe3, 0xc1, 0x17, 0xf5, 0xe4, 0xeb, 0x67, 0x10,
+ 0xb2, 0x9c, 0x8d, 0x88, 0x39, 0x4d, 0x05, 0xb4, 0x62, 0xec, 0x35, 0x52, 0xeb, 0x48, 0xad, 0x73,
+ 0xe0, 0x5a, 0x07, 0xcd, 0xa0, 0x81, 0x11, 0x7e, 0x66, 0x3b, 0xbb, 0x9e, 0xd0, 0x3a, 0x03, 0x8e,
+ 0x67, 0x6f, 0x82, 0xa1, 0xaf, 0x75, 0x5b, 0x40, 0xf8, 0x61, 0xb2, 0x58, 0xab, 0x81, 0x8b, 0xac,
+ 0x7a, 0x2e, 0xf2, 0x33, 0x2f, 0x1d, 0x79, 0x45, 0x05, 0x36, 0x97, 0x75, 0xcb, 0x1f, 0x2c, 0x4c,
+ 0x5d, 0x13, 0x7c, 0x5a, 0x1b, 0x0a, 0xf7, 0xab, 0x5e, 0x4f, 0xab, 0x9e, 0x7f, 0x5a, 0xd8, 0xaf,
+ 0xf1, 0xeb, 0x39, 0x8c, 0x75, 0x0c, 0x0f, 0x0c, 0x2f, 0xc3, 0x43, 0x58, 0x47, 0x32, 0x0c, 0x7d,
+ 0x10, 0xab, 0x39, 0x08, 0xdc, 0x44, 0xc3, 0xf0, 0x05, 0xd6, 0xc1, 0xf5, 0xe4, 0xb8, 0x66, 0x66,
+ 0x47, 0x81, 0xe4, 0x5b, 0xf8, 0x0e, 0xae, 0x24, 0x5c, 0x71, 0x9c, 0xc6, 0x9a, 0x3d, 0x7a, 0x69,
+ 0x39, 0x2f, 0xb7, 0xd5, 0xf6, 0xce, 0x28, 0xed, 0x56, 0x24, 0x7b, 0x47, 0x95, 0xc0, 0x25, 0x88,
+ 0x75, 0xd7, 0x09, 0xff, 0xf3, 0x6f, 0xfe, 0xdb, 0x9c, 0xa8, 0xdd, 0x1c, 0xf9, 0x2b, 0xe2, 0xbc,
+ 0x0a, 0x49, 0xc8, 0x24, 0x56, 0xfa, 0xf1, 0xef, 0x9f, 0xff, 0x00, 0xc8, 0x06, 0x86, 0x89, 0x81,
+ 0xed, 0xac, 0xd7, 0xa6, 0x85, 0xe1, 0x0c, 0x20, 0x23, 0x51, 0x8e, 0x6e, 0x03, 0x13, 0x3f, 0x42,
+ 0x0b, 0xe0, 0x47, 0xdd, 0x28, 0xd8, 0xf7, 0x51, 0x94, 0x77, 0x90, 0xe5, 0x29, 0x88, 0xca, 0xdc,
+ 0x08, 0x77, 0x1e, 0x32, 0x1d, 0x89, 0x62, 0x58, 0x28, 0x34, 0x97, 0xd7, 0x3d, 0x8b, 0x2b, 0x4e,
+ 0x61, 0x2d, 0x92, 0xa9, 0x63, 0x49, 0xd3, 0x43, 0x66, 0xee, 0xe8, 0x42, 0x25, 0x93, 0x57, 0xcd,
+ 0xe4, 0x62, 0xb0, 0x21, 0x99, 0x9d, 0x8d, 0xd9, 0x53, 0xaa, 0x37, 0xda, 0xe0, 0x80, 0x79, 0xfe,
+ 0x53, 0x5f, 0x6a, 0xf4, 0x1a, 0x30, 0x7b, 0x41, 0x34, 0x48, 0x2e, 0xe7, 0xe4, 0xf2, 0x61, 0x84,
+ 0xcb, 0x25, 0x93, 0x4b, 0x26, 0x97, 0x4c, 0x7e, 0x38, 0x4c, 0x9e, 0x5a, 0x28, 0x7a, 0xd0, 0x6c,
+ 0xee, 0xae, 0x55, 0xbd, 0xf9, 0xfc, 0x74, 0x2e, 0x79, 0xbd, 0x72, 0x5e, 0x17, 0x80, 0x0b, 0xc9,
+ 0xf0, 0xcc, 0x0c, 0x3f, 0x3c, 0x4e, 0x86, 0x1f, 0x4a, 0x86, 0xaf, 0x0d, 0xc3, 0x0f, 0x8f, 0x85,
+ 0xe1, 0xdf, 0x94, 0x9b, 0x7a, 0xa8, 0xea, 0x34, 0x50, 0xd0, 0xb9, 0x88, 0xa7, 0x7a, 0x87, 0xae,
+ 0xa5, 0x51, 0xe2, 0x29, 0xea, 0x16, 0x47, 0xc9, 0x27, 0x0b, 0xb4, 0x3c, 0x4a, 0xbc, 0x8c, 0xbe,
+ 0x05, 0x52, 0xf6, 0xa3, 0xb9, 0x2d, 0x91, 0x78, 0xb1, 0xc2, 0xd8, 0x09, 0x3c, 0x7c, 0x8e, 0xa5,
+ 0x67, 0xcc, 0xa6, 0x35, 0x40, 0x67, 0xb2, 0x58, 0x77, 0x18, 0x6b, 0xf3, 0x01, 0x53, 0x3f, 0x99,
+ 0xcf, 0xc1, 0x48, 0x0f, 0xd7, 0x8b, 0xf5, 0xc3, 0xd5, 0x1c, 0x7d, 0x75, 0x07, 0xda, 0xe7, 0x91,
+ 0x05, 0x07, 0x9b, 0x86, 0xb9, 0x32, 0x1d, 0x5b, 0xf5, 0x3b, 0x51, 0x72, 0x9c, 0x5d, 0x48, 0xbc,
+ 0x42, 0x9e, 0x3c, 0x96, 0x87, 0x18, 0x84, 0xf0, 0xfa, 0xad, 0x6e, 0xcc, 0x74, 0x6c, 0x5a, 0xcf,
+ 0x0c, 0x67, 0x5d, 0x0a, 0x9c, 0x56, 0xb6, 0x55, 0xc3, 0x59, 0x4d, 0xa0, 0xc5, 0x71, 0x56, 0x99,
+ 0xe5, 0xba, 0x95, 0x2f, 0xba, 0xe1, 0xd9, 0x7e, 0xa5, 0x1f, 0x15, 0xe5, 0xe9, 0x76, 0x1e, 0x3e,
+ 0xcc, 0xd9, 0xf5, 0x3c, 0x7c, 0xbe, 0x68, 0xa3, 0xef, 0x2d, 0x7a, 0x78, 0x1b, 0x7e, 0x17, 0x70,
+ 0x48, 0xb8, 0xba, 0xa2, 0x27, 0xb6, 0xee, 0xbc, 0x37, 0x3a, 0x1f, 0x0d, 0xdf, 0xf6, 0x46, 0x83,
+ 0xe6, 0xef, 0xe1, 0x01, 0x1c, 0xcf, 0xf3, 0xf2, 0x68, 0x96, 0x8a, 0x66, 0xec, 0x3a, 0x6e, 0xfb,
+ 0xa8, 0xd4, 0x6d, 0x52, 0xb7, 0x35, 0x50, 0xb7, 0xa1, 0xb0, 0x8e, 0x99, 0xa7, 0x11, 0xc7, 0x88,
+ 0xe1, 0x99, 0x60, 0x8e, 0x7b, 0xeb, 0x83, 0xe0, 0x05, 0x77, 0xd9, 0xd7, 0x96, 0x58, 0xe3, 0x3b,
+ 0x8e, 0x67, 0x69, 0x3b, 0xa7, 0x65, 0xbe, 0xa0, 0xd5, 0xba, 0xd3, 0xd4, 0xd1, 0xf8, 0xe5, 0xae,
+ 0xab, 0x8e, 0xc6, 0xfe, 0xc7, 0xae, 0xf7, 0x3f, 0xff, 0x73, 0xef, 0x4e, 0x53, 0xcf, 0x37, 0x9f,
+ 0x07, 0x77, 0x9a, 0x3a, 0x18, 0xb7, 0xef, 0xef, 0xcf, 0xda, 0x3f, 0xfb, 0xaf, 0xec, 0x0f, 0x2a,
+ 0x65, 0xbb, 0xe9, 0xa7, 0x7b, 0x44, 0xf9, 0xb0, 0xc1, 0x28, 0xbf, 0x78, 0x71, 0x11, 0xa3, 0xab,
+ 0xf3, 0x2b, 0xf5, 0xb7, 0xf1, 0x4f, 0xed, 0xf4, 0xfc, 0xb5, 0x7d, 0xd1, 0x6e, 0xed, 0x7e, 0x77,
+ 0xd1, 0xfe, 0xa9, 0x9d, 0x0e, 0x5e, 0x5b, 0xad, 0x94, 0x5f, 0xde, 0xa7, 0xbd, 0xa3, 0xfd, 0xd2,
+ 0x6a, 0xb5, 0x02, 0x64, 0xc7, 0x08, 0xe0, 0x4e, 0xeb, 0x8e, 0xdf, 0x7b, 0x1f, 0xfd, 0xbf, 0x21,
+ 0x09, 0x51, 0x01, 0xb7, 0xcb, 0x27, 0x9c, 0x86, 0xdd, 0x45, 0x56, 0xc7, 0x2b, 0x5c, 0x0c, 0x13,
+ 0xb7, 0xa8, 0x63, 0xdb, 0xb1, 0xa8, 0xf6, 0xbd, 0x12, 0x5c, 0xc9, 0x71, 0xaf, 0x54, 0x70, 0xb1,
+ 0xc4, 0xf5, 0xef, 0x9f, 0xc3, 0x2e, 0xea, 0x5e, 0x50, 0x67, 0x13, 0x33, 0x5d, 0x9b, 0xb6, 0x8d,
+ 0x26, 0x4b, 0x48, 0x73, 0x99, 0x08, 0x90, 0x3d, 0xec, 0x03, 0xd3, 0x46, 0xd0, 0x76, 0x1e, 0xee,
+ 0x65, 0x12, 0x39, 0xf7, 0xec, 0xd3, 0x36, 0x3e, 0x2f, 0x81, 0x0b, 0xe2, 0x89, 0x02, 0xef, 0xfe,
+ 0x81, 0x4c, 0x44, 0x31, 0xf4, 0x3f, 0x3f, 0x0e, 0x9a, 0x67, 0xde, 0xbc, 0xba, 0x5f, 0xcd, 0x40,
+ 0xe1, 0xce, 0xae, 0x2d, 0x68, 0x43, 0x63, 0x0a, 0xcb, 0x54, 0x2b, 0x1f, 0x36, 0x17, 0x5c, 0x80,
+ 0xeb, 0xdf, 0x3f, 0xef, 0xdf, 0x53, 0xf4, 0xd7, 0x57, 0xa5, 0xaf, 0x18, 0xdf, 0x80, 0x86, 0xdd,
+ 0x35, 0x57, 0xe6, 0xa5, 0xa9, 0xd1, 0x14, 0x89, 0xd0, 0x9b, 0x52, 0xa3, 0x19, 0x11, 0x65, 0x2f,
+ 0x37, 0x94, 0x94, 0x71, 0xeb, 0x40, 0x4e, 0x73, 0x69, 0xbe, 0x2d, 0x29, 0x72, 0xe7, 0x00, 0x26,
+ 0x85, 0x0e, 0x42, 0x7e, 0xf7, 0xa0, 0xb2, 0xba, 0x31, 0x53, 0x34, 0xe8, 0x51, 0x88, 0x09, 0xec,
+ 0xb1, 0xbc, 0xcd, 0xa0, 0xf1, 0xb7, 0x19, 0xd0, 0x1d, 0xed, 0xa7, 0x39, 0xc2, 0xcf, 0x76, 0x54,
+ 0x7f, 0xeb, 0xe9, 0x20, 0x95, 0x40, 0xa5, 0xf1, 0x18, 0x3c, 0xdd, 0x79, 0x7b, 0xc6, 0x58, 0x30,
+ 0x75, 0x8d, 0x06, 0x85, 0x21, 0xcb, 0x38, 0x34, 0x9d, 0xe9, 0x22, 0x7e, 0x5c, 0xb4, 0xa6, 0xbb,
+ 0xb3, 0x51, 0xfc, 0xc8, 0xd4, 0xd7, 0x45, 0x92, 0x75, 0xe9, 0x98, 0x95, 0x4f, 0xde, 0x90, 0xbf,
+ 0xd9, 0x59, 0x28, 0xe1, 0x92, 0x2b, 0x72, 0x25, 0x48, 0x7e, 0xc5, 0x07, 0x57, 0x65, 0x07, 0x45,
+ 0x05, 0x07, 0x45, 0xa5, 0xc6, 0xee, 0x22, 0x73, 0xf4, 0x24, 0x8b, 0x7e, 0x4c, 0xe1, 0x5e, 0x6a,
+ 0x75, 0x18, 0xa7, 0x85, 0x2d, 0x5e, 0x22, 0xd3, 0x55, 0xd6, 0x7e, 0x94, 0x0e, 0x43, 0x3b, 0xd9,
+ 0x3c, 0x69, 0x7b, 0x01, 0x44, 0x04, 0x68, 0x17, 0x9f, 0xa9, 0x1a, 0x29, 0x53, 0x13, 0x91, 0x34,
+ 0x50, 0x9a, 0xe6, 0x49, 0x5b, 0x7e, 0x8e, 0xba, 0xa1, 0x56, 0x33, 0xd4, 0xea, 0x25, 0x4b, 0xad,
+ 0x28, 0x8c, 0xb4, 0x9f, 0xa9, 0x3b, 0xb6, 0x2b, 0xf7, 0x3b, 0x79, 0xa5, 0x2c, 0x9a, 0x10, 0x89,
+ 0xcd, 0xbb, 0xe8, 0x86, 0x7c, 0x53, 0x5c, 0xbe, 0x3e, 0xd9, 0x24, 0x69, 0x73, 0x32, 0xf7, 0xcc,
+ 0x39, 0x58, 0xfa, 0x5c, 0xeb, 0x2b, 0xf9, 0x0a, 0x3b, 0xfa, 0x25, 0x74, 0xb5, 0xea, 0xd6, 0x40,
+ 0x29, 0x3e, 0x53, 0x4c, 0xbf, 0xdc, 0x50, 0xba, 0xf2, 0xa8, 0x2f, 0x97, 0x26, 0x88, 0x04, 0xba,
+ 0x53, 0xee, 0x8c, 0x19, 0x53, 0x48, 0x03, 0x4b, 0x37, 0x16, 0xd0, 0x65, 0xf3, 0x4f, 0x50, 0x9f,
+ 0x2f, 0x11, 0x49, 0x26, 0x24, 0x41, 0xa5, 0x64, 0x28, 0x51, 0x32, 0x38, 0xc8, 0xc0, 0xfd, 0x1e,
+ 0x41, 0x32, 0xa4, 0x70, 0x67, 0x4e, 0xfd, 0x8c, 0x28, 0xb9, 0x50, 0x25, 0x53, 0x89, 0x12, 0x0c,
+ 0x7d, 0xad, 0x76, 0x92, 0xe1, 0xb4, 0x54, 0xa4, 0x0d, 0x34, 0xed, 0x00, 0xd0, 0x36, 0xd0, 0x7a,
+ 0x47, 0x86, 0xb7, 0xd1, 0x68, 0x34, 0x6a, 0x3e, 0xde, 0xaa, 0x5d, 0x05, 0xad, 0x26, 0x26, 0x8a,
+ 0xec, 0x06, 0x7b, 0x2b, 0x64, 0xd5, 0x6f, 0xa3, 0x85, 0x01, 0x67, 0x14, 0x8a, 0x3f, 0x00, 0x94,
+ 0x6a, 0xbf, 0x44, 0xb5, 0x9f, 0xa7, 0xf5, 0xfb, 0x95, 0x69, 0xfd, 0x7e, 0xb9, 0x0a, 0xc4, 0xdd,
+ 0xfc, 0xf2, 0xe5, 0xd0, 0xb0, 0xba, 0x25, 0x54, 0xa3, 0xf4, 0x1b, 0x8f, 0xb1, 0xc1, 0x71, 0x61,
+ 0xac, 0xdf, 0x6b, 0x3c, 0xc6, 0xba, 0x47, 0x85, 0x30, 0xe9, 0x0c, 0x55, 0x62, 0x9c, 0x91, 0x4d,
+ 0x1a, 0xc7, 0xa0, 0x36, 0x6a, 0x42, 0x50, 0x69, 0xd6, 0xc8, 0x68, 0x86, 0x64, 0x60, 0x19, 0xcd,
+ 0x90, 0xd1, 0x0c, 0x19, 0xcd, 0x38, 0xc0, 0x68, 0xc6, 0x9b, 0xf8, 0xa7, 0x60, 0x2f, 0xb2, 0x32,
+ 0x97, 0x0a, 0xb2, 0x7f, 0xd3, 0xbf, 0xc1, 0x2f, 0xa6, 0x99, 0xd4, 0x20, 0xbb, 0xd9, 0x4c, 0x25,
+ 0xfa, 0x53, 0x2c, 0x53, 0xf9, 0x2b, 0x7c, 0x42, 0x9b, 0xac, 0xe4, 0xeb, 0x9b, 0xd7, 0x7f, 0x00,
+ 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x96, 0xa3, 0xd9, 0xc2, 0x2a, 0x7c, 0x01,
+ 0x00,
}
)
@@ -1710,6 +1718,9 @@ func initΛEnumTypes(){
"/interface/admin-state": []reflect.Type{
reflect.TypeOf((E_SdcioModelIf_AdminState)(0)),
},
+ "/interface/subinterface/admin-state": []reflect.Type{
+ reflect.TypeOf((E_SdcioModelIf_AdminState)(0)),
+ },
"/interface/subinterface/type": []reflect.Type{
reflect.TypeOf((E_SdcioModelCommon_SiType)(0)),
},