Merge ~bjornt/maas:peer-proxy-ui into maas:master

Proposed by Björn Tillenius
Status: Merged
Approved by: Björn Tillenius
Approved revision: 4b3a4a04c6ae0f0afc967f301d873f130e1d4f28
Merge reported by: MAAS Lander
Merged at revision: not available
Proposed branch: ~bjornt/maas:peer-proxy-ui
Merge into: maas:master
Diff against target: 582 lines (+410/-14)
10 files modified
Makefile (+1/-0)
src/maasserver/forms/__init__.py (+11/-2)
src/maasserver/static/js/angular/directives/proxy_settings.js (+41/-0)
src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js (+190/-0)
src/maasserver/static/partials/proxy-settings.html (+48/-0)
src/maasserver/templates/maasserver/settings.html (+38/-4)
src/maasserver/views/combo.py (+1/-0)
src/maasserver/views/settings.py (+22/-4)
src/maasserver/views/tests/test_settings.py (+45/-2)
src/maastesting/karma.conf.js (+13/-2)
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Andres Rodriguez (community) Needs Fixing
Review via email: mp+327591@code.launchpad.net

Commit message

Change the proxy settings UI to enable configuring a peer proxy.

The network part of the settings page was split into "proxy", "ntp", and "dns", since it was getting too big.

Description of the change

The UI for setting proxy uses angular, so that the widget gets a bit more dynamic and shows the field for proxy URL only when needed. It still renders the required input fields so that the django form still is used to update the proxy settings. Converting it fully to angular was too much work.

Note that the single Javascript test I added is disabled. I couldn't get the tests to work. I'm proposing this for merge anyway, so that the rest of the code can be reviewed, and for someone else to figure out how to get the Javascript tests to work.

The problem I had with the Javascript tests is that the scope doesn't seem to be connected to the template. Inside the template, all scope variables are empty for some reason.

Note also that the UI needs some love to make it look nicer. I wanted to get some general feedback fore spending time on that, though.

To post a comment you must log in.
Revision history for this message
Lee Trager (ltrager) wrote :

I really like splitting NTP and DNS into different sections, it makes the page much easier to read. I think we may want to use a drop down to select the proxy mode. The text field would be disabled for don't use and built-in. I'd ask Maria from design this before reworking incase I'm wrong.

I poked around and can't figure out why MAAS.templates is currently broken and wasn't able to come up with anything, Blake might know.

Revision history for this message
Andres Rodriguez (andreserl) wrote :
Download full text (6.1 KiB)

Maria's design and preference is what we have, but I'll talk to her
tomorrow!

On Fri, Jul 21, 2017 at 1:45 AM Lee Trager <email address hidden> wrote:

> I really like splitting NTP and DNS into different sections, it makes the
> page much easier to read. I think we may want to use a drop down to select
> the proxy mode. The text field would be disabled for don't use and
> built-in. I'd ask Maria from design this before reworking incase I'm wrong.
>
> I poked around and can't figure out why MAAS.templates is currently broken
> and wasn't able to come up with anything, Blake might know.
>
> Diff comments:
>
> > diff --git
> a/src/maasserver/static/js/angular/directives/proxy_settings.js
> b/src/maasserver/static/js/angular/directives/proxy_settings.js
> > new file mode 100644
> > index 0000000..0850058
> > --- /dev/null
> > +++ b/src/maasserver/static/js/angular/directives/proxy_settings.js
> > @@ -0,0 +1,43 @@
> > +/* Copyright 2018 Canonical Ltd. This software is licensed under the
>
> Pulling code from the future? ;)
>
> > + * GNU Affero General Public License version 3 (see the file LICENSE).
> > + *
> > + * Proxy settings directive.
> > +*/
> > +
> > +angular.module('MAAS').directive('maasProxySettings', [
> > + '$sce', 'ConfigsManager', 'ManagerHelperService', 'JSONService',
> > + function($sce, ConfigsManager, ManagerHelperService, JSONService) {
> > + return {
> > + restrict: "E",
> > + scope: {},
> > + templateUrl: 'static/partials/proxy-settings.html',
> > + controller: function($scope, $rootScope, $element,
> $document) {
> > + $scope.loading = true;
> > + $scope.configManager = ConfigsManager;
> > + var managers = [ConfigsManager];
> > + ManagerHelperService.loadManagers(
> > + $scope, managers).then(function() {
> > + $scope.loading = false;
> > + $scope.httpProxy = ConfigsManager.getItemFromList(
> > + "http_proxy");
> > + $scope.enableHttpProxy =
> ConfigsManager.getItemFromList(
> > + "enable_http_proxy");
> > + $scope.usePeerProxy =
> ConfigsManager.getItemFromList(
> > + "use_peer_proxy");
> > + if ($scope.enableHttpProxy.value) {
> > + if ($scope.httpProxy.value) {
> > + if ($scope.usePeerProxy.value) {
> > + $scope.proxy_type = "peer-proxy";
> > + } else {
> > + $scope.proxy_type = "external-proxy";
> > + }
> > + } else {
> > + $scope.proxy_type = "builtin-proxy";
> > + }
> > + } else {
> > + $scope.proxy_type = "no-proxy";
> > + }
> > + });
> > + }
> > + };
> > + }]);
> > diff --git
> a/src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js
> b/src/maasserver/static/js/angula...

