github.com/choria-io/go-choria@v0.28.1-0.20240416190746-b3bf9c7d5a45/providers/agent/mcorpc/golang/registry/registry.go (about)

     1  // Copyright (c) 2021, R.I. Pienaar and the Choria Project contributors
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package registry
     6  
     7  import (
     8  	"context"
     9  	"encoding/json"
    10  	"fmt"
    11  
    12  	"github.com/choria-io/go-choria/build"
    13  	"github.com/choria-io/go-choria/inter"
    14  	"github.com/choria-io/go-choria/providers/agent/mcorpc"
    15  	agentDDL "github.com/choria-io/go-choria/providers/agent/mcorpc/ddl/agent"
    16  	"github.com/choria-io/go-choria/providers/agent/mcorpc/ddl/common"
    17  	"github.com/choria-io/go-choria/server"
    18  	"github.com/choria-io/go-choria/server/agents"
    19  	"github.com/sirupsen/logrus"
    20  )
    21  
    22  // DDLRequest is a request for a DDL file for plugin type Type and name Name
    23  type DDLRequest struct {
    24  	Name       string `json:"name"`
    25  	PluginType string `json:"plugin_type" validate:"enum=agent"`
    26  	Format     string `json:"format" validate:"enum=ddl,json"`
    27  }
    28  
    29  // DDLResponse is the response to a DDL request
    30  type DDLResponse struct {
    31  	Name       string `json:"name"`
    32  	PluginType string `json:"plugin_type"`
    33  	Version    string `json:"version"`
    34  	DDL        string `json:"ddl"`
    35  }
    36  
    37  type NamesRequest struct {
    38  	PluginType string `json:"plugin_type" validate:"enum=agent"`
    39  }
    40  
    41  type NamesResponse struct {
    42  	Names      []string `json:"names"`
    43  	PluginType string   `json:"plugin_type"`
    44  }
    45  
    46  var metadata = &agents.Metadata{
    47  	Name:        "choria_registry",
    48  	Description: "Choria Registry Service",
    49  	Author:      "R.I.Pienaar <rip@devco.net>",
    50  	Version:     build.Version,
    51  	License:     build.License,
    52  	Timeout:     2,
    53  	URL:         "https://choria.io",
    54  	Service:     true,
    55  }
    56  
    57  // New creates a new registry agent
    58  func New(mgr server.AgentManager) (agents.Agent, error) {
    59  	agent := mcorpc.New("choria_registry", metadata, mgr.Choria(), mgr.Logger())
    60  	agent.MustRegisterAction("ddl", ddlAction)
    61  	agent.MustRegisterAction("names", namesAction)
    62  
    63  	agent.SetActivationChecker(func() bool {
    64  		return mgr.Choria().Configuration().Choria.RegistryServiceStore != ""
    65  	})
    66  
    67  	return agent, nil
    68  }
    69  
    70  func namesAction(ctx context.Context, req *mcorpc.Request, reply *mcorpc.Reply, agent *mcorpc.Agent, conn inter.ConnectorInfo) {
    71  	i := NamesRequest{}
    72  	if !mcorpc.ParseRequestData(&i, req, reply) {
    73  		return
    74  	}
    75  
    76  	output := &NamesResponse{
    77  		PluginType: i.PluginType,
    78  	}
    79  	reply.Data = output
    80  
    81  	store := agent.Choria.Configuration().Choria.RegistryServiceStore
    82  
    83  	switch i.PluginType {
    84  	case "agent":
    85  		common.EachFile("agent", []string{store}, func(n, _ string) bool {
    86  			output.Names = append(output.Names, n)
    87  			return false
    88  		})
    89  
    90  	default:
    91  		reply.Statuscode = mcorpc.Aborted
    92  		reply.Statusmsg = fmt.Sprintf("Unsupported plugin type %s", i.PluginType)
    93  	}
    94  }
    95  
    96  func ddlAction(ctx context.Context, req *mcorpc.Request, reply *mcorpc.Reply, agent *mcorpc.Agent, conn inter.ConnectorInfo) {
    97  	i := DDLRequest{}
    98  	if !mcorpc.ParseRequestData(&i, req, reply) {
    99  		return
   100  	}
   101  
   102  	output := &DDLResponse{}
   103  	reply.Data = output
   104  
   105  	store := agent.Choria.Configuration().Choria.RegistryServiceStore
   106  
   107  	switch i.PluginType {
   108  	case "agent":
   109  		addl, err := agentDDL.FindLocally(i.Name, []string{store})
   110  		if abortIfErr(reply, agent.Log, "Could not load DDL", err) {
   111  			return
   112  		}
   113  
   114  		output.Name = i.Name
   115  		output.PluginType = "agent"
   116  		output.Version = addl.Metadata.Version
   117  
   118  		if i.Format == "ddl" {
   119  			output.DDL, err = addl.ToRuby()
   120  			if abortIfErr(reply, agent.Log, "Could not encode DDL", err) {
   121  				return
   122  			}
   123  			return
   124  		}
   125  
   126  		jddl, err := json.Marshal(addl)
   127  		if abortIfErr(reply, agent.Log, "Could not encode DDL", err) {
   128  			return
   129  		}
   130  		output.DDL = string(jddl)
   131  
   132  	default:
   133  		reply.Statuscode = mcorpc.Aborted
   134  		reply.Statusmsg = fmt.Sprintf("Unsupported plugin type %s", i.PluginType)
   135  	}
   136  }
   137  
   138  func abortIfErr(reply *mcorpc.Reply, log *logrus.Entry, msg string, err error) bool {
   139  	if err == nil {
   140  		return false
   141  	}
   142  
   143  	abort(reply, msg)
   144  	log.Errorf("%s: %s", msg, err)
   145  
   146  	return true
   147  }
   148  
   149  func abort(reply *mcorpc.Reply, msg string) {
   150  	reply.Statuscode = mcorpc.Aborted
   151  	reply.Statusmsg = msg
   152  }