diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index afa8b0e12..fb7011437 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -14,4 +14,5 @@ It is a distributed system that combines state of the art cluster resource manag - Do not include modified go.mod and go.sum files in your commits unless you are adding or upgrading a dependency. - When adding features or fixing bugs, add a corresponding unit test if feasible. Use Ginkgo/Gomega, unless a package already uses a different testing framework. - When adding a new feature, extend the documentation accordingly, follow the existing style and structure, and make sure that Tables of Contents are updated. See [Documentation guidelines](docs/CONTRIBUTING.md#documentation-guidelines) for some more details. -- When providing a fix, explain what was causing the issue and how it was fixed. \ No newline at end of file +- When providing a fix, explain what was causing the issue and how it was fixed. +- Avoid using abbreviations and acronyms for variable and function names. They are acceptable if they are commonly used in a given domain, such as "cfg" for "configura +++tion" or "LHC" for "Large Hadron Collider". diff --git a/.github/workflows/control.yml b/.github/workflows/control.yml index 57de4f793..5ad85275a 100644 --- a/.github/workflows/control.yml +++ b/.github/workflows/control.yml @@ -11,6 +11,7 @@ jobs: name: Basic Make Check runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: [macOS-latest, ubuntu-24.04] go: [ '1.24.2' ] diff --git a/Makefile b/Makefile index 58184a101..f59740768 100644 --- a/Makefile +++ b/Makefile @@ -127,7 +127,7 @@ $(WHAT): validate-go-version @$(WHAT_$@_BUILD_FLAGS) go build -mod=vendor $(VERBOSE_$(V)) -o bin/$@ $(LDFLAGS) ./cmd/$@ # special case: if the current WHAT is o2-aliecs-executor, also copy over the shmcleaner script - @if [ $@ == "o2-aliecs-executor" ]; then \ + @if [ $@ = "o2-aliecs-executor" ]; then \ echo -e "\033[1;33mcopy\033[0m ./o2-aliecs-shmcleaner \033[1;33m==>\033[0m \033[1;34m./bin/o2-aliecs-shmcleaner\033[0m"; \ cp o2-aliecs-shmcleaner bin/o2-aliecs-shmcleaner; \ chmod +x bin/o2-aliecs-shmcleaner; \ @@ -140,7 +140,7 @@ $(INSTALL_WHAT): validate-go-version @$(WHAT_$(@:install_%=%)_BUILD_FLAGS) go install -mod=vendor $(VERBOSE_$(V)) $(LDFLAGS) ./cmd/$(@:install_%=%) # special case: if the current WHAT is o2-aliecs-executor, also copy over the shmcleaner script - @if [ $@ == "install_o2-aliecs-executor" ]; then \ + @if [ $@ = "install_o2-aliecs-executor" ]; then \ echo -e "\033[1;33minstall\033[0m ./o2-aliecs-shmcleaner \033[1;33m==>\033[0m \033[1;34m$$GOPATH/bin/o2-aliecs-shmcleaner\033[0m"; \ cp o2-aliecs-shmcleaner $${GOPATH}/bin/o2-aliecs-shmcleaner; \ chmod +x $${GOPATH}/bin/o2-aliecs-shmcleaner; \ diff --git a/README.md b/README.md index 18b4c98f9..4889d30cb 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ There are two ways of interacting with AliECS: * [Task template structure](/docs/handbook/configuration.md#task-template-structure) * [Variables pushed to controlled tasks](/docs/handbook/configuration.md#variables-pushed-to-controlled-tasks) * [Resource wants and limits](/docs/handbook/configuration.md#resource-wants-and-limits) + * [EPN workflow generation](/docs/handbook/configuration.md#epn-workflow-generation) * [Integration plugins](/core/integration/README.md#integration-plugins) * [Plugin system overview](/core/integration/README.md#plugin-system-overview) * [Integrated service operations](/core/integration/README.md#integrated-service-operations) diff --git a/VERSION b/VERSION index 5b07e409f..fffb89137 100644 --- a/VERSION +++ b/VERSION @@ -1,4 +1,4 @@ # GNU Make syntax VERSION_MAJOR := 1 -VERSION_MINOR := 45 +VERSION_MINOR := 46 VERSION_PATCH := 0 diff --git a/common/event/reader.go b/common/event/reader.go index 0b348cafc..f163e692e 100644 --- a/common/event/reader.go +++ b/common/event/reader.go @@ -27,44 +27,42 @@ package event import ( "context" "fmt" + "github.com/AliceO2Group/Control/common/event/topic" "github.com/AliceO2Group/Control/common/logger/infologger" pb "github.com/AliceO2Group/Control/common/protos" "github.com/segmentio/kafka-go" "github.com/spf13/viper" "google.golang.org/protobuf/proto" - "sync" ) // Reader interface provides methods to read events. type Reader interface { + // Next should return the next event or cancel if the context is cancelled. Next(ctx context.Context) (*pb.Event, error) + // Last should return the last available event currently present on the topic (or nil if none) + // or cancel if the context is cancelled. + Last(ctx context.Context) (*pb.Event, error) Close() error } // DummyReader is an implementation of Reader that returns no events. type DummyReader struct{} -// Next returns the next event or nil if there are no more events. func (*DummyReader) Next(context.Context) (*pb.Event, error) { return nil, nil } - -// Close closes the DummyReader. -func (*DummyReader) Close() error { return nil } +func (*DummyReader) Last(context.Context) (*pb.Event, error) { return nil, nil } +func (*DummyReader) Close() error { return nil } // KafkaReader reads events from Kafka and provides a blocking, cancellable API to fetch events. -// Consumption mode is chosen at creation time: -// - latestOnly=false: consume everything (from stored offsets or beginning depending on group state) -// - latestOnly=true: seek to latest offsets on start and only receive messages produced after start type KafkaReader struct { *kafka.Reader - mu sync.Mutex - topic string + topic string + brokers []string + groupID string } // NewReaderWithTopic creates a KafkaReader for the provided topic and starts it. -// If latestOnly is true the reader attempts to seek to the latest offsets on start so that -// only new messages (produced after creation) are consumed. -func NewReaderWithTopic(topic topic.Topic, groupID string, latestOnly bool) *KafkaReader { +func NewReaderWithTopic(topic topic.Topic, groupID string) *KafkaReader { cfg := kafka.ReaderConfig{ Brokers: viper.GetStringSlice("kafkaEndpoints"), Topic: string(topic), @@ -74,39 +72,72 @@ func NewReaderWithTopic(topic topic.Topic, groupID string, latestOnly bool) *Kaf } rk := &KafkaReader{ - Reader: kafka.NewReader(cfg), - topic: string(topic), - } - - if latestOnly { - // best-effort: set offset to last so we don't replay older messages - if err := rk.SetOffset(kafka.LastOffset); err != nil { - log.WithField(infologger.Level, infologger.IL_Devel). - Warnf("failed to set offset to last offset: %v", err) - } + Reader: kafka.NewReader(cfg), + topic: string(topic), + brokers: append([]string{}, cfg.Brokers...), + groupID: groupID, } - return rk } -// Next blocks until the next event is available or ctx is cancelled. It returns an error when the reader is closed -// (io.EOF) or the context is cancelled. The caller is responsible for providing a cancellable ctx. +// Next blocks until the next event is available or ctx is cancelled. func (r *KafkaReader) Next(ctx context.Context) (*pb.Event, error) { if r == nil { return nil, fmt.Errorf("nil reader") } - msg, err := r.ReadMessage(ctx) if err != nil { return nil, err } + return kafkaMessageToEvent(msg) +} - event, err := kafkaMessageToEvent(msg) +// Last fetches the last available message on the topic (considering all partitions). +// If multiple partitions have data, the event with the greatest message timestamp is returned. +func (r *KafkaReader) Last(ctx context.Context) (*pb.Event, error) { + if r == nil { + return nil, fmt.Errorf("nil reader") + } + partitions, err := r.readPartitions() if err != nil { return nil, err } - - return event, nil + var latestEvt *pb.Event + var latestEvtTimeNs int64 + for _, p := range partitions { + if p.Topic != r.topic { + continue + } + first, last, err := r.readFirstAndLast(p.ID) + if err != nil { + log.WithField(infologger.Level, infologger.IL_Devel).WithError(err). + Warnf("failed to read offsets for %s[%d]", r.topic, p.ID) + continue + } + if last <= first { + continue + } + msg, err := r.readAtOffset(ctx, p.ID, last-1) + if err != nil { + log.WithError(err). + WithField(infologger.Level, infologger.IL_Devel). + Warnf("failed to read last message for %s[%d] at offset %d", r.topic, p.ID, last-1) + continue + } + evt, err := kafkaMessageToEvent(msg) + if err != nil { + log.WithError(err). + WithField(infologger.Level, infologger.IL_Devel). + Warnf("failed to decode last message for %s[%d]", r.topic, p.ID) + continue + } + currentEvtTimeNs := msg.Time.UnixNano() + if latestEvt == nil || currentEvtTimeNs > latestEvtTimeNs { + latestEvt = evt + latestEvtTimeNs = currentEvtTimeNs + } + } + return latestEvt, nil } // Close stops the reader. @@ -114,13 +145,7 @@ func (r *KafkaReader) Close() error { if r == nil { return nil } - // Close the underlying kafka reader which will cause ReadMessage to return an error - err := r.Reader.Close() - if err != nil { - log.WithField(infologger.Level, infologger.IL_Devel). - Errorf("failed to close kafka reader: %v", err) - } - return err + return r.Reader.Close() } func kafkaMessageToEvent(m kafka.Message) (*pb.Event, error) { @@ -130,3 +155,55 @@ func kafkaMessageToEvent(m kafka.Message) (*pb.Event, error) { } return &evt, nil } + +func (r *KafkaReader) brokerAddr() (string, error) { + if len(r.brokers) == 0 { + return "", fmt.Errorf("no kafka brokers configured") + } + return r.brokers[0], nil +} + +func (r *KafkaReader) readPartitions() ([]kafka.Partition, error) { + addr, err := r.brokerAddr() + if err != nil { + return nil, err + } + conn, err := kafka.Dial("tcp", addr) + if err != nil { + return nil, err + } + defer conn.Close() + return conn.ReadPartitions(r.topic) +} + +func (r *KafkaReader) readFirstAndLast(partition int) (int64, int64, error) { + addr, err := r.brokerAddr() + if err != nil { + return 0, 0, err + } + conn, err := kafka.DialLeader(context.Background(), "tcp", addr, r.topic, partition) + if err != nil { + return 0, 0, err + } + defer conn.Close() + first, last, err := conn.ReadOffsets() + return first, last, err +} + +func (r *KafkaReader) readAtOffset(ctx context.Context, partition int, offset int64) (kafka.Message, error) { + if offset < 0 { + return kafka.Message{}, fmt.Errorf("invalid offset %d", offset) + } + kr := kafka.NewReader(kafka.ReaderConfig{ + Brokers: append([]string{}, r.brokers...), + Topic: r.topic, + Partition: partition, + MinBytes: 1, + MaxBytes: 10e6, + }) + defer kr.Close() + if err := kr.SetOffset(offset); err != nil { + return kafka.Message{}, err + } + return kr.ReadMessage(ctx) +} diff --git a/common/monitoring/monitoring.go b/common/monitoring/monitoring.go index 91dbd417f..ed22df9da 100644 --- a/common/monitoring/monitoring.go +++ b/common/monitoring/monitoring.go @@ -42,50 +42,38 @@ var ( // atomic holder for the HTTP server instance server atomic.Pointer[http.Server] // objects to store incoming metrics - metricsInternal *MetricsAggregate - metricsHistogramInternal *MetricsReservoirSampling + metricsInternal *MetricsAggregate = NewMetricsAggregate() + metricsHistogramInternal *MetricsReservoirSampling = NewMetricsReservoirSampling() // channel that is used to request end of metrics server, it sends notification when server ended. // It needs to be read!!! - endChannel chan struct{} + endChannel chan struct{} = make(chan struct{}) // channel used to send metrics into the event loop - metricsChannel chan Metric + // 100000 was chosen arbitrarily as a number that seemed sensible to be high enough to provide nice buffer if + // multiple goroutines want to send metrics without blocking each other + metricsChannel chan Metric = make(chan Metric, 100000) // channel used to send metrics meant to be proceesed as histogram into the event loop - metricsHistosChannel chan Metric + // 100000 was chosen arbitrarily as a number that seemed sensible to be high enough to provide nice buffer if + // multiple goroutines want to send metrics without blocking each other + metricsHistosChannel chan Metric = make(chan Metric, 100000) // channel for sending requests to reset actual metrics slice and send it back to caller via metricsExportedToRequest - metricsRequestedChannel chan struct{} + metricsRequestedChannel chan struct{} = make(chan struct{}) // channel used to send metrics to be reported by http request from event loop - metricsExportedToRequest chan []Metric + metricsExportedToRequest chan []Metric = make(chan []Metric) - log = logger.New(logrus.StandardLogger(), "metrics").WithField("level", infologger.IL_Devel) -) - -func initChannels() { - endChannel = make(chan struct{}) - metricsRequestedChannel = make(chan struct{}) - // 100 was chosen arbitrarily as a number that seemed sensible to be high enough to provide nice buffer if - // multiple goroutines want to send metrics without blocking each other - metricsChannel = make(chan Metric, 100000) - metricsHistosChannel = make(chan Metric, 100000) - metricsExportedToRequest = make(chan []Metric) - metricsInternal = NewMetricsAggregate() - metricsHistogramInternal = NewMetricsReservoirSampling() -} + // WaitUntilRunning is waiting until this channel is closed + waitUntilRunningChannel chan struct{} = make(chan struct{}) -func closeChannels() { - close(endChannel) - close(metricsRequestedChannel) - close(metricsChannel) - close(metricsExportedToRequest) -} + log = logger.New(logrus.StandardLogger(), "metrics").WithField(infologger.Level, infologger.IL_Devel) +) // this eventLoop is the main part that processes all metrics send to the package // 4 events can happen: -// 1. metricsChannel receives message from Send() method. We just add the new metric to metrics slice -// 2. metricsHistosChannel receives message from Send() method. We just add the new metric to metrics slice +// 1. metricsChannel receives message from Send() method. We add the new metric to metrics slice +// 2. metricsHistosChannel receives message from Send() method. We add the new metric to metrics slice // 3. metricsRequestChannel receives request to dump and request existing metrics. We send shallow copy of existing // metrics to requestor (via metricsExportedToRequest channel) while resetting current metrics slice // 4. receive request to stop monitoring via endChannel. We send confirmation through endChannel to notify caller @@ -130,14 +118,18 @@ func exportMetricsAndReset(w http.ResponseWriter, r *http.Request) { } func Send(metric *Metric) { - if IsRunning() { - metricsChannel <- *metric + // drop overflowing messages to not slowdown processing, we don't log so we don't flood IL + select { + case metricsChannel <- *metric: + default: } } func SendHistogrammable(metric *Metric) { - if IsRunning() { - metricsHistosChannel <- *metric + // drop overflowing messages to not slowdown processing, we don't log so we don't flood IL + select { + case metricsHistosChannel <- *metric: + default: } } @@ -160,10 +152,10 @@ func Run(port uint16, endpointName string) error { if !server.CompareAndSwap(nil, localServer) { return nil } - initChannels() go eventLoop() handleFunc(endpointName) // block until Shutdown is called + close(waitUntilRunningChannel) return localServer.ListenAndServe() } @@ -176,9 +168,24 @@ func Stop() { defer cancel() localServer.Shutdown(ctx) endChannel <- struct{}{} + _, ok := <-waitUntilRunningChannel + if !ok { + waitUntilRunningChannel = make(chan struct{}) + } + metricsInternal.Clear() + metricsHistogramInternal.Clear() <-endChannel } -func IsRunning() bool { - return server.Load() != nil +// If monitoring is not running it will wait until monitoring is running or +// timeout is triggered. +// \return true if monitoring is running, false if timeout occured +func WaitUntilRunning(timeout time.Duration) bool { + timeoutChan := time.After(timeout) + select { + case <-waitUntilRunningChannel: + return true + case <-timeoutChan: + return false + } } diff --git a/common/monitoring/monitoring_test.go b/common/monitoring/monitoring_test.go index b0da38435..2facaf146 100644 --- a/common/monitoring/monitoring_test.go +++ b/common/monitoring/monitoring_test.go @@ -40,16 +40,8 @@ import ( // blocks until either IsRunning() returns true or timeout is triggered func isRunningWithTimeout(t *testing.T, timeout time.Duration) { - timeoutChan := time.After(timeout) - for !IsRunning() { - select { - case <-timeoutChan: - t.Errorf("Monitoring is not running even after %v", timeout) - return - - default: - time.Sleep(10 * time.Millisecond) - } + if !WaitUntilRunning(timeout) { + t.Errorf("Failed to init monitoring library in %v", timeout) } } @@ -87,17 +79,24 @@ func testFunction(t *testing.T, testToRun func(*testing.T)) { isRunningWithTimeout(t, time.Second) testToRun(t) Stop() + + if len(metricsInternal.GetMetrics()) != 0 { + t.Fatal("didn't clear metrics properly after tests") + } + if len(metricsHistogramInternal.GetMetrics()) != 0 { + t.Fatal("didn't clear histo metrics properly after tests") + } } func TestSendingSingleMetric(t *testing.T) { testFunction(t, func(t *testing.T) { - metric := &Metric{name: "test"} + metric := &Metric{name: "testsinglemetric"} Send(metric) hasNumberOfMetrics(t, time.Second, 1) aggregatedMetrics := metricsInternal.GetMetrics() - if aggregatedMetrics[0].name != "test" { + if aggregatedMetrics[0].name != "testsinglemetric" { t.Errorf("Got wrong name %s in stored metric", aggregatedMetrics[0].name) } }) @@ -105,7 +104,7 @@ func TestSendingSingleMetric(t *testing.T) { func TestExportingMetrics(t *testing.T) { testFunction(t, func(t *testing.T) { - metric := &Metric{name: "test"} + metric := &Metric{name: "testexporting"} Send(metric) hasNumberOfMetrics(t, time.Second, 1) @@ -113,56 +112,64 @@ func TestExportingMetrics(t *testing.T) { metricsToExport := <-metricsExportedToRequest if len(metricsToExport) != 1 { - t.Errorf("Got wrong amount of metrics %d, expected 1", len(metricsToExport)) + t.Fatalf("Got wrong amount of metrics %d, expected 1", len(metricsToExport)) } - if metricsToExport[0].name != "test" { - t.Errorf("Got wrong name of metric %s, expected test", metricsToExport[0].name) + if metricsToExport[0].name != "testexporting" { + t.Fatalf("Got wrong name of metric %s, expected testexporting", metricsToExport[0].name) } }) } func TestHttpRun(t *testing.T) { - go Run(9876, "/metrics") + port := uint16(9876) + endpoint := "/metrics" + go Run(port, endpoint) defer Stop() - isRunningWithTimeout(t, time.Second) + isRunningWithTimeout(t, 5*time.Second) + + sendAndTestMetric(t, port, endpoint, "testhttprun1", time.Unix(10, 0), "tag1", "42", "value1", 11) + sendAndTestMetric(t, port, endpoint, "testhttprun2", time.Unix(11, 0), "tag2", "43", "value2", 12) + sendAndTestMetric(t, port, endpoint, "testhttprun3", time.Unix(12, 0), "tag3", "44", "value3", 13) + sendAndTestMetric(t, port, endpoint, "testhttprun4", time.Unix(13, 0), "tag4", "45", "value4", 14) +} - metric := Metric{name: "test"} - metric.timestamp = time.Unix(10, 0) - metric.AddTag("tag1", "42") - metric.SetFieldInt64("value1", 11) +func sendAndTestMetric(t *testing.T, port uint16, endpoint string, metricName string, timestamp time.Time, tagName string, tagVal string, fieldName string, fieldVal int64) { + metric := Metric{name: metricName, timestamp: timestamp} + metric.AddTag(tagName, tagVal) + metric.SetFieldInt64(fieldName, fieldVal) Send(&metric) - response, err := http.Get("http://localhost:9876/metrics") + response, err := http.Get(fmt.Sprintf("http://localhost:%d%s", port, endpoint)) if err != nil { t.Fatalf("Failed to GET metrics at port 9876: %v", err) } message, err := io.ReadAll(response.Body) if err != nil { - t.Errorf("Failed to read response Body: %v", err) + t.Fatalf("Failed to read response Body: %v", err) } receivedMetrics, err := parseMultipleLineProtocol(string(message)) if err != nil { - t.Errorf("Failed to parse message: %v", string(message)) + t.Fatalf("Failed to parse message: %v with err: %v", string(message), err) } receivedMetric := receivedMetrics[0] - if receivedMetric.Name != "test" { - t.Errorf("Got wrong name of metric %s, expected test", receivedMetric.Name) + if receivedMetric.Name != metricName { + t.Errorf("Got wrong name of metric %s, expected %s", receivedMetric.Name, metricName) } - if receivedMetric.Timestamp != time.Unix(10, 0).UnixNano() { - t.Errorf("Got wrong timestamp of metric %d, expected 10", receivedMetric.Timestamp) + if receivedMetric.Timestamp != timestamp.UnixNano() { + t.Errorf("Got wrong timestamp of metric %d, expected %v", receivedMetric.Timestamp, timestamp.UnixNano()) } if len(receivedMetric.Tags) != 1 { t.Errorf("Got wrong number of tags %d, expected 1", len(receivedMetric.Tags)) } - if receivedMetric.Tags["tag1"] != "42" { + if receivedMetric.Tags[tagName] != tagVal { t.Errorf("Failed to retreive tags: tag1 with value 42, %+v", receivedMetric.Tags) } @@ -170,8 +177,8 @@ func TestHttpRun(t *testing.T) { t.Errorf("Got wrong number of values %d, expected 1", len(receivedMetric.Fields)) } - if receivedMetric.Fields["value1"] != "11i" { - t.Errorf("Failed to retreive tags: value1 with value 11: %+v", receivedMetric.Fields) + if receivedMetric.Fields[fieldName] != fmt.Sprintf("%di", fieldVal) { + t.Errorf("Failed to retreive tags: %s with value %d: %+v", fieldName, fieldVal, receivedMetric.Fields) } } diff --git a/common/protos/common.pb.go b/common/protos/common.pb.go index 5ea0cc482..ce7796310 100644 --- a/common/protos/common.pb.go +++ b/common/protos/common.pb.go @@ -43,6 +43,58 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Production and staging BKP recognizes these special user IDs. +// They are used to associate certain actions (e.g. EOR) with certain subsystem +// or AliECS component rather than a human user. +type SpecialUserId int32 + +const ( + SpecialUserId_INVALID SpecialUserId = 0 + SpecialUserId_LHC SpecialUserId = 60 + SpecialUserId_TIMER SpecialUserId = 65 +) + +// Enum value maps for SpecialUserId. +var ( + SpecialUserId_name = map[int32]string{ + 0: "INVALID", + 60: "LHC", + 65: "TIMER", + } + SpecialUserId_value = map[string]int32{ + "INVALID": 0, + "LHC": 60, + "TIMER": 65, + } +) + +func (x SpecialUserId) Enum() *SpecialUserId { + p := new(SpecialUserId) + *p = x + return p +} + +func (x SpecialUserId) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (SpecialUserId) Descriptor() protoreflect.EnumDescriptor { + return file_protos_common_proto_enumTypes[0].Descriptor() +} + +func (SpecialUserId) Type() protoreflect.EnumType { + return &file_protos_common_proto_enumTypes[0] +} + +func (x SpecialUserId) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SpecialUserId.Descriptor instead. +func (SpecialUserId) EnumDescriptor() ([]byte, []int) { + return file_protos_common_proto_rawDescGZIP(), []int{0} +} + // * // Beam modes as defined and sent by LHC DIP client plus: // * virtual type LOST_BEAMS - that is generated when beam 1 and beam 2 energy values are not equal anymore as per LHC DIP track: dip/acc/LHC/RunControl/SafeBeam @@ -138,11 +190,11 @@ func (x BeamMode) String() string { } func (BeamMode) Descriptor() protoreflect.EnumDescriptor { - return file_protos_common_proto_enumTypes[0].Descriptor() + return file_protos_common_proto_enumTypes[1].Descriptor() } func (BeamMode) Type() protoreflect.EnumType { - return &file_protos_common_proto_enumTypes[0] + return &file_protos_common_proto_enumTypes[1] } func (x BeamMode) Number() protoreflect.EnumNumber { @@ -151,7 +203,7 @@ func (x BeamMode) Number() protoreflect.EnumNumber { // Deprecated: Use BeamMode.Descriptor instead. func (BeamMode) EnumDescriptor() ([]byte, []int) { - return file_protos_common_proto_rawDescGZIP(), []int{0} + return file_protos_common_proto_rawDescGZIP(), []int{1} } type User struct { @@ -414,37 +466,40 @@ var file_protos_common_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x62, 0x65, 0x61, 0x6d, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2c, 0x0a, 0x08, 0x62, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x42, 0x65, 0x61, 0x6d, 0x4d, 0x6f, - 0x64, 0x65, 0x52, 0x08, 0x62, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x2a, 0x80, 0x03, 0x0a, - 0x08, 0x42, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, - 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x45, 0x54, 0x55, 0x50, 0x10, - 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x42, 0x4f, 0x52, 0x54, 0x10, 0x02, 0x12, 0x18, 0x0a, 0x14, - 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x42, 0x45, 0x5f, - 0x42, 0x45, 0x41, 0x4d, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, - 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x10, 0x04, - 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x48, - 0x59, 0x53, 0x49, 0x43, 0x53, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x10, 0x05, 0x12, 0x10, 0x0a, 0x0c, - 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x45, 0x5f, 0x52, 0x41, 0x4d, 0x50, 0x10, 0x06, 0x12, 0x08, - 0x0a, 0x04, 0x52, 0x41, 0x4d, 0x50, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4c, 0x41, 0x54, - 0x5f, 0x54, 0x4f, 0x50, 0x10, 0x08, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x51, 0x55, 0x45, 0x45, 0x5a, - 0x45, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x44, 0x4a, 0x55, 0x53, 0x54, 0x10, 0x0a, 0x12, - 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x53, 0x10, - 0x0b, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x4f, 0x53, 0x54, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x53, 0x10, - 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x42, 0x45, - 0x41, 0x4d, 0x53, 0x10, 0x0d, 0x12, 0x15, 0x0a, 0x11, 0x42, 0x45, 0x41, 0x4d, 0x5f, 0x44, 0x55, - 0x4d, 0x50, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x0e, 0x12, 0x0d, 0x0a, 0x09, - 0x42, 0x45, 0x41, 0x4d, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x0f, 0x12, 0x0d, 0x0a, 0x09, 0x52, - 0x41, 0x4d, 0x50, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x59, - 0x43, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x11, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x43, 0x4f, 0x56, - 0x45, 0x52, 0x59, 0x10, 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x5f, - 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x13, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x49, - 0x52, 0x43, 0x55, 0x4c, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x55, 0x4d, 0x50, - 0x10, 0x14, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x10, 0x15, 0x42, - 0x53, 0x0a, 0x1f, 0x63, 0x68, 0x2e, 0x63, 0x65, 0x72, 0x6e, 0x2e, 0x61, 0x6c, 0x69, 0x63, 0x65, - 0x2e, 0x6f, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x41, - 0x6c, 0x69, 0x63, 0x65, 0x4f, 0x32, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2f, 0x43, 0x6f, 0x6e, 0x74, - 0x72, 0x6f, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x73, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x64, 0x65, 0x52, 0x08, 0x62, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x2a, 0x30, 0x0a, 0x0d, + 0x53, 0x70, 0x65, 0x63, 0x69, 0x61, 0x6c, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x0b, 0x0a, + 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x4c, 0x48, + 0x43, 0x10, 0x3c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x49, 0x4d, 0x45, 0x52, 0x10, 0x41, 0x2a, 0x80, + 0x03, 0x0a, 0x08, 0x42, 0x65, 0x61, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x55, + 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x45, 0x54, 0x55, + 0x50, 0x10, 0x01, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x42, 0x4f, 0x52, 0x54, 0x10, 0x02, 0x12, 0x18, + 0x0a, 0x14, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x42, + 0x45, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x10, 0x03, 0x12, 0x18, 0x0a, 0x14, 0x49, 0x4e, 0x4a, 0x45, + 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, 0x53, 0x45, 0x54, 0x55, 0x50, 0x5f, 0x42, 0x45, 0x41, 0x4d, + 0x10, 0x04, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x4a, 0x45, 0x43, 0x54, 0x49, 0x4f, 0x4e, 0x5f, + 0x50, 0x48, 0x59, 0x53, 0x49, 0x43, 0x53, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x10, 0x05, 0x12, 0x10, + 0x0a, 0x0c, 0x50, 0x52, 0x45, 0x50, 0x41, 0x52, 0x45, 0x5f, 0x52, 0x41, 0x4d, 0x50, 0x10, 0x06, + 0x12, 0x08, 0x0a, 0x04, 0x52, 0x41, 0x4d, 0x50, 0x10, 0x07, 0x12, 0x0c, 0x0a, 0x08, 0x46, 0x4c, + 0x41, 0x54, 0x5f, 0x54, 0x4f, 0x50, 0x10, 0x08, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x51, 0x55, 0x45, + 0x45, 0x5a, 0x45, 0x10, 0x09, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x44, 0x4a, 0x55, 0x53, 0x54, 0x10, + 0x0a, 0x12, 0x10, 0x0a, 0x0c, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, 0x42, 0x45, 0x41, 0x4d, + 0x53, 0x10, 0x0b, 0x12, 0x0e, 0x0a, 0x0a, 0x4c, 0x4f, 0x53, 0x54, 0x5f, 0x42, 0x45, 0x41, 0x4d, + 0x53, 0x10, 0x0c, 0x12, 0x12, 0x0a, 0x0e, 0x55, 0x4e, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x45, 0x5f, + 0x42, 0x45, 0x41, 0x4d, 0x53, 0x10, 0x0d, 0x12, 0x15, 0x0a, 0x11, 0x42, 0x45, 0x41, 0x4d, 0x5f, + 0x44, 0x55, 0x4d, 0x50, 0x5f, 0x57, 0x41, 0x52, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x0e, 0x12, 0x0d, + 0x0a, 0x09, 0x42, 0x45, 0x41, 0x4d, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x0f, 0x12, 0x0d, 0x0a, + 0x09, 0x52, 0x41, 0x4d, 0x50, 0x5f, 0x44, 0x4f, 0x57, 0x4e, 0x10, 0x10, 0x12, 0x0b, 0x0a, 0x07, + 0x43, 0x59, 0x43, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x11, 0x12, 0x0c, 0x0a, 0x08, 0x52, 0x45, 0x43, + 0x4f, 0x56, 0x45, 0x52, 0x59, 0x10, 0x12, 0x12, 0x13, 0x0a, 0x0f, 0x49, 0x4e, 0x4a, 0x45, 0x43, + 0x54, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x55, 0x4d, 0x50, 0x10, 0x13, 0x12, 0x16, 0x0a, 0x12, + 0x43, 0x49, 0x52, 0x43, 0x55, 0x4c, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x4e, 0x44, 0x5f, 0x44, 0x55, + 0x4d, 0x50, 0x10, 0x14, 0x12, 0x0b, 0x0a, 0x07, 0x4e, 0x4f, 0x5f, 0x42, 0x45, 0x41, 0x4d, 0x10, + 0x15, 0x42, 0x53, 0x0a, 0x1f, 0x63, 0x68, 0x2e, 0x63, 0x65, 0x72, 0x6e, 0x2e, 0x61, 0x6c, 0x69, + 0x63, 0x65, 0x2e, 0x6f, 0x32, 0x2e, 0x63, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2e, 0x63, 0x6f, + 0x6d, 0x6d, 0x6f, 0x6e, 0x5a, 0x30, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x41, 0x6c, 0x69, 0x63, 0x65, 0x4f, 0x32, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x2f, 0x43, 0x6f, + 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x73, 0x3b, 0x70, 0x62, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -459,16 +514,17 @@ func file_protos_common_proto_rawDescGZIP() []byte { return file_protos_common_proto_rawDescData } -var file_protos_common_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_protos_common_proto_enumTypes = make([]protoimpl.EnumInfo, 2) var file_protos_common_proto_msgTypes = make([]protoimpl.MessageInfo, 3) var file_protos_common_proto_goTypes = []interface{}{ - (BeamMode)(0), // 0: common.BeamMode - (*User)(nil), // 1: common.User - (*WorkflowTemplateInfo)(nil), // 2: common.WorkflowTemplateInfo - (*BeamInfo)(nil), // 3: common.BeamInfo + (SpecialUserId)(0), // 0: common.SpecialUserId + (BeamMode)(0), // 1: common.BeamMode + (*User)(nil), // 2: common.User + (*WorkflowTemplateInfo)(nil), // 3: common.WorkflowTemplateInfo + (*BeamInfo)(nil), // 4: common.BeamInfo } var file_protos_common_proto_depIdxs = []int32{ - 0, // 0: common.BeamInfo.beamMode:type_name -> common.BeamMode + 1, // 0: common.BeamInfo.beamMode:type_name -> common.BeamMode 1, // [1:1] is the sub-list for method output_type 1, // [1:1] is the sub-list for method input_type 1, // [1:1] is the sub-list for extension type_name @@ -525,7 +581,7 @@ func file_protos_common_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_protos_common_proto_rawDesc, - NumEnums: 1, + NumEnums: 2, NumMessages: 3, NumExtensions: 0, NumServices: 0, diff --git a/common/protos/common.proto b/common/protos/common.proto index f367be9e4..1942c36e2 100644 --- a/common/protos/common.proto +++ b/common/protos/common.proto @@ -40,6 +40,15 @@ message User { string name = 3; } +// Production and staging BKP recognizes these special user IDs. +// They are used to associate certain actions (e.g. EOR) with certain subsystem +// or AliECS component rather than a human user. +enum SpecialUserId { + INVALID = 0; + LHC = 60; + TIMER = 65; +} + message WorkflowTemplateInfo { string name = 1; string description = 2; diff --git a/common/protos/protoutils.go b/common/protos/protoutils.go index e0a009de5..5d3a43d82 100644 --- a/common/protos/protoutils.go +++ b/common/protos/protoutils.go @@ -34,3 +34,17 @@ func WrapEvent(ce isEvent_Payload) *Event { Payload: ce, } } + +// SpecialUser returns a User populated from a SpecialUserId enum: +// - externalId = enum numeric value +// - id = enum numeric value +// - name = enum string name +func SpecialUser(enumId SpecialUserId) *User { + externalId := int32(enumId) + name := enumId.String() + return &User{ + ExternalId: &externalId, + Id: nil, + Name: name, + } +} diff --git a/core/controlcommands/mesoscommandservent.go b/core/controlcommands/mesoscommandservent.go index 2185eea2e..4eded55eb 100644 --- a/core/controlcommands/mesoscommandservent.go +++ b/core/controlcommands/mesoscommandservent.go @@ -26,6 +26,7 @@ package controlcommands import ( "fmt" + "strings" "sync" "time" @@ -144,7 +145,8 @@ func (s *Servent) RunCommand(cmd MesosCommand, receiver MesosCommandTarget) (Mes // By the time we get here, ProcessResponse should have already added a Response to the // pending call, and removed it from servent.pending. case <-time.After(cmd.GetResponseTimeout()): - call.Error = fmt.Errorf("%s timed out for task %s", cmd.GetName(), receiver.TaskId.Value) + userFriendlyCommandName, _ := strings.CutPrefix(cmd.GetName(), "MesosCommand_") + call.Error = fmt.Errorf("%s timed out", userFriendlyCommandName) log.WithPrefix("servent"). WithField("partition", cmd.GetEnvironmentId().String()). diff --git a/core/core.go b/core/core.go index 6919cb45c..f2370f11b 100644 --- a/core/core.go +++ b/core/core.go @@ -90,6 +90,11 @@ func runMetrics() { } }() + monitoringTimeout := 30 * time.Second + if !monitoring.WaitUntilRunning(monitoringTimeout) { + log.WithField(infologger.Level, infologger.IL_Devel).Warnf("Failed to initialize monitoring framework in %v, it might catch up later. For now we are starting without metrics", monitoringTimeout) + } + golangmetrics.Start(10 * time.Second) } diff --git a/core/environment/environment.go b/core/environment/environment.go index 34241d782..fcdac227e 100644 --- a/core/environment/environment.go +++ b/core/environment/environment.go @@ -1232,19 +1232,8 @@ func (env *Environment) subscribeToWfState(taskman *task.Manager) { NewEnvGoErrorEvent(env, newCriticalTasksErrorMessage(env)), ) err := env.TryTransition(NewGoErrorTransition(taskman)) - if err != nil { - if env.Sm.Current() == "ERROR" { - log.WithField("partition", env.id). - WithField("level", infologger.IL_Devel). - Info("skipped requested transition to ERROR: environment already in ERROR state") - } else { - log.WithField("partition", env.id). - WithError(err). - WithField("level", infologger.IL_Devel). - Warn("could not transition gently to ERROR, forcing it") - env.setState(wfState.String()) - } + HandleFailedGoError(err, env) } }) break WORKFLOW_STATE_LOOP @@ -1460,6 +1449,7 @@ func (env *Environment) scheduleAutoStopTransition() (scheduled bool, expected t log.WithField("partition", env.id). WithField("run", env.currentRunNumber). Infof("Executing scheduled auto stop transition following expiration of %s", autoStopDuration) + env.SetLastRequestUser(pb.SpecialUser(pb.SpecialUserId_TIMER)) err = env.TryTransition(NewStopActivityTransition(ManagerInstance().taskman)) if err != nil { log.WithField("partition", env.id). @@ -1472,10 +1462,7 @@ func (env *Environment) scheduleAutoStopTransition() (scheduled bool, expected t err = env.TryTransition(NewGoErrorTransition(ManagerInstance().taskman)) if err != nil { - log.WithField("partition", env.id). - WithField("run", env.currentRunNumber). - Errorf("Forced transition to ERROR failed: %s", err.Error()) - env.setState("ERROR") + HandleFailedGoError(err, env) } return } diff --git a/core/environment/manager.go b/core/environment/manager.go index e797f257a..8546bd0c9 100644 --- a/core/environment/manager.go +++ b/core/environment/manager.go @@ -487,7 +487,7 @@ func (envs *Manager) CreateEnvironment(workflowPath string, userVars map[string] log.WithField("state", envState). WithField("partition", env.Id().String()). WithError(err). - Warnf("auto-transitioning environment failed %s, cleanup in progress", op) + Errorf("auto-transitioning environment failed %s, cleanup in progress", op) the.EventWriterWithTopic(topic.Environment).WriteEvent( NewEnvGoErrorEvent(env, fmt.Sprintf("%s failed: %v", op, err)), @@ -496,10 +496,7 @@ func (envs *Manager) CreateEnvironment(workflowPath string, userVars map[string] envs.taskman), ) if err != nil { - log.WithField("partition", env.Id().String()). - WithField("state", envState). - Debug("could not transition failed auto-transitioning environment to ERROR, cleanup in progress") - env.setState("ERROR") + HandleFailedGoError(err, env) } envTasks := env.Workflow().GetTasks() @@ -603,10 +600,7 @@ func (envs *Manager) CreateEnvironment(workflowPath string, userVars map[string] envs.taskman), ) if errTxErr != nil { - log.WithField("partition", env.Id().String()). - WithField("state", envState). - WithError(errTxErr). - Debug("could not transition to ERROR after failed deployment/configuration, cleanup in progress") + HandleFailedGoError(errTxErr, env) } envTasks := env.Workflow().GetTasks() // TeardownEnvironment manages the envs.mu internally @@ -1064,11 +1058,7 @@ func (envs *Manager) handleIntegratedServiceEvent(evt event.IntegratedServiceEve ) err = env.TryTransition(NewGoErrorTransition(envs.taskman)) if err != nil { - log.WithPrefix("scheduler"). - WithField("partition", envId.String()). - WithError(err). - Error("environment GO_ERROR transition failed after ODC_PARTITION_STATE_CHANGE ERROR event") - env.setState("ERROR") + HandleFailedGoError(err, env) } } }() @@ -1113,6 +1103,7 @@ func (envs *Manager) handleLhcEvents(evt event.IntegratedServiceEvent) { WithField("run", env.currentRunNumber). Info("stopping the run due to beam dump") + env.SetLastRequestUser(evpb.SpecialUser(evpb.SpecialUserId_LHC)) err := env.TryTransition(NewStopActivityTransition(envs.taskman)) if err != nil { log.WithPrefix("scheduler"). @@ -1124,12 +1115,7 @@ func (envs *Manager) handleLhcEvents(evt event.IntegratedServiceEvent) { if env.CurrentState() != "ERROR" { err = env.TryTransition(NewGoErrorTransition(envs.taskman)) if err != nil { - log.WithPrefix("scheduler"). - WithField("partition", envId.String()). - WithField("run", env.currentRunNumber). - WithError(err). - Error("environment GO_ERROR transition failed after a beam dump event, forcing") - env.setState("ERROR") + HandleFailedGoError(err, env) } } } @@ -1474,7 +1460,7 @@ func (envs *Manager) CreateAutoEnvironment(workflowPath string, userVars map[str log.WithField("state", envState). WithField("partition", env.Id().String()). WithError(err). - Warnf("auto-transitioning environment failed %s, cleanup in progress", op) + Errorf("auto-transitioning environment failed %s, cleanup in progress", op) the.EventWriterWithTopic(topic.Environment).WriteEvent( NewEnvGoErrorEvent(env, fmt.Sprintf("%s failed: %v", op, err)), @@ -1483,11 +1469,8 @@ func (envs *Manager) CreateAutoEnvironment(workflowPath string, userVars map[str envs.taskman), ) if err != nil { - log.WithField("partition", env.Id().String()). - WithField("state", envState). - Debug("could not transition failed auto-transitioning environment to ERROR, cleanup in progress") + HandleFailedGoError(err, env) env.sendEnvironmentEvent(&event.EnvironmentEvent{Message: "transition ERROR failed, forcing", EnvironmentID: env.Id().String(), Error: err}) - env.setState("ERROR") } envTasks := env.Workflow().GetTasks() diff --git a/core/environment/transition_goerror.go b/core/environment/transition_goerror.go index 6b59d85f7..c8adb14e2 100644 --- a/core/environment/transition_goerror.go +++ b/core/environment/transition_goerror.go @@ -25,6 +25,7 @@ package environment import ( + "github.com/AliceO2Group/Control/core/controlcommands" "github.com/AliceO2Group/Control/core/task" "github.com/AliceO2Group/Control/core/task/sm" ) @@ -50,12 +51,21 @@ func (t GoErrorTransition) do(env *Environment) (err error) { return t.IsSafeToStop() }) if len(toStop) > 0 { + args := controlcommands.PropertyMap{} + if cvs, err := env.Workflow().ConsolidatedVarStack(); err == nil { + for _, key := range StopActivityParameterKeys { + if value, ok := cvs[key]; ok { + args[key] = value + } + } + } + taskmanMessage := task.NewTransitionTaskMessage( toStop, sm.RUNNING.String(), sm.STOP.String(), sm.CONFIGURED.String(), - nil, + args, env.Id(), ) t.taskman.MessageChannel <- taskmanMessage diff --git a/core/environment/transition_startactivity.go b/core/environment/transition_startactivity.go index 86f13cbad..be7ec03c6 100644 --- a/core/environment/transition_startactivity.go +++ b/core/environment/transition_startactivity.go @@ -38,6 +38,22 @@ import ( "github.com/iancoleman/strcase" ) +var StartActivityParameterKeys = []string{ + "fill_info_fill_number", + "fill_info_filling_scheme", + "fill_info_beam_type", + "fill_info_stable_beams_start_ms", + "fill_info_stable_beams_end_ms", + "run_number", + "run_type", + "run_start_time_ms", + "run_end_time_ms", // included to ensure that a cleared SOEOR timestamp is propagated to all tasks during START-STOP-START + "lhc_period", + "pdp_beam_type", + "pdp_override_run_start_time", + "original_run_number", +} + func NewStartActivityTransition(taskman *task.Manager) Transition { return &StartActivityTransition{ baseTransition: baseTransition{ @@ -81,21 +97,7 @@ func (t StartActivityTransition) do(env *Environment) (err error) { // Get a handle to the consolidated var stack of the root role of the env's workflow if wf := env.Workflow(); wf != nil { if cvs, cvsErr := wf.ConsolidatedVarStack(); cvsErr == nil { - // If bookkeeping is enabled and has fetched the LHC fill info, we can acquire it here - for _, key := range []string{ - "fill_info_fill_number", - "fill_info_filling_scheme", - "fill_info_beam_type", - "fill_info_stable_beam_start_ms", - "fill_info_stable_beam_end_ms", - "run_type", - "run_start_time_ms", - "run_end_time_ms", // included to ensure that a cleared SOEOR timestamp is propagated to all tasks during START-STOP-START - "lhc_period", - "pdp_beam_type", - "pdp_override_run_start_time", - "original_run_number", - } { + for _, key := range StartActivityParameterKeys { if value, ok := cvs[key]; ok { // we push the above parameters with both camelCase and snake_case identifiers for convenience args[strcase.ToLowerCamel(key)] = value diff --git a/core/environment/transition_stopactivity.go b/core/environment/transition_stopactivity.go index 1533c68fe..8653302e1 100644 --- a/core/environment/transition_stopactivity.go +++ b/core/environment/transition_stopactivity.go @@ -36,6 +36,15 @@ import ( "github.com/iancoleman/strcase" ) +var StopActivityParameterKeys = []string{ + "fill_info_fill_number", + "fill_info_filling_scheme", + "fill_info_beam_type", + "fill_info_stable_beams_start_ms", + "fill_info_stable_beams_end_ms", + "run_end_time_ms", +} + func NewStopActivityTransition(taskman *task.Manager) Transition { return &StopActivityTransition{ baseTransition: baseTransition{ @@ -64,11 +73,14 @@ func (t StopActivityTransition) do(env *Environment) (err error) { // Get a handle to the consolidated var stack of the root role of the env's workflow if wf := env.Workflow(); wf != nil { if cvs, cvsErr := wf.ConsolidatedVarStack(); cvsErr == nil { - - // Propagate run end time to all tasks - if value, ok := cvs["run_end_time_ms"]; ok { - args[strcase.ToLowerCamel("run_end_time_ms")] = value - args["run_end_time_ms"] = value + // in principle, only stable beams end should change among fill info vars in a typical scenario, + // but just in case of more creative uses, we push all of them again. + for _, key := range StopActivityParameterKeys { + if value, ok := cvs[key]; ok { + // we push the above parameters with both camelCase and snake_case identifiers for convenience + args[strcase.ToLowerCamel(key)] = value + args[key] = value + } } } } diff --git a/core/environment/utils.go b/core/environment/utils.go index 229fde3e1..1ca0dcad3 100644 --- a/core/environment/utils.go +++ b/core/environment/utils.go @@ -27,14 +27,17 @@ package environment import ( "bytes" "encoding/json" + "errors" "fmt" + "os" + "sort" + "github.com/AliceO2Group/Control/common/logger/infologger" pb "github.com/AliceO2Group/Control/common/protos" "github.com/AliceO2Group/Control/core/task" "github.com/AliceO2Group/Control/core/task/sm" "github.com/AliceO2Group/Control/core/workflow" - "os" - "sort" + "github.com/looplab/fsm" "github.com/AliceO2Group/Control/core/the" "gopkg.in/yaml.v3" @@ -139,3 +142,27 @@ func newCriticalTasksErrorMessage(env *Environment) string { return fmt.Sprintf("%d critical tasks transitioned to ERROR, could not determine the first one to fail", len(criticalTasksInError)) } } + +func HandleFailedGoError(err error, env *Environment) { + var invalidEventErr fsm.InvalidEventError + if errors.As(err, &invalidEventErr) { + // this case can occur if the environment is in either: + // - ERROR (env already transitioned to ERROR for another reason) + // - DONE (an error might have occurred during teardown, but it's already over, no point in spreading panic) + log.WithError(invalidEventErr). + WithField("partition", env.Id().String()). + WithField("run", env.currentRunNumber). + WithField("state", env.CurrentState()). + WithField(infologger.Level, infologger.IL_Support). + Warn("did not perform GO_ERROR transition") + } else { + // in principle this should never happen, so we log it accordingly and force the ERROR state just in case + log.WithError(err). + WithField("partition", env.Id().String()). + WithField("run", env.currentRunNumber). + WithField("state", env.CurrentState()). + WithField(infologger.Level, infologger.IL_Ops). + Error("could not perform GO_ERROR transition due to unexpected error, forcing...") + env.setState("ERROR") + } +} diff --git a/core/environment/utils_test.go b/core/environment/utils_test.go new file mode 100644 index 000000000..bf914be83 --- /dev/null +++ b/core/environment/utils_test.go @@ -0,0 +1,50 @@ +/* + * === This file is part of ALICE O² === + * + * Copyright 2025 CERN and copyright holders of ALICE O². + * Author: Piotr Konopka + * + * 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 environment + +import ( + "github.com/looplab/fsm" + . "github.com/onsi/ginkgo/v2" + . "github.com/onsi/gomega" +) + +var _ = Describe("HandleFailedGoError", func() { + It("does not overwrite state for InvalidEventError", func() { + env := &Environment{} + env.Sm = fsm.NewFSM("DONE", fsm.Events{}, fsm.Callbacks{}) + Expect(env.Sm.Current()).To(Equal("DONE")) + + HandleFailedGoError(fsm.InvalidEventError{Event: "GO_ERROR", State: "DONE"}, env) + Expect(env.Sm.Current()).To(Equal("DONE")) + }) + + It("overwrites state to ERROR for other errors", func() { + env := &Environment{} + env.Sm = fsm.NewFSM("CONFIGURED", fsm.Events{}, fsm.Callbacks{}) + + HandleFailedGoError(fsm.UnknownEventError{Event: "BOOM"}, env) + Expect(env.Sm.Current()).To(Equal("ERROR")) + }) +}) diff --git a/core/integration/bookkeeping/plugin.go b/core/integration/bookkeeping/plugin.go index 476fdb1be..49344a7af 100644 --- a/core/integration/bookkeeping/plugin.go +++ b/core/integration/bookkeeping/plugin.go @@ -1446,10 +1446,10 @@ func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { parentRole.SetGlobalRuntimeVar("fill_info_filling_scheme", lhcInfo.FillingSchemeName) parentRole.SetGlobalRuntimeVar("fill_info_beam_type", lhcInfo.BeamType) if lhcInfo.StableBeamsStart != nil { - parentRole.SetGlobalRuntimeVar("fill_info_stable_beam_start_ms", strconv.FormatInt(*lhcInfo.StableBeamsStart, 10)) + parentRole.SetGlobalRuntimeVar("fill_info_stable_beams_start_ms", strconv.FormatInt(*lhcInfo.StableBeamsStart, 10)) } if lhcInfo.StableBeamsEnd != nil { - parentRole.SetGlobalRuntimeVar("fill_info_stable_beam_end_ms", strconv.FormatInt(*lhcInfo.StableBeamsEnd, 10)) + parentRole.SetGlobalRuntimeVar("fill_info_stable_beams_end_ms", strconv.FormatInt(*lhcInfo.StableBeamsEnd, 10)) } log.WithField("partition", envId). WithField("level", infologger.IL_Devel). @@ -1471,8 +1471,8 @@ func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { parentRole.DeleteGlobalRuntimeVar("fill_info_fill_number") parentRole.DeleteGlobalRuntimeVar("fill_info_filling_scheme") parentRole.DeleteGlobalRuntimeVar("fill_info_beam_type") - parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beam_start_ms") - parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beam_end_ms") + parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beams_start_ms") + parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beams_end_ms") } stack["RetrieveFillInfo"] = func() (out string) { diff --git a/core/integration/lhc/plugin.go b/core/integration/lhc/plugin.go index bb4276551..d29177c6a 100644 --- a/core/integration/lhc/plugin.go +++ b/core/integration/lhc/plugin.go @@ -28,20 +28,22 @@ import ( "context" "encoding/json" "errors" - "github.com/AliceO2Group/Control/common/event/topic" - "github.com/AliceO2Group/Control/common/logger/infologger" - pb "github.com/AliceO2Group/Control/common/protos" "io" + "strconv" "strings" "sync" "time" cmnevent "github.com/AliceO2Group/Control/common/event" + "github.com/AliceO2Group/Control/common/event/topic" "github.com/AliceO2Group/Control/common/logger" + "github.com/AliceO2Group/Control/common/logger/infologger" + pb "github.com/AliceO2Group/Control/common/protos" "github.com/AliceO2Group/Control/common/utils/uid" "github.com/AliceO2Group/Control/core/environment" "github.com/AliceO2Group/Control/core/integration" lhcevent "github.com/AliceO2Group/Control/core/integration/lhc/event" + "github.com/AliceO2Group/Control/core/workflow/callable" "github.com/sirupsen/logrus" "github.com/spf13/viper" ) @@ -51,10 +53,8 @@ var dipClientTopic topic.Topic = "dip.lhc.beam_mode" // Plugin implements integration.Plugin and listens for LHC updates. type Plugin struct { - endpoint string - ctx context.Context - //cancel context.CancelFunc - //wg sync.WaitGroup + endpoint string + ctx context.Context mu sync.Mutex currentState *pb.BeamInfo reader cmnevent.Reader @@ -66,21 +66,73 @@ func NewPlugin(endpoint string) integration.Plugin { } func (p *Plugin) Init(_ string) error { - // use a background context for reader loop; Destroy will Close the reader p.ctx = context.Background() - p.reader = cmnevent.NewReaderWithTopic(dipClientTopic, "", true) - + p.reader = cmnevent.NewReaderWithTopic(dipClientTopic, "o2-aliecs-core.lhc") if p.reader == nil { return errors.New("could not create a kafka reader for LHC plugin") } - go p.readAndInjectLhcUpdates() - log.Debug("LHC plugin initialized (client started)") + // Always perform a short pre-drain to consume any backlog without injecting. + log.WithField(infologger.Level, infologger.IL_Devel). + Info("LHC plugin: draining any initial backlog") + p.drainBacklog(2 * time.Second) + + // If state is still empty, try reading the latest message once. + p.mu.Lock() + empty := p.currentState == nil || p.currentState.BeamMode == pb.BeamMode_UNKNOWN + p.mu.Unlock() + if empty { + if last, err := p.reader.Last(p.ctx); err != nil { + log.WithField(infologger.Level, infologger.IL_Support).WithError(err).Warn("failed to read last LHC state on init") + } else if last != nil { + if bmEvt := last.GetBeamModeEvent(); bmEvt != nil && bmEvt.GetBeamInfo() != nil { + p.mu.Lock() + p.currentState = bmEvt.GetBeamInfo() + p.mu.Unlock() + } + } else { + // nothing to retrieve in the topic, we move on + } + } + + go p.readAndInjectLhcUpdates() + log.WithField(infologger.Level, infologger.IL_Devel).Debug("LHC plugin initialized (client started)") return nil } +// drainBacklog reads messages for a limited time and only updates the plugin state, without injecting to env manager. +func (p *Plugin) drainBacklog(timeout time.Duration) { + drainCtx, cancel := context.WithTimeout(p.ctx, timeout) + defer cancel() + for { + msg, err := p.reader.Next(drainCtx) + if err != nil { + if errors.Is(err, context.DeadlineExceeded) || errors.Is(err, io.EOF) || errors.Is(err, context.Canceled) { + break + } + // transient error: small sleep and continue until timeout + time.Sleep(50 * time.Millisecond) + continue + } + if msg == nil { + continue + } + if beamModeEvent := msg.GetBeamModeEvent(); beamModeEvent != nil && beamModeEvent.GetBeamInfo() != nil { + beamInfo := beamModeEvent.GetBeamInfo() + log.WithField(infologger.Level, infologger.IL_Devel). + Debugf("new LHC update received while draining backlog: BeamMode=%s, FillNumber=%d, FillingScheme=%s, StableBeamsStart=%d, StableBeamsEnd=%d, BeamType=%s", + beamInfo.GetBeamMode().String(), beamInfo.GetFillNumber(), beamInfo.GetFillingSchemeName(), + beamInfo.GetStableBeamsStart(), beamInfo.GetStableBeamsEnd(), beamInfo.GetBeamType()) + + p.mu.Lock() + p.currentState = beamModeEvent.GetBeamInfo() + p.mu.Unlock() + } + } +} + func (p *Plugin) GetName() string { return "lhc" } func (p *Plugin) GetPrettyName() string { return "LHC (DIP/Kafka client)" } func (p *Plugin) GetEndpoint() string { @@ -125,8 +177,18 @@ func (p *Plugin) GetEnvironmentsShortData(envIds []uid.ID) map[uid.ID]string { func (p *Plugin) ObjectStack(_ map[string]string, _ map[string]string) (stack map[string]interface{}) { return make(map[string]interface{}) } -func (p *Plugin) CallStack(_ interface{}) (stack map[string]interface{}) { - return make(map[string]interface{}) +func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { + call, ok := data.(*callable.Call) + if !ok { + return + } + + stack = make(map[string]interface{}) + stack["UpdateFillInfo"] = func() (out string) { + p.updateFillInfo(call) + return + } + return } func (p *Plugin) Destroy() error { @@ -198,3 +260,83 @@ func (p *Plugin) readAndInjectLhcUpdates() { } } } + +// UpdateFillInfo: propagate latest LHC fill info into the environment's global runtime vars +func (p *Plugin) updateFillInfo(call *callable.Call) (out string) { + varStack := call.VarStack + envId, ok := varStack["environment_id"] + if !ok { + err := errors.New("cannot acquire environment ID") + log.Error(err) + + call.VarStack["__call_error_reason"] = err.Error() + call.VarStack["__call_error"] = "LHC plugin Call Stack failed" + return + } + + log := log.WithFields(logrus.Fields{ + "partition": envId, + "call": "UpdateFillInfo", + }) + + parentRole, ok := call.GetParentRole().(callable.ParentRole) + if !ok || parentRole == nil { + log.WithField(infologger.Level, infologger.IL_Support). + Error("cannot access parent role to propagate LHC fill info") + return + } + + if p.currentState == nil { + log.WithField(infologger.Level, infologger.IL_Support). + Warn("attempted to update environment with fill info, but fill info is not available in plugin") + return + } + + // note: the following was causing very weird behaviours, which could be attributed to memory corruption. + // I did not manage to understand why can't we safely clone such a proto message. + // state := proto.Clone(p.currentState).(*pb.BeamInfo) + + p.mu.Lock() + defer p.mu.Unlock() + state := p.currentState + + parentRole.SetGlobalRuntimeVar("fill_info_beam_mode", state.BeamMode.String()) + + // If NO_BEAM, clear all other fill info and return + if state.BeamMode == pb.BeamMode_NO_BEAM { + parentRole.DeleteGlobalRuntimeVar("fill_info_fill_number") + parentRole.DeleteGlobalRuntimeVar("fill_info_filling_scheme") + parentRole.DeleteGlobalRuntimeVar("fill_info_beam_type") + parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beams_start_ms") + parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beams_end_ms") + + log.WithField(infologger.Level, infologger.IL_Devel). + Debug("NO_BEAM — cleared fill info vars and set beam mode only") + return + } + + // Otherwise, propagate latest known info + parentRole.SetGlobalRuntimeVar("fill_info_fill_number", strconv.FormatInt(int64(state.FillNumber), 10)) + parentRole.SetGlobalRuntimeVar("fill_info_filling_scheme", state.FillingSchemeName) + parentRole.SetGlobalRuntimeVar("fill_info_beam_type", state.BeamType) + if state.StableBeamsStart > 0 { + parentRole.SetGlobalRuntimeVar("fill_info_stable_beams_start_ms", strconv.FormatInt(state.StableBeamsStart, 10)) + } else { + parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beams_start_ms") + } + if state.StableBeamsEnd > 0 { + parentRole.SetGlobalRuntimeVar("fill_info_stable_beams_end_ms", strconv.FormatInt(state.StableBeamsEnd, 10)) + } else { + parentRole.DeleteGlobalRuntimeVar("fill_info_stable_beams_end_ms") + } + + log.WithField("fillNumber", state.FillNumber). + WithField("fillingScheme", state.FillingSchemeName). + WithField("beamType", state.BeamType). + WithField("beamMode", state.BeamMode). + WithField("stableStartMs", state.StableBeamsStart). + WithField("stableEndMs", state.StableBeamsEnd). + WithField(infologger.Level, infologger.IL_Devel). + Debug("updated environment fill info from latest snapshot") + return +} diff --git a/core/integration/odc/plugin.go b/core/integration/odc/plugin.go index 11a1d9fa3..1a9a9d261 100644 --- a/core/integration/odc/plugin.go +++ b/core/integration/odc/plugin.go @@ -95,20 +95,22 @@ type OdcStatus struct { } type OdcDeviceId uint64 +type OdcCollectionId uint64 func (o OdcDeviceId) MarshalJSON() ([]byte, error) { return json.Marshal(strconv.FormatUint(uint64(o), 10)) } type OdcPartitionInfo struct { - PartitionId uid.ID `json:"-"` - RunNumber uint32 `json:"runNumber"` - State string `json:"state"` - EcsState sm.State `json:"ecsState"` - DdsSessionId string `json:"ddsSessionId"` - DdsSessionStatus string `json:"ddsSessionStatus"` - Devices map[OdcDeviceId]*OdcDevice `json:"devices"` - Hosts []string `json:"hosts"` + PartitionId uid.ID `json:"-"` + RunNumber uint32 `json:"runNumber"` + State string `json:"state"` + EcsState sm.State `json:"ecsState"` + DdsSessionId string `json:"ddsSessionId"` + DdsSessionStatus string `json:"ddsSessionStatus"` + Devices map[OdcDeviceId]*OdcDevice `json:"devices"` + Hosts []string `json:"hosts"` + Collections map[OdcCollectionId]*OdcCollection `json:"collections"` } type OdcDevice struct { @@ -122,6 +124,14 @@ type OdcDevice struct { Rmsjobid string `json:"rmsjobid"` } +type OdcCollection struct { + CollectionId OdcCollectionId `json:"collectionId"` + State string `json:"state"` + EcsState sm.State `json:"ecsState"` + Path string `json:"path"` + Host string `json:"host"` +} + type partitionStateChangedEventPayload struct { PartitionId uid.ID `json:"partitionId"` DdsSessionId string `json:"ddsSessionId"` @@ -144,6 +154,17 @@ type deviceStateChangedEventPayload struct { Rmsjobid string `json:"rmsjobid"` } +type collectionStateChangedEventPayload struct { + PartitionId uid.ID `json:"partitionId"` + DdsSessionId string `json:"ddsSessionId"` + DdsSessionStatus string `json:"ddsSessionStatus"` + State string `json:"state"` + EcsState sm.State `json:"ecsState"` + CollectionId OdcCollectionId `json:"collectionId"` + Path string `json:"path"` + Host string `json:"host"` +} + func NewPlugin(endpoint string) integration.Plugin { u, err := url.Parse(endpoint) if err != nil { @@ -230,6 +251,7 @@ func (p *Plugin) queryPartitionStatus() { PartitionId: id, RunNumber: uint32(odcPartSt.Runnr), State: odcPartSt.State, + EcsState: fairmq.ToEcsState(odcPartSt.State, sm.UNKNOWN), DdsSessionId: odcPartSt.Sessionid, DdsSessionStatus: odcPartSt.Status.String(), } @@ -266,6 +288,7 @@ func (p *Plugin) queryPartitionStatus() { odcPartInfoSlice[idx].Devices[OdcDeviceId(device.Id)] = &OdcDevice{ TaskId: strconv.FormatUint(device.Id, 10), State: device.State, + EcsState: fairmq.ToEcsState(device.State, sm.UNKNOWN), Path: device.Path, Ignored: device.Ignored, Host: device.Host, @@ -273,6 +296,16 @@ func (p *Plugin) queryPartitionStatus() { Rmsjobid: device.Rmsjobid, } } + odcPartInfoSlice[idx].Collections = make(map[OdcCollectionId]*OdcCollection, len(odcPartStateRep.Collections)) + for _, collection := range odcPartStateRep.Collections { + odcPartInfoSlice[idx].Collections[OdcCollectionId(collection.Id)] = &OdcCollection{ + CollectionId: OdcCollectionId(collection.Id), + State: collection.State, + EcsState: fairmq.ToEcsState(collection.State, sm.UNKNOWN), + Path: collection.Path, + Host: collection.Host, + } + } }(i, id) } wg.Wait() @@ -337,6 +370,45 @@ func (p *Plugin) queryPartitionStatus() { }) } + // detection of collection state change + event publication + for collectionId, collection := range partitionInfo.Collections { + existingCollection, hasCollection := existingPartition.Collections[collectionId] + + oldEcsState := sm.UNKNOWN // we presume the collection didn't exist before + + // if a collection with this ID is already known to us from before + if hasCollection { + // if collection state has changed + if existingCollection.State != collection.State { + // if the state has changed, we take note of the previous state + oldEcsState = existingCollection.EcsState + } else { + // if the state hasn't changed, we set the old ECS state and bail + collection.EcsState = existingCollection.EcsState + continue + } + } + + collection.EcsState = fairmq.ToEcsState(collection.State, oldEcsState) + + payload := collectionStateChangedEventPayload{ + PartitionId: partitionInfo.PartitionId, + DdsSessionId: partitionInfo.DdsSessionId, + DdsSessionStatus: partitionInfo.DdsSessionStatus, + State: collection.State, + EcsState: collection.EcsState, + CollectionId: collection.CollectionId, + Path: collection.Path, + Host: collection.Host, + } + payloadJson, _ := json.Marshal(payload) + the.EventWriterWithTopic(TOPIC).WriteEvent(&pb.Ev_IntegratedServiceEvent{ + Name: "odc.collectionStateChanged", + EnvironmentId: id.String(), + Payload: string(payloadJson[:]), + }) + } + // detection of env (ODC partition) state change + event publication if existingPartition.State != partitionInfo.State { partitionInfo.EcsState = fairmq.ToEcsState(partitionInfo.State, existingPartition.EcsState) @@ -1367,19 +1439,12 @@ func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { WithField("call", "Start"). Warn("cannot acquire run number for ODC") } - originalRunNumber, _ := varStack["original_run_number"] cleanupCountS, ok := varStack["__fmq_cleanup_count"] if !ok { log.WithField("partition", envId). WithField("call", "Start"). Warn("cannot acquire FairMQ devices cleanup count for ODC") } - runStartTimeMs, ok := varStack["run_start_time_ms"] - if !ok { - log.WithField("partition", envId). - WithField("call", "Start"). - Warn("cannot acquire run_start_time_ms") - } var ( runNumberu64 uint64 @@ -1406,12 +1471,12 @@ func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { timeout := callable.AcquireTimeout(ODC_START_TIMEOUT, varStack, "Start", envId) arguments := make(map[string]string) - arguments["run_number"] = rn arguments["runNumber"] = rn - arguments["run_start_time_ms"] = runStartTimeMs arguments["cleanup"] = strconv.Itoa(cleanupCount) - if len(originalRunNumber) > 0 { - arguments["original_run_number"] = originalRunNumber + for _, key := range environment.StartActivityParameterKeys { + if value, ok := varStack[key]; ok { + arguments[key] = value + } } ctx, cancel := integration.NewContext(envId, varStack, timeout) @@ -1450,15 +1515,13 @@ func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { Error("cannot acquire run number for ODC EOR") runNumberu64 = 0 } - runEndTimeMs, ok := varStack["run_end_time_ms"] - if !ok { - log.WithField("partition", envId). - WithField("call", "Stop"). - Warn("cannot acquire run_end_time_ms") - } arguments := make(map[string]string) - arguments["run_end_time_ms"] = runEndTimeMs + for _, key := range environment.StopActivityParameterKeys { + if value, ok := varStack[key]; ok { + arguments[key] = value + } + } timeout := callable.AcquireTimeout(ODC_STOP_TIMEOUT, varStack, "Stop", envId) @@ -1522,15 +1585,12 @@ func (p *Plugin) CallStack(data interface{}) (stack map[string]interface{}) { Error("cannot acquire run number for ODC EOR") runNumberu64 = 0 } - runEndTimeMs, ok := varStack["run_end_time_ms"] - if !ok { - log.WithField("partition", envId). - WithField("call", "EnsureStop"). - Warn("cannot acquire run_end_time_ms") - } - arguments := make(map[string]string) - arguments["run_end_time_ms"] = runEndTimeMs + for _, key := range environment.StopActivityParameterKeys { + if value, ok := varStack[key]; ok { + arguments[key] = value + } + } err = handleStop(ctx, p.odcClient, arguments, paddingTimeout, envId, runNumberu64, call) if err != nil { diff --git a/core/integration/odc/protos/odc.pb.go b/core/integration/odc/protos/odc.pb.go index 4edcb3cc5..9475e2b02 100644 --- a/core/integration/odc/protos/odc.pb.go +++ b/core/integration/odc/protos/odc.pb.go @@ -394,6 +394,78 @@ func (x *Device) GetRmsjobid() string { return "" } +// Collection information +type Collection struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` // Runtime collection ID (same as in DDS) + State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` // Aggregated state as string + Path string `protobuf:"bytes,3,opt,name=path,proto3" json:"path,omitempty"` // Path in the topology + Host string `protobuf:"bytes,5,opt,name=host,proto3" json:"host,omitempty"` // Host where the collection runs +} + +func (x *Collection) Reset() { + *x = Collection{} + if protoimpl.UnsafeEnabled { + mi := &file_protos_odc_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Collection) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Collection) ProtoMessage() {} + +func (x *Collection) ProtoReflect() protoreflect.Message { + mi := &file_protos_odc_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 Collection.ProtoReflect.Descriptor instead. +func (*Collection) Descriptor() ([]byte, []int) { + return file_protos_odc_proto_rawDescGZIP(), []int{3} +} + +func (x *Collection) GetId() uint64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *Collection) GetState() string { + if x != nil { + return x.State + } + return "" +} + +func (x *Collection) GetPath() string { + if x != nil { + return x.Path + } + return "" +} + +func (x *Collection) GetHost() string { + if x != nil { + return x.Host + } + return "" +} + // Device change/get state request type StateRequest struct { state protoimpl.MessageState @@ -410,7 +482,7 @@ type StateRequest struct { func (x *StateRequest) Reset() { *x = StateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[3] + mi := &file_protos_odc_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +495,7 @@ func (x *StateRequest) String() string { func (*StateRequest) ProtoMessage() {} func (x *StateRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[3] + mi := &file_protos_odc_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +508,7 @@ func (x *StateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StateRequest.ProtoReflect.Descriptor instead. func (*StateRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{3} + return file_protos_odc_proto_rawDescGZIP(), []int{4} } func (x *StateRequest) GetPartitionid() string { @@ -480,14 +552,15 @@ type StateReply struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Reply *GeneralReply `protobuf:"bytes,1,opt,name=reply,proto3" json:"reply,omitempty"` // General reply. See GeneralReply message for details. - Devices []*Device `protobuf:"bytes,2,rep,name=devices,proto3" json:"devices,omitempty"` // If detailed reply is requested then this field contains a list of affected devices otherwise it's empty. + Reply *GeneralReply `protobuf:"bytes,1,opt,name=reply,proto3" json:"reply,omitempty"` // General reply. See GeneralReply message for details. + Devices []*Device `protobuf:"bytes,2,rep,name=devices,proto3" json:"devices,omitempty"` // If detailed reply is requested then this field contains a list of affected devices otherwise it's empty. + Collections []*Collection `protobuf:"bytes,3,rep,name=collections,proto3" json:"collections,omitempty"` // If detailed reply is requested then this field contains a list of affected collections otherwise it's empty. } func (x *StateReply) Reset() { *x = StateReply{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[4] + mi := &file_protos_odc_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -500,7 +573,7 @@ func (x *StateReply) String() string { func (*StateReply) ProtoMessage() {} func (x *StateReply) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[4] + mi := &file_protos_odc_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -513,7 +586,7 @@ func (x *StateReply) ProtoReflect() protoreflect.Message { // Deprecated: Use StateReply.ProtoReflect.Descriptor instead. func (*StateReply) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{4} + return file_protos_odc_proto_rawDescGZIP(), []int{5} } func (x *StateReply) GetReply() *GeneralReply { @@ -530,6 +603,13 @@ func (x *StateReply) GetDevices() []*Device { return nil } +func (x *StateReply) GetCollections() []*Collection { + if x != nil { + return x.Collections + } + return nil +} + // Status of each partition type PartitionStatus struct { state protoimpl.MessageState @@ -547,7 +627,7 @@ type PartitionStatus struct { func (x *PartitionStatus) Reset() { *x = PartitionStatus{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[5] + mi := &file_protos_odc_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -560,7 +640,7 @@ func (x *PartitionStatus) String() string { func (*PartitionStatus) ProtoMessage() {} func (x *PartitionStatus) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[5] + mi := &file_protos_odc_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -573,7 +653,7 @@ func (x *PartitionStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use PartitionStatus.ProtoReflect.Descriptor instead. func (*PartitionStatus) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{5} + return file_protos_odc_proto_rawDescGZIP(), []int{6} } func (x *PartitionStatus) GetPartitionid() string { @@ -634,7 +714,7 @@ type StatusReply struct { func (x *StatusReply) Reset() { *x = StatusReply{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[6] + mi := &file_protos_odc_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -647,7 +727,7 @@ func (x *StatusReply) String() string { func (*StatusReply) ProtoMessage() {} func (x *StatusReply) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[6] + mi := &file_protos_odc_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -660,7 +740,7 @@ func (x *StatusReply) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusReply.ProtoReflect.Descriptor instead. func (*StatusReply) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{6} + return file_protos_odc_proto_rawDescGZIP(), []int{7} } func (x *StatusReply) GetMsg() string { @@ -713,7 +793,7 @@ type InitializeRequest struct { func (x *InitializeRequest) Reset() { *x = InitializeRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[7] + mi := &file_protos_odc_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -726,7 +806,7 @@ func (x *InitializeRequest) String() string { func (*InitializeRequest) ProtoMessage() {} func (x *InitializeRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[7] + mi := &file_protos_odc_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -739,7 +819,7 @@ func (x *InitializeRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use InitializeRequest.ProtoReflect.Descriptor instead. func (*InitializeRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{7} + return file_protos_odc_proto_rawDescGZIP(), []int{8} } func (x *InitializeRequest) GetPartitionid() string { @@ -786,7 +866,7 @@ type SubmitRequest struct { func (x *SubmitRequest) Reset() { *x = SubmitRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[8] + mi := &file_protos_odc_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -799,7 +879,7 @@ func (x *SubmitRequest) String() string { func (*SubmitRequest) ProtoMessage() {} func (x *SubmitRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[8] + mi := &file_protos_odc_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -812,7 +892,7 @@ func (x *SubmitRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SubmitRequest.ProtoReflect.Descriptor instead. func (*SubmitRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{8} + return file_protos_odc_proto_rawDescGZIP(), []int{9} } func (x *SubmitRequest) GetPartitionid() string { @@ -868,7 +948,7 @@ type ActivateRequest struct { func (x *ActivateRequest) Reset() { *x = ActivateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[9] + mi := &file_protos_odc_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -881,7 +961,7 @@ func (x *ActivateRequest) String() string { func (*ActivateRequest) ProtoMessage() {} func (x *ActivateRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[9] + mi := &file_protos_odc_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -894,7 +974,7 @@ func (x *ActivateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ActivateRequest.ProtoReflect.Descriptor instead. func (*ActivateRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{9} + return file_protos_odc_proto_rawDescGZIP(), []int{10} } func (x *ActivateRequest) GetPartitionid() string { @@ -960,7 +1040,7 @@ type RunRequest struct { func (x *RunRequest) Reset() { *x = RunRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[10] + mi := &file_protos_odc_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -973,7 +1053,7 @@ func (x *RunRequest) String() string { func (*RunRequest) ProtoMessage() {} func (x *RunRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[10] + mi := &file_protos_odc_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -986,7 +1066,7 @@ func (x *RunRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use RunRequest.ProtoReflect.Descriptor instead. func (*RunRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{10} + return file_protos_odc_proto_rawDescGZIP(), []int{11} } func (x *RunRequest) GetPartitionid() string { @@ -1070,7 +1150,7 @@ type UpdateRequest struct { func (x *UpdateRequest) Reset() { *x = UpdateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[11] + mi := &file_protos_odc_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1083,7 +1163,7 @@ func (x *UpdateRequest) String() string { func (*UpdateRequest) ProtoMessage() {} func (x *UpdateRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[11] + mi := &file_protos_odc_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1096,7 +1176,7 @@ func (x *UpdateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use UpdateRequest.ProtoReflect.Descriptor instead. func (*UpdateRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{11} + return file_protos_odc_proto_rawDescGZIP(), []int{12} } func (x *UpdateRequest) GetPartitionid() string { @@ -1155,7 +1235,7 @@ type ShutdownRequest struct { func (x *ShutdownRequest) Reset() { *x = ShutdownRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[12] + mi := &file_protos_odc_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1168,7 +1248,7 @@ func (x *ShutdownRequest) String() string { func (*ShutdownRequest) ProtoMessage() {} func (x *ShutdownRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[12] + mi := &file_protos_odc_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1181,7 +1261,7 @@ func (x *ShutdownRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ShutdownRequest.ProtoReflect.Descriptor instead. func (*ShutdownRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{12} + return file_protos_odc_proto_rawDescGZIP(), []int{13} } func (x *ShutdownRequest) GetPartitionid() string { @@ -1218,7 +1298,7 @@ type Property struct { func (x *Property) Reset() { *x = Property{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[13] + mi := &file_protos_odc_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1231,7 +1311,7 @@ func (x *Property) String() string { func (*Property) ProtoMessage() {} func (x *Property) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[13] + mi := &file_protos_odc_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1244,7 +1324,7 @@ func (x *Property) ProtoReflect() protoreflect.Message { // Deprecated: Use Property.ProtoReflect.Descriptor instead. func (*Property) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{13} + return file_protos_odc_proto_rawDescGZIP(), []int{14} } func (x *Property) GetKey() string { @@ -1277,7 +1357,7 @@ type SetPropertiesRequest struct { func (x *SetPropertiesRequest) Reset() { *x = SetPropertiesRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[14] + mi := &file_protos_odc_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1290,7 +1370,7 @@ func (x *SetPropertiesRequest) String() string { func (*SetPropertiesRequest) ProtoMessage() {} func (x *SetPropertiesRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[14] + mi := &file_protos_odc_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1303,7 +1383,7 @@ func (x *SetPropertiesRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SetPropertiesRequest.ProtoReflect.Descriptor instead. func (*SetPropertiesRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{14} + return file_protos_odc_proto_rawDescGZIP(), []int{15} } func (x *SetPropertiesRequest) GetPartitionid() string { @@ -1353,7 +1433,7 @@ type ConfigureRequest struct { func (x *ConfigureRequest) Reset() { *x = ConfigureRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[15] + mi := &file_protos_odc_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1366,7 +1446,7 @@ func (x *ConfigureRequest) String() string { func (*ConfigureRequest) ProtoMessage() {} func (x *ConfigureRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[15] + mi := &file_protos_odc_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1379,7 +1459,7 @@ func (x *ConfigureRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ConfigureRequest.ProtoReflect.Descriptor instead. func (*ConfigureRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{15} + return file_protos_odc_proto_rawDescGZIP(), []int{16} } func (x *ConfigureRequest) GetRequest() *StateRequest { @@ -1401,7 +1481,7 @@ type StartRequest struct { func (x *StartRequest) Reset() { *x = StartRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[16] + mi := &file_protos_odc_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1414,7 +1494,7 @@ func (x *StartRequest) String() string { func (*StartRequest) ProtoMessage() {} func (x *StartRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[16] + mi := &file_protos_odc_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1427,7 +1507,7 @@ func (x *StartRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StartRequest.ProtoReflect.Descriptor instead. func (*StartRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{16} + return file_protos_odc_proto_rawDescGZIP(), []int{17} } func (x *StartRequest) GetRequest() *StateRequest { @@ -1449,7 +1529,7 @@ type StopRequest struct { func (x *StopRequest) Reset() { *x = StopRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[17] + mi := &file_protos_odc_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1462,7 +1542,7 @@ func (x *StopRequest) String() string { func (*StopRequest) ProtoMessage() {} func (x *StopRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[17] + mi := &file_protos_odc_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1475,7 +1555,7 @@ func (x *StopRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StopRequest.ProtoReflect.Descriptor instead. func (*StopRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{17} + return file_protos_odc_proto_rawDescGZIP(), []int{18} } func (x *StopRequest) GetRequest() *StateRequest { @@ -1497,7 +1577,7 @@ type ResetRequest struct { func (x *ResetRequest) Reset() { *x = ResetRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[18] + mi := &file_protos_odc_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1510,7 +1590,7 @@ func (x *ResetRequest) String() string { func (*ResetRequest) ProtoMessage() {} func (x *ResetRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[18] + mi := &file_protos_odc_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1523,7 +1603,7 @@ func (x *ResetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ResetRequest.ProtoReflect.Descriptor instead. func (*ResetRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{18} + return file_protos_odc_proto_rawDescGZIP(), []int{19} } func (x *ResetRequest) GetRequest() *StateRequest { @@ -1545,7 +1625,7 @@ type TerminateRequest struct { func (x *TerminateRequest) Reset() { *x = TerminateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[19] + mi := &file_protos_odc_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1558,7 +1638,7 @@ func (x *TerminateRequest) String() string { func (*TerminateRequest) ProtoMessage() {} func (x *TerminateRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[19] + mi := &file_protos_odc_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1571,7 +1651,7 @@ func (x *TerminateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use TerminateRequest.ProtoReflect.Descriptor instead. func (*TerminateRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{19} + return file_protos_odc_proto_rawDescGZIP(), []int{20} } func (x *TerminateRequest) GetRequest() *StateRequest { @@ -1593,7 +1673,7 @@ type StatusRequest struct { func (x *StatusRequest) Reset() { *x = StatusRequest{} if protoimpl.UnsafeEnabled { - mi := &file_protos_odc_proto_msgTypes[20] + mi := &file_protos_odc_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1606,7 +1686,7 @@ func (x *StatusRequest) String() string { func (*StatusRequest) ProtoMessage() {} func (x *StatusRequest) ProtoReflect() protoreflect.Message { - mi := &file_protos_odc_proto_msgTypes[20] + mi := &file_protos_odc_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1619,7 +1699,7 @@ func (x *StatusRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use StatusRequest.ProtoReflect.Descriptor instead. func (*StatusRequest) Descriptor() ([]byte, []int) { - return file_protos_odc_proto_rawDescGZIP(), []int{20} + return file_protos_odc_proto_rawDescGZIP(), []int{21} } func (x *StatusRequest) GetRunning() bool { @@ -1666,21 +1746,30 @@ var file_protos_odc_proto_rawDesc = []byte{ 0x6c, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0a, 0x65, 0x78, 0x70, 0x65, 0x6e, 0x64, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x72, 0x6d, 0x73, 0x6a, 0x6f, 0x62, 0x69, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x72, 0x6d, 0x73, 0x6a, 0x6f, 0x62, 0x69, 0x64, - 0x22, 0x90, 0x01, 0x0a, 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, - 0x6e, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x72, 0x75, 0x6e, 0x6e, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x04, 0x52, 0x05, 0x72, 0x75, 0x6e, 0x6e, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, - 0x65, 0x6f, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, - 0x6f, 0x75, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x65, 0x74, 0x61, 0x69, - 0x6c, 0x65, 0x64, 0x22, 0x5c, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x12, 0x27, 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x11, 0x2e, 0x6f, 0x64, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x07, 0x64, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6f, 0x64, - 0x63, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x22, 0x5a, 0x0a, 0x0a, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x0e, + 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x6f, 0x73, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x68, 0x6f, 0x73, 0x74, 0x22, 0x90, 0x01, 0x0a, + 0x0c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, + 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x12, + 0x14, 0x0a, 0x05, 0x72, 0x75, 0x6e, 0x6e, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, + 0x72, 0x75, 0x6e, 0x6e, 0x72, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, + 0x18, 0x05, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x12, + 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, + 0x61, 0x74, 0x68, 0x12, 0x1a, 0x0a, 0x08, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x22, + 0x8f, 0x01, 0x0a, 0x0a, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x27, + 0x0a, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, + 0x6f, 0x64, 0x63, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x52, 0x05, 0x72, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x25, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0b, 0x2e, 0x6f, 0x64, 0x63, 0x2e, 0x44, + 0x65, 0x76, 0x69, 0x63, 0x65, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x12, 0x31, + 0x0a, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6f, 0x64, 0x63, 0x2e, 0x43, 0x6f, 0x6c, 0x6c, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0b, 0x63, 0x6f, 0x6c, 0x6c, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xc3, 0x01, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x61, 0x72, 0x74, @@ -1879,80 +1968,82 @@ func file_protos_odc_proto_rawDescGZIP() []byte { } var file_protos_odc_proto_enumTypes = make([]protoimpl.EnumInfo, 2) -var file_protos_odc_proto_msgTypes = make([]protoimpl.MessageInfo, 21) +var file_protos_odc_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_protos_odc_proto_goTypes = []interface{}{ (ReplyStatus)(0), // 0: odc.ReplyStatus (SessionStatus)(0), // 1: odc.SessionStatus (*Error)(nil), // 2: odc.Error (*GeneralReply)(nil), // 3: odc.GeneralReply (*Device)(nil), // 4: odc.Device - (*StateRequest)(nil), // 5: odc.StateRequest - (*StateReply)(nil), // 6: odc.StateReply - (*PartitionStatus)(nil), // 7: odc.PartitionStatus - (*StatusReply)(nil), // 8: odc.StatusReply - (*InitializeRequest)(nil), // 9: odc.InitializeRequest - (*SubmitRequest)(nil), // 10: odc.SubmitRequest - (*ActivateRequest)(nil), // 11: odc.ActivateRequest - (*RunRequest)(nil), // 12: odc.RunRequest - (*UpdateRequest)(nil), // 13: odc.UpdateRequest - (*ShutdownRequest)(nil), // 14: odc.ShutdownRequest - (*Property)(nil), // 15: odc.Property - (*SetPropertiesRequest)(nil), // 16: odc.SetPropertiesRequest - (*ConfigureRequest)(nil), // 17: odc.ConfigureRequest - (*StartRequest)(nil), // 18: odc.StartRequest - (*StopRequest)(nil), // 19: odc.StopRequest - (*ResetRequest)(nil), // 20: odc.ResetRequest - (*TerminateRequest)(nil), // 21: odc.TerminateRequest - (*StatusRequest)(nil), // 22: odc.StatusRequest + (*Collection)(nil), // 5: odc.Collection + (*StateRequest)(nil), // 6: odc.StateRequest + (*StateReply)(nil), // 7: odc.StateReply + (*PartitionStatus)(nil), // 8: odc.PartitionStatus + (*StatusReply)(nil), // 9: odc.StatusReply + (*InitializeRequest)(nil), // 10: odc.InitializeRequest + (*SubmitRequest)(nil), // 11: odc.SubmitRequest + (*ActivateRequest)(nil), // 12: odc.ActivateRequest + (*RunRequest)(nil), // 13: odc.RunRequest + (*UpdateRequest)(nil), // 14: odc.UpdateRequest + (*ShutdownRequest)(nil), // 15: odc.ShutdownRequest + (*Property)(nil), // 16: odc.Property + (*SetPropertiesRequest)(nil), // 17: odc.SetPropertiesRequest + (*ConfigureRequest)(nil), // 18: odc.ConfigureRequest + (*StartRequest)(nil), // 19: odc.StartRequest + (*StopRequest)(nil), // 20: odc.StopRequest + (*ResetRequest)(nil), // 21: odc.ResetRequest + (*TerminateRequest)(nil), // 22: odc.TerminateRequest + (*StatusRequest)(nil), // 23: odc.StatusRequest } var file_protos_odc_proto_depIdxs = []int32{ 0, // 0: odc.GeneralReply.status:type_name -> odc.ReplyStatus 2, // 1: odc.GeneralReply.error:type_name -> odc.Error 3, // 2: odc.StateReply.reply:type_name -> odc.GeneralReply 4, // 3: odc.StateReply.devices:type_name -> odc.Device - 1, // 4: odc.PartitionStatus.status:type_name -> odc.SessionStatus - 0, // 5: odc.StatusReply.status:type_name -> odc.ReplyStatus - 2, // 6: odc.StatusReply.error:type_name -> odc.Error - 7, // 7: odc.StatusReply.partitions:type_name -> odc.PartitionStatus - 15, // 8: odc.SetPropertiesRequest.properties:type_name -> odc.Property - 5, // 9: odc.ConfigureRequest.request:type_name -> odc.StateRequest - 5, // 10: odc.StartRequest.request:type_name -> odc.StateRequest - 5, // 11: odc.StopRequest.request:type_name -> odc.StateRequest - 5, // 12: odc.ResetRequest.request:type_name -> odc.StateRequest - 5, // 13: odc.TerminateRequest.request:type_name -> odc.StateRequest - 9, // 14: odc.ODC.Initialize:input_type -> odc.InitializeRequest - 10, // 15: odc.ODC.Submit:input_type -> odc.SubmitRequest - 11, // 16: odc.ODC.Activate:input_type -> odc.ActivateRequest - 12, // 17: odc.ODC.Run:input_type -> odc.RunRequest - 13, // 18: odc.ODC.Update:input_type -> odc.UpdateRequest - 17, // 19: odc.ODC.Configure:input_type -> odc.ConfigureRequest - 16, // 20: odc.ODC.SetProperties:input_type -> odc.SetPropertiesRequest - 5, // 21: odc.ODC.GetState:input_type -> odc.StateRequest - 18, // 22: odc.ODC.Start:input_type -> odc.StartRequest - 19, // 23: odc.ODC.Stop:input_type -> odc.StopRequest - 20, // 24: odc.ODC.Reset:input_type -> odc.ResetRequest - 21, // 25: odc.ODC.Terminate:input_type -> odc.TerminateRequest - 14, // 26: odc.ODC.Shutdown:input_type -> odc.ShutdownRequest - 22, // 27: odc.ODC.Status:input_type -> odc.StatusRequest - 3, // 28: odc.ODC.Initialize:output_type -> odc.GeneralReply - 3, // 29: odc.ODC.Submit:output_type -> odc.GeneralReply - 3, // 30: odc.ODC.Activate:output_type -> odc.GeneralReply - 3, // 31: odc.ODC.Run:output_type -> odc.GeneralReply - 3, // 32: odc.ODC.Update:output_type -> odc.GeneralReply - 6, // 33: odc.ODC.Configure:output_type -> odc.StateReply - 3, // 34: odc.ODC.SetProperties:output_type -> odc.GeneralReply - 6, // 35: odc.ODC.GetState:output_type -> odc.StateReply - 6, // 36: odc.ODC.Start:output_type -> odc.StateReply - 6, // 37: odc.ODC.Stop:output_type -> odc.StateReply - 6, // 38: odc.ODC.Reset:output_type -> odc.StateReply - 6, // 39: odc.ODC.Terminate:output_type -> odc.StateReply - 3, // 40: odc.ODC.Shutdown:output_type -> odc.GeneralReply - 8, // 41: odc.ODC.Status:output_type -> odc.StatusReply - 28, // [28:42] is the sub-list for method output_type - 14, // [14:28] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 5, // 4: odc.StateReply.collections:type_name -> odc.Collection + 1, // 5: odc.PartitionStatus.status:type_name -> odc.SessionStatus + 0, // 6: odc.StatusReply.status:type_name -> odc.ReplyStatus + 2, // 7: odc.StatusReply.error:type_name -> odc.Error + 8, // 8: odc.StatusReply.partitions:type_name -> odc.PartitionStatus + 16, // 9: odc.SetPropertiesRequest.properties:type_name -> odc.Property + 6, // 10: odc.ConfigureRequest.request:type_name -> odc.StateRequest + 6, // 11: odc.StartRequest.request:type_name -> odc.StateRequest + 6, // 12: odc.StopRequest.request:type_name -> odc.StateRequest + 6, // 13: odc.ResetRequest.request:type_name -> odc.StateRequest + 6, // 14: odc.TerminateRequest.request:type_name -> odc.StateRequest + 10, // 15: odc.ODC.Initialize:input_type -> odc.InitializeRequest + 11, // 16: odc.ODC.Submit:input_type -> odc.SubmitRequest + 12, // 17: odc.ODC.Activate:input_type -> odc.ActivateRequest + 13, // 18: odc.ODC.Run:input_type -> odc.RunRequest + 14, // 19: odc.ODC.Update:input_type -> odc.UpdateRequest + 18, // 20: odc.ODC.Configure:input_type -> odc.ConfigureRequest + 17, // 21: odc.ODC.SetProperties:input_type -> odc.SetPropertiesRequest + 6, // 22: odc.ODC.GetState:input_type -> odc.StateRequest + 19, // 23: odc.ODC.Start:input_type -> odc.StartRequest + 20, // 24: odc.ODC.Stop:input_type -> odc.StopRequest + 21, // 25: odc.ODC.Reset:input_type -> odc.ResetRequest + 22, // 26: odc.ODC.Terminate:input_type -> odc.TerminateRequest + 15, // 27: odc.ODC.Shutdown:input_type -> odc.ShutdownRequest + 23, // 28: odc.ODC.Status:input_type -> odc.StatusRequest + 3, // 29: odc.ODC.Initialize:output_type -> odc.GeneralReply + 3, // 30: odc.ODC.Submit:output_type -> odc.GeneralReply + 3, // 31: odc.ODC.Activate:output_type -> odc.GeneralReply + 3, // 32: odc.ODC.Run:output_type -> odc.GeneralReply + 3, // 33: odc.ODC.Update:output_type -> odc.GeneralReply + 7, // 34: odc.ODC.Configure:output_type -> odc.StateReply + 3, // 35: odc.ODC.SetProperties:output_type -> odc.GeneralReply + 7, // 36: odc.ODC.GetState:output_type -> odc.StateReply + 7, // 37: odc.ODC.Start:output_type -> odc.StateReply + 7, // 38: odc.ODC.Stop:output_type -> odc.StateReply + 7, // 39: odc.ODC.Reset:output_type -> odc.StateReply + 7, // 40: odc.ODC.Terminate:output_type -> odc.StateReply + 3, // 41: odc.ODC.Shutdown:output_type -> odc.GeneralReply + 9, // 42: odc.ODC.Status:output_type -> odc.StatusReply + 29, // [29:43] is the sub-list for method output_type + 15, // [15:29] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_protos_odc_proto_init() } @@ -1998,7 +2089,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StateRequest); i { + switch v := v.(*Collection); i { case 0: return &v.state case 1: @@ -2010,7 +2101,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StateReply); i { + switch v := v.(*StateRequest); i { case 0: return &v.state case 1: @@ -2022,7 +2113,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*PartitionStatus); i { + switch v := v.(*StateReply); i { case 0: return &v.state case 1: @@ -2034,7 +2125,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StatusReply); i { + switch v := v.(*PartitionStatus); i { case 0: return &v.state case 1: @@ -2046,7 +2137,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*InitializeRequest); i { + switch v := v.(*StatusReply); i { case 0: return &v.state case 1: @@ -2058,7 +2149,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SubmitRequest); i { + switch v := v.(*InitializeRequest); i { case 0: return &v.state case 1: @@ -2070,7 +2161,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ActivateRequest); i { + switch v := v.(*SubmitRequest); i { case 0: return &v.state case 1: @@ -2082,7 +2173,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*RunRequest); i { + switch v := v.(*ActivateRequest); i { case 0: return &v.state case 1: @@ -2094,7 +2185,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*UpdateRequest); i { + switch v := v.(*RunRequest); i { case 0: return &v.state case 1: @@ -2106,7 +2197,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ShutdownRequest); i { + switch v := v.(*UpdateRequest); i { case 0: return &v.state case 1: @@ -2118,7 +2209,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Property); i { + switch v := v.(*ShutdownRequest); i { case 0: return &v.state case 1: @@ -2130,7 +2221,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SetPropertiesRequest); i { + switch v := v.(*Property); i { case 0: return &v.state case 1: @@ -2142,7 +2233,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ConfigureRequest); i { + switch v := v.(*SetPropertiesRequest); i { case 0: return &v.state case 1: @@ -2154,7 +2245,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StartRequest); i { + switch v := v.(*ConfigureRequest); i { case 0: return &v.state case 1: @@ -2166,7 +2257,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*StopRequest); i { + switch v := v.(*StartRequest); i { case 0: return &v.state case 1: @@ -2178,7 +2269,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ResetRequest); i { + switch v := v.(*StopRequest); i { case 0: return &v.state case 1: @@ -2190,7 +2281,7 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*TerminateRequest); i { + switch v := v.(*ResetRequest); i { case 0: return &v.state case 1: @@ -2202,6 +2293,18 @@ func file_protos_odc_proto_init() { } } file_protos_odc_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TerminateRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protos_odc_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*StatusRequest); i { case 0: return &v.state @@ -2220,7 +2323,7 @@ func file_protos_odc_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_protos_odc_proto_rawDesc, NumEnums: 2, - NumMessages: 21, + NumMessages: 22, NumExtensions: 0, NumServices: 1, }, diff --git a/core/integration/odc/protos/odc.proto b/core/integration/odc/protos/odc.proto index 9ce3c187b..6caa07a76 100644 --- a/core/integration/odc/protos/odc.proto +++ b/core/integration/odc/protos/odc.proto @@ -58,8 +58,8 @@ enum SessionStatus { message Error { string msg = 1; // Detailed error message int32 code = 2; // Error code. - // TODO: Make error codes specific for each concrete request and/or error type. - // TODO: Add link to a documented error codes. + // TODO: Make error codes specific for each concrete request and/or error type. + // TODO: Add link to a documented error codes. } // General reply to requests @@ -89,6 +89,14 @@ message Device { string rmsjobid = 7; // job IDs from the resource management system } +//Collection information +message Collection { + uint64 id = 1; // Runtime collection ID (same as in DDS) + string state = 2; // Aggregated state as string + string path = 3; // Path in the topology + string host = 5; // Host where the collection runs +} + // Device change/get state request message StateRequest { string partitionid = 1; // Partition ID from ECS @@ -102,6 +110,7 @@ message StateRequest { message StateReply { GeneralReply reply = 1; // General reply. See GeneralReply message for details. repeated Device devices = 2; // If detailed reply is requested then this field contains a list of affected devices otherwise it's empty. + repeated Collection collections = 3; // If detailed reply is requested then this field contains a list of affected collections otherwise it's empty. } // Status of each partition diff --git a/core/server.go b/core/server.go index 86bacb288..b6e50b816 100644 --- a/core/server.go +++ b/core/server.go @@ -718,10 +718,18 @@ func (m *RpcServer) DestroyEnvironment(cxt context.Context, req *pb.DestroyEnvir } if req.AllowInRunningState && env.CurrentState() == "RUNNING" { - err = env.TryTransition(environment.MakeTransition(m.state.taskman, pb.ControlEnvironmentRequest_STOP_ACTIVITY)) + err = env.TryTransition(environment.NewStopActivityTransition(m.state.taskman)) if err != nil { - log.WithField("partition", env.Id().String()). - Warn("could not perform STOP transition for environment teardown, forcing") + log.WithError(err). + WithField("partition", env.Id().String()). + Warn("could not perform STOP transition for environment teardown, going to ERROR, then forcing") + the.EventWriterWithTopic(topic.Environment).WriteEvent( + environment.NewEnvGoErrorEvent(env, "STOP_ACTIVITY during environment destruction failed"), + ) + err = env.TryTransition(environment.NewGoErrorTransition(m.state.taskman)) + if err != nil { + environment.HandleFailedGoError(err, env) + } reply, err = m.doTeardownAndCleanup(env, true /*force*/, false /*keepTasks*/) return } @@ -746,10 +754,18 @@ func (m *RpcServer) DestroyEnvironment(cxt context.Context, req *pb.DestroyEnvir // This might transition to STANDBY if needed, or do nothing if we're already there if env.CurrentState() == "CONFIGURED" { - err = env.TryTransition(environment.MakeTransition(m.state.taskman, pb.ControlEnvironmentRequest_RESET)) + err = env.TryTransition(environment.NewResetTransition(m.state.taskman)) if err != nil { - log.WithField("partition", env.Id().String()). - Warnf("cannot teardown environment in state %s, forcing", env.CurrentState()) + log.WithError(err). + WithField("partition", env.Id().String()). + Warnf("cannot teardown environment in state %s, going to ERROR, then forcing", env.CurrentState()) + the.EventWriterWithTopic(topic.Environment).WriteEvent( + environment.NewEnvGoErrorEvent(env, "RESET during environment destruction failed"), + ) + err = env.TryTransition(environment.NewGoErrorTransition(m.state.taskman)) + if err != nil { + environment.HandleFailedGoError(err, env) + } reply, err = m.doTeardownAndCleanup(env, true /*force*/, false /*keepTasks*/) return } diff --git a/docs/development.md b/docs/development.md index 20247acc7..b9c189841 100644 --- a/docs/development.md +++ b/docs/development.md @@ -24,6 +24,7 @@ Bugs go to [JIRA](https://its.cern.ch/jira/projects/OCTRL/issues). * Checkout the tag which the patch release should be based on, e.g. `git checkout v1.34.0` * Create a branch called `branch_`, e.g. `git checkout -b branch_v1.34.1`. + * Cherry-pick desired commits 3. Bump `VERSION` file, commit, push (or pull request). 4. Go to a [new GitHub release draft](https://github.com/AliceO2Group/Control/releases/new). Use "Generate release notes" to create a list of changes. Write a short summary at the top. diff --git a/docs/handbook/configuration.md b/docs/handbook/configuration.md index 798114606..6acb3370e 100644 --- a/docs/handbook/configuration.md +++ b/docs/handbook/configuration.md @@ -424,30 +424,30 @@ Depending on the specification in the task template (`command.env`, `command.arg In addition to the above, which varies depending on the configuration of the environment itself as well as on the configuration of the system as a whole, some special values are pushed by AliECS itself during `START_ACTIVITY`: - * `runNumber` + * `run_number` * `fill_info_fill_number` * `fill_info_filling_scheme` * `fill_info_beam_type` - * `fill_info_stable_beam_start_ms` - * `fill_info_stable_beam_end_ms` + * `fill_info_stable_beams_start_ms` + * `fill_info_stable_beams_end_ms` * `run_type` * `run_start_time_ms` + * `run_end_time_ms` (as an empty value) * `lhc_period` - * `fillInfoFillNumber` - * `fillInfoFillingScheme` - * `fillInfoBeamType` - * `fillInfoStableBeamStartMs` - * `fillInfoStableBeamEndMs` - * `runType` - * `runStartTimeMs` - * `lhcPeriod` * `pdp_beam_type` * `pdp_override_run_start_time` * `original_run_number` +For AliECS-controlled tasks, the same values are additionally pushed with keys in camelCase format. + The following values are pushed by AliECS during `STOP_ACTIVITY`: * `run_end_time_ms` + * `fill_info_fill_number` + * `fill_info_filling_scheme` + * `fill_info_beam_type` + * `fill_info_stable_beam_start_ms` + * `fill_info_stable_beam_end_ms` FairMQ task implementors should expect that these values are written to the FairMQ properties map right before the `RUN` and `STOP` transitions via `SetProperty` calls. @@ -469,3 +469,9 @@ limits: defaults: (...) ``` + +## EPN workflow generation + +Workflow generation for EPNs is not the responsibility of ECS, but you can find +more details [here](https://alice-pdp-operations.docs.cern.ch/workflow/#for-the-epns). + diff --git a/docs/handbook/operation_order.md b/docs/handbook/operation_order.md index cd81e77ee..7f1ef830d 100644 --- a/docs/handbook/operation_order.md +++ b/docs/handbook/operation_order.md @@ -32,11 +32,11 @@ This is the order of actions happening at a healthy start of run. - `before_START_ACTIVITY` hooks with negative weights are executed: - `trg.PrepareForRun()` at `-200` + - `lhc.UpdateFillInfo()` at `-50` - `"run_number"` is set. - `"run_start_time_ms"` is set using the current time. It is considered as the SOR and SOSOR timestamps. - `before_START_ACTIVITY` hooks with positive weights (incl. 0) are executed: - `trg.RunLoad()`, `bookkeeping.StartOfRun()` at `10` - - `bookkeeping.RetrieveFillInfo()` at `11` - `kafka.PublishStartActivityUpdate()` at `50` - `dcs.StartOfRun()`, `odc.Start()` (does not need to return now), `ccdb.RunStart()` at `100` @@ -72,6 +72,7 @@ This is the order of actions happening at a healthy end of run. ### before_STOP_ACTIVITY - `before_STOP_ACTIVITY` hooks with negative weights are executed + - `lhc.UpdateFillInfo()` at `-50` - `trg.RunStop()` at `-10` - `"run_end_time_ms"` is set using the current time. It is considered as the EOR and SOEOR timestamps. - `before_STOP_ACTIVITY` hooks with positive weights (incl. 0) are executed: diff --git a/docs/running_docker.md b/docs/running_docker.md index e5d43698a..11fbb4fbd 100644 --- a/docs/running_docker.md +++ b/docs/running_docker.md @@ -4,7 +4,7 @@ > This method is **not intended for production use**. > It serves only as a **proof of concept** for testing Docker images as part of an existing pipeline. > -> Currently, it has been tested with the `alma9-flp-node` image running the *readout* component. +> Currently, it was tested with the `alma9-flp-node` image running the *readout* component with CRU. --- @@ -45,55 +45,69 @@ For example, to run readout, modify the `_plain_command` section of [`readout.ya When running readout, we successfully used the following command inside the `alma9-flp-node` image: ```bash -sudo /usr/bin/docker run --name readout --replace \ - --user "$(id -u flp):$(id -u flp)" \ +sudo -E docker run --name readout --replace \ + --user flp -v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro \ + --privileged \ --network=host --ipc=host \ - -e O2_DETECTOR -e O2_PARTITION -e OCC_CONTROL_PORT \ - -e O2_SYSTEM -e O2_ROLE \ + -v /tmp:/tmp \ + -v /lib/modules/$(uname -r):/lib/modules/$(uname -r) \ + -e O2_DETECTOR -e O2_PARTITION -e OCC_CONTROL_PORT -e O2_SYSTEM -e O2_ROLE \ gitlab-registry.cern.ch/aliceo2group/dockerfiles/alma9-flp-node:2 \ /opt/o2/bin/o2-readout-exe ``` > 🧩 **Note** > We are not claiming that this is the most efficient way how to run this image, just that it works. +> +#### Explanation of command + +Let's explain all parts of the `docker run` command and what is their purpose. As RHEL uses Podman by default +instead of docker we are going to comment on Podman parameters, but docker should be equivalent or pretty close. + +- `sudo -E` switch to the rootful mode of Podman and pass all of the environment variables +- `docker run --name readout --replace` start container with the name readout and replace already existing container +- `--privileged` runs container with extended privileges and allows access to the devices and other resources +on host system with the same privileges as user running the container (`flp` in our case). Readout communicates +directly with CRUs and others connected via PCIe so we need to make these available inside the container. +- `--user flp -v /etc/group:/etc/group:ro -v /etc/passwd:/etc/passwd:ro` run container as flp user provide same user +and group settings as on a host machine. This is necessary as readout is using shared memory which is mapped under +flp user and needs access to [BAR](https://github.com/AliceO2Group/ReadoutCard?tab=readme-ov-file#bar-interface) +interfaces of CRU which belong to the `pda` group. We used this way of setting up user privileges and ids as there is +no guarantee that ids would match if we would hardwire user into docker image +- `--network=host` bind container's network to the host's. This allows services running outside of docker to communicate +with internals (eg. gRPC, IL, ... ). It should be changed to open just required ports. +- `--ipc=host` readout uses FairMQ which communicates through shared memory Inter-Process Communication. +As we are now running readout inside the docker with the rest of data distribution running bare metal we +need to have access to the hosting OS shared memory. This is the main requirement for running as rootful. +If we run container in rootless mode with this flag set, Podman switches into elevated privileges mode that blocks +other cli commands from the same user command until this command is finished unless running under root. +We tried to just bind `/dev/shm/` but readout failed on permission errors. +- `-v /tmp:/tmp` binds `/tmp` of host to the container for monitoring purposes. +- `-v /lib/modules/$(uname -r):/lib/modules/$(uname -r)` binds folder with host's kernel modules for the usage of PDA +used by readout itself. +- `e ...` pass environment variables required by readout to the container #### Environment Variables -To identify all required environment variables: +--- + +## Tips and Tricks + +- To identify all required environment variables: 1. Open the **ECS GUI**. 2. Go to the **Environment Details** page for the relevant task. 3. Review the variables defined there — these match those used when running the binary outside Docker. -#### Shared Memory Communication - -To enable shared memory communication between processes, add the `--ipc=host` flag when running the container. -However, doing so requires **elevated privileges**. - -While **Podman** can run without root privileges, it pauses other Podman processes for the same user. -This means commands like `podman ps -a` or starting multiple containers in parallel will not work. - -Therefore, you should run containers using the same user as the rest of the pipeline: - -```bash ---user "$(id -u flp):$(id -u flp)" -``` - -This ensures shared memory segments are created under the same user context. - ---- - -## Tips and Tricks - -* Production systems running RHEL do not install native Docker via: +- Production systems running RHEL do not install native Docker via: ```bash dnf install docker ``` - Instead, they use **Podman**, which emulates Docker’s behavior but may differ in certain aspects. + Instead, they use Podman, which emulates Docker’s behavior but may differ in certain aspects. -* To check whether ECS has started a container, run: +- To check whether ECS has started a container, run: ```bash docker ps -a @@ -107,7 +121,7 @@ This ensures shared memory segments are created under the same user context. > su - flp > ``` -* To view container logs directly from Docker: +- To view container logs directly from Docker: ```bash docker logs diff --git a/go.mod b/go.mod index 5cf831e29..1fd24d1c8 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,6 @@ replace github.com/imdario/mergo => github.com/imdario/mergo v0.3.16 replace github.com/armon/go-metrics => github.com/hashicorp/go-metrics v0.5.3 require ( - github.com/AlecAivazis/survey/v2 v2.3.7 github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible // indirect @@ -58,11 +57,10 @@ require ( github.com/spf13/viper v1.18.2 github.com/teo/logrus-prefixed-formatter v0.5.3-0.20230717095749-669d57324f0a github.com/valyala/fasttemplate v1.2.2 - github.com/xeipuuv/gojsonschema v1.2.0 github.com/xlab/treeprint v1.2.0 - golang.org/x/crypto v0.36.0 - golang.org/x/net v0.38.0 - golang.org/x/sys v0.31.0 + golang.org/x/crypto v0.45.0 + golang.org/x/net v0.47.0 + golang.org/x/sys v0.38.0 google.golang.org/grpc v1.62.1 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.3.0 google.golang.org/protobuf v1.34.1 @@ -76,6 +74,7 @@ require ( github.com/gogo/protobuf v1.3.2 github.com/hashicorp/go-multierror v1.1.1 github.com/iancoleman/strcase v0.3.0 + github.com/influxdata/line-protocol/v2 v2.2.1 github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.34.1 github.com/swaggo/http-swagger/v2 v2.0.2 @@ -89,7 +88,7 @@ require ( github.com/armon/go-metrics v0.5.3 // indirect github.com/beorn7/perks v1.0.1 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect - github.com/cloudflare/circl v1.3.7 // indirect + github.com/cloudflare/circl v1.6.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.4 // indirect github.com/cyphar/filepath-securejoin v0.2.5 // indirect github.com/emirpasic/gods v1.18.1 // indirect @@ -118,11 +117,9 @@ require ( github.com/huandu/xstrings v1.4.0 // indirect github.com/imdario/mergo v0.3.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/influxdata/line-protocol/v2 v2.2.1 // indirect github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v1.2.0 // indirect github.com/klauspost/compress v1.17.7 // indirect github.com/kylelemons/godebug v1.1.0 // indirect @@ -162,14 +159,12 @@ require ( github.com/urfave/cli/v2 v2.3.0 // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect - github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/mod v0.23.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/term v0.30.0 // indirect - golang.org/x/text v0.23.0 // indirect - golang.org/x/tools v0.30.0 // indirect + golang.org/x/mod v0.29.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect + golang.org/x/tools v0.38.0 // indirect google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240123012728-ef4313101c80 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect diff --git a/go.sum b/go.sum index e63fcbbfc..a23533be8 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= -github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= -github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= @@ -15,8 +13,6 @@ github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuN github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= -github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= github.com/ProtonMail/go-crypto v1.1.3 h1:nRBOetoydLeUb4nHajyO2bKqMLfWQ/ZPwkXqXxPxCFk= github.com/ProtonMail/go-crypto v1.1.3/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -42,15 +38,13 @@ github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= -github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= -github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= +github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= +github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/cpuguy83/go-md2man/v2 v2.0.4 h1:wfIWP927BUkWJb2NmU/kNDYIBTh/ziUX91+lVfRxZq4= github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= -github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/cyphar/filepath-securejoin v0.2.5 h1:6iR5tXJ/e6tJZzzdMc1km3Sa7RRIVBKAK32O2s7AYfo= github.com/cyphar/filepath-securejoin v0.2.5/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -59,8 +53,6 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ= github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI= -github.com/dmarkham/enumer v1.5.8 h1:fIF11F9l5jyD++YYvxcSH5WgHfeaSGPaN/T4kOQ4qEM= -github.com/dmarkham/enumer v1.5.8/go.mod h1:d10o8R3t/gROm2p3BXqTkMt2+HMuxEmWCXzorAruYak= github.com/dmarkham/enumer v1.5.11 h1:quorLCaEfzjJ23Pf7PB9lyyaHseh91YfTM/sAD/4Mbo= github.com/dmarkham/enumer v1.5.11/go.mod h1:yixql+kDDQRYqcuBM2n9Vlt7NoT9ixgXhaXry8vmRg8= github.com/elazarl/goproxy v1.2.1 h1:njjgvO6cRG9rIqN2ebkqy6cQz2Njkx7Fsfv/zIZqgug= @@ -195,8 +187,6 @@ github.com/hashicorp/memberlist v0.5.0 h1:EtYPN8DpAURiapus508I4n9CzHs2W+8NZGbmmR github.com/hashicorp/memberlist v0.5.0/go.mod h1:yvyXLpo0QaGE59Y7hDTsTzDD25JYBZ4mHgHUZ8lrOI0= github.com/hashicorp/serf v0.10.1 h1:Z1H2J60yRKvfDYAOZLd2MU0ND4AH/WDz7xYHDWQsIPY= github.com/hashicorp/serf v0.10.1/go.mod h1:yL2t6BqATOLGc5HF7qbFkTfXoPIY0WZdWHfEvMqbG+4= -github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= -github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= github.com/huandu/xstrings v1.4.0 h1:D17IlohoQq4UcpqD7fDk80P7l+lwAmlFaBHgOipl2FU= github.com/huandu/xstrings v1.4.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -206,6 +196,7 @@ github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+h github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/line-protocol-corpus v0.0.0-20210519164801-ca6fa5da0184/go.mod h1:03nmhxzZ7Xk2pdG+lmMd7mHDfeVOYFyhOgwO61qWU98= +github.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937 h1:MHJNQ+p99hFATQm6ORoLmpUCF7ovjwEFshs/NHzAbig= github.com/influxdata/line-protocol-corpus v0.0.0-20210922080147-aa28ccfb8937/go.mod h1:BKR9c0uHSmRgM/se9JhFHtTT7JTO67X23MtKMHtZcpo= github.com/influxdata/line-protocol/v2 v2.0.0-20210312151457-c52fdecb625a/go.mod h1:6+9Xt5Sq1rWx+glMgxhcg2c0DUaehK+5TDcPZ76GypY= github.com/influxdata/line-protocol/v2 v2.1.0/go.mod h1:QKw43hdUBg3GTk2iC3iyCxksNj7PX9aUSeYOYE/ceHY= @@ -224,8 +215,6 @@ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQ github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k= github.com/k0kubun/pp v3.0.1+incompatible h1:3tqvf7QgUnZ5tXO6pNAZlrvHgl6DvifjDrd9g2S9Z40= github.com/k0kubun/pp v3.0.1+incompatible/go.mod h1:GWse8YhT0p8pT4ir3ZgBbfZild3tgzSScAn6HmfYukg= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= @@ -255,7 +244,6 @@ github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3v github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= @@ -276,7 +264,6 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mesos/mesos-go v0.0.11 h1:jMp9+W3zLu46g8EuP2su2Sjj7ipBh4N/g65c0kzGl/8= github.com/mesos/mesos-go v0.0.11/go.mod h1:kPYCMQ9gsOXVAle1OsoY4I1+9kPu8GHkf88aV59fDr4= -github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI= github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso= @@ -416,7 +403,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.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 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.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= @@ -449,13 +435,6 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb h1:zGWFAtiMcyryUHoUjUJX0/lt1H2+i2Ka2n+D3DImSNo= -github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= -github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= -github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= -github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ= github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -471,18 +450,16 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34= -golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc= +golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= +golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8= -golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM= -golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= +golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -497,8 +474,8 @@ golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= +golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= 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= @@ -507,8 +484,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -542,29 +519,28 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= -golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -573,10 +549,8 @@ golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= -golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg= -golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI= -golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY= -golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY= +golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= +golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=