Read more...

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks like your using "{{ }}" in the angular directives in the HTML. I am very surprised that it works, since we set the template tag parser differently in MAAS so it works with Django. "{{ }}" is also used by Django, so we change it to "{$ $}".

@Lee - The issue is that you need the new dependency. So if you do "make clean && make" you would get the new dependency.

review: Needs Fixing
Revision history for this message
Blake Rouse (blake-rouse) wrote :

Also looks like you have debugger statement in JS test.

./src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js
      62: Unexpected 'debugger'.
      62: Line contains a call to debugger.
Makefile:336: recipe for target 'lint-js' failed
make: *** [lint-js] Error 123

review: Needs Fixing
Revision history for this message
Andres Rodriguez (andreserl) wrote :

A few inline fixes wrt wording.

review: Needs Fixing
Revision history for this message
Björn Tillenius (bjornt) wrote :

> Looks like your using "{{ }}" in the angular directives in the HTML. I am very
> surprised that it works, since we set the template tag parser differently in
> MAAS so it works with Django. "{{ }}" is also used by Django, so we change it
> to "{$ $}".
>
> @Lee - The issue is that you need the new dependency. So if you do "make clean
> && make" you would get the new dependency.

Oh. Yeah, it seems to work with {{ }} as well, but I've changed it to {$ $} now. I was hoping that it would be the cause for the tests not working, but I still can't get the tests to work.

Revision history for this message
Björn Tillenius (bjornt) wrote :

> Also looks like you have debugger statement in JS test.
>
> ./src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js
> 62: Unexpected 'debugger'.
> 62: Line contains a call to debugger.
> Makefile:336: recipe for target 'lint-js' failed
> make: *** [lint-js] Error 123

Fixed. I tried to debug the tests, but had no luck doing so.

Revision history for this message
Björn Tillenius (bjornt) wrote :

I addressed all the inlines comments. Will work on adding more Javascript tests, since Blake provided a patch to get the tests working.

Revision history for this message
Björn Tillenius (bjornt) wrote :

I've pushed the Javascript tests now, so it's ready for re-review.

Revision history for this message
Blake Rouse (blake-rouse) wrote :

Looks good other then the "{{}}" which should be fixed before landing this.

review: Approve
Revision history for this message
Björn Tillenius (bjornt) wrote :

I replaced {{ }} with {$ $}. I also addressed the review comments from design as well.

Revision history for this message
MAAS Lander (maas-lander) wrote :
~bjornt/maas:peer-proxy-ui updated
4b3a4a0... by Björn Tillenius

