Skip to content

Commit

Permalink
Improve route form
Browse files Browse the repository at this point in the history
* Make "Split traffic across multiple services" a checkbox like "Secure route"
* Add consistent section headings for "Alernate Services" and "Security"
* Fix bug where `insecureEdgeTerminationPolicy` was initialized to an
  invalid value, causing an error creating edge terminated routes
* Fix a bug where the range slider was not properly initialized for
  existing values
  • Loading branch information
spadgett committed Dec 22, 2016
1 parent ddb780e commit b139986
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 73 deletions.
85 changes: 62 additions & 23 deletions app/scripts/directives/oscRouting.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,31 @@ angular.module("openshiftConsole")
hostReadOnly: "="
},
templateUrl: 'views/directives/osc-routing.html',
controller: function($scope) {
$scope.disableCertificateInputs = function() {
var termination = _.get($scope, 'route.tls.termination');
link: function(scope, element, attrs, formCtl) {
scope.form = formCtl;
scope.controls = {};
scope.options = {
secureRoute: false,
alternateServices: false
};

scope.disableWildcards = Constants.DISABLE_WILDCARD_ROUTES;
scope.disableCertificateInputs = function() {
var termination = _.get(scope, 'route.tls.termination');
return !termination || termination === 'passthrough';
};
$scope.insecureTrafficOptions = [

scope.insecureTrafficOptions = [
{value: '', label: 'None'},
{value: 'Allow', label: 'Allow'},
{value: 'Redirect', label: 'Redirect'}
];
},
link: function(scope, element, attrs, formCtl) {
scope.form = formCtl;
scope.controls = {};

scope.disableWildcards = Constants.DISABLE_WILDCARD_ROUTES;
if (!_.has(scope, 'route.tls.insecureEdgeTerminationPolicy')) {
// Initialize the value to the empty string so the option 'None' is
// shown in the select.
_.set(scope, 'route.tls.insecureEdgeTerminationPolicy', '');
}

// Use different patterns for validating hostnames if wildcard subdomains are supported.
if (scope.disableWildcards) {
Expand Down Expand Up @@ -119,6 +128,8 @@ angular.module("openshiftConsole")
return _.includes(iteratee, value, index + 1);
}).value();
formCtl.$setValidity("duplicateServices", !scope.duplicateServices.length);

scope.options.alternateServices = !_.isEmpty(alternateServices);
}, true);

var showCertificateWarning = function() {
Expand All @@ -140,52 +151,61 @@ angular.module("openshiftConsole")
// Show a warning if previously-set certificates won't be used because
// the TLS termination is now incompatible.
scope.$watch('route.tls.termination', function() {
scope.secureRoute = !!_.get(scope, 'route.tls.termination');
scope.options.secureRoute = !!_.get(scope, 'route.tls.termination');
scope.showCertificatesNotUsedWarning = showCertificateWarning();
});

var previousTermination;
scope.$watch('secureRoute', function(newValue, oldValue) {
scope.$watch('options.secureRoute', function(newValue, oldValue) {
if (newValue === oldValue) {
return;
}

// Set the default behavior of insecure connections to 'None'
if (newValue && !_.get(scope, 'route.tls.insecureEdgeTerminationPolicy')) {
_.set(scope, 'route.tls.insecureEdgeTerminationPolicy', scope.insecureTrafficOptions[0]);
}

var termination = _.get(scope, 'route.tls.termination');
if (!scope.securetRoute && termination) {
// Remember previous value if user switches back to secure.
previousTermination = termination;
delete scope.route.tls.termination;
}

if (scope.secureRoute && !termination) {
if (scope.options.secureRoute && !termination) {
// Restore previous termination value or default to edge if no previous value.
_.set(scope, 'route.tls.termination', previousTermination || 'edge');
}
});

scope.$watch('options.alternateServices', function(alternateServices, previousValue) {
if (alternateServices === previousValue) {
return;
}

if (!alternateServices) {
scope.route.alternateServices = [];
}

if (alternateServices && _.isEmpty(scope.route.alternateServices)) {
scope.addAlternateService();
}
});

scope.addAlternateService = function() {
scope.route.alternateServices = scope.route.alternateServices || [];
var firstUnselected = _.find(scope.services, function(service) {
return service !== scope.route.to.service && !_.some(scope.route.alternateServices, { service: service });
});

if (!_.has(scope, 'route.to.weight')) {
_.set(scope, 'route.to.weight', 1);
}

// Add a new value.
scope.route.alternateServices.push({
service: firstUnselected,
weight: 1
});

if (!_.has(scope, 'route.to.weight')) {
_.set(scope, 'route.to.weight', 1);
}
};

scope.weightAsPercentage = function(weight) {
scope.weightAsPercentage = function(weight, format) {
weight = weight || 0;

var total = _.get(scope, 'route.to.weight', 0);
Expand All @@ -198,10 +218,29 @@ angular.module("openshiftConsole")
}

var percentage = (weight / total) * 100;
return d3.round(percentage, 1) + '%';
return format ? (d3.round(percentage, 1) + '%') : percentage;
};

var initializingSlider = false;
scope.$watch('route.alternateServices.length', function(alternateServicesCount) {
if (alternateServicesCount === 0 && _.has(scope, 'route.to.weight')) {
// Reset the primary service weight. This rebalances the percentages when adding a new alternate service.
delete scope.route.to.weight;
}

if (alternateServicesCount === 1) {
initializingSlider = true;
scope.controls.rangeSlider = scope.weightAsPercentage(scope.route.to.weight);
}
});

scope.$watch('controls.rangeSlider', function(weight, previous) {
// Don't update the routes if we're setting the initial slider value.
if (initializingSlider) {
initializingSlider = false;
return;
}

if (weight === previous) {
return;
}
Expand Down
39 changes: 25 additions & 14 deletions app/views/directives/osc-routing.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,6 @@
</osc-routing-service>
</div>

<div ng-if="alternateServiceOptions.length && !route.alternateServices.length" class="form-group">
<a href="" ng-click="addAlternateService()">Split traffic across multiple services</a>
</div>

<!-- Target Port -->
<div ng-if="route.portOptions.length" class="form-group">
<label for="routeTargetPort">Target Port</label>
Expand All @@ -133,9 +129,23 @@
</div>
</div>


<!-- Alternate Services for A/B Traffic -->
<div ng-if="route.alternateServices.length">
<div ng-if="alternateServiceOptions.length">
<h3>Alternate Services</h3>
<div class="form-group">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="options.alternateServices" aria-describedby="secure-route-help">
Split traffic across multiple services
</label>
<div class="help-block">
Routes can direct traffic to multiple services for A/B testing. Each service has a weight
controlling how much traffic it gets.
</div>
</div>
</div>

<div ng-repeat="alternate in route.alternateServices" class="form-group">
<osc-routing-service model="alternate"
services="alternateServiceOptions"
Expand All @@ -162,12 +172,12 @@ <h3>Service Weights</h3>
<div class="weight-slider-values">
<div>
<span class="service-name">{{route.to.service.metadata.name}}</span>
<span class="weight-percentage">{{weightAsPercentage(route.to.weight)}}</span>
<span class="weight-percentage">{{weightAsPercentage(route.to.weight, true)}}</span>
</div>
<div>
<span class="weight-percentage hidden-xs">{{weightAsPercentage(route.alternateServices[0].weight)}}</span>
<span class="weight-percentage hidden-xs">{{weightAsPercentage(route.alternateServices[0].weight, true)}}</span>
<span class="service-name">{{route.alternateServices[0].service.metadata.name}}</span>
<span class="weight-percentage visible-xs-inline">{{weightAsPercentage(route.alternateServices[0].weight)}}</span>
<span class="weight-percentage visible-xs-inline">{{weightAsPercentage(route.alternateServices[0].weight, true)}}</span>
</div>
</div>
<label class="sr-only" for="weight-slider">Service {{route.to.service.metadata.name}} Weight</label>
Expand Down Expand Up @@ -195,17 +205,18 @@ <h3>Service Weights</h3>
</div>
</div>

<h3>Security</h3>
<div class="checkbox">
<label>
<input type="checkbox" ng-model="secureRoute" aria-describedby="secure-route-help">
<input type="checkbox" ng-model="options.secureRoute" aria-describedby="secure-route-help">
Secure route
</label>
<div class="help-block" id="secure-route-help">
Routes can be secured using several TLS termination types for serving certificates.
</div>
</div>

<div ng-show="secureRoute">
<div ng-show="options.secureRoute">
<!-- TLS Termination -->
<div class="form-group">
<label for="tlsTermination">TLS Termination</label>
Expand All @@ -221,9 +232,9 @@ <h3>Service Weights</h3>
</div>

<!-- Insecure Edge Termination Policy -->
<div class="form-group">
<div class="form-group" ng-if="route.tls.termination === 'edge'">
<label for="insecureTraffic">Insecure Traffic</label>
<ui-select ng-model="route.tls.insecureEdgeTerminationPolicy" ng-disabled="route.tls.termination !== 'edge'" input-id="insecureTraffic" aria-describedby="route-insecure-policy-help" search-enabled="false">
<ui-select ng-model="route.tls.insecureEdgeTerminationPolicy" input-id="insecureTraffic" aria-describedby="route-insecure-policy-help" search-enabled="false">
<ui-select-match>{{$select.selected.label}}</ui-select-match>
<ui-select-choices repeat="option.value as option in insecureTrafficOptions">
{{option.label}}
Expand Down Expand Up @@ -300,8 +311,8 @@ <h3>Certificates</h3>
not already showing the generic certificate warning above. -->
<div ng-if="route.tls.destinationCACertificate && route.tls.termination !== 'reencrypt' && !showCertificatesNotUsedWarning" class="has-warning">
<span class="help-block">
The destination CA certificate will not be used. Destination CA
certificates are only used for re-encrypt termination.
The destination CA certificate will be removed from the route.
Destination CA certificates are only used for re-encrypt termination.
</span>
</div>
</div>
Expand Down
53 changes: 29 additions & 24 deletions dist/scripts/scripts.js
Original file line number Diff line number Diff line change
Expand Up @@ -9905,11 +9905,14 @@ routingDisabled:"=",
hostReadOnly:"="
},
templateUrl:"views/directives/osc-routing.html",
controller:[ "$scope", function(a) {
a.disableCertificateInputs = function() {
var b = _.get(a, "route.tls.termination");
return !b || "passthrough" === b;
}, a.insecureTrafficOptions = [ {
link:function(b, c, d, e) {
b.form = e, b.controls = {}, b.options = {
secureRoute:!1,
alternateServices:!1
}, b.disableWildcards = a.DISABLE_WILDCARD_ROUTES, b.disableCertificateInputs = function() {
var a = _.get(b, "route.tls.termination");
return !a || "passthrough" === a;
}, b.insecureTrafficOptions = [ {
value:"",
label:"None"
}, {
Expand All @@ -9918,10 +9921,7 @@ label:"Allow"
}, {
value:"Redirect",
label:"Redirect"
} ];
} ],
link:function(b, c, d, e) {
b.form = e, b.controls = {}, b.disableWildcards = a.DISABLE_WILDCARD_ROUTES, b.disableWildcards ? b.hostnamePattern = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/ :b.hostnamePattern = /^(\*(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))+|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)$/;
} ], _.has(b, "route.tls.insecureEdgeTerminationPolicy") || _.set(b, "route.tls.insecureEdgeTerminationPolicy", ""), b.disableWildcards ? b.hostnamePattern = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$/ :b.hostnamePattern = /^(\*(\.[a-z0-9]([-a-z0-9]*[a-z0-9]))+|[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)$/;
var f = function(a) {
a && (b.unnamedServicePort = 1 === a.spec.ports.length && !a.spec.ports[0].name, a.spec.ports.length && !b.unnamedServicePort ? b.route.portOptions = _.map(a.spec.ports, function(a) {
return {
Expand All @@ -9937,42 +9937,47 @@ return a === b;
}), b.$watch("route.alternateServices", function(a) {
b.duplicateServices = _(a).map("service").filter(function(a, b, c) {
return _.includes(c, a, b + 1);
}).value(), e.$setValidity("duplicateServices", !b.duplicateServices.length);
}).value(), e.$setValidity("duplicateServices", !b.duplicateServices.length), b.options.alternateServices = !_.isEmpty(a);
}, !0);
var g = function() {
return !!b.route.tls && ((!b.route.tls.termination || "passthrough" === b.route.tls.termination) && (b.route.tls.certificate || b.route.tls.key || b.route.tls.caCertificate || b.route.tls.destinationCACertificate));
};
b.$watch("route.tls.termination", function() {
b.secureRoute = !!_.get(b, "route.tls.termination"), b.showCertificatesNotUsedWarning = g();
b.options.secureRoute = !!_.get(b, "route.tls.termination"), b.showCertificatesNotUsedWarning = g();
});
var h;
b.$watch("secureRoute", function(a, c) {
b.$watch("options.secureRoute", function(a, c) {
if (a !== c) {
a && !_.get(b, "route.tls.insecureEdgeTerminationPolicy") && _.set(b, "route.tls.insecureEdgeTerminationPolicy", b.insecureTrafficOptions[0]);
var d = _.get(b, "route.tls.termination");
!b.securetRoute && d && (h = d, delete b.route.tls.termination), b.secureRoute && !d && _.set(b, "route.tls.termination", h || "edge");
!b.securetRoute && d && (h = d, delete b.route.tls.termination), b.options.secureRoute && !d && _.set(b, "route.tls.termination", h || "edge");
}
}), b.$watch("options.alternateServices", function(a, c) {
a !== c && (a || (b.route.alternateServices = []), a && _.isEmpty(b.route.alternateServices) && b.addAlternateService());
}), b.addAlternateService = function() {
b.route.alternateServices = b.route.alternateServices || [];
var a = _.find(b.services, function(a) {
return a !== b.route.to.service && !_.some(b.route.alternateServices, {
service:a
});
});
b.route.alternateServices.push({
_.has(b, "route.to.weight") || _.set(b, "route.to.weight", 1), b.route.alternateServices.push({
service:a,
weight:1
}), _.has(b, "route.to.weight") || _.set(b, "route.to.weight", 1);
}, b.weightAsPercentage = function(a) {
});
}, b.weightAsPercentage = function(a, c) {
a = a || 0;
var c = _.get(b, "route.to.weight", 0);
var d = _.get(b, "route.to.weight", 0);
if (_.each(b.route.alternateServices, function(a) {
c += _.get(a, "weight", 0);
}), !c) return "";
var d = a / c * 100;
return d3.round(d, 1) + "%";
}, b.$watch("controls.rangeSlider", function(a, c) {
a !== c && (a = parseInt(a, 10), _.set(b, "route.to.weight", a), _.set(b, "route.alternateServices[0].weight", 100 - a));
d += _.get(a, "weight", 0);
}), !d) return "";
var e = a / d * 100;
return c ? d3.round(e, 1) + "%" :e;
};
var i = !1;
b.$watch("route.alternateServices.length", function(a) {
0 === a && _.has(b, "route.to.weight") && delete b.route.to.weight, 1 === a && (i = !0, b.controls.rangeSlider = b.weightAsPercentage(b.route.to.weight));
}), b.$watch("controls.rangeSlider", function(a, c) {
return i ? void (i = !1) :void (a !== c && (a = parseInt(a, 10), _.set(b, "route.to.weight", a), _.set(b, "route.alternateServices[0].weight", 100 - a)));
});
}
};
Expand Down
Loading

0 comments on commit b139986

Please sign in to comment.