mirror of
https://github.com/status-im/consul.git
synced 2025-01-10 13:55:55 +00:00
agent: First pass at parsing service and check definition
This commit is contained in:
parent
db4bf65e2e
commit
1a5158212c
@ -69,18 +69,7 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
|
||||
}
|
||||
|
||||
// Construct the health check
|
||||
health := structs.HealthCheck{
|
||||
Node: s.agent.config.NodeName,
|
||||
CheckID: args.ID,
|
||||
Name: args.Name,
|
||||
Status: structs.HealthUnknown,
|
||||
Notes: args.Notes,
|
||||
}
|
||||
|
||||
// Fixup the ID if not given
|
||||
if health.CheckID == "" && health.Name != "" {
|
||||
health.CheckID = health.Name
|
||||
}
|
||||
health := args.HealthCheck(s.agent.config.NodeName)
|
||||
|
||||
// Verify the check type
|
||||
chkType := &args.CheckType
|
||||
@ -91,7 +80,7 @@ func (s *HTTPServer) AgentRegisterCheck(resp http.ResponseWriter, req *http.Requ
|
||||
}
|
||||
|
||||
// Add the check
|
||||
return s.agent.AddCheck(&health, chkType), nil
|
||||
return s.agent.AddCheck(health, chkType), nil
|
||||
}
|
||||
|
||||
func (s *HTTPServer) AgentDeregisterCheck(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
@ -132,21 +121,11 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Construct the health check
|
||||
ns := structs.NodeService{
|
||||
ID: args.ID,
|
||||
Service: args.Name,
|
||||
Tag: args.Tag,
|
||||
Port: args.Port,
|
||||
}
|
||||
|
||||
// Fixup the ID if not given
|
||||
if ns.ID == "" && ns.Service != "" {
|
||||
ns.ID = ns.Service
|
||||
}
|
||||
// Get the node service
|
||||
ns := args.NodeService()
|
||||
|
||||
// Verify the check type
|
||||
chkType := args.Check
|
||||
chkType := args.CheckType()
|
||||
if chkType != nil && !chkType.Valid() {
|
||||
resp.WriteHeader(400)
|
||||
resp.Write([]byte("Must provide TTL or Script and Interval!"))
|
||||
@ -154,7 +133,7 @@ func (s *HTTPServer) AgentRegisterService(resp http.ResponseWriter, req *http.Re
|
||||
}
|
||||
|
||||
// Add the check
|
||||
return s.agent.AddService(&ns, chkType), nil
|
||||
return s.agent.AddService(ns, chkType), nil
|
||||
}
|
||||
|
||||
func (s *HTTPServer) AgentDeregisterService(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
|
||||
|
@ -197,7 +197,25 @@ func (c *Command) Run(args []string) int {
|
||||
defer c.httpServer.Shutdown()
|
||||
}
|
||||
|
||||
// TODO: Register services/checks
|
||||
// Register the services
|
||||
for _, service := range config.Services {
|
||||
ns := service.NodeService()
|
||||
chkType := service.CheckType()
|
||||
if err := c.agent.AddService(ns, chkType); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to register service '%s': %v", service.Name, err))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Register the checks
|
||||
for _, check := range config.Checks {
|
||||
health := check.HealthCheck(config.NodeName)
|
||||
chkType := &check.CheckType
|
||||
if err := c.agent.AddCheck(health, chkType); err != nil {
|
||||
c.Ui.Error(fmt.Sprintf("Failed to register check '%s': %v %v", check.Name, err, check))
|
||||
return 1
|
||||
}
|
||||
}
|
||||
|
||||
// Let the agent know we've finished registration
|
||||
c.agent.StartSync()
|
||||
|
@ -93,6 +93,12 @@ type Config struct {
|
||||
// the INT signal. Defaults false. This can be changed on reload.
|
||||
SkipLeaveOnInt bool `mapstructure:"skip_leave_on_interrupt"`
|
||||
|
||||
// Checks holds the provided check definitions
|
||||
Checks []*CheckDefinition
|
||||
|
||||
// Services holds the provided service definitions
|
||||
Services []*ServiceDefinition
|
||||
|
||||
// ConsulConfig can either be provided or a default one created
|
||||
ConsulConfig *consul.Config
|
||||
}
|
||||
@ -124,14 +130,29 @@ func (c *Config) EncryptBytes() ([]byte, error) {
|
||||
// format and decodes it into a proper Config structure.
|
||||
func DecodeConfig(r io.Reader) (*Config, error) {
|
||||
var raw interface{}
|
||||
var result Config
|
||||
dec := json.NewDecoder(r)
|
||||
if err := dec.Decode(&raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Check the result type
|
||||
if obj, ok := raw.(map[string]interface{}); ok {
|
||||
// Check for a "service" or "check" key, meaning
|
||||
// this is actually a definition entry
|
||||
if sub, ok := obj["service"]; ok {
|
||||
service, err := DecodeServiceDefinition(sub)
|
||||
result.Services = append(result.Services, service)
|
||||
return &result, err
|
||||
} else if sub, ok := obj["check"]; ok {
|
||||
check, err := DecodeCheckDefinition(sub)
|
||||
result.Checks = append(result.Checks, check)
|
||||
return &result, err
|
||||
}
|
||||
}
|
||||
|
||||
// Decode
|
||||
var md mapstructure.Metadata
|
||||
var result Config
|
||||
msdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Metadata: &md,
|
||||
Result: &result,
|
||||
@ -147,6 +168,85 @@ func DecodeConfig(r io.Reader) (*Config, error) {
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// DecodeServiceDefinition is used to decode a service definition
|
||||
func DecodeServiceDefinition(raw interface{}) (*ServiceDefinition, error) {
|
||||
var sub interface{}
|
||||
rawMap, ok := raw.(map[string]interface{})
|
||||
if !ok {
|
||||
goto AFTER_FIX
|
||||
}
|
||||
sub, ok = rawMap["check"]
|
||||
if !ok {
|
||||
goto AFTER_FIX
|
||||
}
|
||||
if err := FixupCheckType(sub); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
AFTER_FIX:
|
||||
var md mapstructure.Metadata
|
||||
var result ServiceDefinition
|
||||
msdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Metadata: &md,
|
||||
Result: &result,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := msdec.Decode(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func FixupCheckType(raw interface{}) error {
|
||||
// Handle decoding of time durations
|
||||
rawMap, ok := raw.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
if ttl, ok := rawMap["ttl"]; ok {
|
||||
ttlS, ok := ttl.(string)
|
||||
if ok {
|
||||
if dur, err := time.ParseDuration(ttlS); err != nil {
|
||||
return err
|
||||
} else {
|
||||
rawMap["ttl"] = dur
|
||||
}
|
||||
}
|
||||
}
|
||||
if interval, ok := rawMap["interval"]; ok {
|
||||
intervalS, ok := interval.(string)
|
||||
if ok {
|
||||
if dur, err := time.ParseDuration(intervalS); err != nil {
|
||||
return err
|
||||
} else {
|
||||
rawMap["interval"] = dur
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DecodeCheckDefinition is used to decode a check definition
|
||||
func DecodeCheckDefinition(raw interface{}) (*CheckDefinition, error) {
|
||||
if err := FixupCheckType(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var md mapstructure.Metadata
|
||||
var result CheckDefinition
|
||||
msdec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
Metadata: &md,
|
||||
Result: &result,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := msdec.Decode(raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// MergeConfig merges two configurations together to make a single new
|
||||
// configuration.
|
||||
func MergeConfig(a, b *Config) *Config {
|
||||
@ -210,6 +310,12 @@ func MergeConfig(a, b *Config) *Config {
|
||||
if b.SkipLeaveOnInt == true {
|
||||
result.SkipLeaveOnInt = true
|
||||
}
|
||||
if b.Checks != nil {
|
||||
result.Checks = append(result.Checks, b.Checks...)
|
||||
}
|
||||
if b.Services != nil {
|
||||
result.Services = append(result.Services, b.Services...)
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
|
@ -1,25 +1,56 @@
|
||||
package agent
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/consul/consul/structs"
|
||||
)
|
||||
|
||||
// ServiceDefinition is used to JSON decode the Service definitions
|
||||
type ServiceDefinition struct {
|
||||
ID string
|
||||
Name string
|
||||
Tag string
|
||||
Port int
|
||||
Check *CheckType
|
||||
Check CheckType
|
||||
}
|
||||
|
||||
func (s *ServiceDefinition) NodeService() *structs.NodeService {
|
||||
ns := &structs.NodeService{
|
||||
ID: s.ID,
|
||||
Service: s.Name,
|
||||
Tag: s.Tag,
|
||||
Port: s.Port,
|
||||
}
|
||||
if ns.ID == "" && ns.Service != "" {
|
||||
ns.ID = ns.Service
|
||||
}
|
||||
return ns
|
||||
}
|
||||
|
||||
func (s *ServiceDefinition) CheckType() *CheckType {
|
||||
if s.Check.Script == "" && s.Check.Interval == 0 && s.Check.TTL == 0 {
|
||||
return nil
|
||||
}
|
||||
return &s.Check
|
||||
}
|
||||
|
||||
// ChecKDefinition is used to JSON decode the Check definitions
|
||||
type CheckDefinition struct {
|
||||
ID string
|
||||
Name string
|
||||
Notes string
|
||||
CheckType
|
||||
ID string
|
||||
Name string
|
||||
Notes string
|
||||
CheckType `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
// UnionDefinition is used to decode when we don't know if
|
||||
// we are being given a ServiceDefinition or a CheckDefinition
|
||||
type UnionDefinition struct {
|
||||
Service *ServiceDefinition
|
||||
Check *CheckDefinition
|
||||
func (c *CheckDefinition) HealthCheck(node string) *structs.HealthCheck {
|
||||
health := &structs.HealthCheck{
|
||||
Node: node,
|
||||
CheckID: c.ID,
|
||||
Name: c.Name,
|
||||
Status: structs.HealthUnknown,
|
||||
Notes: c.Notes,
|
||||
}
|
||||
if health.CheckID == "" && health.Name != "" {
|
||||
health.CheckID = health.Name
|
||||
}
|
||||
return health
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user