feat: agent specifications query and get endpoints
arcad/emissary/pipeline/head This commit looks good
Details
arcad/emissary/pipeline/head This commit looks good
Details
This commit is contained in:
parent
cec5c783fe
commit
85ccf2e1df
|
@ -45,17 +45,29 @@ func (c *Controller) reconcileAgent(ctx context.Context, client *client.Client,
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
specs, err := client.GetAgentSpecs(ctx, agent.ID)
|
specHeaders, err := client.QueryAgentSpecs(ctx, agent.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = errors.WithStack(err)
|
err = errors.WithStack(err)
|
||||||
logger.Error(ctx, "could not retrieve agent specs", logger.CapturedE(err))
|
logger.Error(ctx, "could not query agent specs", logger.CapturedE(err))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
state.ClearSpecs()
|
state.ClearSpecs()
|
||||||
|
|
||||||
for _, spec := range specs {
|
for _, sh := range specHeaders {
|
||||||
|
spec, err := client.GetAgentSpec(ctx, agent.ID, sh.DefinitionName, sh.DefinitionVersion)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(
|
||||||
|
ctx, "could not retrieve agent spec",
|
||||||
|
logger.F("specName", sh.DefinitionName),
|
||||||
|
logger.F("specVersion", sh.DefinitionVersion),
|
||||||
|
logger.CapturedE(errors.WithStack(err)),
|
||||||
|
)
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
state.SetSpec(spec)
|
state.SetSpec(spec)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,18 @@ import (
|
||||||
func GetCommand() *cli.Command {
|
func GetCommand() *cli.Command {
|
||||||
return &cli.Command{
|
return &cli.Command{
|
||||||
Name: "get",
|
Name: "get",
|
||||||
Usage: "Get agent specifications",
|
Usage: "Get agent specification",
|
||||||
Flags: agentFlag.WithAgentFlags(),
|
Flags: agentFlag.WithAgentFlags(
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "spec-name",
|
||||||
|
Usage: "use `NAME` as specification's name",
|
||||||
|
},
|
||||||
|
&cli.StringFlag{
|
||||||
|
Name: "spec-version",
|
||||||
|
Usage: "use `VERSION` as specification's version",
|
||||||
|
Value: "0.0.0",
|
||||||
|
},
|
||||||
|
),
|
||||||
Action: func(ctx *cli.Context) error {
|
Action: func(ctx *cli.Context) error {
|
||||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||||
agentID, err := agentFlag.AssertAgentID(ctx)
|
agentID, err := agentFlag.AssertAgentID(ctx)
|
||||||
|
@ -29,16 +39,26 @@ func GetCommand() *cli.Command {
|
||||||
return errors.WithStack(apierr.Wrap(err))
|
return errors.WithStack(apierr.Wrap(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
specDefName, err := assertSpecDefName(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
specDefVersion, err := assertSpecDefVersion(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||||
|
|
||||||
specs, err := client.GetAgentSpecs(ctx.Context, agentID)
|
spec, err := client.GetAgentSpec(ctx.Context, agentID, specDefName, specDefVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(apierr.Wrap(err))
|
return errors.WithStack(apierr.Wrap(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
hints := specHints(baseFlags.OutputMode)
|
hints := specHints(baseFlags.OutputMode)
|
||||||
|
|
||||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, clientFlag.AsAnySlice(specs)...); err != nil {
|
if err := format.Write(baseFlags.Format, os.Stdout, hints, spec); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,28 @@ import (
|
||||||
"gitlab.com/wpetit/goweb/cli/format/table"
|
"gitlab.com/wpetit/goweb/cli/format/table"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func specHeaderHints(outputMode format.OutputMode) format.Hints {
|
||||||
|
return format.Hints{
|
||||||
|
OutputMode: outputMode,
|
||||||
|
Props: []format.Prop{
|
||||||
|
format.NewProp("ID", "ID"),
|
||||||
|
format.NewProp("DefinitionName", "Def. Name"),
|
||||||
|
format.NewProp("DefinitionVersion", "Def. Version"),
|
||||||
|
format.NewProp("Revision", "Revision"),
|
||||||
|
format.NewProp("CreatedAt", "CreatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||||
|
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func specHints(outputMode format.OutputMode) format.Hints {
|
func specHints(outputMode format.OutputMode) format.Hints {
|
||||||
return format.Hints{
|
return format.Hints{
|
||||||
OutputMode: outputMode,
|
OutputMode: outputMode,
|
||||||
Props: []format.Prop{
|
Props: []format.Prop{
|
||||||
format.NewProp("ID", "ID"),
|
format.NewProp("ID", "ID"),
|
||||||
format.NewProp("Revision", "Revision"),
|
|
||||||
format.NewProp("DefinitionName", "Def. Name"),
|
format.NewProp("DefinitionName", "Def. Name"),
|
||||||
format.NewProp("DefinitionVersion", "Def. Version"),
|
format.NewProp("DefinitionVersion", "Def. Version"),
|
||||||
|
format.NewProp("Revision", "Revision"),
|
||||||
format.NewProp("Data", "Data"),
|
format.NewProp("Data", "Data"),
|
||||||
format.NewProp("CreatedAt", "CreatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
format.NewProp("CreatedAt", "CreatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||||
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
package spec
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
|
||||||
|
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||||
|
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
"gitlab.com/wpetit/goweb/cli/format"
|
||||||
|
)
|
||||||
|
|
||||||
|
func QueryCommand() *cli.Command {
|
||||||
|
return &cli.Command{
|
||||||
|
Name: "query",
|
||||||
|
Usage: "Query agent specifications",
|
||||||
|
Flags: agentFlag.WithAgentFlags(),
|
||||||
|
Action: func(ctx *cli.Context) error {
|
||||||
|
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||||
|
agentID, err := agentFlag.AssertAgentID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
token, err := clientFlag.GetToken(baseFlags)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(apierr.Wrap(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||||
|
|
||||||
|
specs, err := client.QueryAgentSpecs(ctx.Context, agentID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(apierr.Wrap(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
hints := specHeaderHints(baseFlags.OutputMode)
|
||||||
|
|
||||||
|
if err := format.Write(baseFlags.Format, os.Stdout, hints, clientFlag.AsAnySlice(specs)...); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ func Root() *cli.Command {
|
||||||
Usage: "Specifications related commands",
|
Usage: "Specifications related commands",
|
||||||
Subcommands: []*cli.Command{
|
Subcommands: []*cli.Command{
|
||||||
GetCommand(),
|
GetCommand(),
|
||||||
|
QueryCommand(),
|
||||||
UpdateCommand(),
|
UpdateCommand(),
|
||||||
DeleteCommand(),
|
DeleteCommand(),
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,7 @@ import (
|
||||||
jsonpatch "github.com/evanphx/json-patch/v5"
|
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"gitlab.com/wpetit/goweb/api"
|
||||||
"gitlab.com/wpetit/goweb/cli/format"
|
"gitlab.com/wpetit/goweb/cli/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -73,21 +74,12 @@ func UpdateCommand() *cli.Command {
|
||||||
|
|
||||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||||
|
|
||||||
specs, err := client.GetAgentSpecs(ctx.Context, agentID)
|
existingSpec, err := client.GetAgentSpec(ctx.Context, agentID, specDefName, specDefVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.WithStack(apierr.Wrap(err))
|
var apiErr api.Error
|
||||||
}
|
if !errors.As(err, &apiErr) || apiErr.Code != api.ErrCodeNotFound {
|
||||||
|
return errors.WithStack(apierr.Wrap(err))
|
||||||
var existingSpec spec.Spec
|
|
||||||
|
|
||||||
for _, s := range specs {
|
|
||||||
if s.SpecDefinitionName() != specDefName || s.SpecDefinitionVersion() != specDefVersion {
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
existingSpec = s
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
revision := 0
|
revision := 0
|
||||||
|
|
|
@ -19,7 +19,8 @@ type AgentRepository interface {
|
||||||
Delete(ctx context.Context, id AgentID) error
|
Delete(ctx context.Context, id AgentID) error
|
||||||
|
|
||||||
UpdateSpec(ctx context.Context, id AgentID, name string, version string, revision int, data map[string]any) (*Spec, error)
|
UpdateSpec(ctx context.Context, id AgentID, name string, version string, revision int, data map[string]any) (*Spec, error)
|
||||||
GetSpecs(ctx context.Context, id AgentID) ([]*Spec, error)
|
QuerySpecs(ctx context.Context, id AgentID) ([]*SpecHeader, error)
|
||||||
|
GetSpec(ctx context.Context, id AgentID, name string, version string) (*Spec, error)
|
||||||
DeleteSpec(ctx context.Context, id AgentID, name string, version string) error
|
DeleteSpec(ctx context.Context, id AgentID, name string, version string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,16 +6,21 @@ import (
|
||||||
|
|
||||||
type SpecID int64
|
type SpecID int64
|
||||||
|
|
||||||
|
type SpecHeader struct {
|
||||||
|
ID SpecID `json:"id"`
|
||||||
|
DefinitionName string `json:"name"`
|
||||||
|
DefinitionVersion string `json:"version"`
|
||||||
|
Revision int `json:"revision"`
|
||||||
|
CreatedAt time.Time `json:"createdAt"`
|
||||||
|
UpdatedAt time.Time `json:"updatedAt"`
|
||||||
|
TenantID TenantID `json:"tenantId"`
|
||||||
|
AgentID AgentID `json:"agentId"`
|
||||||
|
}
|
||||||
|
|
||||||
type Spec struct {
|
type Spec struct {
|
||||||
ID SpecID `json:"id"`
|
SpecHeader
|
||||||
DefinitionName string `json:"name"`
|
|
||||||
DefinitionVersion string `json:"version"`
|
Data map[string]any `json:"data"`
|
||||||
Data map[string]any `json:"data"`
|
|
||||||
Revision int `json:"revision"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
UpdatedAt time.Time `json:"updatedAt"`
|
|
||||||
TenantID TenantID `json:"tenantId"`
|
|
||||||
AgentID AgentID `json:"agentId"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Spec) SpecDefinitionName() string {
|
func (s *Spec) SpecDefinitionName() string {
|
||||||
|
|
|
@ -154,9 +154,44 @@ func (r *AgentRepository) DeleteSpec(ctx context.Context, agentID datastore.Agen
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetSpec implements datastore.AgentRepository.
|
||||||
|
func (r *AgentRepository) GetSpec(ctx context.Context, agentID datastore.AgentID, name string, version string) (*datastore.Spec, error) {
|
||||||
|
var spec datastore.Spec
|
||||||
|
|
||||||
|
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
|
||||||
|
exists, err := r.agentExists(ctx, tx, agentID)
|
||||||
|
if err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !exists {
|
||||||
|
return errors.WithStack(datastore.ErrNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
query := `SELECT id, name, version, revision, data, created_at, updated_at, agent_id, tenant_id FROM specs WHERE agent_id = $1 AND name = $2 AND version = $3`
|
||||||
|
|
||||||
|
row := tx.QueryRowContext(ctx, query, agentID, name, version)
|
||||||
|
|
||||||
|
var data JSONMap
|
||||||
|
|
||||||
|
if err := row.Scan(&spec.ID, &spec.DefinitionName, &spec.DefinitionVersion, &spec.Revision, &data, &spec.CreatedAt, &spec.UpdatedAt, &spec.AgentID, &spec.TenantID); err != nil {
|
||||||
|
return errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.Data = data
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &spec, nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetSpecs implements datastore.AgentRepository.
|
// GetSpecs implements datastore.AgentRepository.
|
||||||
func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentID) ([]*datastore.Spec, error) {
|
func (r *AgentRepository) QuerySpecs(ctx context.Context, agentID datastore.AgentID) ([]*datastore.SpecHeader, error) {
|
||||||
specs := make([]*datastore.Spec, 0)
|
specs := make([]*datastore.SpecHeader, 0)
|
||||||
|
|
||||||
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
|
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
|
||||||
exists, err := r.agentExists(ctx, tx, agentID)
|
exists, err := r.agentExists(ctx, tx, agentID)
|
||||||
|
@ -169,7 +204,7 @@ func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentI
|
||||||
}
|
}
|
||||||
|
|
||||||
query := `
|
query := `
|
||||||
SELECT id, name, version, revision, data, created_at, updated_at, agent_id, tenant_id
|
SELECT id, name, version, revision, created_at, updated_at, agent_id, tenant_id
|
||||||
FROM specs
|
FROM specs
|
||||||
WHERE agent_id = $1
|
WHERE agent_id = $1
|
||||||
`
|
`
|
||||||
|
@ -187,19 +222,16 @@ func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentI
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
spec := &datastore.Spec{}
|
spec := &datastore.SpecHeader{}
|
||||||
|
|
||||||
data := JSONMap{}
|
|
||||||
|
|
||||||
var tenantID sql.NullString
|
var tenantID sql.NullString
|
||||||
if err := rows.Scan(&spec.ID, &spec.DefinitionName, &spec.DefinitionVersion, &spec.Revision, &data, &spec.CreatedAt, &spec.UpdatedAt, &spec.AgentID, &tenantID); err != nil {
|
if err := rows.Scan(&spec.ID, &spec.DefinitionName, &spec.DefinitionVersion, &spec.Revision, &spec.CreatedAt, &spec.UpdatedAt, &spec.AgentID, &tenantID); err != nil {
|
||||||
return errors.WithStack(err)
|
return errors.WithStack(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tenantID.Valid {
|
if tenantID.Valid {
|
||||||
spec.TenantID = datastore.TenantID(tenantID.String)
|
spec.TenantID = datastore.TenantID(tenantID.String)
|
||||||
}
|
}
|
||||||
spec.Data = data
|
|
||||||
|
|
||||||
specs = append(specs, spec)
|
specs = append(specs, spec)
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,11 +84,11 @@ var agentRepositoryTestCases = []agentRepositoryTestCase{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Try to get specs of an unexistant agent",
|
Name: "Try to query specs of an unexistant agent",
|
||||||
Run: func(ctx context.Context, repo datastore.AgentRepository) error {
|
Run: func(ctx context.Context, repo datastore.AgentRepository) error {
|
||||||
var unexistantAgentID datastore.AgentID = 9999
|
var unexistantAgentID datastore.AgentID = 9999
|
||||||
|
|
||||||
specs, err := repo.GetSpecs(ctx, unexistantAgentID)
|
specs, err := repo.QuerySpecs(ctx, unexistantAgentID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return errors.New("error should not be nil")
|
return errors.New("error should not be nil")
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,20 +4,24 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||||
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"gitlab.com/wpetit/goweb/api"
|
"gitlab.com/wpetit/goweb/api"
|
||||||
"gitlab.com/wpetit/goweb/logger"
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (m *Mount) getAgentSpecs(w http.ResponseWriter, r *http.Request) {
|
func (m *Mount) getAgentSpec(w http.ResponseWriter, r *http.Request) {
|
||||||
agentID, ok := getAgentID(w, r)
|
agentID, ok := getAgentID(w, r)
|
||||||
if !ok {
|
if !ok {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
specName := chi.URLParam(r, "specName")
|
||||||
|
specVersion := chi.URLParam(r, "specVersion")
|
||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
|
|
||||||
specs, err := m.agentRepo.GetSpecs(ctx, agentID)
|
spec, err := m.agentRepo.GetSpec(ctx, agentID, specName, specVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, datastore.ErrNotFound) {
|
if errors.Is(err, datastore.ErrNotFound) {
|
||||||
api.ErrorResponse(w, http.StatusNotFound, ErrCodeNotFound, nil)
|
api.ErrorResponse(w, http.StatusNotFound, ErrCodeNotFound, nil)
|
||||||
|
@ -34,8 +38,8 @@ func (m *Mount) getAgentSpecs(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
|
|
||||||
api.DataResponse(w, http.StatusOK, struct {
|
api.DataResponse(w, http.StatusOK, struct {
|
||||||
Specs []*datastore.Spec `json:"specs"`
|
Spec *datastore.Spec `json:"spec"`
|
||||||
}{
|
}{
|
||||||
Specs: specs,
|
Spec: spec,
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -35,7 +35,8 @@ func (m *Mount) Mount(r chi.Router) {
|
||||||
r.With(assertAgentOrUserWithWriteAccess).Put("/{agentID}", m.updateAgent)
|
r.With(assertAgentOrUserWithWriteAccess).Put("/{agentID}", m.updateAgent)
|
||||||
r.With(assertUserWithWriteAccess).Delete("/{agentID}", m.deleteAgent)
|
r.With(assertUserWithWriteAccess).Delete("/{agentID}", m.deleteAgent)
|
||||||
|
|
||||||
r.With(assertAgentOrUserWithReadAccess).Get("/{agentID}/specs", m.getAgentSpecs)
|
r.With(assertAgentOrUserWithReadAccess).Get("/{agentID}/specs", m.queryAgentSpec)
|
||||||
|
r.With(assertAgentOrUserWithReadAccess).Get("/{agentID}/specs/{specName}/{specVersion}", m.getAgentSpec)
|
||||||
r.With(assertUserWithWriteAccess).Post("/{agentID}/specs", m.updateAgentSpec)
|
r.With(assertUserWithWriteAccess).Post("/{agentID}/specs", m.updateAgentSpec)
|
||||||
r.With(assertUserWithWriteAccess).Delete("/{agentID}/specs", m.deleteAgentSpec)
|
r.With(assertUserWithWriteAccess).Delete("/{agentID}/specs", m.deleteAgentSpec)
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"gitlab.com/wpetit/goweb/api"
|
||||||
|
"gitlab.com/wpetit/goweb/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (m *Mount) queryAgentSpec(w http.ResponseWriter, r *http.Request) {
|
||||||
|
agentID, ok := getAgentID(w, r)
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx := r.Context()
|
||||||
|
|
||||||
|
specHeaders, err := m.agentRepo.QuerySpecs(ctx, agentID)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, datastore.ErrNotFound) {
|
||||||
|
api.ErrorResponse(w, http.StatusNotFound, ErrCodeNotFound, nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = errors.WithStack(err)
|
||||||
|
logger.Error(ctx, "could not query specs", logger.CapturedE(err))
|
||||||
|
|
||||||
|
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retro-compatibility mode: return full specs temporarily
|
||||||
|
specs := make([]*datastore.Spec, 0, len(specHeaders))
|
||||||
|
for _, sh := range specHeaders {
|
||||||
|
spec, err := m.agentRepo.GetSpec(ctx, agentID, sh.DefinitionName, sh.DefinitionVersion)
|
||||||
|
if err != nil {
|
||||||
|
err = errors.WithStack(err)
|
||||||
|
logger.Error(ctx, "could not query specs", logger.CapturedE(err))
|
||||||
|
|
||||||
|
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
specs = append(specs, spec)
|
||||||
|
}
|
||||||
|
|
||||||
|
api.DataResponse(w, http.StatusOK, struct {
|
||||||
|
Specs []*datastore.Spec `json:"specs"`
|
||||||
|
}{
|
||||||
|
Specs: specs,
|
||||||
|
})
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package client
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *Client) GetAgentSpec(ctx context.Context, agentID AgentID, specName string, specVersion string, funcs ...OptionFunc) (*datastore.Spec, error) {
|
||||||
|
response := withResponse[struct {
|
||||||
|
Spec *datastore.Spec `json:"spec"`
|
||||||
|
}]()
|
||||||
|
|
||||||
|
path := fmt.Sprintf("/api/v1/agents/%d/specs/%s/%s", agentID, specName, specVersion)
|
||||||
|
|
||||||
|
if err := c.apiGet(ctx, path, &response, funcs...); err != nil {
|
||||||
|
return nil, errors.WithStack(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.Error != nil {
|
||||||
|
return nil, errors.WithStack(response.Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data.Spec, nil
|
||||||
|
}
|
|
@ -5,13 +5,12 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (c *Client) GetAgentSpecs(ctx context.Context, agentID AgentID, funcs ...OptionFunc) ([]Spec, error) {
|
func (c *Client) QueryAgentSpecs(ctx context.Context, agentID AgentID, funcs ...OptionFunc) ([]*datastore.SpecHeader, error) {
|
||||||
response := withResponse[struct {
|
response := withResponse[struct {
|
||||||
Specs []*datastore.Spec `json:"specs"`
|
Specs []*datastore.SpecHeader `json:"specs"`
|
||||||
}]()
|
}]()
|
||||||
|
|
||||||
path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID)
|
path := fmt.Sprintf("/api/v1/agents/%d/specs", agentID)
|
||||||
|
@ -24,10 +23,5 @@ func (c *Client) GetAgentSpecs(ctx context.Context, agentID AgentID, funcs ...Op
|
||||||
return nil, errors.WithStack(response.Error)
|
return nil, errors.WithStack(response.Error)
|
||||||
}
|
}
|
||||||
|
|
||||||
specs := make([]spec.Spec, 0, len(response.Data.Specs))
|
return response.Data.Specs, nil
|
||||||
for _, s := range response.Data.Specs {
|
|
||||||
specs = append(specs, spec.Spec(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
return specs, nil
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue