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 }