Skip to content
Snippets Groups Projects
Select Git revision
  • main default protected
  • 0.2.2
  • 0.2.1
  • 0.2.0
  • 0.1.1
  • ska-ser-k8s-spookd-0.1.0
6 results

config.go

config.go 2.36 KiB
package main

import (
	"fmt"
	"github.com/google/uuid"
	"gitlab.com/ska-telescope/ska-ser-k8s-spookd/pkg/set"
	"golang.org/x/exp/maps"
	"golang.org/x/exp/slices"
	k8s "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/validation"
	"reflect"
	"strings"
)

var uuidNS = uuid.MustParse("f56d1c80-a44d-4937-9bef-41f2acf75e9f")

func GenerateDevices(hostname string, deviceConfig DeviceConfig) ([]Device, error) {
	// these are for validation
	devsById := make(map[uuid.UUID]Device)
	hostsByDevId := make(map[uuid.UUID]set.Set[string])

	var devs []Device

	for _, w := range deviceConfig.DeviceMapping {
		for _, d := range w.Devices {

			if !IsExtendedResourceName(d.ResourceName) {
				return nil, fmt.Errorf("device config includes invalid resource name \"%s\"", d.ResourceName)
			}

			if d.UUID == uuid.Nil {
				d.UUID = uuid.NewSHA1(uuidNS, []byte(string(d.ResourceName)+"#"+d.InstanceID))
			}

			// devices may be declared twice, but only if they're specified identically
			if val, ok := devsById[d.UUID]; ok {
				if !reflect.DeepEqual(d, val) {
					return nil, fmt.Errorf("device %s redeclared with different env", d)
				}
			} else {
				devsById[d.UUID] = d
			}

			// TODO make this obsolete by coordinating state between nodes
			// devices can only be assigned to a single node
			hostsByDevId[d.UUID] = set.FromSlice(w.Hosts).Union(hostsByDevId[d.UUID])
			if len(hostsByDevId[d.UUID]) > 1 {
				return nil, fmt.Errorf("device %s allocated to more than one host: %v", d, maps.Keys(hostsByDevId[d.UUID]))
			}

			if slices.Contains(w.Hosts, hostname) {
				devs = append(devs, d)
			}
		}
	}

	return devs, nil
}

// these two cribbed from https://github.com/kubernetes/kubernetes/blob/v1.23.6/pkg/apis/core/helper/helpers.go#L174
// because go get failed

func IsNativeResource(name k8s.ResourceName) bool {
	return !strings.Contains(string(name), "/") ||
		strings.Contains(string(name), k8s.ResourceDefaultNamespacePrefix)
}

func IsExtendedResourceName(name k8s.ResourceName) bool {
	if IsNativeResource(name) || strings.HasPrefix(string(name), k8s.DefaultResourceRequestsPrefix) {
		return false
	}
	// Ensure it satisfies the rules in IsQualifiedName() after converted into quota resource name
	nameForQuota := fmt.Sprintf("%s%s", k8s.DefaultResourceRequestsPrefix, string(name))
	if errs := validation.IsQualifiedName(string(nameForQuota)); len(errs) != 0 {
		return false
	}
	return true
}