Format imports.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/Makefile b/Makefile
index 488fa82..9bbab61 100644
--- a/Makefile
+++ b/Makefile
@@ -187,6 +187,7 @@ define karma-deps
187 karma-opera-launcher@0.3.0187 karma-opera-launcher@0.3.0
188 karma-phantomjs-launcher@0.2.3188 karma-phantomjs-launcher@0.2.3
189 karma-failed-reporter@0.0.3189 karma-failed-reporter@0.0.3
190 karma-ng-html2js-preprocessor@1.0.0
190 phantomjs@2.1.7191 phantomjs@2.1.7
191endef192endef
192193
diff --git a/src/maasserver/forms/__init__.py b/src/maasserver/forms/__init__.py
index a7314d0..35832d6 100644
--- a/src/maasserver/forms/__init__.py
+++ b/src/maasserver/forms/__init__.py
@@ -1418,12 +1418,21 @@ class MAASForm(ConfigForm):
1418 enable_analytics = get_config_field('enable_analytics')1418 enable_analytics = get_config_field('enable_analytics')
14191419
14201420
1421class NetworkForm(ConfigForm):1421class ProxyForm(ConfigForm):
1422 """Settings page, Network section."""1422 """Settings page, Proxy section."""
1423 enable_http_proxy = get_config_field('enable_http_proxy')1423 enable_http_proxy = get_config_field('enable_http_proxy')
1424 use_peer_proxy = get_config_field('use_peer_proxy')
1424 http_proxy = get_config_field('http_proxy')1425 http_proxy = get_config_field('http_proxy')
1426
1427
1428class DNSForm(ConfigForm):
1429 """Settings page, DNS section."""
1425 upstream_dns = get_config_field('upstream_dns')1430 upstream_dns = get_config_field('upstream_dns')
1426 dnssec_validation = get_config_field('dnssec_validation')1431 dnssec_validation = get_config_field('dnssec_validation')
1432
1433
1434class NTPForm(ConfigForm):
1435 """Settings page, NTP section."""
1427 ntp_servers = get_config_field('ntp_servers')1436 ntp_servers = get_config_field('ntp_servers')
1428 ntp_external_only = get_config_field('ntp_external_only')1437 ntp_external_only = get_config_field('ntp_external_only')
14291438
diff --git a/src/maasserver/static/js/angular/directives/proxy_settings.js b/src/maasserver/static/js/angular/directives/proxy_settings.js
1430new file mode 1006441439new file mode 100644
index 0000000..3e97777
--- /dev/null
+++ b/src/maasserver/static/js/angular/directives/proxy_settings.js
@@ -0,0 +1,41 @@
1/* Copyright 2017 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *
4 * Proxy settings directive.
5*/
6
7angular.module('MAAS').directive('maasProxySettings', [
8 '$sce', 'ConfigsManager', 'ManagerHelperService', 'JSONService',
9 function($sce, ConfigsManager, ManagerHelperService, JSONService) {
10 return {
11 restrict: "E",
12 scope: {},
13 templateUrl: 'static/partials/proxy-settings.html',
14 controller: function($scope, $rootScope, $element, $document) {
15 $scope.loading = true;
16 ManagerHelperService.loadManager(
17 $scope, ConfigsManager).then(function() {
18 $scope.loading = false;
19 $scope.httpProxy = ConfigsManager.getItemFromList(
20 "http_proxy");
21 $scope.enableHttpProxy = ConfigsManager.getItemFromList(
22 "enable_http_proxy");
23 $scope.usePeerProxy = ConfigsManager.getItemFromList(
24 "use_peer_proxy");
25 if ($scope.enableHttpProxy.value) {
26 if ($scope.httpProxy.value) {
27 if ($scope.usePeerProxy.value) {
28 $scope.proxy_type = "peer-proxy";
29 } else {
30 $scope.proxy_type = "external-proxy";
31 }
32 } else {
33 $scope.proxy_type = "builtin-proxy";
34 }
35 } else {
36 $scope.proxy_type = "no-proxy";
37 }
38 });
39 }
40 };
41 }]);
diff --git a/src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js b/src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js
0new file mode 10064442new file mode 100644
index 0000000..ce06777
--- /dev/null
+++ b/src/maasserver/static/js/angular/directives/tests/test_proxy_settings.js
@@ -0,0 +1,190 @@
1/* Copyright 2017 Canonical Ltd. This software is licensed under the
2 * GNU Affero General Public License version 3 (see the file LICENSE).
3 *
4 * Unit tests for MAAS proxy settings directive.
5 */
6
7describe("maasProxySettings", function() {
8
9 // Load the MAAS module.
10 beforeEach(module("MAAS"));
11 // Make the templates available.
12 beforeEach(module("MAAS.templates"));
13
14 // Get required angular pieces and create a new scope before each test.
15 var $scope, $compile, $q, ConfigsManager, ManagerHelperService;
16 beforeEach(inject(function($rootScope, $injector) {
17 $scope = $rootScope.$new();
18 $compile = $injector.get("$compile");
19 $q = $injector.get("$q");
20 ConfigsManager = $injector.get("ConfigsManager");
21 ManagerHelperService = $injector.get("ManagerHelperService");
22 }));
23
24 // Create the config options.
25 var httpProxy, enableHttpProxy, usePeerProxy;
26 beforeEach(function() {
27 httpProxy = {
28 name: 'http_proxy',
29 value: ''
30 };
31 enableHttpProxy = {
32 name: 'enable_http_proxy',
33 value: true
34 };
35 usePeerProxy = {
36 name: 'use_peer_proxy',
37 value: false
38 };
39 ConfigsManager._items = [httpProxy, enableHttpProxy, usePeerProxy];
40 });
41
42 // Return the compiled directive.
43 function compileDirective() {
44 var loadManagerDefer = $q.defer();
45 spyOn(ManagerHelperService, "loadManager").and.returnValue(
46 loadManagerDefer.promise);
47
48 var html = "<div><maas-proxy-settings></maas-proxy-settings></div>";
49 var directive = $compile(html)($scope);
50 $scope.$digest();
51 loadManagerDefer.resolve();
52 $scope.$digest();
53
54 return angular.element(
55 directive.find("maas-proxy-settings"));
56 }
57
58 it("no-proxy without http proxy", function() {
59 enableHttpProxy.value = false;
60 usePeerProxy.value = false;
61 httpProxy.value = '';
62 var directive = compileDirective(
63 '<maas-proxy-settings></maas-proxy-settings>');
64 var scope = directive.isolateScope();
65 var enableProxyField = angular.element(directive.find(
66 "#id_proxy-enable_http_proxy"));
67 var httpProxyField = angular.element(directive.find(
68 "#id_proxy-http_proxy"));
69 var usePeerProxyField = angular.element(directive.find(
70 "#id_proxy-use_peer_proxy"));
71 expect(scope.proxy_type).toBe("no-proxy");
72 expect(enableProxyField.attr("value")).toBe("False");
73 expect(httpProxyField.attr("value")).toBe(undefined);
74 expect(usePeerProxyField.attr("value")).toBe("False");
75 });
76
77 it("no-proxy with http_proxy set", function() {
78 enableHttpProxy.value = false;
79 usePeerProxy.value = false;
80 httpProxy.value = 'http://proxy.example.com/';
81 var directive = compileDirective(
82 '<maas-proxy-settings></maas-proxy-settings>');
83 var scope = directive.isolateScope();
84 var enableProxyField = angular.element(directive.find(
85 "#id_proxy-enable_http_proxy"));
86 var httpProxyField = angular.element(directive.find(
87 "#id_proxy-http_proxy"));
88 var usePeerProxyField = angular.element(directive.find(
89 "#id_proxy-use_peer_proxy"));
90 expect(scope.proxy_type).toBe("no-proxy");
91 expect(enableProxyField.attr("value")).toBe("False");
92 expect(httpProxyField.attr("value")).toBe(undefined);
93 expect(usePeerProxyField.attr("value")).toBe("False");
94 });
95
96 it("no-proxy with use_peer_proxy set", function() {
97 enableHttpProxy.value = false;
98 usePeerProxy.value = true;
99 httpProxy.value = 'http://peer-proxy.example.com/';
100 var directive = compileDirective(
101 '<maas-proxy-settings></maas-proxy-settings>');
102 var scope = directive.isolateScope();
103 var enableProxyField = angular.element(directive.find(
104 "#id_proxy-enable_http_proxy"));
105 var httpProxyField = angular.element(directive.find(
106 "#id_proxy-http_proxy"));
107 var usePeerProxyField = angular.element(directive.find(
108 "#id_proxy-use_peer_proxy"));
109 expect(scope.proxy_type).toBe("no-proxy");
110 expect(enableProxyField.attr("value")).toBe("False");
111 expect(httpProxyField.attr("value")).toBe(undefined);
112 expect(usePeerProxyField.attr("value")).toBe("False");
113 });
114
115 it("builtin-proxy", function() {
116 enableHttpProxy.value = true;
117 usePeerProxy.value = false;
118 httpProxy.value = '';
119 var directive = compileDirective(
120 '<maas-proxy-settings></maas-proxy-settings>');
121 var scope = directive.isolateScope();
122 var enableProxyField = angular.element(directive.find(
123 "#id_proxy-enable_http_proxy"));
124 var httpProxyField = angular.element(directive.find(
125 "#id_proxy-http_proxy"));
126 var usePeerProxyField = angular.element(directive.find(
127 "#id_proxy-use_peer_proxy"));
128 expect(scope.proxy_type).toBe("builtin-proxy");
129 expect(enableProxyField.attr("value")).toBe("True");
130 expect(httpProxyField.attr("value")).toBe(undefined);
131 expect(usePeerProxyField.attr("value")).toBe("False");
132 });
133
134 it("builtin-proxy with use_peer_proxy set", function() {
135 enableHttpProxy.value = true;
136 usePeerProxy.value = true;
137 httpProxy.value = '';
138 var directive = compileDirective(
139 '<maas-proxy-settings></maas-proxy-settings>');
140 var scope = directive.isolateScope();
141 var enableProxyField = angular.element(directive.find(
142 "#id_proxy-enable_http_proxy"));
143 var httpProxyField = angular.element(directive.find(
144 "#id_proxy-http_proxy"));
145 var usePeerProxyField = angular.element(directive.find(
146 "#id_proxy-use_peer_proxy"));
147 expect(scope.proxy_type).toBe("builtin-proxy");
148 expect(enableProxyField.attr("value")).toBe("True");
149 expect(httpProxyField.attr("value")).toBe(undefined);
150 expect(usePeerProxyField.attr("value")).toBe("False");
151 });
152
153 it("external-proxy set", function() {
154 enableHttpProxy.value = true;
155 usePeerProxy.value = false;
156 httpProxy.value = 'http://proxy.example.com/';
157 var directive = compileDirective(
158 '<maas-proxy-settings></maas-proxy-settings>');
159 var scope = directive.isolateScope();
160 var enableProxyField = angular.element(directive.find(
161 "#id_proxy-enable_http_proxy"));
162 var httpProxyField = angular.element(directive.find(
163 "#id_proxy-http_proxy"));
164 var usePeerProxyField = angular.element(directive.find(
165 "#id_proxy-use_peer_proxy"));
166 expect(scope.proxy_type).toBe("external-proxy");
167 expect(enableProxyField.attr("value")).toBe("True");
168 expect(httpProxyField.attr("value")).toBe("http://proxy.example.com/");
169 expect(usePeerProxyField.attr("value")).toBe("False");
170 });
171
172 it("peer-proxy set", function() {
173 enableHttpProxy.value = true;
174 usePeerProxy.value = true;
175 httpProxy.value = 'http://proxy.example.com/';
176 var directive = compileDirective(
177 '<maas-proxy-settings></maas-proxy-settings>');
178 var scope = directive.isolateScope();
179 var enableProxyField = angular.element(directive.find(
180 "#id_proxy-enable_http_proxy"));
181 var httpProxyField = angular.element(directive.find(
182 "#id_proxy-http_proxy"));
183 var usePeerProxyField = angular.element(directive.find(
184 "#id_proxy-use_peer_proxy"));
185 expect(scope.proxy_type).toBe("peer-proxy");
186 expect(enableProxyField.attr("value")).toBe("True");
187 expect(httpProxyField.attr("value")).toBe("http://proxy.example.com/");
188 expect(usePeerProxyField.attr("value")).toBe("True");
189 });
190});
diff --git a/src/maasserver/static/partials/proxy-settings.html b/src/maasserver/static/partials/proxy-settings.html
0new file mode 100644191new file mode 100644
index 0000000..a3ee21b
--- /dev/null
+++ b/src/maasserver/static/partials/proxy-settings.html
@@ -0,0 +1,48 @@
1<li class="help-msg">
2<div>
3 <label>HTTP proxy used by MAAS to download images, and by provisioned machines for APT packages.</label>
4</div>
5<div>
6 <input type="radio" ng-model="proxy_type" name="maas_proxy"
7 id="maas_no_proxy" value="no-proxy">
8 <label for="maas_no_proxy">Don't use a proxy</label>
9</div>
10<div>
11 <input type="radio" ng-model="proxy_type" name="maas_proxy"
12 id="maas_builtin_proxy" value="builtin-proxy">
13 <label for="maas_builtin_proxy">MAAS Built-in</label>
14</div>
15<div>
16 <input type="radio" ng-model="proxy_type" name="maas_proxy" id="maas_external_proxy" value="external-proxy">
17 <label for="maas_external_proxy">External</label>
18 <input type="url" ng-if="proxy_type == 'external-proxy'"
19 id="id_proxy-http_proxy" name="proxy-http_proxy"
20 ng-model="httpProxy.value" value="{$ httpProxy.value $}">
21 <span ng-if="proxy_type == 'external-proxy'" class="help u-display--block">
22 <small>
23 Enter the external proxy URL MAAS will use to download images and
24 machines to download APT packages.
25 </small>
26 </span>
27</div>
28<div>
29 <input type="radio" ng-model="proxy_type" name="maas_proxy" id="maas_peer_proxy" value="peer-proxy">
30 <label for="maas_peer_proxy">Peer</label>
31 <input type="url" ng-if="proxy_type == 'peer-proxy'"
32 id="id_proxy-http_proxy" name="proxy-http_proxy"
33 ng-model="httpProxy.value" value="{$ httpProxy.value $}">
34 <span ng-if="proxy_type == 'peer-proxy'" class="help u-display--block">
35 <small>
36 Enter the external proxy URL that the MAAS built-in proxy will use
37 as an upstream cache peer. Machines will be configured to use MAAS'
38 built-in proxy to download APT packages.
39 </small>
40 </span>
41</div>
42<input type="hidden" id="id_proxy-enable_http_proxy"
43 name="proxy-enable_http_proxy"
44 value="{$ proxy_type == 'no-proxy' ? 'False' : 'True' $}" >
45<input type="hidden" id="id_proxy-use_peer_proxy"
46 name="proxy-use_peer_proxy"
47 value="{$ proxy_type == 'peer-proxy' ? 'True' : 'False' $}" >
48</li>
diff --git a/src/maasserver/templates/maasserver/settings.html b/src/maasserver/templates/maasserver/settings.html
index 9c82b3d..2f87f22 100644
--- a/src/maasserver/templates/maasserver/settings.html
+++ b/src/maasserver/templates/maasserver/settings.html
@@ -5,6 +5,8 @@
5{% block title %}Settings{% endblock %}5{% block title %}Settings{% endblock %}
6{% block page-title %}Settings{% endblock %}6{% block page-title %}Settings{% endblock %}
77
8{% block ng-app %}data-ng-app="MAAS"{% endblock %}
9
8{% block head %}10{% block head %}
9{% endblock %}11{% endblock %}
1012
@@ -157,14 +159,46 @@
157 </div>159 </div>
158 </div>160 </div>
159 <div class="eight-col u-border--bottom">161 <div class="eight-col u-border--bottom">
160 <div id="network" class="eight-col">162 <div id="proxy" class="eight-col">
161 <h2>Network Configuration</h2>163 <h2>Proxy</h2>
164 <span class="u-text--loading" data-ng-if="loading"><i class="icon icon--loading u-animation--spin"></i> Loading...</span>
165
166 <form action="{% url 'settings' %}" method="post">
167 {% csrf_token %}
168 <ul>
169 <maas-proxy-settings data-ng-if="!loading"></maas-proxy-settings>
170 </ul>
171 <input type="hidden" name="proxy_submit" value="1" />
172 <button type="submit" class="button--positive button--inline u-float--right">Save</button>
173 </form>
174 </div>
175 </div>
176 <div class="eight-col u-border--bottom">
177 <div id="dns" class="eight-col">
178 <h2>DNS</h2>
179 <form action="{% url 'settings' %}" method="post">
180 {% csrf_token %}
181 <ul>
182 {% for field in dns_form %}
183 {% include "maasserver/form_field.html" %}
184 {% endfor %}
185 </ul>
186 <input type="hidden" name="dns_submit" value="1" />
187 <button type="submit" class="button--positive button--inline u-float--right">Save</button>
188 </form>
189 </div>
190 </div>
191 <div class="eight-col u-border--bottom">
192 <div id="ntp" class="eight-col">
193 <h2>NTP</h2>
162 <form action="{% url 'settings' %}" method="post">194 <form action="{% url 'settings' %}" method="post">
163 {% csrf_token %}195 {% csrf_token %}
164 <ul>196 <ul>
165 {% for field in network_form %} {% include "maasserver/form_field.html" %} {% endfor %}197 {% for field in ntp_form %}
198 {% include "maasserver/form_field.html" %}
199 {% endfor %}
166 </ul>200 </ul>
167 <input type="hidden" name="network_submit" value="1" />201 <input type="hidden" name="ntp_submit" value="1" />
168 <button type="submit" class="button--positive button--inline u-float--right">Save</button>202 <button type="submit" class="button--positive button--inline u-float--right">Save</button>
169 </form>203 </form>
170 </div>204 </div>
diff --git a/src/maasserver/views/combo.py b/src/maasserver/views/combo.py
index b1d6615..55e2d2d 100644
--- a/src/maasserver/views/combo.py
+++ b/src/maasserver/views/combo.py
@@ -119,6 +119,7 @@ MERGE_VIEWS = {
119 "js/angular/directives/placeholder.js",119 "js/angular/directives/placeholder.js",
120 "js/angular/directives/pod_parameters.js",120 "js/angular/directives/pod_parameters.js",
121 "js/angular/directives/power_parameters.js",121 "js/angular/directives/power_parameters.js",
122 "js/angular/directives/proxy_settings.js",
122 "js/angular/directives/release_name.js",123 "js/angular/directives/release_name.js",
123 "js/angular/directives/release_options.js",124 "js/angular/directives/release_options.js",
124 "js/angular/directives/script_select.js",125 "js/angular/directives/script_select.js",
diff --git a/src/maasserver/views/settings.py b/src/maasserver/views/settings.py
index 2a410fa..6549d34 100644
--- a/src/maasserver/views/settings.py
+++ b/src/maasserver/views/settings.py
@@ -33,12 +33,14 @@ from maasserver.exceptions import CannotDeleteUserException
33from maasserver.forms import (33from maasserver.forms import (
34 CommissioningForm,34 CommissioningForm,
35 DeployForm,35 DeployForm,
36 DNSForm,
36 EditUserForm,37 EditUserForm,
37 GlobalKernelOptsForm,38 GlobalKernelOptsForm,
38 MAASForm,39 MAASForm,
39 NetworkDiscoveryForm,40 NetworkDiscoveryForm,
40 NetworkForm,
41 NewUserCreationForm,41 NewUserCreationForm,
42 NTPForm,
43 ProxyForm,
42 StorageSettingsForm,44 StorageSettingsForm,
43 ThirdPartyDriversForm,45 ThirdPartyDriversForm,
44 UbuntuForm,46 UbuntuForm,
@@ -211,8 +213,22 @@ def settings(request):
211 return response213 return response
212214
213 # Process the network form.215 # Process the network form.
214 network_form, response = process_form(216 proxy_form, response = process_form(
215 request, NetworkForm, reverse('settings'), 'network',217 request, ProxyForm, reverse('settings'), 'proxy',
218 "Configuration updated.")
219 if response is not None:
220 return response
221
222 # Process the DNS form.
223 dns_form, response = process_form(
224 request, DNSForm, reverse('settings'), 'dns',
225 "Configuration updated.")
226 if response is not None:
227 return response
228
229 # Process the NTP form.
230 ntp_form, response = process_form(
231 request, NTPForm, reverse('settings'), 'ntp',
216 "Configuration updated.")232 "Configuration updated.")
217 if response is not None:233 if response is not None:
218 return response234 return response
@@ -279,7 +295,9 @@ def settings(request):
279 'show_license_keys': show_license_keys,295 'show_license_keys': show_license_keys,
280 'license_keys': license_keys,296 'license_keys': license_keys,
281 'maas_form': maas_form,297 'maas_form': maas_form,
282 'network_form': network_form,298 'proxy_form': proxy_form,
299 'dns_form': dns_form,
300 'ntp_form': ntp_form,
283 'network_discovery_form': network_discovery_form,301 'network_discovery_form': network_discovery_form,
284 'third_party_drivers_form': third_party_drivers_form,302 'third_party_drivers_form': third_party_drivers_form,
285 'storage_settings_form': storage_settings_form,303 'storage_settings_form': storage_settings_form,
diff --git a/src/maasserver/views/tests/test_settings.py b/src/maasserver/views/tests/test_settings.py
index 1f6a941..c7ba9b0 100644
--- a/src/maasserver/views/tests/test_settings.py
+++ b/src/maasserver/views/tests/test_settings.py
@@ -107,7 +107,7 @@ class SettingsTest(MAASServerTestCase):
107 self.assertEqual(107 self.assertEqual(
108 new_name, Config.objects.get_config('maas_name'))108 new_name, Config.objects.get_config('maas_name'))
109109
110 def test_settings_network_POST(self):110 def test_proxy_proxy_POST(self):
111 # Disable boot source cache signals.111 # Disable boot source cache signals.
112 self.addCleanup(bootsources.signals.enable)112 self.addCleanup(bootsources.signals.enable)
113 bootsources.signals.disable()113 bootsources.signals.disable()
@@ -116,13 +116,56 @@ class SettingsTest(MAASServerTestCase):
116 response = self.client.post(116 response = self.client.post(
117 reverse('settings'),117 reverse('settings'),
118 get_prefixed_form_data(118 get_prefixed_form_data(
119 prefix='network',119 prefix='proxy',
120 data={120 data={
121 'http_proxy': new_proxy,121 'http_proxy': new_proxy,
122 'enable_http_proxy': True,
123 'use_peer_proxy': True,
122 }))124 }))
123 self.assertEqual(125 self.assertEqual(
124 http.client.FOUND, response.status_code, response.content)126 http.client.FOUND, response.status_code, response.content)
125 self.assertEqual(new_proxy, Config.objects.get_config('http_proxy'))127 self.assertEqual(new_proxy, Config.objects.get_config('http_proxy'))
128 self.assertTrue(Config.objects.get_config('enable_http_proxy'))
129 self.assertTrue(Config.objects.get_config('use_peer_proxy'))
130
131 def test_settings_dns_POST(self):
132 # Disable boot source cache signals.
133 self.addCleanup(bootsources.signals.enable)
134 bootsources.signals.disable()
135 self.client_log_in(as_admin=True)
136 new_upstream = "8.8.8.8"
137 response = self.client.post(
138 reverse('settings'),
139 get_prefixed_form_data(
140 prefix='dns',
141 data={
142 'upstream_dns': new_upstream,
143 'dnssec_validation': 'no',
144 }))
145 self.assertEqual(
146 http.client.FOUND, response.status_code, response.content)
147 self.assertEqual(
148 new_upstream, Config.objects.get_config('upstream_dns'))
149 self.assertEqual('no', Config.objects.get_config('dnssec_validation'))
150
151 def test_settings_ntp_POST(self):
152 # Disable boot source cache signals.
153 self.addCleanup(bootsources.signals.enable)
154 bootsources.signals.disable()
155 self.client_log_in(as_admin=True)
156 new_servers = "ntp.example.com"
157 response = self.client.post(
158 reverse('settings'),
159 get_prefixed_form_data(
160 prefix='ntp',
161 data={
162 'ntp_servers': new_servers,
163 'ntp_external_only': True,
164 }))
165 self.assertEqual(
166 http.client.FOUND, response.status_code, response.content)
167 self.assertEqual(new_servers, Config.objects.get_config('ntp_servers'))
168 self.assertTrue(Config.objects.get_config('ntp_external_only'))
126169
127 def test_settings_commissioning_POST(self):170 def test_settings_commissioning_POST(self):
128 self.client_log_in(as_admin=True)171 self.client_log_in(as_admin=True)
diff --git a/src/maastesting/karma.conf.js b/src/maastesting/karma.conf.js
index 66fe913..33e5f5f 100644
--- a/src/maastesting/karma.conf.js
+++ b/src/maastesting/karma.conf.js
@@ -24,7 +24,8 @@ module.exports = function(config) {
24 '../../src/maasserver/static/js/angular/maas.js',24 '../../src/maasserver/static/js/angular/maas.js',
25 '../../src/maasserver/static/js/angular/testing/*.js',25 '../../src/maasserver/static/js/angular/testing/*.js',
26 '../../src/maasserver/static/js/angular/*/*.js',26 '../../src/maasserver/static/js/angular/*/*.js',
27 '../../src/maasserver/static/js/angular/*/tests/test_*.js'27 '../../src/maasserver/static/js/angular/*/tests/test_*.js',
28 '../../src/maasserver/static/partials/*.html'
28 ],29 ],
2930
3031
@@ -36,8 +37,17 @@ module.exports = function(config) {
36 // preprocess matching files before serving them to the browser37 // preprocess matching files before serving them to the browser
37 // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor38 // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
38 preprocessors: {39 preprocessors: {
40 '../../src/maasserver/static/partials/*.html': ['ng-html2js']
39 },41 },
4042
43 ngHtml2JsPreprocessor: {
44 // If your build process changes the path to your templates,
45 // use stripPrefix and prependPrefix to adjust it.
46 stripPrefix: ".*src/maasserver/",
47
48 // the name of the Angular module to create
49 moduleName: 'MAAS.templates'
50 },
4151
42 // test results reporter to use52 // test results reporter to use
43 // possible values: 'dots', 'progress'53 // possible values: 'dots', 'progress'
@@ -79,7 +89,8 @@ module.exports = function(config) {
79 'karma-firefox-launcher',89 'karma-firefox-launcher',
80 'karma-opera-launcher',90 'karma-opera-launcher',
81 'karma-phantomjs-launcher',91 'karma-phantomjs-launcher',
82 'karma-failed-reporter'92 'karma-failed-reporter',
93 'karma-ng-html2js-preprocessor'
83 ]94 ]
84 });95 });
85};96};

Subscribers

People subscribed via source and target branches