From 99dd53bea5b4a2f35c983e4e76fd1534bafdc3c3 Mon Sep 17 00:00:00 2001 From: Teo Mrnjavac Date: Fri, 18 Dec 2020 16:56:20 +0100 Subject: [PATCH] [WIP][apricot] A Processor and Repository for Configuration Templates This looks to create apricot as a standalone binary. Its primary interface is protos/apricot.proto, and it serves as a shim daemon (apricot/server.go) for configuration.Service, the non-remote implementation of the apricot.Service interface. A remote interface will be apricot/client.go, and this too should implement apricot.Service. Most code should be further refactored so that using the interface makes all calls indistinguishable whether the call is compiled-in, or a gRPC call implemented in apricot.Client. coconut should then be cleaned up and Consul KV access code should be deduplicated. In the end, consul conf should mostly remain as a thin wrapper around apricot.Client. --- Makefile | 4 +- apricot/client.go | 1 + apricot/protos/apricot.pb.go | 988 ++++++++++++++++++ apricot/protos/apricot.proto | 80 ++ apricot/server.go | 168 +++ coconut/configuration/configuration.go | 60 +- coconut/configuration/configurationutil.go | 2 +- .../configuration_suite_test.go | 4 +- .../{ => cfgbackend}/configuration_test.yaml | 0 .../{ => cfgbackend}/configurationmap.go | 2 +- .../{ => cfgbackend}/consulsource.go | 5 +- configuration/{ => cfgbackend}/source.go | 4 +- configuration/{ => cfgbackend}/source_test.go | 114 +- configuration/{ => cfgbackend}/yamlsource.go | 4 +- configuration/componentcfg/componentcfg.go | 81 +- configuration/componentcfg/query.go | 110 ++ configuration/instance.go | 56 + configuration/repos/repo.go | 7 +- configuration/repos/repomanager.go | 8 +- configuration/{confsys => }/service.go | 100 +- configuration/serviceutil.go | 46 + configuration/template/fields.go | 5 +- configuration/template/loader.go | 8 +- configuration/template/stack.go | 18 +- configuration/the/singleton.go | 6 +- core/task/manager.go | 2 +- 26 files changed, 1612 insertions(+), 271 deletions(-) create mode 100644 apricot/client.go create mode 100644 apricot/protos/apricot.pb.go create mode 100644 apricot/protos/apricot.proto create mode 100644 apricot/server.go rename configuration/{ => cfgbackend}/configuration_suite_test.go (87%) rename configuration/{ => cfgbackend}/configuration_test.yaml (100%) rename configuration/{ => cfgbackend}/configurationmap.go (99%) rename configuration/{ => cfgbackend}/consulsource.go (99%) rename configuration/{ => cfgbackend}/source.go (98%) rename configuration/{ => cfgbackend}/source_test.go (72%) rename configuration/{ => cfgbackend}/yamlsource.go (99%) create mode 100644 configuration/componentcfg/query.go create mode 100644 configuration/instance.go rename configuration/{confsys => }/service.go (79%) create mode 100644 configuration/serviceutil.go diff --git a/Makefile b/Makefile index d1b89c180..46349d20b 100644 --- a/Makefile +++ b/Makefile @@ -53,8 +53,8 @@ WHAT_walnut_BUILD_FLAGS=$(BUILD_ENV_FLAGS) INSTALL_WHAT:=$(patsubst %, install_%, $(WHAT)) -GENERATE_DIRS := ./core ./executor ./coconut/cmd ./odcshim ./walnut -SRC_DIRS := ./cmd/* ./core ./coconut ./executor ./common ./configuration ./occ/peanut ./odcshim ./walnut +GENERATE_DIRS := ./apricot ./core ./executor ./coconut/cmd ./odcshim ./walnut +SRC_DIRS := ./apricot ./cmd/* ./core ./coconut ./executor ./common ./configuration ./occ/peanut ./odcshim ./walnut # Use linker flags to provide version/build settings to the target PROD :=-X=$(REPOPATH)/common/product diff --git a/apricot/client.go b/apricot/client.go new file mode 100644 index 000000000..6a8d2ce15 --- /dev/null +++ b/apricot/client.go @@ -0,0 +1 @@ +package apricot diff --git a/apricot/protos/apricot.pb.go b/apricot/protos/apricot.pb.go new file mode 100644 index 000000000..e0ae17c11 --- /dev/null +++ b/apricot/protos/apricot.pb.go @@ -0,0 +1,988 @@ +// +// === This file is part of ALICE O² === +// +// Copyright 2020 CERN and copyright holders of ALICE O². +// Author: Teo Mrnjavac +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// +// In applying this license CERN does not waive the privileges and +// immunities granted to it by virtue of its status as an +// Intergovernmental Organization or submit itself to any jurisdiction. + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.25.0 +// protoc v3.12.4 +// source: protos/apricot.proto + +package apricotpb + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + 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) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type RunType int32 + +const ( + RunType_NULL RunType = 0 + RunType_ANY RunType = 1 + RunType_PHYSICS RunType = 2 + RunType_TECHNICAL RunType = 3 +) + +// Enum value maps for RunType. +var ( + RunType_name = map[int32]string{ + 0: "NULL", + 1: "ANY", + 2: "PHYSICS", + 3: "TECHNICAL", + } + RunType_value = map[string]int32{ + "NULL": 0, + "ANY": 1, + "PHYSICS": 2, + "TECHNICAL": 3, + } +) + +func (x RunType) Enum() *RunType { + p := new(RunType) + *p = x + return p +} + +func (x RunType) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (RunType) Descriptor() protoreflect.EnumDescriptor { + return file_protos_apricot_proto_enumTypes[0].Descriptor() +} + +func (RunType) Type() protoreflect.EnumType { + return &file_protos_apricot_proto_enumTypes[0] +} + +func (x RunType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use RunType.Descriptor instead. +func (RunType) EnumDescriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{0} +} + +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{0} +} + +type ComponentQuery struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Component string `protobuf:"bytes,1,opt,name=component,proto3" json:"component,omitempty"` + RunType RunType `protobuf:"varint,2,opt,name=runType,proto3,enum=apricot.RunType" json:"runType,omitempty"` + MachineRole string `protobuf:"bytes,3,opt,name=machineRole,proto3" json:"machineRole,omitempty"` + Entry string `protobuf:"bytes,4,opt,name=entry,proto3" json:"entry,omitempty"` + Timestamp string `protobuf:"bytes,5,opt,name=timestamp,proto3" json:"timestamp,omitempty"` +} + +func (x *ComponentQuery) Reset() { + *x = ComponentQuery{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComponentQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComponentQuery) ProtoMessage() {} + +func (x *ComponentQuery) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComponentQuery.ProtoReflect.Descriptor instead. +func (*ComponentQuery) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{1} +} + +func (x *ComponentQuery) GetComponent() string { + if x != nil { + return x.Component + } + return "" +} + +func (x *ComponentQuery) GetRunType() RunType { + if x != nil { + return x.RunType + } + return RunType_NULL +} + +func (x *ComponentQuery) GetMachineRole() string { + if x != nil { + return x.MachineRole + } + return "" +} + +func (x *ComponentQuery) GetEntry() string { + if x != nil { + return x.Entry + } + return "" +} + +func (x *ComponentQuery) GetTimestamp() string { + if x != nil { + return x.Timestamp + } + return "" +} + +type ComponentRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to QueryPath: + // *ComponentRequest_Path + // *ComponentRequest_Query + QueryPath isComponentRequest_QueryPath `protobuf_oneof:"queryPath"` + ProcessTemplate bool `protobuf:"varint,3,opt,name=processTemplate,proto3" json:"processTemplate,omitempty"` + VarStack map[string]string `protobuf:"bytes,4,rep,name=varStack,proto3" json:"varStack,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *ComponentRequest) Reset() { + *x = ComponentRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComponentRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComponentRequest) ProtoMessage() {} + +func (x *ComponentRequest) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComponentRequest.ProtoReflect.Descriptor instead. +func (*ComponentRequest) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{2} +} + +func (m *ComponentRequest) GetQueryPath() isComponentRequest_QueryPath { + if m != nil { + return m.QueryPath + } + return nil +} + +func (x *ComponentRequest) GetPath() string { + if x, ok := x.GetQueryPath().(*ComponentRequest_Path); ok { + return x.Path + } + return "" +} + +func (x *ComponentRequest) GetQuery() *ComponentQuery { + if x, ok := x.GetQueryPath().(*ComponentRequest_Query); ok { + return x.Query + } + return nil +} + +func (x *ComponentRequest) GetProcessTemplate() bool { + if x != nil { + return x.ProcessTemplate + } + return false +} + +func (x *ComponentRequest) GetVarStack() map[string]string { + if x != nil { + return x.VarStack + } + return nil +} + +type isComponentRequest_QueryPath interface { + isComponentRequest_QueryPath() +} + +type ComponentRequest_Path struct { + Path string `protobuf:"bytes,1,opt,name=path,proto3,oneof"` +} + +type ComponentRequest_Query struct { + Query *ComponentQuery `protobuf:"bytes,2,opt,name=query,proto3,oneof"` +} + +func (*ComponentRequest_Path) isComponentRequest_QueryPath() {} + +func (*ComponentRequest_Query) isComponentRequest_QueryPath() {} + +type ComponentRuntimeRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Component string `protobuf:"bytes,1,opt,name=component,proto3" json:"component,omitempty"` + Entry string `protobuf:"bytes,2,opt,name=entry,proto3" json:"entry,omitempty"` +} + +func (x *ComponentRuntimeRequest) Reset() { + *x = ComponentRuntimeRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComponentRuntimeRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComponentRuntimeRequest) ProtoMessage() {} + +func (x *ComponentRuntimeRequest) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComponentRuntimeRequest.ProtoReflect.Descriptor instead. +func (*ComponentRuntimeRequest) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{3} +} + +func (x *ComponentRuntimeRequest) GetComponent() string { + if x != nil { + return x.Component + } + return "" +} + +func (x *ComponentRuntimeRequest) GetEntry() string { + if x != nil { + return x.Entry + } + return "" +} + +type ComponentResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Payload string `protobuf:"bytes,1,opt,name=payload,proto3" json:"payload,omitempty"` +} + +func (x *ComponentResponse) Reset() { + *x = ComponentResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComponentResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComponentResponse) ProtoMessage() {} + +func (x *ComponentResponse) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComponentResponse.ProtoReflect.Descriptor instead. +func (*ComponentResponse) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{4} +} + +func (x *ComponentResponse) GetPayload() string { + if x != nil { + return x.Payload + } + return "" +} + +type RunNumberResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RunNumber uint32 `protobuf:"varint,1,opt,name=runNumber,proto3" json:"runNumber,omitempty"` +} + +func (x *RunNumberResponse) Reset() { + *x = RunNumberResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RunNumberResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RunNumberResponse) ProtoMessage() {} + +func (x *RunNumberResponse) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RunNumberResponse.ProtoReflect.Descriptor instead. +func (*RunNumberResponse) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{5} +} + +func (x *RunNumberResponse) GetRunNumber() uint32 { + if x != nil { + return x.RunNumber + } + return 0 +} + +type StringMap struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StringMap map[string]string `protobuf:"bytes,1,rep,name=stringMap,proto3" json:"stringMap,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` +} + +func (x *StringMap) Reset() { + *x = StringMap{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_apricot_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StringMap) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StringMap) ProtoMessage() {} + +func (x *StringMap) ProtoReflect() protoreflect.Message { + mi := &file_protos_apricot_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StringMap.ProtoReflect.Descriptor instead. +func (*StringMap) Descriptor() ([]byte, []int) { + return file_protos_apricot_proto_rawDescGZIP(), []int{6} +} + +func (x *StringMap) GetStringMap() map[string]string { + if x != nil { + return x.StringMap + } + return nil +} + +var File_protos_apricot_proto protoreflect.FileDescriptor + +var file_protos_apricot_proto_rawDesc = []byte{ + 0x0a, 0x14, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x73, 0x2f, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x22, + 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xb0, 0x01, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, + 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x2a, 0x0a, 0x07, 0x72, 0x75, 0x6e, + 0x54, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x61, 0x70, 0x72, + 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x52, 0x75, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x52, 0x07, 0x72, 0x75, + 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, + 0x52, 0x6f, 0x6c, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6d, 0x61, 0x63, 0x68, + 0x69, 0x6e, 0x65, 0x52, 0x6f, 0x6c, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1c, 0x0a, + 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x22, 0x92, 0x02, 0x0a, 0x10, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x14, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, + 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x2f, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x51, 0x75, 0x65, 0x72, 0x79, 0x48, 0x00, + 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x28, 0x0a, 0x0f, 0x70, 0x72, 0x6f, 0x63, 0x65, + 0x73, 0x73, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x12, 0x43, 0x0a, 0x08, 0x76, 0x61, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x18, 0x04, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x43, 0x6f, + 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x56, + 0x61, 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x08, 0x76, 0x61, + 0x72, 0x53, 0x74, 0x61, 0x63, 0x6b, 0x1a, 0x3b, 0x0a, 0x0d, 0x56, 0x61, 0x72, 0x53, 0x74, 0x61, + 0x63, 0x6b, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x42, 0x0b, 0x0a, 0x09, 0x71, 0x75, 0x65, 0x72, 0x79, 0x50, 0x61, 0x74, 0x68, + 0x22, 0x4d, 0x0a, 0x17, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x75, 0x6e, + 0x74, 0x69, 0x6d, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x63, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6e, 0x74, + 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x22, + 0x2d, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x70, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x31, + 0x0a, 0x11, 0x52, 0x75, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x72, 0x75, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x09, 0x72, 0x75, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, + 0x72, 0x22, 0x8a, 0x01, 0x0a, 0x09, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x12, + 0x3f, 0x0a, 0x09, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x18, 0x01, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x09, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, + 0x1a, 0x3c, 0x0a, 0x0e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x2a, 0x38, + 0x0a, 0x07, 0x52, 0x75, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x55, 0x4c, + 0x4c, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x41, 0x4e, 0x59, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, + 0x50, 0x48, 0x59, 0x53, 0x49, 0x43, 0x53, 0x10, 0x02, 0x12, 0x0d, 0x0a, 0x09, 0x54, 0x45, 0x43, + 0x48, 0x4e, 0x49, 0x43, 0x41, 0x4c, 0x10, 0x03, 0x32, 0xda, 0x02, 0x0a, 0x07, 0x41, 0x70, 0x72, + 0x69, 0x63, 0x6f, 0x74, 0x12, 0x3c, 0x0a, 0x0c, 0x4e, 0x65, 0x77, 0x52, 0x75, 0x6e, 0x4e, 0x75, + 0x6d, 0x62, 0x65, 0x72, 0x12, 0x0e, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x52, + 0x75, 0x6e, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x22, 0x00, 0x12, 0x33, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x73, 0x12, 0x0e, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x22, 0x00, 0x12, 0x2f, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x56, 0x61, + 0x72, 0x73, 0x12, 0x0e, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x4d, 0x61, 0x70, 0x22, 0x00, 0x12, 0x54, 0x0a, 0x19, 0x47, 0x65, 0x74, 0x43, + 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, + 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x55, + 0x0a, 0x13, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x75, + 0x6e, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x20, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x75, 0x6e, 0x74, 0x69, 0x6d, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, + 0x74, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x0a, 0x22, 0x63, 0x68, 0x2e, 0x63, 0x65, 0x72, 0x6e, + 0x2e, 0x61, 0x6c, 0x69, 0x63, 0x65, 0x2e, 0x6f, 0x32, 0x2e, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, + 0x74, 0x2e, 0x72, 0x70, 0x63, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x10, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x3b, 0x61, 0x70, 0x72, 0x69, 0x63, 0x6f, 0x74, 0x70, 0x62, 0x62, 0x06, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_protos_apricot_proto_rawDescOnce sync.Once + file_protos_apricot_proto_rawDescData = file_protos_apricot_proto_rawDesc +) + +func file_protos_apricot_proto_rawDescGZIP() []byte { + file_protos_apricot_proto_rawDescOnce.Do(func() { + file_protos_apricot_proto_rawDescData = protoimpl.X.CompressGZIP(file_protos_apricot_proto_rawDescData) + }) + return file_protos_apricot_proto_rawDescData +} + +var file_protos_apricot_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_protos_apricot_proto_msgTypes = make([]protoimpl.MessageInfo, 9) +var file_protos_apricot_proto_goTypes = []interface{}{ + (RunType)(0), // 0: apricot.RunType + (*Empty)(nil), // 1: apricot.Empty + (*ComponentQuery)(nil), // 2: apricot.ComponentQuery + (*ComponentRequest)(nil), // 3: apricot.ComponentRequest + (*ComponentRuntimeRequest)(nil), // 4: apricot.ComponentRuntimeRequest + (*ComponentResponse)(nil), // 5: apricot.ComponentResponse + (*RunNumberResponse)(nil), // 6: apricot.RunNumberResponse + (*StringMap)(nil), // 7: apricot.StringMap + nil, // 8: apricot.ComponentRequest.VarStackEntry + nil, // 9: apricot.StringMap.StringMapEntry +} +var file_protos_apricot_proto_depIdxs = []int32{ + 0, // 0: apricot.ComponentQuery.runType:type_name -> apricot.RunType + 2, // 1: apricot.ComponentRequest.query:type_name -> apricot.ComponentQuery + 8, // 2: apricot.ComponentRequest.varStack:type_name -> apricot.ComponentRequest.VarStackEntry + 9, // 3: apricot.StringMap.stringMap:type_name -> apricot.StringMap.StringMapEntry + 1, // 4: apricot.Apricot.NewRunNumber:input_type -> apricot.Empty + 1, // 5: apricot.Apricot.GetDefaults:input_type -> apricot.Empty + 1, // 6: apricot.Apricot.GetVars:input_type -> apricot.Empty + 3, // 7: apricot.Apricot.GetComponentConfiguration:input_type -> apricot.ComponentRequest + 4, // 8: apricot.Apricot.GetComponentRuntime:input_type -> apricot.ComponentRuntimeRequest + 6, // 9: apricot.Apricot.NewRunNumber:output_type -> apricot.RunNumberResponse + 7, // 10: apricot.Apricot.GetDefaults:output_type -> apricot.StringMap + 7, // 11: apricot.Apricot.GetVars:output_type -> apricot.StringMap + 5, // 12: apricot.Apricot.GetComponentConfiguration:output_type -> apricot.ComponentResponse + 5, // 13: apricot.Apricot.GetComponentRuntime:output_type -> apricot.ComponentResponse + 9, // [9:14] is the sub-list for method output_type + 4, // [4:9] is the sub-list for method input_type + 4, // [4:4] is the sub-list for extension type_name + 4, // [4:4] is the sub-list for extension extendee + 0, // [0:4] is the sub-list for field type_name +} + +func init() { file_protos_apricot_proto_init() } +func file_protos_apricot_proto_init() { + if File_protos_apricot_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_protos_apricot_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_apricot_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComponentQuery); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_apricot_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComponentRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_apricot_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComponentRuntimeRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_apricot_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ComponentResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_apricot_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RunNumberResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_apricot_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StringMap); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + file_protos_apricot_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*ComponentRequest_Path)(nil), + (*ComponentRequest_Query)(nil), + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_protos_apricot_proto_rawDesc, + NumEnums: 1, + NumMessages: 9, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_protos_apricot_proto_goTypes, + DependencyIndexes: file_protos_apricot_proto_depIdxs, + EnumInfos: file_protos_apricot_proto_enumTypes, + MessageInfos: file_protos_apricot_proto_msgTypes, + }.Build() + File_protos_apricot_proto = out.File + file_protos_apricot_proto_rawDesc = nil + file_protos_apricot_proto_goTypes = nil + file_protos_apricot_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// ApricotClient is the client API for Apricot service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type ApricotClient interface { + NewRunNumber(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*RunNumberResponse, error) + GetDefaults(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StringMap, error) + GetVars(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StringMap, error) + GetComponentConfiguration(ctx context.Context, in *ComponentRequest, opts ...grpc.CallOption) (*ComponentResponse, error) + GetComponentRuntime(ctx context.Context, in *ComponentRuntimeRequest, opts ...grpc.CallOption) (*ComponentResponse, error) +} + +type apricotClient struct { + cc grpc.ClientConnInterface +} + +func NewApricotClient(cc grpc.ClientConnInterface) ApricotClient { + return &apricotClient{cc} +} + +func (c *apricotClient) NewRunNumber(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*RunNumberResponse, error) { + out := new(RunNumberResponse) + err := c.cc.Invoke(ctx, "/apricot.Apricot/NewRunNumber", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *apricotClient) GetDefaults(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StringMap, error) { + out := new(StringMap) + err := c.cc.Invoke(ctx, "/apricot.Apricot/GetDefaults", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *apricotClient) GetVars(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*StringMap, error) { + out := new(StringMap) + err := c.cc.Invoke(ctx, "/apricot.Apricot/GetVars", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *apricotClient) GetComponentConfiguration(ctx context.Context, in *ComponentRequest, opts ...grpc.CallOption) (*ComponentResponse, error) { + out := new(ComponentResponse) + err := c.cc.Invoke(ctx, "/apricot.Apricot/GetComponentConfiguration", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *apricotClient) GetComponentRuntime(ctx context.Context, in *ComponentRuntimeRequest, opts ...grpc.CallOption) (*ComponentResponse, error) { + out := new(ComponentResponse) + err := c.cc.Invoke(ctx, "/apricot.Apricot/GetComponentRuntime", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// ApricotServer is the server API for Apricot service. +type ApricotServer interface { + NewRunNumber(context.Context, *Empty) (*RunNumberResponse, error) + GetDefaults(context.Context, *Empty) (*StringMap, error) + GetVars(context.Context, *Empty) (*StringMap, error) + GetComponentConfiguration(context.Context, *ComponentRequest) (*ComponentResponse, error) + GetComponentRuntime(context.Context, *ComponentRuntimeRequest) (*ComponentResponse, error) +} + +// UnimplementedApricotServer can be embedded to have forward compatible implementations. +type UnimplementedApricotServer struct { +} + +func (*UnimplementedApricotServer) NewRunNumber(context.Context, *Empty) (*RunNumberResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method NewRunNumber not implemented") +} +func (*UnimplementedApricotServer) GetDefaults(context.Context, *Empty) (*StringMap, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetDefaults not implemented") +} +func (*UnimplementedApricotServer) GetVars(context.Context, *Empty) (*StringMap, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetVars not implemented") +} +func (*UnimplementedApricotServer) GetComponentConfiguration(context.Context, *ComponentRequest) (*ComponentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetComponentConfiguration not implemented") +} +func (*UnimplementedApricotServer) GetComponentRuntime(context.Context, *ComponentRuntimeRequest) (*ComponentResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method GetComponentRuntime not implemented") +} + +func RegisterApricotServer(s *grpc.Server, srv ApricotServer) { + s.RegisterService(&_Apricot_serviceDesc, srv) +} + +func _Apricot_NewRunNumber_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApricotServer).NewRunNumber(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apricot.Apricot/NewRunNumber", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApricotServer).NewRunNumber(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apricot_GetDefaults_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApricotServer).GetDefaults(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apricot.Apricot/GetDefaults", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApricotServer).GetDefaults(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apricot_GetVars_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApricotServer).GetVars(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apricot.Apricot/GetVars", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApricotServer).GetVars(ctx, req.(*Empty)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apricot_GetComponentConfiguration_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ComponentRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApricotServer).GetComponentConfiguration(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apricot.Apricot/GetComponentConfiguration", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApricotServer).GetComponentConfiguration(ctx, req.(*ComponentRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Apricot_GetComponentRuntime_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(ComponentRuntimeRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ApricotServer).GetComponentRuntime(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/apricot.Apricot/GetComponentRuntime", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ApricotServer).GetComponentRuntime(ctx, req.(*ComponentRuntimeRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _Apricot_serviceDesc = grpc.ServiceDesc{ + ServiceName: "apricot.Apricot", + HandlerType: (*ApricotServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "NewRunNumber", + Handler: _Apricot_NewRunNumber_Handler, + }, + { + MethodName: "GetDefaults", + Handler: _Apricot_GetDefaults_Handler, + }, + { + MethodName: "GetVars", + Handler: _Apricot_GetVars_Handler, + }, + { + MethodName: "GetComponentConfiguration", + Handler: _Apricot_GetComponentConfiguration_Handler, + }, + { + MethodName: "GetComponentRuntime", + Handler: _Apricot_GetComponentRuntime_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "protos/apricot.proto", +} diff --git a/apricot/protos/apricot.proto b/apricot/protos/apricot.proto new file mode 100644 index 000000000..71ab27953 --- /dev/null +++ b/apricot/protos/apricot.proto @@ -0,0 +1,80 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2020 CERN and copyright holders of ALICE O². + * Author: Teo Mrnjavac + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In applying this license CERN does not waive the privileges and + * immunities granted to it by virtue of its status as an + * Intergovernmental Organization or submit itself to any jurisdiction. + */ + +syntax = "proto3"; + +package apricot; +option java_package = "ch.cern.alice.o2.apricot.rpcserver"; +option go_package = "protos;apricotpb"; + +service Apricot { + rpc NewRunNumber(Empty) returns (RunNumberResponse) {} + rpc GetDefaults(Empty) returns (StringMap) {} + rpc GetVars(Empty) returns (StringMap) {} + rpc GetComponentConfiguration(ComponentRequest) returns (ComponentResponse) {} + rpc GetComponentRuntime(ComponentRuntimeRequest) returns (ComponentResponse) {} +} + +enum RunType { + NULL = 0; + ANY = 1; + PHYSICS = 2; + TECHNICAL = 3; +} + +message Empty {} + +message ComponentQuery { + string component = 1; + RunType runType = 2; + string machineRole = 3; + string entry = 4; + string timestamp = 5; +} + +message ComponentRequest { + oneof queryPath { + string path = 1; + ComponentQuery query = 2; + } + bool processTemplate = 3; + map varStack = 4; +} + +message ComponentRuntimeRequest { + string component = 1; + string entry = 2; +} + +message ComponentResponse { + string payload = 1; +} + +message RunNumberResponse { + uint32 runNumber = 1; +} + +message StringMap { + map stringMap = 1; +} \ No newline at end of file diff --git a/apricot/server.go b/apricot/server.go new file mode 100644 index 000000000..390c1aeff --- /dev/null +++ b/apricot/server.go @@ -0,0 +1,168 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2020 CERN and copyright holders of ALICE O². + * Author: Teo Mrnjavac + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In applying this license CERN does not waive the privileges and + * immunities granted to it by virtue of its status as an + * Intergovernmental Organization or submit itself to any jurisdiction. + */ + +// A Processor and ReposItory for COnfiguration Templates +package apricot + +import ( + "context" + "runtime" + + apricotpb "github.com/AliceO2Group/Control/apricot/protos" + "github.com/AliceO2Group/Control/common/logger" + "github.com/AliceO2Group/Control/configuration/componentcfg" + "github.com/sirupsen/logrus" + "github.com/spf13/viper" + "google.golang.org/grpc" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/reflection" + "google.golang.org/grpc/status" +) + +//go:generate protoc --go_out=plugins=grpc:. protos/apricot.proto + + +var log = logger.New(logrus.StandardLogger(),"apricot") + +var( + E_OK = status.New(codes.OK, "") + E_CONFIGURATION_BACKEND_UNAVAILABLE = status.Errorf(codes.Internal, "configuration backend unavailable") + E_BAD_INPUT = status.Errorf(codes.InvalidArgument, "bad request received") +) + +type RepoService interface { + +} +type Service interface { + RepoService + NewRunNumber() (runNumber uint32, err error) + GetDefaults() map[string]string + GetVars() map[string]string + GetComponentConfiguration(query *componentcfg.Query) (payload string, err error) + GetAndProcessComponentConfiguration(query *componentcfg.Query, varStack map[string]string) (payload string, err error) +} + +type RpcServer struct { + service Service +} + +func (m *RpcServer) NewRunNumber(_ context.Context, _ *apricotpb.Empty) (*apricotpb.RunNumberResponse, error) { + if m == nil || m.service == nil { + return nil, E_CONFIGURATION_BACKEND_UNAVAILABLE + } + m.logMethod() + rn, err := m.service.NewRunNumber() + return &apricotpb.RunNumberResponse{RunNumber: rn}, err +} + +func (m *RpcServer) GetDefaults(_ context.Context, _ *apricotpb.Empty) (*apricotpb.StringMap, error) { + if m == nil || m.service == nil { + return nil, E_CONFIGURATION_BACKEND_UNAVAILABLE + } + m.logMethod() + varStack := m.service.GetDefaults() + return &apricotpb.StringMap{StringMap: varStack}, E_OK.Err() +} + +func (m *RpcServer) GetVars(_ context.Context, _ *apricotpb.Empty) (*apricotpb.StringMap, error) { + if m == nil || m.service == nil { + return nil, E_CONFIGURATION_BACKEND_UNAVAILABLE + } + m.logMethod() + varStack := m.service.GetVars() + return &apricotpb.StringMap{StringMap: varStack}, E_OK.Err() +} + +func (m *RpcServer) GetComponentConfiguration(_ context.Context, request *apricotpb.ComponentRequest) (*apricotpb.ComponentResponse, error) { + if m == nil || m.service == nil { + return nil, E_CONFIGURATION_BACKEND_UNAVAILABLE + } + m.logMethod() + + if request == nil { + return nil, E_BAD_INPUT + } + + var path *componentcfg.Query + if rawPath := request.GetPath(); len(rawPath) > 0 { + var err error + path, err = componentcfg.NewQuery(rawPath) + if err != nil { + return nil, E_BAD_INPUT + } + } else if query := request.GetQuery(); query != nil { + path = &componentcfg.Query{ + Component: query.Component, + Flavor: query.RunType.String(), + Rolename: query.MachineRole, + EntryKey: query.Entry, + Timestamp: query.Timestamp, + } + } else { + return nil, E_BAD_INPUT + } + + var payload string + var err error + if request.ProcessTemplate { + payload, err = m.service.GetAndProcessComponentConfiguration(path.Path()) + } else { + payload, err := m.service.GetComponentConfiguration(path.Path()) + if err != nil { + return nil, err + } + return &apricotpb.ComponentResponse{Payload: payload}, E_OK.Err() + } +} + +func (m *RpcServer) GetComponentRuntime(ctx context.Context, request *apricotpb.ComponentRuntimeRequest) (*apricotpb.ComponentResponse, error) { + panic("implement me") +} + +func NewServer(service Service) *grpc.Server { + s := grpc.NewServer() + apricotpb.RegisterApricotServer(s, &RpcServer{ + service: service, + }) + // Register reflection service on gRPC server. + reflection.Register(s) + return s +} + +func (m *RpcServer) logMethod() { + if !viper.GetBool("verbose") { + return + } + pc, _, _, ok := runtime.Caller(1) + if !ok { + return + } + fun := runtime.FuncForPC(pc) + if fun == nil { + return + } + log.WithPrefix("apricot"). + WithField("method", fun.Name()). + Trace("handling RPC request") +} diff --git a/coconut/configuration/configuration.go b/coconut/configuration/configuration.go index bd83fb06e..e9a882cd1 100644 --- a/coconut/configuration/configuration.go +++ b/coconut/configuration/configuration.go @@ -39,7 +39,7 @@ import ( "github.com/AliceO2Group/Control/common/logger" "github.com/AliceO2Group/Control/common/utils" - "github.com/AliceO2Group/Control/configuration" + "github.com/AliceO2Group/Control/configuration/cfgbackend" "github.com/AliceO2Group/Control/configuration/componentcfg" "github.com/AliceO2Group/Control/configuration/the" "github.com/briandowns/spinner" @@ -54,7 +54,7 @@ var log = logger.New(logrus.StandardLogger(), "coconut") type RunFunc func(*cobra.Command, []string) -type ConfigurationCall func(*configuration.ConsulSource, *cobra.Command, []string, io.Writer) (error, int) +type ConfigurationCall func(*cfgbackend.ConsulSource, *cobra.Command, []string, io.Writer) (error, int) const ( EC_ZERO = iota @@ -78,7 +78,7 @@ func WrapCall(call ConfigurationCall) RunFunc { s.Suffix = " working..." s.Start() - cfg, err := configuration.NewConsulSource(strings.TrimPrefix(endpoint, "consul://")) + cfg, err := cfgbackend.NewConsulSource(strings.TrimPrefix(endpoint, "consul://")) if err != nil { var fields logrus.Fields if logrus.GetLevel() == logrus.DebugLevel { @@ -109,7 +109,7 @@ func WrapCall(call ConfigurationCall) RunFunc { } } -func Dump(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o io.Writer) (err error, code int) { +func Dump(cfg *cfgbackend.ConsulSource, cmd *cobra.Command, args []string, o io.Writer) (err error, code int) { if len(args) != 1 { err = errors.New(fmt.Sprintf("accepts 1 arg(s), received %d", len(args))) return err, EC_INVALID_ARGS @@ -146,7 +146,7 @@ func Dump(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o } // coconut conf list -func List(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o io.Writer)(err error, code int) { +func List(cfg *cfgbackend.ConsulSource, cmd *cobra.Command, args []string, o io.Writer)(err error, code int) { keyPrefix := componentcfg.ConfigComponentsPath useTimestamp := false if len(args) > 1 { @@ -188,9 +188,9 @@ func List(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o return nil, EC_ZERO } -func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o io.Writer)(err error, code int) { +func Show(cfg *cfgbackend.ConsulSource, cmd *cobra.Command, args []string, o io.Writer)(err error, code int) { var timestamp string - var p = &componentcfg.Path{} + var query = &componentcfg.Query{} if len(args) < 1 || len(args) > 2 { return errors.New(fmt.Sprintf("accepts 1 or 2 arg(s), but received %d", len(args))), EC_INVALID_ARGS @@ -210,19 +210,19 @@ func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o err = errors.New("flag `-t / --timestamp` must not be provided when using format ///@") return err, EC_INVALID_ARGS } - p, err = componentcfg.NewPath(args[0]) + query, err = componentcfg.NewQuery(args[0]) if err != nil { return err, EC_INVALID_ARGS } - timestamp = p.Timestamp + timestamp = query.Timestamp } else if strings.Contains(args[0], "/") { // coconut conf show c/R/r/e # no timestamp - p, err = componentcfg.NewPath(args[0]) + query, err = componentcfg.NewQuery(args[0]) if err != nil { return err, EC_INVALID_ARGS } if timestamp == "" { - timestamp = p.Timestamp + timestamp = query.Timestamp } } } else { @@ -233,20 +233,20 @@ func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o if !componentcfg.IsInputSingleValidWord(args[0]) || !componentcfg.IsInputSingleValidWord(args[1]) { return errors.New(EC_INVALID_ARGS_MSG), EC_INVALID_ARGS } else { - p.Component = args[0] - p.EntryKey = args[1] - p.Flavor = "ANY" - p.Rolename = "any" + query.Component = args[0] + query.EntryKey = args[1] + query.Flavor = "ANY" + query.Rolename = "any" } } - fullKeyToQuery := p.AbsoluteWithoutTimestamp() + fullKeyToQuery := query.AbsoluteWithoutTimestamp() if timestamp == "" { // No timestamp was passed, either via -t or @ // We need to ascertain whether the required entry is versioned // or unversioned. - keyPrefix := p.AbsoluteWithoutTimestamp() + keyPrefix := query.AbsoluteWithoutTimestamp() if cfg.IsDir(keyPrefix) { // The requested path is a Consul folder, so we should // look inside to find the latest timestamp. @@ -254,7 +254,7 @@ func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o if err != nil { return err, EC_CONNECTION_ERROR } - timestamp, err = componentcfg.GetLatestTimestamp(keys, p) + timestamp, err = componentcfg.GetLatestTimestamp(keys, query) if err != nil { return err, EC_EMPTY_DATA } @@ -268,11 +268,11 @@ func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o // We can safely append it to the full query path. fullKeyToQuery += componentcfg.SEPARATOR + timestamp } - p.Timestamp = timestamp + query.Timestamp = timestamp // At this point we know what to query, either fullKeyToQuery // for a raw configuration.ConsulSource query, or a - // componentcfg.Path that can be fed to the.ConfSvc(). + // componentcfg.Query that can be fed to the.ConfSvc(). var( cfgPayload string simulate bool @@ -301,8 +301,8 @@ func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o return err, EC_INVALID_ARGS } - fmt.Fprintf(o,"%s", p.Path()) - cfgPayload, err = the.ConfSvc().GetAndProcessComponentConfiguration(p.Path(), extraVarsMap) + fmt.Fprintf(o,"%s", query.Path()) + cfgPayload, err = the.ConfSvc().GetAndProcessComponentConfiguration(query, extraVarsMap) if err != nil { return err, EC_CONNECTION_ERROR } @@ -321,8 +321,8 @@ func Show(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o return nil, EC_ZERO } -func History(cfg *configuration.ConsulSource, _ *cobra.Command, args []string, o io.Writer)(err error, code int) { - p := &componentcfg.Path{} +func History(cfg *cfgbackend.ConsulSource, _ *cobra.Command, args []string, o io.Writer)(err error, code int) { + p := &componentcfg.Query{} if len(args) < 1 || len(args) > 2 { return errors.New(fmt.Sprintf("accepts 1 or 2 arg(s), but received %d", len(args))), EC_INVALID_ARGS @@ -332,7 +332,7 @@ func History(cfg *configuration.ConsulSource, _ *cobra.Command, args []string, o if componentcfg.IsInputSingleValidWord(args[0]) { p.Component = args[0] } else if componentcfg.IsInputCompEntryTsValid(args[0]) && !strings.Contains(args[0], "@"){ - p, err = componentcfg.NewPath(args[0]) + p, err = componentcfg.NewQuery(args[0]) if err != nil { return err, EC_INVALID_ARGS } @@ -369,8 +369,8 @@ func History(cfg *configuration.ConsulSource, _ *cobra.Command, args []string, o entry := p.EntryKey for _, value := range keys { - var thisPath *componentcfg.Path - thisPath, err = componentcfg.NewPath(value) + var thisPath *componentcfg.Query + thisPath, err = componentcfg.NewQuery(value) if err != nil { continue } @@ -392,7 +392,7 @@ func History(cfg *configuration.ConsulSource, _ *cobra.Command, args []string, o return nil, 0 } -func Import(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, o io.Writer)(err error, code int) { +func Import(cfg *cfgbackend.ConsulSource, cmd *cobra.Command, args []string, o io.Writer)(err error, code int) { useNewComponent, err := cmd.Flags().GetBool("new-component") if err != nil { return err, EC_INVALID_ARGS @@ -408,14 +408,14 @@ func Import(cfg *configuration.ConsulSource, cmd *cobra.Command, args []string, // Parse and Format input arguments var filePath string - var p = &componentcfg.Path{} + var p = &componentcfg.Query{} if len(args) < 2 || len(args) > 3 { return errors.New(fmt.Sprintf("accepts 2 or 3 args but received %d", len(args))), EC_INVALID_ARGS } else { switch len(args) { case 2: // coconut conf import component/RUNTYPE/role/entry filepath - p, err = componentcfg.NewPath(args[0]) + p, err = componentcfg.NewQuery(args[0]) if err != nil { return err, EC_INVALID_ARGS } diff --git a/coconut/configuration/configurationutil.go b/coconut/configuration/configurationutil.go index e01d825dc..63b3982c8 100644 --- a/coconut/configuration/configurationutil.go +++ b/coconut/configuration/configurationutil.go @@ -103,7 +103,7 @@ func drawTableHistoryConfigs(headers []string, history []string, max int, o io.W table.SetColMinWidth(0, max) for _, value := range history { - p, err := componentcfg.NewPath(value) + p, err := componentcfg.NewQuery(value) if err != nil { continue } diff --git a/configuration/configuration_suite_test.go b/configuration/cfgbackend/configuration_suite_test.go similarity index 87% rename from configuration/configuration_suite_test.go rename to configuration/cfgbackend/configuration_suite_test.go index bc4f5d411..fdbb2984f 100644 --- a/configuration/configuration_suite_test.go +++ b/configuration/cfgbackend/configuration_suite_test.go @@ -1,4 +1,4 @@ -package configuration_test +package cfgbackend_test import ( "io" @@ -29,7 +29,7 @@ var _ = BeforeSuite(func() { Expect(err).NotTo(HaveOccurred()) defer from.Close() - to, err := os.OpenFile(*tmpDir + "/" + configFile, os.O_RDWR|os.O_CREATE, 0666) + to, err := os.OpenFile(*tmpDir+ "/" +configFile, os.O_RDWR|os.O_CREATE, 0666) Expect(err).NotTo(HaveOccurred()) defer to.Close() diff --git a/configuration/configuration_test.yaml b/configuration/cfgbackend/configuration_test.yaml similarity index 100% rename from configuration/configuration_test.yaml rename to configuration/cfgbackend/configuration_test.yaml diff --git a/configuration/configurationmap.go b/configuration/cfgbackend/configurationmap.go similarity index 99% rename from configuration/configurationmap.go rename to configuration/cfgbackend/configurationmap.go index b2171b8e3..186978e3d 100644 --- a/configuration/configurationmap.go +++ b/configuration/cfgbackend/configurationmap.go @@ -22,7 +22,7 @@ * Intergovernmental Organization or submit itself to any jurisdiction. */ -package configuration +package cfgbackend import ( "errors" diff --git a/configuration/consulsource.go b/configuration/cfgbackend/consulsource.go similarity index 99% rename from configuration/consulsource.go rename to configuration/cfgbackend/consulsource.go index e6812a2be..4ff2f692e 100644 --- a/configuration/consulsource.go +++ b/configuration/cfgbackend/consulsource.go @@ -22,14 +22,15 @@ * Intergovernmental Organization or submit itself to any jurisdiction. */ -package configuration +package cfgbackend import ( - "github.com/hashicorp/consul/api" "errors" "fmt" "strconv" "strings" + + "github.com/hashicorp/consul/api" "gopkg.in/yaml.v3" ) diff --git a/configuration/source.go b/configuration/cfgbackend/source.go similarity index 98% rename from configuration/source.go rename to configuration/cfgbackend/source.go index 17cb3ea2f..b9bac1eea 100644 --- a/configuration/source.go +++ b/configuration/cfgbackend/source.go @@ -25,11 +25,11 @@ // Package configuration defines the Source interface as the // main access point to O² Configuration backends. // Consul and YAML backends are also provided. -package configuration +package cfgbackend import ( - "strings" "errors" + "strings" ) type ROSource interface { diff --git a/configuration/source_test.go b/configuration/cfgbackend/source_test.go similarity index 72% rename from configuration/source_test.go rename to configuration/cfgbackend/source_test.go index f19d0d62c..e98c24e97 100644 --- a/configuration/source_test.go +++ b/configuration/cfgbackend/source_test.go @@ -1,7 +1,7 @@ -package configuration_test +package cfgbackend_test import ( - . "github.com/AliceO2Group/Control/configuration" + "github.com/AliceO2Group/Control/configuration/cfgbackend" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" "gopkg.in/yaml.v3" @@ -9,80 +9,80 @@ import ( var _ = Describe("Source", func() { var ( - c Source + c cfgbackend.Source err error ) DoConfigurationTests := func() { var ( - o2_control_tasks_1_map = Map{ - "name": String("fairmq-ex-1-n-1-sampler"), - "control": Map{ - "mode": String("fairmq"), + o2_control_tasks_1_map = cfgbackend.Map{ + "name": cfgbackend.String("fairmq-ex-1-n-1-sampler"), + "control": cfgbackend.Map{ + "mode": cfgbackend.String("fairmq"), }, - "wants": Map{ - "cpu": String("1"), - "memory": String("256"), - "ports": String("1"), + "wants": cfgbackend.Map{ + "cpu": cfgbackend.String("1"), + "memory": cfgbackend.String("256"), + "ports": cfgbackend.String("1"), }, - "bind": Array{ - Map{ - "name": String("data1"), - "type": String("push"), - "sndBufSize": String("1000"), - "rcvBufSize": String("1000"), - "rateLogging": String("0"), + "bind": cfgbackend.Array{ + cfgbackend.Map{ + "name": cfgbackend.String("data1"), + "type": cfgbackend.String("push"), + "sndBufSize": cfgbackend.String("1000"), + "rcvBufSize": cfgbackend.String("1000"), + "rateLogging": cfgbackend.String("0"), }, }, - "properties": Map{ - "severity": String("trace"), - "color": String("false"), + "properties": cfgbackend.Map{ + "severity": cfgbackend.String("trace"), + "color": cfgbackend.String("false"), }, - "command": Map{ - "env": Array{}, - "shell": String("true"), - "arguments": Array{}, - "value": String("fairmq-ex-1-n-1-sampler"), + "command": cfgbackend.Map{ + "env": cfgbackend.Array{}, + "shell": cfgbackend.String("true"), + "arguments": cfgbackend.Array{}, + "value": cfgbackend.String("fairmq-ex-1-n-1-sampler"), }, } - recursivePutMap = Map{ - "firstKey": String("one"), - "secondKey": Array{ - Map{ - "name": String("first"), - "type": String("an array item"), + recursivePutMap = cfgbackend.Map{ + "firstKey": cfgbackend.String("one"), + "secondKey": cfgbackend.Array{ + cfgbackend.Map{ + "name": cfgbackend.String("first"), + "type": cfgbackend.String("an array item"), }, - Map{ - "name": String("second"), - "type": String("an array item"), + cfgbackend.Map{ + "name": cfgbackend.String("second"), + "type": cfgbackend.String("an array item"), }, - Map{ - "name": String("third"), - "type": String("and yet another array item"), + cfgbackend.Map{ + "name": cfgbackend.String("third"), + "type": cfgbackend.String("and yet another array item"), }, }, - "thirdKey": Map{ - "just some": String("stuff"), + "thirdKey": cfgbackend.Map{ + "just some": cfgbackend.String("stuff"), }, } - recursivePutArray = Array{ - Map{ - "name": String("first"), - "type": String("an array item with a property map inside"), - "properties": Map{ - "just some": String("stuff"), + recursivePutArray = cfgbackend.Array{ + cfgbackend.Map{ + "name": cfgbackend.String("first"), + "type": cfgbackend.String("an array item with a property map inside"), + "properties": cfgbackend.Map{ + "just some": cfgbackend.String("stuff"), }, }, - Map{ - "name": String("second"), - "type": String("an array item"), + cfgbackend.Map{ + "name": cfgbackend.String("second"), + "type": cfgbackend.String("an array item"), }, - Map{ - "name": String("third"), - "type": String("and yet another array item"), + cfgbackend.Map{ + "name": cfgbackend.String("third"), + "type": cfgbackend.String("and yet another array item"), }, } - recursivePutString = String("this is a bit underwhelming compared to the other two...") + recursivePutString = cfgbackend.String("this is a bit underwhelming compared to the other two...") ) It("should return no error when creating an instance", func() { @@ -210,11 +210,11 @@ var _ = Describe("Source", func() { Describe("when interacting with an instance", func() { Context("with Consul backend", func() { BeforeEach(func() { - c, err = NewSource("consul://dummy") + c, err = cfgbackend.NewSource("consul://dummy") }) It("should be of type *ConsulSource", func() { - _, ok := c.(*ConsulSource) + _, ok := c.(*cfgbackend.ConsulSource) Expect(ok).To(Equal(true)) }) @@ -223,11 +223,11 @@ var _ = Describe("Source", func() { Context("with YAML file backend", func() { BeforeEach(func() { - c, err = NewSource("file://" + *tmpDir + "/" + configFile) + c, err = cfgbackend.NewSource("file://" + *tmpDir + "/" + configFile) }) It("should be of type *YamlSource", func() { - _, ok := c.(*YamlSource) + _, ok := c.(*cfgbackend.YamlSource) Expect(ok).To(Equal(true)) }) diff --git a/configuration/yamlsource.go b/configuration/cfgbackend/yamlsource.go similarity index 99% rename from configuration/yamlsource.go rename to configuration/cfgbackend/yamlsource.go index ce5918755..25cf93630 100644 --- a/configuration/yamlsource.go +++ b/configuration/cfgbackend/yamlsource.go @@ -22,7 +22,7 @@ * Intergovernmental Organization or submit itself to any jurisdiction. */ -package configuration +package cfgbackend import ( "errors" @@ -399,7 +399,7 @@ func (yc *YamlSource) PutRecursive(key string, value Item) (err error) { func (yc *YamlSource) PutRecursiveYaml(key string, value []byte) (err error) { var ( - raw interface{} + raw interface{} cooked Item ) err = yaml.Unmarshal(value, &raw) diff --git a/configuration/componentcfg/componentcfg.go b/configuration/componentcfg/componentcfg.go index 9606ddcdd..d8ec44187 100644 --- a/configuration/componentcfg/componentcfg.go +++ b/configuration/componentcfg/componentcfg.go @@ -27,7 +27,6 @@ package componentcfg import ( "errors" - "regexp" "strconv" "strings" "time" @@ -42,84 +41,6 @@ const( SEPARATOR_RUNE = '/' ) -var ( - // component /RUNTYPE /rolename /entry @timestamp - inputFullRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+)(\/[A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}(\@[0-9]+)?$`) -) - -type Path struct { - Component string - Flavor string - Rolename string - EntryKey string - Timestamp string -} - -func NewPath(path string) (p *Path, err error) { - p = &Path{ - Component: "", - Flavor: "", - Rolename: "", - EntryKey: "", - Timestamp: "", - } - if IsInputCompEntryTsValid(path) { - if strings.Contains(path, "@") { - // coconut conf show component/FLAVOR/rolename/entry@timestamp - arg := strings.Replace(path, "@", SEPARATOR, 1) - params := strings.Split(arg, SEPARATOR) - p.Component = params[0] - p.Flavor = params[1] - p.Rolename = params[2] - p.EntryKey = params[3] - p.Timestamp = params[4] - } else if strings.Contains(path, SEPARATOR) { - // coconut conf show component/FLAVOR/rolename/entry - params := strings.Split(path, SEPARATOR) - p.Component = params[0] - p.Flavor = params[1] - p.Rolename = params[2] - p.EntryKey = params[3] - // and if we received a raw path (with / instead of @ before timestamp): - if len(params) > 4 && len(params[4]) > 0 { - p.Timestamp = params[4] - } - } - } else { - err = errors.New("bad component configuration key format") - return - } - - return p, nil -} - -func (p *Path) Path() string { - path := p.WithoutTimestamp() - if len(p.Timestamp) > 0 { - return path + "@" + p.Timestamp - } - return path -} - -func (p *Path) Raw() string { - path := p.WithoutTimestamp() - if len(p.Timestamp) > 0 { - return path + SEPARATOR + p.Timestamp - } - return path -} - -func (p *Path) WithoutTimestamp() string { - return p.Component + SEPARATOR + p.Flavor + SEPARATOR + p.Rolename + SEPARATOR + p.EntryKey -} - -func (p *Path) AbsoluteRaw() string { - return ConfigComponentsPath + p.Raw() -} - -func (p *Path) AbsoluteWithoutTimestamp() string { - return ConfigComponentsPath + p.WithoutTimestamp() -} func IsInputCompEntryTsValid(input string) bool { return inputFullRegex.MatchString(input) @@ -142,7 +63,7 @@ func GetTimestampInFormat(timestamp string, timeFormat string)(string, error){ // Method to return the latest timestamp for a specified component & entry // If no keys were passed an error and code exit 3 will be returned -func GetLatestTimestamp(keys []string, p *Path)(timestamp string, err error) { +func GetLatestTimestamp(keys []string, p *Query)(timestamp string, err error) { keyPrefix := p.AbsoluteWithoutTimestamp() if len(keys) == 0 { err = errors.New("no keys found") diff --git a/configuration/componentcfg/query.go b/configuration/componentcfg/query.go new file mode 100644 index 000000000..d83a35e14 --- /dev/null +++ b/configuration/componentcfg/query.go @@ -0,0 +1,110 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2020 CERN and copyright holders of ALICE O². + * Author: Teo Mrnjavac + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In applying this license CERN does not waive the privileges and + * immunities granted to it by virtue of its status as an + * Intergovernmental Organization or submit itself to any jurisdiction. + */ + +package componentcfg + +import ( + "errors" + "regexp" + "strings" +) + +var ( + // component /RUNTYPE /rolename /entry @timestamp + inputFullRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+)(\/[A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}(\@[0-9]+)?$`) +) + +type Query struct { + Component string + Flavor string + Rolename string + EntryKey string + Timestamp string +} + +func NewQuery(path string) (p *Query, err error) { + p = &Query{ + Component: "", + Flavor: "", + Rolename: "", + EntryKey: "", + Timestamp: "", + } + if IsInputCompEntryTsValid(path) { + if strings.Contains(path, "@") { + // coconut conf show component/FLAVOR/rolename/entry@timestamp + arg := strings.Replace(path, "@", SEPARATOR, 1) + params := strings.Split(arg, SEPARATOR) + p.Component = params[0] + p.Flavor = params[1] + p.Rolename = params[2] + p.EntryKey = params[3] + p.Timestamp = params[4] + } else if strings.Contains(path, SEPARATOR) { + // coconut conf show component/FLAVOR/rolename/entry + params := strings.Split(path, SEPARATOR) + p.Component = params[0] + p.Flavor = params[1] + p.Rolename = params[2] + p.EntryKey = params[3] + // and if we received a raw path (with / instead of @ before timestamp): + if len(params) > 4 && len(params[4]) > 0 { + p.Timestamp = params[4] + } + } + } else { + err = errors.New("bad component configuration key format") + return + } + + return p, nil +} + +func (p *Query) Path() string { + path := p.WithoutTimestamp() + if len(p.Timestamp) > 0 { + return path + "@" + p.Timestamp + } + return path +} + +func (p *Query) Raw() string { + path := p.WithoutTimestamp() + if len(p.Timestamp) > 0 { + return path + SEPARATOR + p.Timestamp + } + return path +} + +func (p *Query) WithoutTimestamp() string { + return p.Component + SEPARATOR + p.Flavor + SEPARATOR + p.Rolename + SEPARATOR + p.EntryKey +} + +func (p *Query) AbsoluteRaw() string { + return ConfigComponentsPath + p.Raw() +} + +func (p *Query) AbsoluteWithoutTimestamp() string { + return ConfigComponentsPath + p.WithoutTimestamp() +} diff --git a/configuration/instance.go b/configuration/instance.go new file mode 100644 index 000000000..e3bb6bdff --- /dev/null +++ b/configuration/instance.go @@ -0,0 +1,56 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2020 CERN and copyright holders of ALICE O². + * Author: Teo Mrnjavac + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In applying this license CERN does not waive the privileges and + * immunities granted to it by virtue of its status as an + * Intergovernmental Organization or submit itself to any jurisdiction. + */ + +package configuration + +import ( + "sync" + + "github.com/spf13/viper" +) + +var ( + once sync.Once + instance *Service +) + +func Instance() *Service { + once.Do(func() { + var( + err error + configUri string + ) + if viper.IsSet("config_endpoint") { //coconut + configUri = viper.GetString("config_endpoint") + } else { + configUri = viper.GetString("globalConfigurationUri") + } + instance, err = newService(configUri) + if err != nil { + log.WithField("globalConfigurationUri", configUri).Fatal("bad configuration URI") + } + }) + return instance +} + diff --git a/configuration/repos/repo.go b/configuration/repos/repo.go index cbb5d2bf3..badee0532 100644 --- a/configuration/repos/repo.go +++ b/configuration/repos/repo.go @@ -29,11 +29,10 @@ import ( "io/ioutil" "strings" + "github.com/AliceO2Group/Control/configuration" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/gobwas/glob" - - "github.com/AliceO2Group/Control/configuration/confsys" ) type Repo struct { @@ -80,7 +79,7 @@ func (r *Repo) GetIdentifier() string { } func (r *Repo) getCloneDir() string { - cloneDir := confsys.Instance().GetReposPath() + cloneDir := configuration.Instance().GetReposPath() if cloneDir[len(cloneDir)-1:] != "/" { cloneDir += "/" } @@ -91,7 +90,7 @@ func (r *Repo) getCloneDir() string { } func (r *Repo) getCloneParentDirs() []string { - cleanDir := confsys.Instance().GetReposPath() + cleanDir := configuration.Instance().GetReposPath() if cleanDir[len(cleanDir)-1:] != "/" { cleanDir += "/" } diff --git a/configuration/repos/repomanager.go b/configuration/repos/repomanager.go index d2e8559f5..5dbc2d3cf 100644 --- a/configuration/repos/repomanager.go +++ b/configuration/repos/repomanager.go @@ -35,7 +35,7 @@ import ( "github.com/AliceO2Group/Control/common/logger" "github.com/AliceO2Group/Control/common/utils" - "github.com/AliceO2Group/Control/configuration/confsys" + "github.com/AliceO2Group/Control/configuration" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/plumbing" "github.com/gobwas/glob" @@ -56,7 +56,7 @@ var ( instance *RepoManager ) -func Instance(service *confsys.Service) *RepoManager { +func Instance(service *configuration.Service) *RepoManager { once.Do(func() { instance = initializeRepos(service) }) @@ -69,10 +69,10 @@ type RepoManager struct { defaultRevision string defaultRevisions map[string]string mutex sync.Mutex - cService *confsys.Service + cService *configuration.Service } -func initializeRepos(service *confsys.Service) *RepoManager { +func initializeRepos(service *configuration.Service) *RepoManager { rm := RepoManager{repoList: map[string]*Repo{}} rm.cService = service diff --git a/configuration/confsys/service.go b/configuration/service.go similarity index 79% rename from configuration/confsys/service.go rename to configuration/service.go index a37f9d95d..00ca34e94 100644 --- a/configuration/confsys/service.go +++ b/configuration/service.go @@ -1,7 +1,7 @@ /* * === This file is part of ALICE O² === * - * Copyright 2019 CERN and copyright holders of ALICE O². + * Copyright 2019-2020 CERN and copyright holders of ALICE O². * Author: Teo Mrnjavac * * This program is free software: you can redistribute it and/or modify @@ -22,7 +22,7 @@ * Intergovernmental Organization or submit itself to any jurisdiction. */ -package confsys +package configuration import ( "encoding/json" @@ -33,10 +33,9 @@ import ( "path/filepath" "strconv" "strings" - "sync" "github.com/AliceO2Group/Control/common/logger" - "github.com/AliceO2Group/Control/configuration" + "github.com/AliceO2Group/Control/configuration/cfgbackend" "github.com/AliceO2Group/Control/configuration/componentcfg" "github.com/AliceO2Group/Control/configuration/template" "github.com/flosch/pongo2/v4" @@ -46,34 +45,8 @@ import ( var log = logger.New(logrus.StandardLogger(), "confsys") -var ( - once sync.Once - instance *Service -) - -func Instance() *Service { - once.Do(func() { - var( - err error - configUri string - ) - if viper.IsSet("config_endpoint") { //coconut - configUri = viper.GetString("config_endpoint") - } else { - configUri = viper.GetString("globalConfigurationUri") - } - instance, err = newService(configUri) - if err != nil { - log.WithField("globalConfigurationUri", configUri).Fatal("bad configuration URI") - } - }) - return instance -} - - - type Service struct { - src configuration.Source + src cfgbackend.Source } /* Expected structure: @@ -105,13 +78,13 @@ func formatKey(key string) (consulKey string) { } func newService(uri string) (svc *Service, err error) { - var src configuration.Source - src, err = configuration.NewSource(uri) + var src cfgbackend.Source + src, err = cfgbackend.NewSource(uri) return &Service{src: src}, err } func (s *Service) NewDefaultRepo(defaultRepo string) error { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.Put(filepath.Join(s.GetConsulPath(),"default_repo"), defaultRepo) } else { data := []byte(defaultRepo) @@ -120,7 +93,7 @@ func (s *Service) NewDefaultRepo(defaultRepo string) error { } func (s *Service) GetDefaultRepo() (defaultRepo string, err error) { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.Get(filepath.Join(s.GetConsulPath(),"default_repo")) } else { var defaultRepoData []byte @@ -134,7 +107,7 @@ func (s *Service) GetDefaultRepo() (defaultRepo string, err error) { } func (s *Service) NewDefaultRevision(defaultRevision string) error { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.Put(filepath.Join(s.GetConsulPath(),"default_revision"), defaultRevision) } else { data := []byte(defaultRevision) @@ -143,7 +116,7 @@ func (s *Service) NewDefaultRevision(defaultRevision string) error { } func (s *Service) GetDefaultRevision() (defaultRevision string, err error) { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.Get(filepath.Join(s.GetConsulPath(),"default_revision")) } else { var defaultRevisionData []byte @@ -158,7 +131,7 @@ func (s *Service) GetDefaultRevision() (defaultRevision string, err error) { func (s *Service) GetRepoDefaultRevisions() (map[string]string, error) { var defaultRevisions map[string]string - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { data, err := cSrc.Get(filepath.Join(s.GetConsulPath(),"default_revisions")) if err != nil { return nil, err @@ -183,7 +156,7 @@ func (s *Service) SetRepoDefaultRevisions(defaultRevisions map[string]string) er return err } - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { err = cSrc.Put(filepath.Join(s.GetConsulPath(),"default_revisions"), string(data)) } else { err = ioutil.WriteFile(filepath.Join(s.GetReposPath(),"default_revisions.json"), data, 0644) @@ -192,7 +165,7 @@ func (s *Service) SetRepoDefaultRevisions(defaultRevisions map[string]string) er } func (s *Service) NewRunNumber() (runNumber uint32, err error) { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.GetNextUInt32(filepath.Join(s.GetConsulPath(),"run_number")) } else { // Unsafe check-and-set, only for file backend @@ -222,7 +195,7 @@ func (s *Service) NewRunNumber() (runNumber uint32, err error) { } } -func (s *Service) GetROSource() configuration.ROSource { +func (s *Service) GetROSource() cfgbackend.ROSource { return s.src } @@ -253,25 +226,6 @@ func (s *Service) GetVars() map[string]string { return s.getStringMap(filepath.Join(s.GetConsulPath(),"vars")) } -func (s *Service) getStringMap(path string) map[string]string { - tree, err := s.src.GetRecursive(path) - if err != nil { - return nil - } - if tree.Type() == configuration.IT_Map { - responseMap := tree.Map() - theMap := make(map[string]string, len(responseMap)) - for k, v := range responseMap { - if v.Type() != configuration.IT_Value { - continue - } - theMap[k] = v.Value() - } - return theMap - } - return nil -} - // Or maybe even "RefreshConfig" which will refresh all the things that happen to be runtime-refreshable func (s *Service) RefreshRepositories() { panic("not implemented yet") @@ -285,8 +239,8 @@ func (s *Service) GenerateWorkflowDescriptor(wfPath string, vars map[string]stri } // Persist Mesos Framework ID by saving to Consul, or to a local file. -func (s *Service) NewMesosFID(fidValue string) error { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { +func (s *Service) SetMesosFID(fidValue string) error { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.Put(filepath.Join(s.GetConsulPath(),"mesos_fid"), fidValue) } else { data := []byte(fidValue) @@ -296,7 +250,7 @@ func (s *Service) NewMesosFID(fidValue string) error { // Retrieve Mesos Framework ID from Consul, or local file. func (s *Service) GetMesosFID() (fidValue string, err error) { - if cSrc, ok := s.src.(*configuration.ConsulSource); ok { + if cSrc, ok := s.src.(*cfgbackend.ConsulSource); ok { return cSrc.Get(filepath.Join(s.GetConsulPath(),"mesos_fid")) } else { var byteFidValue []byte @@ -313,41 +267,41 @@ func (s *Service) GetReposPath() string { return filepath.Join(viper.GetString("coreWorkingDir"), "repos") } -func (s *Service) GetComponentConfiguration(path string) (payload string, err error) { - var p *componentcfg.Path - p, err = componentcfg.NewPath(path) - if err != nil { +func (s *Service) GetComponentConfiguration(query *componentcfg.Query) (payload string, err error) { + if query == nil { return } var timestamp string - if len(p.Timestamp) == 0 { - keyPrefix := p.AbsoluteWithoutTimestamp() + if len(query.Timestamp) == 0 { + keyPrefix := query.AbsoluteWithoutTimestamp() if s.src.IsDir(keyPrefix) { var keys []string keys, err = s.src.GetKeysByPrefix(keyPrefix) if err != nil { return } - timestamp, err = componentcfg.GetLatestTimestamp(keys, p) + timestamp, err = componentcfg.GetLatestTimestamp(keys, query) if err != nil { return } } } - absKey := p.AbsoluteWithoutTimestamp() + componentcfg.SEPARATOR + timestamp + absKey := query.AbsoluteWithoutTimestamp() + componentcfg.SEPARATOR + timestamp if exists, _ := s.src.Exists(absKey); exists && len(timestamp) > 0 { payload, err = s.src.Get(absKey) } else { // falling back to timestampless configuration - absKey = p.AbsoluteWithoutTimestamp() + absKey = query.AbsoluteWithoutTimestamp() payload, err = s.src.Get(absKey) } return } -func (s *Service) GetAndProcessComponentConfiguration(path string, varStack map[string]string) (payload string, err error) { +func (s *Service) GetAndProcessComponentConfiguration(query *componentcfg.Query, varStack map[string]string) (payload string, err error) { + path := query.Path() + // We need to decompose the requested GetConfig path into prefix and suffix, // with the last / as separator (any timestamp if present stays part of the // suffix). diff --git a/configuration/serviceutil.go b/configuration/serviceutil.go new file mode 100644 index 000000000..1f6b67896 --- /dev/null +++ b/configuration/serviceutil.go @@ -0,0 +1,46 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2019-2020 CERN and copyright holders of ALICE O². + * Author: Teo Mrnjavac + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * In applying this license CERN does not waive the privileges and + * immunities granted to it by virtue of its status as an + * Intergovernmental Organization or submit itself to any jurisdiction. + */ + +package configuration + +import "github.com/AliceO2Group/Control/configuration/cfgbackend" + +func (s *Service) getStringMap(path string) map[string]string { + tree, err := s.src.GetRecursive(path) + if err != nil { + return nil + } + if tree.Type() == cfgbackend.IT_Map { + responseMap := tree.Map() + theMap := make(map[string]string, len(responseMap)) + for k, v := range responseMap { + if v.Type() != cfgbackend.IT_Value { + continue + } + theMap[k] = v.Value() + } + return theMap + } + return nil +} diff --git a/configuration/template/fields.go b/configuration/template/fields.go index e1c467180..b9cec9536 100644 --- a/configuration/template/fields.go +++ b/configuration/template/fields.go @@ -34,6 +34,7 @@ import ( "github.com/AliceO2Group/Control/common/gera" "github.com/AliceO2Group/Control/common/logger" + "github.com/AliceO2Group/Control/configuration/componentcfg" "github.com/antonmedv/expr" "github.com/antonmedv/expr/vm" "github.com/sirupsen/logrus" @@ -48,8 +49,8 @@ type Sequence map[Stage]Fields type BuildObjectStackFunc func(stage Stage) map[string]interface{} type ComponentConfigurationService interface { - GetComponentConfiguration(path string) (payload string, err error) - GetAndProcessComponentConfiguration(path string, varStack map[string]string) (payload string, err error) + GetComponentConfiguration(query *componentcfg.Query) (payload string, err error) + GetAndProcessComponentConfiguration(query *componentcfg.Query, varStack map[string]string) (payload string, err error) } func (sf Sequence) Execute(confSvc ComponentConfigurationService, parentPath string, varStack VarStack, buildObjectStack BuildObjectStackFunc, stringTemplateCache map[string]template.Template) (err error) { diff --git a/configuration/template/loader.go b/configuration/template/loader.go index 3b40ed374..f1bc98d53 100644 --- a/configuration/template/loader.go +++ b/configuration/template/loader.go @@ -28,6 +28,8 @@ import ( "fmt" "io" "strings" + + "github.com/AliceO2Group/Control/configuration/componentcfg" ) // Implements pongo2.TemplateLoader to fetch included templates from Consul paths @@ -58,7 +60,11 @@ func (c *ConsulTemplateLoader) Abs(base, name string) string { } func (c *ConsulTemplateLoader) Get(path string) (io.Reader, error) { - payload, err := c.confSvc.GetComponentConfiguration(path) + query, err := componentcfg.NewQuery(path) + if err != nil { + return strings.NewReader(fmt.Sprintf("{\"error\":\"%s\"}", err.Error())), err + } + payload, err := c.confSvc.GetComponentConfiguration(query) if err != nil { log.WithError(err). WithField("path", path). diff --git a/configuration/template/stack.go b/configuration/template/stack.go index 618ac1c14..b69e25ecf 100644 --- a/configuration/template/stack.go +++ b/configuration/template/stack.go @@ -35,6 +35,7 @@ import ( "github.com/AliceO2Group/Control/common/utils" "github.com/AliceO2Group/Control/common/utils/uid" + "github.com/AliceO2Group/Control/configuration/componentcfg" "github.com/sirupsen/logrus" ) @@ -46,24 +47,33 @@ func MakeConfigAccessFuncs(confSvc ComponentConfigurationService, varStack map[s return ConfigAccessFuncs{ "GetConfigLegacy": func(path string) string { defer utils.TimeTrack(time.Now(),"GetConfigLegacy", log.WithPrefix("template")) - payload, err := confSvc.GetComponentConfiguration(path) + query, err := componentcfg.NewQuery(path) + if err != nil { + return fmt.Sprintf("{\"error\":\"%s\"}", err.Error()) + } + + payload, err := confSvc.GetComponentConfiguration(query) if err != nil { log.WithError(err). - WithField("path", path). + WithField("path", query.Path()). Warn("failed to get component configuration") return fmt.Sprintf("{\"error\":\"%s\"}", err.Error()) } fields := Fields{WrapPointer(&payload)} - err = fields.Execute(confSvc, path, varStack, nil, make(map[string]texttemplate.Template)) + err = fields.Execute(confSvc, query.Path(), varStack, nil, make(map[string]texttemplate.Template)) log.Warn(varStack) log.Warn(payload) return payload }, "GetConfig": func(path string) string { defer utils.TimeTrack(time.Now(),"GetConfig", log.WithPrefix("template")) + query, err := componentcfg.NewQuery(path) + if err != nil { + return fmt.Sprintf("{\"error\":\"%s\"}", err.Error()) + } - payload, err := confSvc.GetAndProcessComponentConfiguration(path, varStack) + payload, err := confSvc.GetAndProcessComponentConfiguration(query, varStack) if err != nil { return fmt.Sprintf("{\"error\":\"%s\"}", err.Error()) } diff --git a/configuration/the/singleton.go b/configuration/the/singleton.go index f3460b5e0..000a96868 100644 --- a/configuration/the/singleton.go +++ b/configuration/the/singleton.go @@ -25,12 +25,12 @@ package the import ( - "github.com/AliceO2Group/Control/configuration/confsys" + "github.com/AliceO2Group/Control/configuration" "github.com/AliceO2Group/Control/configuration/repos" ) -func ConfSvc() *confsys.Service { - return confsys.Instance() +func ConfSvc() *configuration.Service { + return configuration.Instance() } func RepoManager() *repos.RepoManager { diff --git a/core/task/manager.go b/core/task/manager.go index a6a669740..97545b19e 100644 --- a/core/task/manager.go +++ b/core/task/manager.go @@ -97,7 +97,7 @@ func NewManager(shutdown func(), store.NewInMemorySingleton(), store.DoSet().AndThen(func(_ store.Setter, v string, _ error) error { // Store Mesos Framework ID to configuration. - err = the.ConfSvc().NewMesosFID(v) + err = the.ConfSvc().SetMesosFID(v) if err != nil { log.WithField("error", err).Error("cannot write to configuration") }