Skip to content

Commit

Permalink
[core] support query parameters in apricot URIs in JIT
Browse files Browse the repository at this point in the history
  • Loading branch information
knopers8 authored and teo committed Mar 19, 2024
1 parent 7de4a9b commit 9a10964
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 6 deletions.
49 changes: 47 additions & 2 deletions configuration/componentcfg/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ package componentcfg

import (
"errors"
"net/url"
"regexp"
"strconv"
"strings"

apricotpb "github.com/AliceO2Group/Control/apricot/protos"
Expand All @@ -42,8 +44,9 @@ var (
// component /RUNTYPE /rolename /entry @timestamp
inputFullRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+)(\/[A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}(\@[0-9]+)?$`)
// component /RUNTYPE /rolename
inputEntriesRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+)(\/[A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}$`)
E_BAD_KEY = errors.New("bad component configuration key format")
inputEntriesRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+)(\/[A-Z0-9-_]+){1}(\/[a-z-A-Z0-9-_]+){1}$`)
inputParametersRegex = regexp.MustCompile(`^([a-zA-Z0-9-_]+=[a-zA-Z0-9-_,]+)(&[a-zA-Z0-9-_]+=[a-zA-Z0-9-_,]+)*$`)
E_BAD_KEY = errors.New("bad component configuration key format")
)

func IsStringValidQueryPathWithOptionalTimestamp(input string) bool {
Expand All @@ -52,6 +55,9 @@ func IsStringValidQueryPathWithOptionalTimestamp(input string) bool {
func IsStringValidEntriesQueryPath(input string) bool {
return inputEntriesRegex.MatchString(input)
}
func IsStringValidQueryParameters(input string) bool {
return inputParametersRegex.MatchString(input)
}

type EntriesQuery struct {
Component string
Expand Down Expand Up @@ -192,3 +198,42 @@ func (p *Query) AbsoluteRaw() string {
func (p *Query) AbsoluteWithoutTimestamp() string {
return ConfigComponentsPath + p.WithoutTimestamp()
}

type QueryParameters struct {
ProcessTemplates bool
VarStack map[string]string
}

func NewQueryParameters(parameters string) (p *QueryParameters, err error) {
p = &QueryParameters{
ProcessTemplates: false,
VarStack: make(map[string]string),
}
parameters = strings.TrimSpace(parameters)

if !IsStringValidQueryParameters(parameters) {
err = E_BAD_KEY
return
}
keyValues, err := url.ParseQuery(parameters)
if err != nil {
return
}
// in our case, we support just one value per key, thus we map the returned keyValues accordingly
for key, values := range keyValues {
if len(values) != 1 {
err = E_BAD_KEY
return
}
if key == "process" {
p.ProcessTemplates, err = strconv.ParseBool(values[0])
if err != nil {
return
}
} else {
p.VarStack[key] = values[0]
}
}

return p, nil
}
51 changes: 51 additions & 0 deletions configuration/componentcfg/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,57 @@ var _ = Describe("query", func() {
})
})
})

Describe("Component configuration query parameters", func() {
var (
q *componentcfg.QueryParameters
err error
)

When("creating new valid query parameters", func() {
BeforeEach(func() {
q, err = componentcfg.NewQueryParameters("process=true&a=aaa&b=123&C_D3=C,C,C")
})
It("should be parsed without reporting errors", func() {
Expect(err).To(BeNil())
})
It("should have parsed the process variable correctly", func() {
Expect(q.ProcessTemplates).To(BeTrue())
})
It("should have parsed the var stack correctly", func() {
Expect(q.VarStack["a"]).To(Equal("aaa"))
Expect(q.VarStack["b"]).To(Equal("123"))
Expect(q.VarStack["C_D3"]).To(Equal("C,C,C"))
})
})

Describe("dealing with incorrectly formatted query parameters", func() {
When("query parameters are empty", func() {
BeforeEach(func() {
q, err = componentcfg.NewQueryParameters("")
})
It("should return an error", func() {
Expect(err).To(MatchError(componentcfg.E_BAD_KEY))
})
})
When("a key has empty value", func() {
BeforeEach(func() {
q, err = componentcfg.NewQueryParameters("process=")
})
It("should return an error", func() {
Expect(err).To(MatchError(componentcfg.E_BAD_KEY))
})
})
When("there are two identical keys", func() {
BeforeEach(func() {
q, err = componentcfg.NewQueryParameters("a=33&a=34")
})
It("should return an error", func() {
Expect(err).To(MatchError(componentcfg.E_BAD_KEY))
})
})
})
})
})

func TestQuery(t *testing.T) {
Expand Down
23 changes: 19 additions & 4 deletions configuration/template/dplutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func jitDplGenerate(confSvc ConfigurationService, varStack map[string]string, wo
var payloads []string

// Match any consul URL
re := regexp.MustCompile(`(consul-json|apricot)://[^ |\n]*`)
re := regexp.MustCompile(`(consul-json|apricot)://[^ |"\n]*`)
matches := re.FindAllStringSubmatch(dplCommand, nMaxExpectedQcPayloads)
matches = append(matches)

Expand All @@ -57,13 +57,28 @@ func jitDplGenerate(confSvc ConfigurationService, varStack map[string]string, wo
keyRe := regexp.MustCompile(`components/[^']*`)
consulKeyMatch := keyRe.FindAllStringSubmatch(match[0], 1)
consulKey := strings.SplitAfter(consulKeyMatch[0][0], "components/")
// split between the query and its parameters if there are any
consulKeyTokens := strings.Split(consulKey[1], "?")

// And query Apricot for the configuration payload
newQ, err := componentcfg.NewQuery(consulKey[1])
// Query Apricot for the configuration payload
query, err := componentcfg.NewQuery(consulKeyTokens[0])
if err != nil {
return "", fmt.Errorf("JIT could not create a query out of path '%s'. error: %w", consulKey[1], err)
}
payload, err := confSvc.GetComponentConfiguration(newQ)
// parse parameters if they are present
queryParams := &componentcfg.QueryParameters{ProcessTemplates: false, VarStack: nil}
if len(consulKeyTokens) == 2 {
queryParams, err = componentcfg.NewQueryParameters(consulKeyTokens[1])
if err != nil {
return "", fmt.Errorf("JIT could not parse query parameters of path '%s', error: %w", consulKey[1], err)
}
}
var payload string
if queryParams.ProcessTemplates {
payload, err = confSvc.GetAndProcessComponentConfiguration(query, queryParams.VarStack)
} else {
payload, err = confSvc.GetComponentConfiguration(query)
}

if err != nil {
return "", fmt.Errorf("JIT failed trying to query QC payload '%s', error: %w", match, err)
Expand Down

0 comments on commit 9a10964

Please sign in to comment.