 9bdcbe0447
			
		
	
	9bdcbe0447
	
	
	
		
			
			Major integrations and fixes: - Added BACKBEAT SDK integration for P2P operation timing - Implemented beat-aware status tracking for distributed operations - Added Docker secrets support for secure license management - Resolved KACHING license validation via HTTPS/TLS - Updated docker-compose configuration for clean stack deployment - Disabled rollback policies to prevent deployment failures - Added license credential storage (CHORUS-DEV-MULTI-001) Technical improvements: - BACKBEAT P2P operation tracking with phase management - Enhanced configuration system with file-based secrets - Improved error handling for license validation - Clean separation of KACHING and CHORUS deployment stacks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			165 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			165 lines
		
	
	
		
			4.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // Copyright 2018, OpenCensus Authors
 | |
| //
 | |
| // Licensed under the Apache License, Version 2.0 (the "License");
 | |
| // you may not use this file except in compliance with the License.
 | |
| // You may obtain a copy of the License at
 | |
| //
 | |
| //     http://www.apache.org/licenses/LICENSE-2.0
 | |
| //
 | |
| // Unless required by applicable law or agreed to in writing, software
 | |
| // distributed under the License is distributed on an "AS IS" BASIS,
 | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| // See the License for the specific language governing permissions and
 | |
| // limitations under the License.
 | |
| 
 | |
| // Package resource provides functionality for resource, which capture
 | |
| // identifying information about the entities for which signals are exported.
 | |
| package resource
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"regexp"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| )
 | |
| 
 | |
| // Environment variables used by FromEnv to decode a resource.
 | |
| const (
 | |
| 	EnvVarType   = "OC_RESOURCE_TYPE"
 | |
| 	EnvVarLabels = "OC_RESOURCE_LABELS"
 | |
| )
 | |
| 
 | |
| // Resource describes an entity about which identifying information and metadata is exposed.
 | |
| // For example, a type "k8s.io/container" may hold labels describing the pod name and namespace.
 | |
| type Resource struct {
 | |
| 	Type   string
 | |
| 	Labels map[string]string
 | |
| }
 | |
| 
 | |
| // EncodeLabels encodes a labels map to a string as provided via the OC_RESOURCE_LABELS environment variable.
 | |
| func EncodeLabels(labels map[string]string) string {
 | |
| 	sortedKeys := make([]string, 0, len(labels))
 | |
| 	for k := range labels {
 | |
| 		sortedKeys = append(sortedKeys, k)
 | |
| 	}
 | |
| 	sort.Strings(sortedKeys)
 | |
| 
 | |
| 	s := ""
 | |
| 	for i, k := range sortedKeys {
 | |
| 		if i > 0 {
 | |
| 			s += ","
 | |
| 		}
 | |
| 		s += k + "=" + strconv.Quote(labels[k])
 | |
| 	}
 | |
| 	return s
 | |
| }
 | |
| 
 | |
| var labelRegex = regexp.MustCompile(`^\s*([[:ascii:]]{1,256}?)=("[[:ascii:]]{0,256}?")\s*,`)
 | |
| 
 | |
| // DecodeLabels decodes a serialized label map as used in the OC_RESOURCE_LABELS variable.
 | |
| // A list of labels of the form `<key1>="<value1>",<key2>="<value2>",...` is accepted.
 | |
| // Domain names and paths are accepted as label keys.
 | |
| // Most users will want to use FromEnv instead.
 | |
| func DecodeLabels(s string) (map[string]string, error) {
 | |
| 	m := map[string]string{}
 | |
| 	// Ensure a trailing comma, which allows us to keep the regex simpler
 | |
| 	s = strings.TrimRight(strings.TrimSpace(s), ",") + ","
 | |
| 
 | |
| 	for len(s) > 0 {
 | |
| 		match := labelRegex.FindStringSubmatch(s)
 | |
| 		if len(match) == 0 {
 | |
| 			return nil, fmt.Errorf("invalid label formatting, remainder: %s", s)
 | |
| 		}
 | |
| 		v := match[2]
 | |
| 		if v == "" {
 | |
| 			v = match[3]
 | |
| 		} else {
 | |
| 			var err error
 | |
| 			if v, err = strconv.Unquote(v); err != nil {
 | |
| 				return nil, fmt.Errorf("invalid label formatting, remainder: %s, err: %s", s, err)
 | |
| 			}
 | |
| 		}
 | |
| 		m[match[1]] = v
 | |
| 
 | |
| 		s = s[len(match[0]):]
 | |
| 	}
 | |
| 	return m, nil
 | |
| }
 | |
| 
 | |
| // FromEnv is a detector that loads resource information from the OC_RESOURCE_TYPE
 | |
| // and OC_RESOURCE_labelS environment variables.
 | |
| func FromEnv(context.Context) (*Resource, error) {
 | |
| 	res := &Resource{
 | |
| 		Type: strings.TrimSpace(os.Getenv(EnvVarType)),
 | |
| 	}
 | |
| 	labels := strings.TrimSpace(os.Getenv(EnvVarLabels))
 | |
| 	if labels == "" {
 | |
| 		return res, nil
 | |
| 	}
 | |
| 	var err error
 | |
| 	if res.Labels, err = DecodeLabels(labels); err != nil {
 | |
| 		return nil, err
 | |
| 	}
 | |
| 	return res, nil
 | |
| }
 | |
| 
 | |
| var _ Detector = FromEnv
 | |
| 
 | |
| // merge resource information from b into a. In case of a collision, a takes precedence.
 | |
| func merge(a, b *Resource) *Resource {
 | |
| 	if a == nil {
 | |
| 		return b
 | |
| 	}
 | |
| 	if b == nil {
 | |
| 		return a
 | |
| 	}
 | |
| 	res := &Resource{
 | |
| 		Type:   a.Type,
 | |
| 		Labels: map[string]string{},
 | |
| 	}
 | |
| 	if res.Type == "" {
 | |
| 		res.Type = b.Type
 | |
| 	}
 | |
| 	for k, v := range b.Labels {
 | |
| 		res.Labels[k] = v
 | |
| 	}
 | |
| 	// Labels from resource a overwrite labels from resource b.
 | |
| 	for k, v := range a.Labels {
 | |
| 		res.Labels[k] = v
 | |
| 	}
 | |
| 	return res
 | |
| }
 | |
| 
 | |
| // Detector attempts to detect resource information.
 | |
| // If the detector cannot find resource information, the returned resource is nil but no
 | |
| // error is returned.
 | |
| // An error is only returned on unexpected failures.
 | |
| type Detector func(context.Context) (*Resource, error)
 | |
| 
 | |
| // MultiDetector returns a Detector that calls all input detectors in order and
 | |
| // merges each result with the previous one. In case a type of label key is already set,
 | |
| // the first set value is takes precedence.
 | |
| // It returns on the first error that a sub-detector encounters.
 | |
| func MultiDetector(detectors ...Detector) Detector {
 | |
| 	return func(ctx context.Context) (*Resource, error) {
 | |
| 		return detectAll(ctx, detectors...)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| // detectall calls all input detectors sequentially an merges each result with the previous one.
 | |
| // It returns on the first error that a sub-detector encounters.
 | |
| func detectAll(ctx context.Context, detectors ...Detector) (*Resource, error) {
 | |
| 	var res *Resource
 | |
| 	for _, d := range detectors {
 | |
| 		r, err := d(ctx)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 		res = merge(res, r)
 | |
| 	}
 | |
| 	return res, nil
 | |
| }
 |