diff --git a/Consul/Agent.cs b/Consul/Agent.cs
index 1350f84..d575bed 100644
--- a/Consul/Agent.cs
+++ b/Consul/Agent.cs
@@ -26,598 +26,601 @@
namespace Consul
{
- ///
- /// The status of a TTL check
- ///
- public class TTLStatus : IEquatable
- {
- private static readonly TTLStatus passingStatus = new TTLStatus() { Status = "passing", LegacyStatus = "pass" };
- private static readonly TTLStatus warningStatus = new TTLStatus() { Status = "warning", LegacyStatus = "warn" };
- private static readonly TTLStatus criticalStatus = new TTLStatus() { Status = "critical", LegacyStatus = "fail" };
-
- public string Status { get; private set; }
- internal string LegacyStatus { get; private set; }
-
- public static TTLStatus Pass
- {
- get { return passingStatus; }
- }
-
- public static TTLStatus Warn
- {
- get { return warningStatus; }
- }
-
- public static TTLStatus Critical
- {
- get { return criticalStatus; }
- }
-
- [Obsolete("Use TTLStatus.Critical instead. This status will be an error in 0.7.0+", true)]
- public static TTLStatus Fail
- {
- get { return criticalStatus; }
- }
-
- public bool Equals(TTLStatus other)
- {
- return other != null && ReferenceEquals(this, other);
- }
-
- public override bool Equals(object other)
- {
- // other could be a reference type, the is operator will return false if null
- return other is TTLStatus && Equals(other as TTLStatus);
- }
-
- public override int GetHashCode()
- {
- return Status.GetHashCode();
- }
- }
-
- public class TTLStatusConverter : JsonConverter
- {
- public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
- {
- serializer.Serialize(writer, ((TTLStatus)value).Status);
- }
-
- public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
- JsonSerializer serializer)
- {
- var status = (string)serializer.Deserialize(reader, typeof(string));
- switch (status)
- {
- case "pass":
- return TTLStatus.Pass;
- case "passing":
- return TTLStatus.Pass;
- case "warn":
- return TTLStatus.Warn;
- case "warning":
- return TTLStatus.Warn;
- case "fail":
- return TTLStatus.Critical;
- case "critical":
- return TTLStatus.Critical;
- default:
- throw new ArgumentException("Invalid TTL status value during deserialization");
- }
- }
-
- public override bool CanConvert(Type objectType)
- {
- return objectType == typeof(TTLStatus);
- }
- }
-
- ///
- /// AgentCheck represents a check known to the agent
- ///
- public class AgentCheck
- {
- public string Node { get; set; }
- public string CheckID { get; set; }
- public string Name { get; set; }
-
- [JsonConverter(typeof(HealthStatusConverter))]
- public HealthStatus Status { get; set; }
-
- public string Notes { get; set; }
- public string Output { get; set; }
- public string ServiceID { get; set; }
- public string ServiceName { get; set; }
- }
-
- ///
- /// AgentService represents a service known to the agent
- ///
- public class AgentService
- {
- public string ID { get; set; }
- public string Service { get; set; }
- public string[] Tags { get; set; }
- public int Port { get; set; }
- public string Address { get; set; }
- public bool EnableTagOverride { get; set; }
- public IDictionary Meta { get; set; }
- }
-
- ///
- /// AgentMember represents a cluster member known to the agent
- ///
- public class AgentMember
- {
- public string Name { get; set; }
- public string Addr { get; set; }
- public ushort Port { get; set; }
- public Dictionary Tags { get; set; }
- public int Status { get; set; }
- public byte ProtocolMin { get; set; }
- public byte ProtocolMax { get; set; }
- public byte ProtocolCur { get; set; }
- public byte DelegateMin { get; set; }
- public byte DelegateMax { get; set; }
- public byte DelegateCur { get; set; }
-
- public AgentMember()
- {
- Tags = new Dictionary();
- }
- }
-
- ///
- /// AgentServiceRegistration is used to register a new service
- ///
- public class AgentServiceRegistration
- {
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string ID { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string Name { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string[] Tags { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public int Port { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string Address { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public bool EnableTagOverride { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public AgentServiceCheck Check { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public AgentServiceCheck[] Checks { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public IDictionary Meta { get; set; }
- }
-
- ///
- /// AgentCheckRegistration is used to register a new check
- ///
- public class AgentCheckRegistration : AgentServiceCheck
- {
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string ID { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string Name { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string Notes { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string ServiceID { get; set; }
- }
-
- ///
- /// AgentServiceCheck is used to create an associated check for a service
- ///
- public class AgentServiceCheck
- {
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string Script { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string DockerContainerID { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string Shell { get; set; } // Only supported for Docker.
-
- [JsonConverter(typeof(DurationTimespanConverter))]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public TimeSpan? Interval { get; set; }
-
- [JsonConverter(typeof(DurationTimespanConverter))]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public TimeSpan? Timeout { get; set; }
-
- [JsonConverter(typeof(DurationTimespanConverter))]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public TimeSpan? TTL { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string HTTP { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public string TCP { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- [JsonConverter(typeof(HealthStatusConverter))]
- public HealthStatus Status { get; set; }
-
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public bool TLSSkipVerify { get; set; }
-
- ///
- /// In Consul 0.7 and later, checks that are associated with a service
- /// may also contain this optional DeregisterCriticalServiceAfter field,
- /// which is a timeout in the same Go time format as Interval and TTL. If
- /// a check is in the critical state for more than this configured value,
- /// then its associated service (and all of its associated checks) will
- /// automatically be deregistered.
- ///
- [JsonConverter(typeof(DurationTimespanConverter))]
- [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
- public TimeSpan? DeregisterCriticalServiceAfter { get; set; }
- }
-
- public enum LogLevel
- {
- Info,
- Trace,
- Debug,
- Warn,
- Err
- }
-
- ///
- /// Agent can be used to query the Agent endpoints
- ///
- public class Agent : IAgentEndpoint
- {
- private class CheckUpdate
- {
- public string Status { get; set; }
- public string Output { get; set; }
- }
- private readonly ConsulClient _client;
- private string _nodeName;
- private readonly AsyncLock _nodeNameLock;
-
- internal Agent(ConsulClient c)
- {
- _client = c;
- _nodeNameLock = new AsyncLock();
- }
-
- ///
- /// Self is used to query the agent we are speaking to for information about itself
- ///
- /// A somewhat dynamic object representing the various data elements in Self
- public Task>>> Self(CancellationToken ct = default(CancellationToken))
- {
- return _client.Get>>("/v1/agent/self").Execute(ct);
- }
-
- ///
- /// NodeName is used to get the node name of the agent
- ///
- [Obsolete("This property will be removed in 0.8.0. Replace uses of it with a call to 'await GetNodeName()'")]
- public string NodeName
- {
- get
- {
- return GetNodeName().ConfigureAwait(false).GetAwaiter().GetResult();
- }
- }
-
- ///
- /// GetNodeName is used to get the node name of the agent. The value is cached per instance of ConsulClient after the first use.
- ///
- public async Task GetNodeName(CancellationToken ct = default(CancellationToken))
- {
- if (_nodeName == null)
- {
- using (await _nodeNameLock.LockAsync().ConfigureAwait(false))
- {
- if (_nodeName == null)
- {
- _nodeName = (await Self(ct)).Response["Config"]["NodeName"];
- }
- }
- }
-
- return _nodeName;
- }
-
- ///
- /// Checks returns the locally registered checks
- ///
- /// A map of the registered check names and check data
- public Task>> Checks(CancellationToken ct = default(CancellationToken))
- {
- return _client.Get>("/v1/agent/checks").Execute(ct);
- }
-
- ///
- /// Services returns the locally registered services
- ///
- /// A map of the registered services and service data
- public Task>> Services(CancellationToken ct = default(CancellationToken))
- {
- return _client.Get>("/v1/agent/services").Execute(ct);
- }
-
- ///
- /// Members returns the known gossip members. The WAN flag can be used to query a server for WAN members.
- ///
- /// An array of gossip peers
- public Task> Members(bool wan, CancellationToken ct = default(CancellationToken))
- {
- var req = _client.Get("/v1/agent/members");
- if (wan)
- {
- req.Params["wan"] = "1";
- }
- return req.Execute(ct);
- }
-
- ///
- /// ServiceRegister is used to register a new service with the local agent
- ///
- /// A service registration object
- /// An empty write result
- public Task ServiceRegister(AgentServiceRegistration service, CancellationToken ct = default(CancellationToken))
- {
- return _client.Put("/v1/agent/service/register", service).Execute(ct);
- }
-
- ///
- /// ServiceRegister is used to register a new service with the local agent
- ///
- /// The service ID
- /// An empty write result
- public Task ServiceDeregister(string serviceID, CancellationToken ct = default(CancellationToken))
- {
- return _client.PutNothing(string.Format("/v1/agent/service/deregister/{0}", serviceID)).Execute(ct);
- }
-
- ///
- /// PassTTL is used to set a TTL check to the passing state
- ///
- /// The check ID
- /// An optional, arbitrary string to write to the check status
- public Task PassTTL(string checkID, string note, CancellationToken ct = default(CancellationToken))
- {
- return LegacyUpdateTTL(checkID, note, TTLStatus.Pass, ct);
- }
-
- ///
- /// WarnTTL is used to set a TTL check to the warning state
- ///
- /// The check ID
- /// An optional, arbitrary string to write to the check status
- public Task WarnTTL(string checkID, string note, CancellationToken ct = default(CancellationToken))
- {
- return LegacyUpdateTTL(checkID, note, TTLStatus.Warn, ct);
- }
-
- ///
- /// FailTTL is used to set a TTL check to the failing state
- ///
- /// The check ID
- /// An optional, arbitrary string to write to the check status
- public Task FailTTL(string checkID, string note, CancellationToken ct = default(CancellationToken))
- {
- return LegacyUpdateTTL(checkID, note, TTLStatus.Critical, ct);
- }
-
- ///
- /// UpdateTTL is used to update the TTL of a check
- ///
- /// The check ID
- /// An optional, arbitrary string to write to the check status
- /// The state to set the check to
- /// An empty write result
- public Task UpdateTTL(string checkID, string output, TTLStatus status, CancellationToken ct = default(CancellationToken))
- {
- var u = new CheckUpdate
- {
- Status = status.Status,
- Output = output
- };
- return _client.Put(string.Format("/v1/agent/check/update/{0}", checkID), u).Execute(ct);
- }
-
- private Task LegacyUpdateTTL(string checkID, string note, TTLStatus status, CancellationToken ct = default(CancellationToken))
- {
- var request = _client.PutNothing(string.Format("/v1/agent/check/{0}/{1}", status.LegacyStatus, checkID));
- if (!string.IsNullOrEmpty(note))
- {
- request.Params.Add("note", note);
- }
- return request.Execute(ct);
- }
-
- ///
- /// CheckRegister is used to register a new check with the local agent
- ///
- /// A check registration object
- /// An empty write result
- public Task CheckRegister(AgentCheckRegistration check, CancellationToken ct = default(CancellationToken))
- {
- return _client.Put("/v1/agent/check/register", check).Execute(ct);
- }
-
- ///
- /// CheckDeregister is used to deregister a check with the local agent
- ///
- /// The check ID to deregister
- /// An empty write result
- public Task CheckDeregister(string checkID, CancellationToken ct = default(CancellationToken))
- {
- return _client.PutNothing(string.Format("/v1/agent/check/deregister/{0}", checkID)).Execute(ct);
- }
-
- ///
- /// Join is used to instruct the agent to attempt a join to another cluster member
- ///
- /// The address to join to
- /// Join the WAN pool
- /// An empty write result
- public Task Join(string addr, bool wan, CancellationToken ct = default(CancellationToken))
- {
- var req = _client.PutNothing(string.Format("/v1/agent/join/{0}", addr));
- if (wan)
- {
- req.Params["wan"] = "1";
- }
- return req.Execute(ct);
- }
-
- ///
- /// ForceLeave is used to have the agent eject a failed node
- ///
- /// The node name to remove. An attempt to eject a node that doesn't exist will still be successful
- /// An empty write result
- public Task ForceLeave(string node, CancellationToken ct = default(CancellationToken))
- {
- return _client.PutNothing(string.Format("/v1/agent/force-leave/{0}", node)).Execute(ct);
- }
-
-
- ///
- /// Leave is used to have the agent gracefully leave the cluster and shutdown
- ///
- /// An empty write result
- public Task Leave(string node, CancellationToken ct = default(CancellationToken))
- {
- return _client.PutNothing("/v1/agent/leave").Execute(ct);
- }
-
- ///
- /// Reload triggers a configuration reload for the agent we are connected to.
- ///
- /// An empty write result
- public Task Reload(string node, CancellationToken ct = default(CancellationToken))
- {
- return _client.PutNothing("/v1/agent/reload").Execute(ct);
- }
-
- ///
- /// EnableServiceMaintenance toggles service maintenance mode on for the given service ID
- ///
- /// The service ID
- /// An optional reason
- /// An empty write result
- public Task EnableServiceMaintenance(string serviceID, string reason, CancellationToken ct = default(CancellationToken))
- {
- var req = _client.PutNothing(string.Format("/v1/agent/service/maintenance/{0}", serviceID));
- req.Params["enable"] = "true";
- req.Params["reason"] = reason;
- return req.Execute(ct);
- }
-
- ///
- /// DisableServiceMaintenance toggles service maintenance mode off for the given service ID
- ///
- /// The service ID
- /// An empty write result
- public Task DisableServiceMaintenance(string serviceID, CancellationToken ct = default(CancellationToken))
- {
- var req = _client.PutNothing(string.Format("/v1/agent/service/maintenance/{0}", serviceID));
- req.Params["enable"] = "false";
- return req.Execute(ct);
- }
-
- ///
- /// EnableNodeMaintenance toggles node maintenance mode on for the agent we are connected to
- ///
- /// An optional reason
- /// An empty write result
- public Task EnableNodeMaintenance(string reason, CancellationToken ct = default(CancellationToken))
- {
- var req = _client.PutNothing("/v1/agent/maintenance");
- req.Params["enable"] = "true";
- req.Params["reason"] = reason;
- return req.Execute(ct);
- }
-
- ///
- /// DisableNodeMaintenance toggles node maintenance mode off for the agent we are connected to
- ///
- /// An empty write result
- public Task DisableNodeMaintenance(CancellationToken ct = default(CancellationToken))
- {
- var req = _client.PutNothing("/v1/agent/maintenance");
- req.Params["enable"] = "false";
- return req.Execute(ct);
- }
-
- ///
- /// Monitor yields log lines to display streaming logs from the agent
- /// Providing a CancellationToken can be used to close the connection and stop the
- /// log stream, otherwise the log stream will time out based on the HTTP Client's timeout value.
- ///
- public async Task Monitor(LogLevel level = default(LogLevel), CancellationToken ct = default(CancellationToken))
- {
- var req = _client.Get("/v1/agent/monitor");
- req.Params["loglevel"] = level.ToString().ToLowerInvariant();
- var res = await req.ExecuteStreaming(ct).ConfigureAwait(false);
- return new LogStream(res.Response);
- }
-
- public class LogStream : IEnumerable>, IDisposable
- {
- private Stream m_stream;
- private StreamReader m_streamreader;
- internal LogStream(Stream s)
- {
- m_stream = s;
- m_streamreader = new StreamReader(s);
- }
-
- public void Dispose()
- {
- m_streamreader.Dispose();
- m_stream.Dispose();
- }
-
- public IEnumerator> GetEnumerator()
- {
-
- while (!m_streamreader.EndOfStream)
- {
- yield return m_streamreader.ReadLineAsync();
- }
- }
-
- IEnumerator IEnumerable.GetEnumerator()
- {
- return GetEnumerator();
- }
- }
- }
-
- public partial class ConsulClient : IConsulClient
- {
- private Lazy _agent;
-
- ///
- /// Agent returns a handle to the agent endpoints
- ///
- public IAgentEndpoint Agent
- {
- get { return _agent.Value; }
- }
- }
+ ///
+ /// The status of a TTL check
+ ///
+ public class TTLStatus : IEquatable
+ {
+ private static readonly TTLStatus passingStatus = new TTLStatus() { Status = "passing", LegacyStatus = "pass" };
+ private static readonly TTLStatus warningStatus = new TTLStatus() { Status = "warning", LegacyStatus = "warn" };
+ private static readonly TTLStatus criticalStatus = new TTLStatus() { Status = "critical", LegacyStatus = "fail" };
+
+ public string Status { get; private set; }
+ internal string LegacyStatus { get; private set; }
+
+ public static TTLStatus Pass
+ {
+ get { return passingStatus; }
+ }
+
+ public static TTLStatus Warn
+ {
+ get { return warningStatus; }
+ }
+
+ public static TTLStatus Critical
+ {
+ get { return criticalStatus; }
+ }
+
+ [Obsolete("Use TTLStatus.Critical instead. This status will be an error in 0.7.0+", true)]
+ public static TTLStatus Fail
+ {
+ get { return criticalStatus; }
+ }
+
+ public bool Equals(TTLStatus other)
+ {
+ return other != null && ReferenceEquals(this, other);
+ }
+
+ public override bool Equals(object other)
+ {
+ // other could be a reference type, the is operator will return false if null
+ return other is TTLStatus && Equals(other as TTLStatus);
+ }
+
+ public override int GetHashCode()
+ {
+ return Status.GetHashCode();
+ }
+ }
+
+ public class TTLStatusConverter : JsonConverter
+ {
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
+ {
+ serializer.Serialize(writer, ((TTLStatus)value).Status);
+ }
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue,
+ JsonSerializer serializer)
+ {
+ var status = (string)serializer.Deserialize(reader, typeof(string));
+ switch (status)
+ {
+ case "pass":
+ return TTLStatus.Pass;
+ case "passing":
+ return TTLStatus.Pass;
+ case "warn":
+ return TTLStatus.Warn;
+ case "warning":
+ return TTLStatus.Warn;
+ case "fail":
+ return TTLStatus.Critical;
+ case "critical":
+ return TTLStatus.Critical;
+ default:
+ throw new ArgumentException("Invalid TTL status value during deserialization");
+ }
+ }
+
+ public override bool CanConvert(Type objectType)
+ {
+ return objectType == typeof(TTLStatus);
+ }
+ }
+
+ ///
+ /// AgentCheck represents a check known to the agent
+ ///
+ public class AgentCheck
+ {
+ public string Node { get; set; }
+ public string CheckID { get; set; }
+ public string Name { get; set; }
+
+ [JsonConverter(typeof(HealthStatusConverter))]
+ public HealthStatus Status { get; set; }
+
+ public string Notes { get; set; }
+ public string Output { get; set; }
+ public string ServiceID { get; set; }
+ public string ServiceName { get; set; }
+ }
+
+ ///
+ /// AgentService represents a service known to the agent
+ ///
+ public class AgentService
+ {
+ public string ID { get; set; }
+ public string Service { get; set; }
+ public string[] Tags { get; set; }
+ public int Port { get; set; }
+ public string Address { get; set; }
+ public bool EnableTagOverride { get; set; }
+ public IDictionary Meta { get; set; }
+ }
+
+ ///
+ /// AgentMember represents a cluster member known to the agent
+ ///
+ public class AgentMember
+ {
+ public string Name { get; set; }
+ public string Addr { get; set; }
+ public ushort Port { get; set; }
+ public Dictionary Tags { get; set; }
+ public int Status { get; set; }
+ public byte ProtocolMin { get; set; }
+ public byte ProtocolMax { get; set; }
+ public byte ProtocolCur { get; set; }
+ public byte DelegateMin { get; set; }
+ public byte DelegateMax { get; set; }
+ public byte DelegateCur { get; set; }
+
+ public AgentMember()
+ {
+ Tags = new Dictionary();
+ }
+ }
+
+ ///
+ /// AgentServiceRegistration is used to register a new service
+ ///
+ public class AgentServiceRegistration
+ {
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string ID { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string Name { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string[] Tags { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public int Port { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string Address { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public bool EnableTagOverride { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public AgentServiceCheck Check { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public AgentServiceCheck[] Checks { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public IDictionary Meta { get; set; }
+ }
+
+ ///
+ /// AgentCheckRegistration is used to register a new check
+ ///
+ public class AgentCheckRegistration : AgentServiceCheck
+ {
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string ID { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string Name { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string Notes { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string ServiceID { get; set; }
+ }
+
+ ///
+ /// AgentServiceCheck is used to create an associated check for a service
+ ///
+ public class AgentServiceCheck
+ {
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string Script { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string DockerContainerID { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string Shell { get; set; } // Only supported for Docker.
+
+ [JsonConverter(typeof(DurationTimespanConverter))]
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public TimeSpan? Interval { get; set; }
+
+ [JsonConverter(typeof(DurationTimespanConverter))]
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public TimeSpan? Timeout { get; set; }
+
+ [JsonConverter(typeof(DurationTimespanConverter))]
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public TimeSpan? TTL { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string HTTP { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string TCP { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public string GRPC { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ [JsonConverter(typeof(HealthStatusConverter))]
+ public HealthStatus Status { get; set; }
+
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public bool TLSSkipVerify { get; set; }
+
+ ///
+ /// In Consul 0.7 and later, checks that are associated with a service
+ /// may also contain this optional DeregisterCriticalServiceAfter field,
+ /// which is a timeout in the same Go time format as Interval and TTL. If
+ /// a check is in the critical state for more than this configured value,
+ /// then its associated service (and all of its associated checks) will
+ /// automatically be deregistered.
+ ///
+ [JsonConverter(typeof(DurationTimespanConverter))]
+ [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
+ public TimeSpan? DeregisterCriticalServiceAfter { get; set; }
+ }
+
+ public enum LogLevel
+ {
+ Info,
+ Trace,
+ Debug,
+ Warn,
+ Err
+ }
+
+ ///
+ /// Agent can be used to query the Agent endpoints
+ ///
+ public class Agent : IAgentEndpoint
+ {
+ private class CheckUpdate
+ {
+ public string Status { get; set; }
+ public string Output { get; set; }
+ }
+ private readonly ConsulClient _client;
+ private string _nodeName;
+ private readonly AsyncLock _nodeNameLock;
+
+ internal Agent(ConsulClient c)
+ {
+ _client = c;
+ _nodeNameLock = new AsyncLock();
+ }
+
+ ///
+ /// Self is used to query the agent we are speaking to for information about itself
+ ///
+ /// A somewhat dynamic object representing the various data elements in Self
+ public Task>>> Self(CancellationToken ct = default(CancellationToken))
+ {
+ return _client.Get>>("/v1/agent/self").Execute(ct);
+ }
+
+ ///
+ /// NodeName is used to get the node name of the agent
+ ///
+ [Obsolete("This property will be removed in 0.8.0. Replace uses of it with a call to 'await GetNodeName()'")]
+ public string NodeName
+ {
+ get
+ {
+ return GetNodeName().ConfigureAwait(false).GetAwaiter().GetResult();
+ }
+ }
+
+ ///
+ /// GetNodeName is used to get the node name of the agent. The value is cached per instance of ConsulClient after the first use.
+ ///
+ public async Task GetNodeName(CancellationToken ct = default(CancellationToken))
+ {
+ if (_nodeName == null)
+ {
+ using (await _nodeNameLock.LockAsync().ConfigureAwait(false))
+ {
+ if (_nodeName == null)
+ {
+ _nodeName = (await Self(ct)).Response["Config"]["NodeName"];
+ }
+ }
+ }
+
+ return _nodeName;
+ }
+
+ ///
+ /// Checks returns the locally registered checks
+ ///
+ /// A map of the registered check names and check data
+ public Task>> Checks(CancellationToken ct = default(CancellationToken))
+ {
+ return _client.Get>("/v1/agent/checks").Execute(ct);
+ }
+
+ ///
+ /// Services returns the locally registered services
+ ///
+ /// A map of the registered services and service data
+ public Task>> Services(CancellationToken ct = default(CancellationToken))
+ {
+ return _client.Get>("/v1/agent/services").Execute(ct);
+ }
+
+ ///
+ /// Members returns the known gossip members. The WAN flag can be used to query a server for WAN members.
+ ///
+ /// An array of gossip peers
+ public Task> Members(bool wan, CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.Get("/v1/agent/members");
+ if (wan)
+ {
+ req.Params["wan"] = "1";
+ }
+ return req.Execute(ct);
+ }
+
+ ///
+ /// ServiceRegister is used to register a new service with the local agent
+ ///
+ /// A service registration object
+ /// An empty write result
+ public Task ServiceRegister(AgentServiceRegistration service, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.Put("/v1/agent/service/register", service).Execute(ct);
+ }
+
+ ///
+ /// ServiceRegister is used to register a new service with the local agent
+ ///
+ /// The service ID
+ /// An empty write result
+ public Task ServiceDeregister(string serviceID, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.PutNothing(string.Format("/v1/agent/service/deregister/{0}", serviceID)).Execute(ct);
+ }
+
+ ///
+ /// PassTTL is used to set a TTL check to the passing state
+ ///
+ /// The check ID
+ /// An optional, arbitrary string to write to the check status
+ public Task PassTTL(string checkID, string note, CancellationToken ct = default(CancellationToken))
+ {
+ return LegacyUpdateTTL(checkID, note, TTLStatus.Pass, ct);
+ }
+
+ ///
+ /// WarnTTL is used to set a TTL check to the warning state
+ ///
+ /// The check ID
+ /// An optional, arbitrary string to write to the check status
+ public Task WarnTTL(string checkID, string note, CancellationToken ct = default(CancellationToken))
+ {
+ return LegacyUpdateTTL(checkID, note, TTLStatus.Warn, ct);
+ }
+
+ ///
+ /// FailTTL is used to set a TTL check to the failing state
+ ///
+ /// The check ID
+ /// An optional, arbitrary string to write to the check status
+ public Task FailTTL(string checkID, string note, CancellationToken ct = default(CancellationToken))
+ {
+ return LegacyUpdateTTL(checkID, note, TTLStatus.Critical, ct);
+ }
+
+ ///
+ /// UpdateTTL is used to update the TTL of a check
+ ///
+ /// The check ID
+ /// An optional, arbitrary string to write to the check status
+ /// The state to set the check to
+ /// An empty write result
+ public Task UpdateTTL(string checkID, string output, TTLStatus status, CancellationToken ct = default(CancellationToken))
+ {
+ var u = new CheckUpdate
+ {
+ Status = status.Status,
+ Output = output
+ };
+ return _client.Put(string.Format("/v1/agent/check/update/{0}", checkID), u).Execute(ct);
+ }
+
+ private Task LegacyUpdateTTL(string checkID, string note, TTLStatus status, CancellationToken ct = default(CancellationToken))
+ {
+ var request = _client.PutNothing(string.Format("/v1/agent/check/{0}/{1}", status.LegacyStatus, checkID));
+ if (!string.IsNullOrEmpty(note))
+ {
+ request.Params.Add("note", note);
+ }
+ return request.Execute(ct);
+ }
+
+ ///
+ /// CheckRegister is used to register a new check with the local agent
+ ///
+ /// A check registration object
+ /// An empty write result
+ public Task CheckRegister(AgentCheckRegistration check, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.Put("/v1/agent/check/register", check).Execute(ct);
+ }
+
+ ///
+ /// CheckDeregister is used to deregister a check with the local agent
+ ///
+ /// The check ID to deregister
+ /// An empty write result
+ public Task CheckDeregister(string checkID, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.PutNothing(string.Format("/v1/agent/check/deregister/{0}", checkID)).Execute(ct);
+ }
+
+ ///
+ /// Join is used to instruct the agent to attempt a join to another cluster member
+ ///
+ /// The address to join to
+ /// Join the WAN pool
+ /// An empty write result
+ public Task Join(string addr, bool wan, CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.PutNothing(string.Format("/v1/agent/join/{0}", addr));
+ if (wan)
+ {
+ req.Params["wan"] = "1";
+ }
+ return req.Execute(ct);
+ }
+
+ ///
+ /// ForceLeave is used to have the agent eject a failed node
+ ///
+ /// The node name to remove. An attempt to eject a node that doesn't exist will still be successful
+ /// An empty write result
+ public Task ForceLeave(string node, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.PutNothing(string.Format("/v1/agent/force-leave/{0}", node)).Execute(ct);
+ }
+
+
+ ///
+ /// Leave is used to have the agent gracefully leave the cluster and shutdown
+ ///
+ /// An empty write result
+ public Task Leave(string node, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.PutNothing("/v1/agent/leave").Execute(ct);
+ }
+
+ ///
+ /// Reload triggers a configuration reload for the agent we are connected to.
+ ///
+ /// An empty write result
+ public Task Reload(string node, CancellationToken ct = default(CancellationToken))
+ {
+ return _client.PutNothing("/v1/agent/reload").Execute(ct);
+ }
+
+ ///
+ /// EnableServiceMaintenance toggles service maintenance mode on for the given service ID
+ ///
+ /// The service ID
+ /// An optional reason
+ /// An empty write result
+ public Task EnableServiceMaintenance(string serviceID, string reason, CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.PutNothing(string.Format("/v1/agent/service/maintenance/{0}", serviceID));
+ req.Params["enable"] = "true";
+ req.Params["reason"] = reason;
+ return req.Execute(ct);
+ }
+
+ ///
+ /// DisableServiceMaintenance toggles service maintenance mode off for the given service ID
+ ///
+ /// The service ID
+ /// An empty write result
+ public Task DisableServiceMaintenance(string serviceID, CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.PutNothing(string.Format("/v1/agent/service/maintenance/{0}", serviceID));
+ req.Params["enable"] = "false";
+ return req.Execute(ct);
+ }
+
+ ///
+ /// EnableNodeMaintenance toggles node maintenance mode on for the agent we are connected to
+ ///
+ /// An optional reason
+ /// An empty write result
+ public Task EnableNodeMaintenance(string reason, CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.PutNothing("/v1/agent/maintenance");
+ req.Params["enable"] = "true";
+ req.Params["reason"] = reason;
+ return req.Execute(ct);
+ }
+
+ ///
+ /// DisableNodeMaintenance toggles node maintenance mode off for the agent we are connected to
+ ///
+ /// An empty write result
+ public Task DisableNodeMaintenance(CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.PutNothing("/v1/agent/maintenance");
+ req.Params["enable"] = "false";
+ return req.Execute(ct);
+ }
+
+ ///
+ /// Monitor yields log lines to display streaming logs from the agent
+ /// Providing a CancellationToken can be used to close the connection and stop the
+ /// log stream, otherwise the log stream will time out based on the HTTP Client's timeout value.
+ ///
+ public async Task Monitor(LogLevel level = default(LogLevel), CancellationToken ct = default(CancellationToken))
+ {
+ var req = _client.Get("/v1/agent/monitor");
+ req.Params["loglevel"] = level.ToString().ToLowerInvariant();
+ var res = await req.ExecuteStreaming(ct).ConfigureAwait(false);
+ return new LogStream(res.Response);
+ }
+
+ public class LogStream : IEnumerable>, IDisposable
+ {
+ private Stream m_stream;
+ private StreamReader m_streamreader;
+ internal LogStream(Stream s)
+ {
+ m_stream = s;
+ m_streamreader = new StreamReader(s);
+ }
+
+ public void Dispose()
+ {
+ m_streamreader.Dispose();
+ m_stream.Dispose();
+ }
+
+ public IEnumerator> GetEnumerator()
+ {
+
+ while (!m_streamreader.EndOfStream)
+ {
+ yield return m_streamreader.ReadLineAsync();
+ }
+ }
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+ }
+ }
+
+ public partial class ConsulClient : IConsulClient
+ {
+ private Lazy _agent;
+
+ ///
+ /// Agent returns a handle to the agent endpoints
+ ///
+ public IAgentEndpoint Agent
+ {
+ get { return _agent.Value; }
+ }
+ }
}