From a1fc2debeb849e00734c951f48076b1cb532111d Mon Sep 17 00:00:00 2001 From: Marcel Dias Date: Thu, 5 Oct 2017 14:32:51 -0300 Subject: [PATCH 1/5] Add Upstreams --- src/html/index.html | 5 ++ src/html/upstreams/form.html | 45 ++++++++++++++++ src/html/upstreams/index.html | 93 +++++++++++++++++++++++++++++++++ src/js/app.js | 21 ++++++++ src/js/controllers/upstream.js | 50 ++++++++++++++++++ src/js/controllers/upstreams.js | 71 +++++++++++++++++++++++++ 6 files changed, 285 insertions(+) create mode 100644 src/html/upstreams/form.html create mode 100644 src/html/upstreams/index.html create mode 100644 src/js/controllers/upstream.js create mode 100644 src/js/controllers/upstreams.js diff --git a/src/html/index.html b/src/html/index.html index 4ad72cc..16820ef 100644 --- a/src/html/index.html +++ b/src/html/index.html @@ -42,6 +42,11 @@ https +
  • + + input + +
  • diff --git a/src/html/upstreams/form.html b/src/html/upstreams/form.html new file mode 100644 index 0000000..384547c --- /dev/null +++ b/src/html/upstreams/form.html @@ -0,0 +1,45 @@ +
    +

    {{title}}

    + +
    +
    +
    +

    + The upstream object represents a virtual hostname and can be used to loadbalance incoming requests over multiple services (targets). So for example an upstream named service.v1.xyz with an API object created with an upstream_url=https://service.v1.xyz/some/path. Requests for this API would be proxied to the targets defined within the upstream. +

    + +

    + Checkout Kong documentation for the meaning of the form parameters. +

    +
    +
    +
    +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    +
    + +
    +
    + +
    +
    +
    diff --git a/src/html/upstreams/index.html b/src/html/upstreams/index.html new file mode 100644 index 0000000..e291089 --- /dev/null +++ b/src/html/upstreams/index.html @@ -0,0 +1,93 @@ +
    + + + +

    + Upstreams +

    + +

    + +

    + +
    +

    + You haven't defined any Upstream in Kong yet. +

    +

    + + add_box + Add Upstream + +

    +
    + + + + + + + + + + + + + + + + + + + + + +
    IDNameSlotsCreated
    {{upstream.id}}{{upstream.name}}{{upstream.slots}}{{upstream.created_at | date}} + + mode_edit + + + delete + +
    +
    + + + diff --git a/src/js/app.js b/src/js/app.js index 4669f0d..bb119a8 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -195,6 +195,27 @@ var app = angular.module('app', ['ngRoute', 'ngCookies', 'ngAnimate', 'ngSanitiz isAppReady: isAppReady, } }) + .when('/upstreams', { + templateUrl: 'html/upstreams/index.html', + controller: 'UpstreamsController', + resolve: { + isAppReady: isAppReady + } + }) + .when('/upstreams/add', { + templateUrl: 'html/upstreams/form.html', + controller: 'UpstreamController', + resolve: { + isAppReady: isAppReady + } + }) + .when('/upstreams/:id', { + templateUrl: 'html/upstreams/form.html', + controller: 'UpstreamController', + resolve: { + isAppReady: isAppReady, + } + }) .otherwise({redirectTo: '/'}); }]) .run(['$rootScope', 'Kong', '$location', function($rootScope, Kong, $location) { diff --git a/src/js/controllers/upstream.js b/src/js/controllers/upstream.js new file mode 100644 index 0000000..8b5d135 --- /dev/null +++ b/src/js/controllers/upstream.js @@ -0,0 +1,50 @@ +angular.module('app').controller("UpstreamController", ["$scope", "Kong", "$location", "$routeParams", "Alert", "$route", function ($scope, Kong, $location, $routeParams, Alert, $route) { + + $scope.upstream = {}; + + onInit(); + + function onInit() { + if ($routeParams.id) { + Kong.get('/upstreams/' + $routeParams.id).then( function(data) { + $scope.upstream = data; + }); + $scope.title = "Edit Upstream"; + $scope.action = "Save"; + $scope.location = $location; + } else { + $scope.title = "Add a Upstream"; + $scope.action = "Create"; + } + } + + $scope.isEdit = function () { + return $routeParams.id != null; + } + + $scope.save = function () { + if ( $scope.isEdit() ) { + //seting orderlist to a empty list will generate new orderlist. + //This is needed if we update the number of slots + //Also orderlist will be removed in Kong 0.12. See https://github.com/Mashape/kong/issues/2933#issuecomment-334520555 + $scope.upstream.orderlist = []; + Kong.put('/upstreams', $scope.upstream).then(function () { + Alert.success('Upstream updated'); + $scope.error = {}; + }, function (response) { + $scope.error = response.data; + }); + } else { + Kong.post('/upstreams', $scope.upstream).then(function () { + Alert.success('Upstream created'); + // clearing inputs. + $scope.upstream = {}; + + // clearing errors. + $scope.error = {}; + }, function (response) { + $scope.error = response.data; + }); + } + }; +}]); diff --git a/src/js/controllers/upstreams.js b/src/js/controllers/upstreams.js new file mode 100644 index 0000000..7e3da81 --- /dev/null +++ b/src/js/controllers/upstreams.js @@ -0,0 +1,71 @@ +angular.module('app').controller("UpstreamsController", ["$scope", "Kong", function ($scope, Kong) { + $scope.upstreams = []; + $scope.total = null; + $scope.offset = null; + $scope.searchResults = {}; + $scope.searching = false; + + var loaded_pages = []; + + $scope.loadMore = function() { + var page = '/upstreams?'; + if ($scope.offset) { + page += 'offset=' + $scope.offset + '&'; + } + if (loaded_pages.indexOf(page) !== -1) { + return; + } + loaded_pages.push(page); + + Kong.get(page).then(function(collection) { + if ($scope.total === null) { + $scope.total = 0; + } + $scope.upstreams.push.apply($scope.upstreams, collection.data); + $scope.total += collection.total; + $scope.offset = collection.offset ? collection.offset : null; + }); + }; + $scope.loadMore(); + + $scope.showDeleteModal = function (id, name) { + $scope.current = {id: id, name: name}; + $('#deleteUpstream').openModal(); + }; + + $scope.abortDelete = function () { + $('#deleteUpstream').closeModal(); + }; + + $scope.performDelete = function () { + $('#deleteUpstream').closeModal(); + Kong.delete('/upstreams/' + $scope.current.id).then(function (response) { + $scope.total -= 1; + $scope.upstreams.forEach(function(element, index) { + if (element.id === $scope.current.id) { + $scope.upstreams.splice(index, 1); + } + }); + }); + }; + + $scope.searchUpstreams = function() { + $scope.searchResults = {}; + var input = $scope.searchInput; + if (!input) { + $scope.searching = false; + return; + } + + $scope.searching = true; + + var populateResults = function(response) { + angular.forEach(response.data, function(value) { + $scope.searchResults[value.id] = value.name; + }); + }; + + Kong.get('/upstreams?id=' + input).then(populateResults); + Kong.get('/upstreams?name=' + input).then(populateResults); + }; +}]); From 2f8d6e890df4732ee40e9bb1981b11feba5b094a Mon Sep 17 00:00:00 2001 From: Marcel Dias Date: Sun, 29 Oct 2017 01:50:12 -0400 Subject: [PATCH 2/5] Add targets html and Controllers --- src/html/targets/form.html | 58 +++++++++++++++++++++++ src/html/targets/index.html | 87 +++++++++++++++++++++++++++++++++++ src/js/controllers/target.js | 55 ++++++++++++++++++++++ src/js/controllers/targets.js | 75 ++++++++++++++++++++++++++++++ 4 files changed, 275 insertions(+) create mode 100644 src/html/targets/form.html create mode 100644 src/html/targets/index.html create mode 100644 src/js/controllers/target.js create mode 100644 src/js/controllers/targets.js diff --git a/src/html/targets/form.html b/src/html/targets/form.html new file mode 100644 index 0000000..2e3ab7e --- /dev/null +++ b/src/html/targets/form.html @@ -0,0 +1,58 @@ +
    +

    {{title}}

    + +
    +
    +
    +

    + A target is an ip address/hostname with a port that identifies an instance of a backend service. Every upstream can have many targets, and the targets can be dynamically added. Changes are effectuated on the fly. + Because the upstream maintains a history of target changes, the targets cannot be deleted or modified. To disable a target, post a new one with weight=0; alternatively, use the DELETE convenience method to accomplish the same. + The current target object definition is the one with the latest created_at. +

    + +

    + Checkout Kong documentation for the meaning of the form parameters. +

    +
    +
    +
    +
    +
    + + +
    +
    + + + +
    +
    + + + +
    +
    + + + +
    + +
    + +
    +
    + +
    +
    +
    diff --git a/src/html/targets/index.html b/src/html/targets/index.html new file mode 100644 index 0000000..56d295a --- /dev/null +++ b/src/html/targets/index.html @@ -0,0 +1,87 @@ +
    + +
      + +
    • + + add + +
    • +
    + +

    + {{title}} +

    + +

    + +

    + +
    +

    + You haven't defined any Target for {{upstream.name}} +

    +

    + + add_box + Add Target + +

    +
    + + + + + + + + + + + + + + + + + + + + + +
    IDTargetWeightCreated
    {{target.id}}{{target.target}}{{target.weight}}{{target.created_at | date}} + + delete + +
    + + +
    + + + diff --git a/src/js/controllers/target.js b/src/js/controllers/target.js new file mode 100644 index 0000000..eb0075e --- /dev/null +++ b/src/js/controllers/target.js @@ -0,0 +1,55 @@ +angular.module('app').controller("TargetController", ["$scope", "Kong", "$location", "$routeParams", "Alert", "$route", function ($scope, Kong, $location, $routeParams, Alert, $route) { + + $scope.target = {}; + $scope.upstream = {}; + + onInit(); + + function onInit() { + console.log('upstream_id = ' + $routeParams.upstream_id); + Kong.get('/upstreams/' + $routeParams.upstream_id).then( function(data) { + $scope.upstream = data; + }); + + $scope.target.upstream_id = $routeParams.upstream_id; + + if ($routeParams.id) { + Kong.get('/upstreams/' + $routeParams.upstream_id + '/targets/' + $routeParams.id).then( function(data) { + $scope.target = data; + }); + $scope.title = "Edit Target"; + $scope.action = "Save"; + $scope.location = $location; + } else { + $scope.title = "Add a Target"; + $scope.action = "Create"; + } + } + + $scope.isEdit = function () { + return $routeParams.id != null; + } + + $scope.save = function () { + if ( $scope.isEdit() ) { + Kong.put('/upstreams/' + $scope.upstream.id + '/targets', $scope.target).then(function () { + Alert.success('Target updated'); + $scope.error = {}; + }, function (response) { + $scope.error = response.data; + }); + } else { + Kong.post('/upstreams/' + $scope.upstream.id + '/targets', $scope.target).then(function () { + Alert.success('Target created'); + // clearing inputs. + $scope.target = {}; + $scope.target.upstream_id = $scope.upstream.id; + + // clearing errors. + $scope.error = {}; + }, function (response) { + $scope.error = response.data; + }); + } + }; +}]); diff --git a/src/js/controllers/targets.js b/src/js/controllers/targets.js new file mode 100644 index 0000000..e0d37ee --- /dev/null +++ b/src/js/controllers/targets.js @@ -0,0 +1,75 @@ +angular.module('app').controller("TargetsController", ["$scope", "Kong", "$routeParams", "upstream", function ($scope, Kong, $routeParams, upstream) { + $scope.targets = []; + $scope.total = null; + $scope.offset = null; + $scope.searchResults = {}; + $scope.searching = false; + $scope.upstream = upstream; + $scope.active = true; + $scope.title = ''; + + var loaded_pages = []; + + onInit(); + + function onInit() { + $scope.title = 'Targets of ' + upstream.name; + } + + $scope.loadMore = function() { + var page = '/upstreams/' + upstream.id + '/targets'; + if ($scope.active) { + page += "/active"; + } + if ($scope.offset) { + page += '?offset=' + $scope.offset + '&'; + } + if (loaded_pages.indexOf(page) !== -1) { + return; + } + loaded_pages.push(page); + + Kong.get(page).then(function(collection) { + if ($scope.total === null) { + $scope.total = 0; + } + $scope.targets.push.apply($scope.targets, collection.data); + $scope.total += collection.total; + $scope.offset = collection.offset ? collection.offset : null; + }); + }; + $scope.loadMore(); + + $scope.test = function() { + console.log('active == ' + $scope.active); + } + + $scope.reloadList = function() { + $scope.targets = []; + $scope.total = null; + $scope.offset = null; + loaded_pages = []; + $scope.loadMore(); + } + + $scope.showDeleteModal = function (id, name, upstream_id) { + $scope.current = {id: id, name: name, upstream_id : upstream_id}; + $('#deleteTarget').openModal(); + }; + + $scope.abortDelete = function () { + $('#deleteTarget').closeModal(); + }; + + $scope.performDelete = function () { + $('#deleteTarget').closeModal(); + Kong.delete('/upstreams/' + $scope.current.upstream_id + '/targets/' + $scope.current.id ).then(function (response) { + $scope.total -= 1; + $scope.targets.forEach(function(element, index) { + if (element.id === $scope.current.id) { + $scope.targets.splice(index, 1); + } + }); + }); + }; +}]); From c19c4ca6b894aec53d150836a1b4bfbc4fd61984 Mon Sep 17 00:00:00 2001 From: Marcel Dias Date: Sun, 29 Oct 2017 01:51:55 -0400 Subject: [PATCH 3/5] Add targets routes --- src/js/app.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/js/app.js b/src/js/app.js index bb119a8..0375528 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -216,6 +216,24 @@ var app = angular.module('app', ['ngRoute', 'ngCookies', 'ngAnimate', 'ngSanitiz isAppReady: isAppReady, } }) + .when('/upstreams/:upstream_id/targets', { + templateUrl: 'html/targets/index.html', + controller: 'TargetsController', + resolve: { + isAppReady: isAppReady, + upstream: ['Kong', '$route', function (Kong, $route) { + var id = $route.current.params.upstream_id; + return Kong.get('/upstreams/' + id); + }] + } + }) + .when('/upstreams/:upstream_id/targets/add', { + templateUrl: 'html/targets/form.html', + controller: 'TargetController', + resolve: { + isAppReady: isAppReady + } + }) .otherwise({redirectTo: '/'}); }]) .run(['$rootScope', 'Kong', '$location', function($rootScope, Kong, $location) { From 5045c4dc189ff7a59d046f591af054288fed47ad Mon Sep 17 00:00:00 2001 From: Marcel Dias Date: Sun, 29 Oct 2017 01:52:31 -0400 Subject: [PATCH 4/5] Add navigation between upstream and targets --- src/html/upstreams/form.html | 15 ++++++++++++++- src/html/upstreams/index.html | 5 ++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/html/upstreams/form.html b/src/html/upstreams/form.html index 384547c..bee96dd 100644 --- a/src/html/upstreams/form.html +++ b/src/html/upstreams/form.html @@ -33,7 +33,20 @@

    {{title}}

    -
    + + + +
    diff --git a/src/html/upstreams/index.html b/src/html/upstreams/index.html index e291089..59427f8 100644 --- a/src/html/upstreams/index.html +++ b/src/html/upstreams/index.html @@ -51,7 +51,7 @@

    - +
    @@ -69,6 +69,9 @@

    ID{{upstream.slots}} {{upstream.created_at | date}} + + input + mode_edit From 65c2b9c906b303442bb517ead0c07b6e7efc0ea3 Mon Sep 17 00:00:00 2001 From: Marcel Dias Date: Sun, 29 Oct 2017 02:04:18 -0400 Subject: [PATCH 5/5] Remove unused search method --- src/js/controllers/certificates.js | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/js/controllers/certificates.js b/src/js/controllers/certificates.js index 03e27f7..435b3c7 100644 --- a/src/js/controllers/certificates.js +++ b/src/js/controllers/certificates.js @@ -48,23 +48,4 @@ angular.module('app').controller("CertificatesController", ["$scope", "Kong", fu }); }); }; - - $scope.searchCertificates = function() { - $scope.searchResults = {}; - var input = $scope.searchInput; - if (!input) { - $scope.searching = false; - return; - } - - $scope.searching = true; - - var populateResults = function(response) { - angular.forEach(response.data, function(value) { - $scope.searchResults[value.id] = value.id; - }); - }; - - Kong.get('/certificates?id=' + input).then(populateResults); - }; }]);