Merge lp:~hatch/juju-gui/parse-pending-types into lp:juju-gui/experimental
- parse-pending-types
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1217 |
Proposed branch: | lp:~hatch/juju-gui/parse-pending-types |
Merge into: | lp:juju-gui/experimental |
Diff against target: |
282 lines (+52/-71) 9 files modified
app/models/handlers.js (+4/-1) app/models/models.js (+16/-17) app/store/env/simulator.js (+2/-12) app/views/environment.js (+2/-23) app/views/inspector.js (+1/-1) app/views/utils.js (+15/-7) app/views/viewlets/service-overview.js (+6/-4) test/test_model.js (+5/-5) test/test_service_module.js (+1/-1) |
To merge this branch: | bzr merge lp:~hatch/juju-gui/parse-pending-types |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Juju GUI Hackers | Pending | ||
Review via email: mp+197441@code.launchpad.net |
Commit message
Description of the change
Adds pending and dying statuses to the inspector
A service in various states of pending are now properly represented in the
inspector.
Dying services are now left on the canvas with their inspectors until the service
is entirely destroyed from Juju.
Jeff Pihach (hatch) wrote : | # |
Madison Scott-Clary (makyo) wrote : | # |
LGTM, QA okay, one question, feel free to say no! Thanks.
https:/
File app/models/
https:/
app/models/
We have a constant ALIVE, might it make sense to do he samefor DYING?
Jeff Pihach (hatch) wrote : | # |
*** Submitted:
Adds pending and dying statuses to the inspector
A service in various states of pending are now properly represented in
the
inspector.
Dying services are now left on the canvas with their inspectors until
the service
is entirely destroyed from Juju.
R=matthew.scott
CC=
https:/
Preview Diff
1 | === modified file 'app/models/handlers.js' | |||
2 | --- app/models/handlers.js 2013-11-19 22:30:18 +0000 | |||
3 | +++ app/models/handlers.js 2013-12-02 21:33:17 +0000 | |||
4 | @@ -172,7 +172,10 @@ | |||
5 | 172 | public_address: change.PublicAddress | 172 | public_address: change.PublicAddress |
6 | 173 | }; | 173 | }; |
7 | 174 | var service = db.services.getById(change.Name.split('/')[0]); | 174 | var service = db.services.getById(change.Name.split('/')[0]); |
9 | 175 | service.get('units').process_delta(action, unitData, db); | 175 | if (service) { |
10 | 176 | // The service can be destroyed before the last unit delta comes in. | ||
11 | 177 | service.get('units').process_delta(action, unitData, db); | ||
12 | 178 | } | ||
13 | 176 | db.machines.process_delta(action, machineData, db); | 179 | db.machines.process_delta(action, machineData, db); |
14 | 177 | }, | 180 | }, |
15 | 178 | 181 | ||
16 | 179 | 182 | ||
17 | === modified file 'app/models/models.js' | |||
18 | --- app/models/models.js 2013-11-26 20:38:05 +0000 | |||
19 | +++ app/models/models.js 2013-12-02 21:33:17 +0000 | |||
20 | @@ -191,18 +191,21 @@ | |||
21 | 191 | }, | 191 | }, |
22 | 192 | 192 | ||
23 | 193 | /** | 193 | /** |
25 | 194 | Return true if this service life is "alive", false otherwise. | 194 | Return true if this service life is 'alive' or 'dying', false otherwise. |
26 | 195 | 195 | ||
27 | 196 | A model instance is alive if its life cycle (i.e. the "life" attribute) | 196 | A model instance is alive if its life cycle (i.e. the "life" attribute) |
31 | 197 | is set to "alive". Other possible values, as they arrive from the | 197 | is set to 'alive' or 'dying'. The other possible value, as they arrive |
32 | 198 | juju-core delta stream, are "dying" and "dead", in which cases the | 198 | from the juju-core delta stream is 'dead'. |
30 | 199 | service is not considered alive. | ||
33 | 200 | 199 | ||
34 | 201 | @method isAlive | 200 | @method isAlive |
35 | 202 | @return {Boolean} Whether this service is alive. | 201 | @return {Boolean} Whether this service is alive. |
36 | 203 | */ | 202 | */ |
37 | 204 | isAlive: function() { | 203 | isAlive: function() { |
39 | 205 | return this.get('life') === ALIVE; | 204 | var life = this.get('life'); |
40 | 205 | if (life === ALIVE || life === 'dying') { | ||
41 | 206 | return true; | ||
42 | 207 | } | ||
43 | 208 | return false; | ||
44 | 206 | }, | 209 | }, |
45 | 207 | 210 | ||
46 | 208 | /** | 211 | /** |
47 | @@ -413,14 +416,10 @@ | |||
48 | 413 | model: Service, | 416 | model: Service, |
49 | 414 | 417 | ||
50 | 415 | /** | 418 | /** |
59 | 416 | Return a list of visible model instances. | 419 | Return a list of visible model instances. A model instance is visible |
60 | 417 | 420 | when it is alive or dying. | |
61 | 418 | A model instance is visible when it is alive or when, even if it is dying | 421 | |
62 | 419 | or dead, one or more of its units are in an error state. | 422 | @method visible |
55 | 420 | In the latter case, we want to still display the service in order to | ||
56 | 421 | allow users to retry or resolve its units. | ||
57 | 422 | |||
58 | 423 | @method alive | ||
63 | 424 | @return {Y.ModelList} The resulting visible model instances. | 423 | @return {Y.ModelList} The resulting visible model instances. |
64 | 425 | */ | 424 | */ |
65 | 426 | visible: function() { | 425 | visible: function() { |
66 | @@ -593,10 +592,12 @@ | |||
67 | 593 | get_informative_states_for_service: function(service) { | 592 | get_informative_states_for_service: function(service) { |
68 | 594 | var aggregate_map = {}, | 593 | var aggregate_map = {}, |
69 | 595 | relationError = {}, | 594 | relationError = {}, |
71 | 596 | units_for_service = service.get('units'); | 595 | units_for_service = service.get('units'), |
72 | 596 | serviceLife = service.get('life'); | ||
73 | 597 | 597 | ||
74 | 598 | units_for_service.each(function(unit) { | 598 | units_for_service.each(function(unit) { |
76 | 599 | var state = utils.determineCategoryType(utils.simplifyState(unit)); | 599 | var state = utils.determineCategoryType( |
77 | 600 | utils.simplifyState(unit, serviceLife)); | ||
78 | 600 | if (aggregate_map[state] === undefined) { | 601 | if (aggregate_map[state] === undefined) { |
79 | 601 | aggregate_map[state] = 1; | 602 | aggregate_map[state] = 1; |
80 | 602 | } else { | 603 | } else { |
81 | @@ -633,9 +634,7 @@ | |||
82 | 633 | var previous_unit_count = service.get('unit_count'); | 634 | var previous_unit_count = service.get('unit_count'); |
83 | 634 | service.set('unit_count', sum); | 635 | service.set('unit_count', sum); |
84 | 635 | service.set('aggregated_status', aggregate[0]); | 636 | service.set('aggregated_status', aggregate[0]); |
85 | 636 | |||
86 | 637 | service.set('relationChangeTrigger', { error: aggregate[1] }); | 637 | service.set('relationChangeTrigger', { error: aggregate[1] }); |
87 | 638 | |||
88 | 639 | // Set Google Analytics tracking event. | 638 | // Set Google Analytics tracking event. |
89 | 640 | if (previous_unit_count !== sum && window._gaq) { | 639 | if (previous_unit_count !== sum && window._gaq) { |
90 | 641 | window._gaq.push(['_trackEvent', 'Service Stats', 'Update', | 640 | window._gaq.push(['_trackEvent', 'Service Stats', 'Update', |
91 | 642 | 641 | ||
92 | === modified file 'app/store/env/simulator.js' | |||
93 | --- app/store/env/simulator.js 2013-11-22 22:52:30 +0000 | |||
94 | +++ app/store/env/simulator.js 2013-12-02 21:33:17 +0000 | |||
95 | @@ -157,18 +157,8 @@ | |||
96 | 157 | unit.agent_state_info = undefined; | 157 | unit.agent_state_info = undefined; |
97 | 158 | unit.agent_state_data = {}; | 158 | unit.agent_state_data = {}; |
98 | 159 | } else if (roll <= 0.7) { | 159 | } else if (roll <= 0.7) { |
111 | 160 | if (window.flags && window.flags.simPend) { | 160 | if (roll <= 0.5) { |
112 | 161 | // Because the GUI does not yet support parsing the 'life' | 161 | unit.agent_state = 'installing'; |
101 | 162 | // status attribute from core and including it in the | ||
102 | 163 | // aggregate status this is here to simply simulate the | ||
103 | 164 | // functionality in the inspector unit list, until it is. | ||
104 | 165 | if (roll <= 0.4) { | ||
105 | 166 | unit.agent_state = 'dying'; | ||
106 | 167 | } else if (roll <= 0.5) { | ||
107 | 168 | unit.agent_state = 'installing'; | ||
108 | 169 | } else { | ||
109 | 170 | unit.agent_state = 'pending'; | ||
110 | 171 | } | ||
113 | 172 | } else { | 162 | } else { |
114 | 173 | unit.agent_state = 'pending'; | 163 | unit.agent_state = 'pending'; |
115 | 174 | } | 164 | } |
116 | 175 | 165 | ||
117 | === modified file 'app/views/environment.js' | |||
118 | --- app/views/environment.js 2013-11-13 15:41:46 +0000 | |||
119 | +++ app/views/environment.js 2013-12-02 21:33:17 +0000 | |||
120 | @@ -151,32 +151,11 @@ | |||
121 | 151 | this.topo.fire('hideServiceMenu'); | 151 | this.topo.fire('hideServiceMenu'); |
122 | 152 | }, this); | 152 | }, this); |
123 | 153 | 153 | ||
124 | 154 | model.get('units').on('deltaChange', function(e) { | ||
125 | 155 | var service = e.service; | ||
126 | 156 | var units = service.get('units'); | ||
127 | 157 | |||
128 | 158 | var started = !units.some(function(unit) { | ||
129 | 159 | if ((/-?error$/).test(unit.agent_state)) { | ||
130 | 160 | return true; | ||
131 | 161 | } | ||
132 | 162 | }); | ||
133 | 163 | |||
134 | 164 | if (started && service.get('life') === 'dying') { | ||
135 | 165 | var inspector = this.getInspector(service.get('packageName')); | ||
136 | 166 | if (inspector) { inspector.viewletManager.destroy(); } | ||
137 | 167 | this.topo.fire('hideServiceMenu'); | ||
138 | 168 | } | ||
139 | 169 | }, this); | ||
140 | 170 | |||
141 | 171 | // If the service is destroyed from the console then we need to | 154 | // If the service is destroyed from the console then we need to |
142 | 172 | // destroy the inspector and hide the service menu. | 155 | // destroy the inspector and hide the service menu. |
144 | 173 | model.after(['lifeChange', 'destroy'], function(e) { | 156 | model.on('destroy', function(e) { |
145 | 174 | var service = e.currentTarget; | 157 | var service = e.currentTarget; |
151 | 175 | // The user can put the service in a dying state from the console | 158 | var inspector = this.getInspector(service.get('id')); |
147 | 176 | // but it will not be destroyed if any of its units has errors. | ||
148 | 177 | if (service.isAlive() || service.hasErrors()) { return; } | ||
149 | 178 | |||
150 | 179 | var inspector = this.getInspector(service.get('packageName')); | ||
152 | 180 | if (inspector) { inspector.viewletManager.destroy(); } | 159 | if (inspector) { inspector.viewletManager.destroy(); } |
153 | 181 | this.topo.fire('hideServiceMenu'); | 160 | this.topo.fire('hideServiceMenu'); |
154 | 182 | }, this); | 161 | }, this); |
155 | 183 | 162 | ||
156 | === modified file 'app/views/inspector.js' | |||
157 | --- app/views/inspector.js 2013-10-11 19:33:07 +0000 | |||
158 | +++ app/views/inspector.js 2013-12-02 21:33:17 +0000 | |||
159 | @@ -507,8 +507,8 @@ | |||
160 | 507 | */ | 507 | */ |
161 | 508 | _onInitiateDestroy: function(evt) { | 508 | _onInitiateDestroy: function(evt) { |
162 | 509 | evt.halt(); | 509 | evt.halt(); |
163 | 510 | this.closeInspector(); | ||
164 | 511 | this.initiateServiceDestroy(); | 510 | this.initiateServiceDestroy(); |
165 | 511 | this._onCancelDestroy(evt); | ||
166 | 512 | this.options.environment.topo.fire('clearState'); | 512 | this.options.environment.topo.fire('clearState'); |
167 | 513 | }, | 513 | }, |
168 | 514 | 514 | ||
169 | 515 | 515 | ||
170 | === modified file 'app/views/utils.js' | |||
171 | --- app/views/utils.js 2013-11-27 19:27:32 +0000 | |||
172 | +++ app/views/utils.js 2013-12-02 21:33:17 +0000 | |||
173 | @@ -1232,14 +1232,21 @@ | |||
174 | 1232 | 1232 | ||
175 | 1233 | @method simplifyState | 1233 | @method simplifyState |
176 | 1234 | @param {Object} unit A service unit. | 1234 | @param {Object} unit A service unit. |
177 | 1235 | @param {String} life The life status of the units service. | ||
178 | 1235 | @return {String} the filtered agent state of the unit. | 1236 | @return {String} the filtered agent state of the unit. |
179 | 1236 | */ | 1237 | */ |
186 | 1237 | utils.simplifyState = function(unit) { | 1238 | utils.simplifyState = function(unit, life) { |
187 | 1238 | var state = unit.agent_state; | 1239 | var state = unit.agent_state, |
188 | 1239 | if (state === 'started') { return 'running'; } | 1240 | inError = (/-?error$/).test(state); |
189 | 1240 | if ((/-?error$/).test(state)) { return 'error'; } | 1241 | if (life === 'dying' && !inError) { |
190 | 1241 | // "pending", "installed", and "stopped", plus anything unforeseen | 1242 | return 'dying'; |
191 | 1242 | return state; | 1243 | } else { |
192 | 1244 | if (state === 'started') { return 'running'; } | ||
193 | 1245 | if (inError) { return 'error'; } | ||
194 | 1246 | // "pending", "installed", and "stopped", plus anything unforeseen | ||
195 | 1247 | return state; | ||
196 | 1248 | } | ||
197 | 1249 | |||
198 | 1243 | }; | 1250 | }; |
199 | 1244 | 1251 | ||
200 | 1245 | /** | 1252 | /** |
201 | @@ -1267,7 +1274,8 @@ | |||
202 | 1267 | 1274 | ||
203 | 1268 | @method determineCategoryType | 1275 | @method determineCategoryType |
204 | 1269 | @param {String} category The category name to test. | 1276 | @param {String} category The category name to test. |
206 | 1270 | @param {String} The category type 'error', 'landscape', 'pending', 'running' | 1277 | @return {String} The category type |
207 | 1278 | 'error', 'landscape', 'pending', 'running' | ||
208 | 1271 | */ | 1279 | */ |
209 | 1272 | utils.determineCategoryType = function(category) { | 1280 | utils.determineCategoryType = function(category) { |
210 | 1273 | if ((/fail|error/).test(category)) { return 'error'; } | 1281 | if ((/fail|error/).test(category)) { return 'error'; } |
211 | 1274 | 1282 | ||
212 | === modified file 'app/views/viewlets/service-overview.js' | |||
213 | --- app/views/viewlets/service-overview.js 2013-11-21 23:21:49 +0000 | |||
214 | +++ app/views/viewlets/service-overview.js 2013-12-02 21:33:17 +0000 | |||
215 | @@ -83,11 +83,14 @@ | |||
216 | 83 | [{ type: 'service', upgradeAvailable: true, upgradeTo: ...}]. | 83 | [{ type: 'service', upgradeAvailable: true, upgradeTo: ...}]. |
217 | 84 | */ | 84 | */ |
218 | 85 | function updateStatusList(unitList) { | 85 | function updateStatusList(unitList) { |
219 | 86 | // Disable: Possible strict violation for the entire function | ||
220 | 87 | /* jshint -W040 */ | ||
221 | 86 | var statuses = [], | 88 | var statuses = [], |
223 | 87 | unitByStatus = {}; | 89 | unitByStatus = {}, |
224 | 90 | serviceLife = this.model.get('life'); | ||
225 | 88 | 91 | ||
226 | 89 | unitList.each(function(unit) { | 92 | unitList.each(function(unit) { |
228 | 90 | var category = utils.simplifyState(unit); | 93 | var category = utils.simplifyState(unit, serviceLife); |
229 | 91 | // If the unit is in error we want it's category to be it's real error. | 94 | // If the unit is in error we want it's category to be it's real error. |
230 | 92 | if (category === 'error') { category = unit.agent_state_info; } | 95 | if (category === 'error') { category = unit.agent_state_info; } |
231 | 93 | 96 | ||
232 | @@ -112,8 +115,7 @@ | |||
233 | 112 | units: unitByStatus[category] | 115 | units: unitByStatus[category] |
234 | 113 | }); | 116 | }); |
235 | 114 | }); | 117 | }); |
238 | 115 | // Disable: Possible strict violation | 118 | |
237 | 116 | /* jshint -W040 */ | ||
239 | 117 | return sortStatuses(addCharmUpgrade(statuses, this.model)); | 119 | return sortStatuses(addCharmUpgrade(statuses, this.model)); |
240 | 118 | } | 120 | } |
241 | 119 | 121 | ||
242 | 120 | 122 | ||
243 | === modified file 'test/test_model.js' | |||
244 | --- test/test_model.js 2013-11-26 22:30:42 +0000 | |||
245 | +++ test/test_model.js 2013-12-02 21:33:17 +0000 | |||
246 | @@ -1034,9 +1034,9 @@ | |||
247 | 1034 | assert.isTrue(django.isAlive()); | 1034 | assert.isTrue(django.isAlive()); |
248 | 1035 | }); | 1035 | }); |
249 | 1036 | 1036 | ||
253 | 1037 | it('instances identify if they are not alive (dying or dead)', function() { | 1037 | it('instances identify if they are not alive (dead)', function() { |
254 | 1038 | assert.isFalse(rails.isAlive(), rails.get('id')); | 1038 | assert.isTrue(rails.isAlive(), rails.get('id')); |
255 | 1039 | assert.isFalse(wordpress.isAlive(), wordpress.get('id')); | 1039 | assert.isTrue(wordpress.isAlive(), wordpress.get('id')); |
256 | 1040 | assert.isFalse(mysql.isAlive(), mysql.get('id')); | 1040 | assert.isFalse(mysql.isAlive(), mysql.get('id')); |
257 | 1041 | }); | 1041 | }); |
258 | 1042 | 1042 | ||
259 | @@ -1052,8 +1052,8 @@ | |||
260 | 1052 | 1052 | ||
261 | 1053 | it('can be filtered so that it returns only visible models', function() { | 1053 | it('can be filtered so that it returns only visible models', function() { |
262 | 1054 | var filtered = list.visible(); | 1054 | var filtered = list.visible(); |
265 | 1055 | assert.strictEqual(2, filtered.size()); | 1055 | assert.strictEqual(filtered.size(), 3); |
266 | 1056 | assert.deepEqual([django, wordpress], filtered.toArray()); | 1056 | assert.deepEqual(filtered.toArray(), [rails, django, wordpress]); |
267 | 1057 | }); | 1057 | }); |
268 | 1058 | }); | 1058 | }); |
269 | 1059 | }); | 1059 | }); |
270 | 1060 | 1060 | ||
271 | === modified file 'test/test_service_module.js' | |||
272 | --- test/test_service_module.js 2013-11-21 12:18:26 +0000 | |||
273 | +++ test/test_service_module.js 2013-12-02 21:33:17 +0000 | |||
274 | @@ -258,7 +258,7 @@ | |||
275 | 258 | // There are five services in total. | 258 | // There are five services in total. |
276 | 259 | assert.strictEqual(5, db.services.size(), 'total'); | 259 | assert.strictEqual(5, db.services.size(), 'total'); |
277 | 260 | // But only three of those are actually displayed. | 260 | // But only three of those are actually displayed. |
279 | 261 | assert.strictEqual(3, Y.Object.size(boxes), 'displayed'); | 261 | assert.strictEqual(4, Y.Object.size(boxes), 'displayed'); |
280 | 262 | // And they are the visible ones. | 262 | // And they are the visible ones. |
281 | 263 | assert.deepPropertyVal(boxes, 'haproxy.model', haproxy); | 263 | assert.deepPropertyVal(boxes, 'haproxy.model', haproxy); |
282 | 264 | assert.deepPropertyVal(boxes, 'django.model', django); | 264 | assert.deepPropertyVal(boxes, 'django.model', django); |
Reviewers: mp+197441_ code.launchpad. net,
Message:
Please take a look.
Description:
Adds pending and dying statuses to the inspector
A service in various states of pending are now properly represented in
the
inspector.
Dying services are now left on the canvas with their inspectors until
the service
is entirely destroyed from Juju.
To QA:
Sandbox:
Deploy some services and make sure you can destroy them in various ways.
Deploy a service with a lot of units and wait for the simulator to show
pending and installing statuses
Real Env:
Deploy 4 instances of failtester
Set one to fail on install hook
Open one of the pending services inspectors and then delete it from the
console
It should enter a 'dying' state then remove from the canvas when
finished
Wait for the remaining failtester services to come green/red
Destroy one from the GUI, it should enter a 'dying' state and then
remove from the canvas
closing the inspector when it's done.
Open the other green one, destroy it from the console, it should enter a
'dying' state and
then remove from the canvas
Open the red one's inspector, destroy it from the console, nothing
should happen in the GUI
Resolve the unit in error in the GUI and the service should enter a
'dying' state then
remove from the canvas when done.
https:/ /code.launchpad .net/~hatch/ juju-gui/ parse-pending- types/+ merge/197441
(do not edit description out of merge proposal)
Please review this at https:/ /codereview. appspot. com/36240043/
Affected files (+54, -71 lines): handlers. js models. js env/simulator. js environment. js inspector. js viewlets/ service- overview. js service_ module. js
A [revision details]
M app/models/
M app/models/
M app/store/
M app/views/
M app/views/
M app/views/utils.js
M app/views/
M test/test_model.js
M test/test_