mirror of
https://github.com/absmach/magistrala.git
synced 2026-06-23 04:10:28 +00:00
683809dc6b
Property Based Tests / api-test (push) Has been cancelled
Continuous Delivery / lint-and-build (push) Has been cancelled
Deploy GitHub Pages / swagger-ui (push) Has been cancelled
CI Pipeline / Lint Proto (push) Has been cancelled
Continuous Delivery / Build and Push Docker Images (push) Has been cancelled
CI Pipeline / lint-and-build (push) Has been cancelled
CI Pipeline / Test ${{ matrix.module }} (push) Has been cancelled
CI Pipeline / Upload Coverage (push) Has been cancelled
CI Pipeline / Detect Changes (push) Has been cancelled
Signed-off-by: nyagamunene <stevenyaga2014@gmail.com>
110 lines
2.9 KiB
Go
110 lines
2.9 KiB
Go
// Copyright (c) Abstract Machines
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package bootstrap
|
|
|
|
import (
|
|
"fmt"
|
|
"text/template"
|
|
|
|
"github.com/absmach/magistrala/pkg/errors"
|
|
)
|
|
|
|
var errBindingSlot = errors.New("invalid binding slot")
|
|
|
|
func validateProfileBindingSlots(profile Profile) error {
|
|
seen := make(map[string]struct{}, len(profile.BindingSlots))
|
|
for _, slot := range profile.BindingSlots {
|
|
if slot.Name == "" {
|
|
return fmt.Errorf("%w: slot name is required", errBindingSlot)
|
|
}
|
|
if slot.Type == "" {
|
|
return fmt.Errorf("%w: slot %q type is required", errBindingSlot, slot.Name)
|
|
}
|
|
if _, ok := seen[slot.Name]; ok {
|
|
return fmt.Errorf("%w: duplicate slot %q", errBindingSlot, slot.Name)
|
|
}
|
|
seen[slot.Name] = struct{}{}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateRequestedBindings(profile Profile, requested []BindingRequest) error {
|
|
if len(profile.BindingSlots) == 0 {
|
|
return nil
|
|
}
|
|
|
|
slots := make(map[string]BindingSlot, len(profile.BindingSlots))
|
|
for _, slot := range profile.BindingSlots {
|
|
slots[slot.Name] = slot
|
|
}
|
|
|
|
seen := make(map[string]struct{}, len(requested))
|
|
for _, binding := range requested {
|
|
slot, ok := slots[binding.Slot]
|
|
if !ok {
|
|
return fmt.Errorf("%w: unknown slot %q", errBindingSlot, binding.Slot)
|
|
}
|
|
if slot.Type != binding.Type {
|
|
return fmt.Errorf("%w: slot %q expects %q, got %q", errBindingSlot, binding.Slot, slot.Type, binding.Type)
|
|
}
|
|
if _, ok := seen[binding.Slot]; ok {
|
|
return fmt.Errorf("%w: duplicate binding for slot %q", errBindingSlot, binding.Slot)
|
|
}
|
|
seen[binding.Slot] = struct{}{}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func validateRequiredBindings(profile Profile, bindings []BindingSnapshot) error {
|
|
if len(profile.BindingSlots) == 0 {
|
|
return nil
|
|
}
|
|
|
|
bound := make(map[string]BindingSnapshot, len(bindings))
|
|
for _, binding := range bindings {
|
|
bound[binding.Slot] = binding
|
|
}
|
|
|
|
for _, slot := range profile.BindingSlots {
|
|
binding, ok := bound[slot.Name]
|
|
if !slot.Required && !ok {
|
|
continue
|
|
}
|
|
if slot.Required && !ok {
|
|
return fmt.Errorf("%w: required slot %q is not bound", errBindingSlot, slot.Name)
|
|
}
|
|
if binding.Type != slot.Type {
|
|
return fmt.Errorf("%w: slot %q expects %q, got %q", errBindingSlot, slot.Name, slot.Type, binding.Type)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func mergeBindingSnapshots(existing, updated []BindingSnapshot) []BindingSnapshot {
|
|
merged := make(map[string]BindingSnapshot, len(existing)+len(updated))
|
|
for _, binding := range existing {
|
|
merged[binding.Slot] = binding
|
|
}
|
|
for _, binding := range updated {
|
|
merged[binding.Slot] = binding
|
|
}
|
|
|
|
bindings := make([]BindingSnapshot, 0, len(merged))
|
|
for _, binding := range merged {
|
|
bindings = append(bindings, binding)
|
|
}
|
|
return bindings
|
|
}
|
|
|
|
func validateProfileTemplate(p Profile) error {
|
|
if p.ContentTemplate == "" || p.ContentFormat == ContentFormatRaw {
|
|
return nil
|
|
}
|
|
_, err := template.New("bootstrap").Funcs(allowlistedFuncs()).Parse(p.ContentTemplate)
|
|
if err != nil {
|
|
return errors.Wrap(ErrRenderFailed, err)
|
|
}
|
|
return nil
|
|
}
|