/// <summary> /// Adds or updates a traffic manager rule. /// </summary> /// <param name="rule">The rule definition.</param> /// <param name="deferUpdate"> /// <para> /// Optionally defers expicitly notifying the <b>neon-proxy-manager</b> of the /// change until <see cref="Update()"/> is called or the <b>neon-proxy-manager</b> /// performs the periodic check for changes (which defaults to 60 seconds). You /// may consider passing <paramref name="deferUpdate"/><c>=true</c> when you are /// modifying a multiple rules at the same time to avoid making the proxy manager /// and proxy instances handle each rule change individually. /// </para> /// <para> /// Instead, you could pass <paramref name="deferUpdate"/><c>=true</c> for all of /// the rule changes and then call <see cref="Update()"/> afterwards. /// </para> /// </param> /// <returns> /// <c>true</c> if it existed and was updated, <b>false</b> /// if the traffic manager rule didn't already exist and was added. /// </returns> /// <exception cref="HiveDefinitionException">Thrown if the rule is not valid.</exception> public bool SetRule(TrafficRule rule, bool deferUpdate = false) { Covenant.Requires <ArgumentNullException>(rule != null); Covenant.Requires <ArgumentNullException>(HiveDefinition.IsValidName(rule.Name)); if (!IsPublic) { // Ensure that the [PublicPort] is disabled for non-public rules // just to be absolutely sure that these endpoints are not exposed // to the Internet for cloud deployments and to avoid operators // being freaked out if they see a non-zero port here. var httpRule = rule as TrafficHttpRule; if (httpRule != null) { foreach (var frontEnd in httpRule.Frontends) { frontEnd.PublicPort = 0; } } else { var tcpRule = rule as TrafficTcpRule; if (tcpRule != null) { foreach (var frontEnd in tcpRule.Frontends) { frontEnd.PublicPort = 0; } } } } // $todo(jeff.lill): // // We're going to minimially ensure that the rule is valid. It would // be better to do full server side validation. var context = new TrafficValidationContext(Name, GetSettings()) { ValidateCertificates = false, // Disable this because we didn't download the certs. ValidateResolvers = false }; rule.Validate(context); context.ThrowIfErrors(); // Publish the rule. var ruleKey = GetProxyRuleKey(rule.Name); var update = hive.Consul.Client.KV.Exists(ruleKey).Result; // Load the full proxy definition and hive certificates, add/replace // the rule being set and then verify that the rule is OK. var proxyDefinition = GetDefinition(); var certificates = hive.Certificate.GetAll(); proxyDefinition.Rules[rule.Name] = rule; proxyDefinition.Validate(certificates); var validationContext = proxyDefinition.Validate(certificates); validationContext.ThrowIfErrors(); // Save the rule to the hive and signal that the // load balancers need to be updated. hive.Consul.Client.KV.PutObject(ruleKey, rule, Formatting.Indented).Wait(); if (!deferUpdate) { Update(); } return(update); }