From 0e4b5720d9981dfd2a214dec57531068b2438d78 Mon Sep 17 00:00:00 2001 From: Armon Dadgar Date: Fri, 20 Dec 2013 15:33:13 -0800 Subject: [PATCH] Filling in Agent basics --- command/agent/agent.go | 100 +++++++++++++++++++++++++++++++++++++++- command/agent/config.go | 52 ++++++++++++++++++++- consul/config.go | 4 +- 3 files changed, 152 insertions(+), 4 deletions(-) diff --git a/command/agent/agent.go b/command/agent/agent.go index fe3bafca0..ea9deaa0b 100644 --- a/command/agent/agent.go +++ b/command/agent/agent.go @@ -1,5 +1,10 @@ package agent +import ( + "fmt" + "github.com/hashicorp/consul/consul" +) + /* The agent is the long running process that is run on every machine. It exposes an RPC interface that is used by the CLI to control the @@ -10,6 +15,11 @@ package agent */ type Agent struct { config *Config + + // We have one of a client or a server, depending + // on our configuration + server *consul.Server + client *consul.Client } // Create is used to create a new Agent. Returns @@ -18,16 +28,102 @@ func Create(config *Config) (*Agent, error) { agent := &Agent{ config: config, } + + // Setup either the client or the server + var err error + if config.Server { + err = agent.setupServer() + } else { + err = agent.setupClient() + } + if err != nil { + return nil, err + } + return agent, nil } +// consulConfig is used to return a consul configuration +func (a *Agent) consulConfig() *consul.Config { + // Start with the provided config or default config + var base *consul.Config + if a.config.ConsulConfig != nil { + base = a.config.ConsulConfig + } else { + base = consul.DefaultConfig() + } + + // Override with our config + if a.config.Datacenter != "" { + base.Datacenter = a.config.Datacenter + } + if a.config.DataDir != "" { + base.DataDir = a.config.DataDir + } + if a.config.NodeName != "" { + base.NodeName = a.config.NodeName + } + if a.config.SerfBindAddr != "" { + base.SerfLANConfig.MemberlistConfig.BindAddr = a.config.SerfBindAddr + base.SerfWANConfig.MemberlistConfig.BindAddr = a.config.SerfBindAddr + } + if a.config.SerfLanPort != 0 { + base.SerfLANConfig.MemberlistConfig.Port = a.config.SerfLanPort + } + if a.config.SerfWanPort != 0 { + base.SerfWANConfig.MemberlistConfig.Port = a.config.SerfWanPort + } + if a.config.ServerRPCAddr != "" { + base.RPCAddr = a.config.ServerRPCAddr + } + + return base +} + +// setupServer is used to initialize the Consul server +func (a *Agent) setupServer() error { + server, err := consul.NewServer(a.consulConfig()) + if err != nil { + return fmt.Errorf("Failed to start Consul server: %v", err) + } + a.server = server + return nil +} + +// setupClient is used to initialize the Consul client +func (a *Agent) setupClient() error { + client, err := consul.NewClient(a.consulConfig()) + if err != nil { + return fmt.Errorf("Failed to start Consul client: %v", err) + } + a.client = client + return nil +} + +// RPC is used to make an RPC call to the Consul servers +// This allows the agent to implement the Consul.Interface +func (a *Agent) RPC(method string, args interface{}, reply interface{}) error { + if a.server != nil { + return a.server.RPC(method, args, reply) + } + return a.client.RPC(method, args, reply) +} + // Leave prepares the agent for a graceful shutdown func (a *Agent) Leave() error { - return nil + if a.server != nil { + return a.server.Leave() + } else { + return a.client.Leave() + } } // Shutdown is used to hard stop the agent. Should be preceeded // by a call to Leave to do it gracefully. func (a *Agent) Shutdown() error { - return nil + if a.server != nil { + return a.server.Shutdown() + } else { + return a.client.Shutdown() + } } diff --git a/command/agent/config.go b/command/agent/config.go index c059cfcdd..005ff0ded 100644 --- a/command/agent/config.go +++ b/command/agent/config.go @@ -1,12 +1,62 @@ package agent +import ( + "github.com/hashicorp/consul/consul" +) + +// This is the default port we use for co +const DefaultBindPort int = 8300 + // Config is the configuration that can be set for an Agent. // Some of this is configurable as CLI flags, but most must // be set using a configuration file. type Config struct { + // Datacenter is the datacenter this node is in. Defaults to dc1 + Datacenter string + + // DataDir is the directory to store our state in + DataDir string + + // LogLevel is the level of the logs to putout + LogLevel string + + // Node name is the name we use to advertise. Defaults to hostname. + NodeName string + + // RPCAddr is the address and port to listen on for the + // agent's RPC interface. + RPCAddr string + + // BindAddr is the address that Consul's RPC and Serf's will + // bind to. This address should be routable by all other hosts. + SerfBindAddr string + + // SerfLanPort is the port we use for the lan-local serf cluster + // This is used for all nodes. + SerfLanPort int + + // SerfWanPort is the port we use for the wan serf cluster. + // This is only for the Consul servers + SerfWanPort int + + // ServerRPCAddr is the address we use for Consul server communication. + // Defaults to 0.0.0.0:8300 + ServerRPCAddr string + + // Server controls if this agent acts like a Consul server, + // or merely as a client. Servers have more state, take part + // in leader election, etc. + Server bool + + // ConsulConfig can either be provided or a default one created + ConsulConfig *consul.Config } // DefaultConfig is used to return a sane default configuration func DefaultConfig() *Config { - return &Config{} + return &Config{ + LogLevel: "INFO", + RPCAddr: "127.0.0.1:8400", + Server: false, + } } diff --git a/consul/config.go b/consul/config.go index e33175025..554272d61 100644 --- a/consul/config.go +++ b/consul/config.go @@ -9,7 +9,9 @@ import ( ) const ( + DefaultDC = "dc1" DefaultRPCAddr = "0.0.0.0:8300" + DefaultRPCPort = 8000 DefaultLANSerfPort = 8301 DefaultWANSerfPort = 8302 ) @@ -51,7 +53,7 @@ func DefaultConfig() *Config { } conf := &Config{ - Datacenter: "dc1", + Datacenter: DefaultDC, NodeName: hostname, RPCAddr: DefaultRPCAddr, RaftConfig: raft.DefaultConfig(),