~gary/juju-gui/fixsavetext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
.. Run "make view-main-doc" to render this file and read it in the browser
   alongside the whole project documentation. To do this, you need the
   dependencies described in the "Documentation" section below.

=======
HACKING
=======

Here is how to develop on this codebase.

Developer Install
=================

Before you get the GUI you need to get Juju. We use the fresh one from the Juju
PPA. For PyJuju, the original Python-based implementation, we also use a custom
branch of Juju that supplies the websocket API we need.  (GoJuju, the newer
Go-based implementation, will have a websocket API provided for us directly as
part of the software.)

::

  sudo add-apt-repository ppa:juju/pkgs
  sudo apt-get update
  sudo apt-get install juju zookeeper

Next you will also need to get the Juju branch that has API access.
Currently that work resides in a pipeline of Juju branches. The
recommended branch to use as a server is ``rapi-rollup`` by hazmat::

  bzr branch lp:~hazmat/juju/rapi-rollup

For development, we always use a nice testing script in that branch that
allows you to interact with Juju without actually deploying real machines.  In
the rapi-rollup branch, run ``python improv.py -h`` to get an idea of its
capabilities.  Note that your Python needs Twisted and Zookeeper installed,
but the ``sudo apt-get install juju zookeeper`` command above should have
already taken care of that for you.

Go ahead and use the branch's ``sample.json`` file to pre-populate the
environment.  In the future, you might want to investigate the ``large.json``
also available there.

::

  python improv.py -f sample.json

Now it is time to actually get the GUI itself set up.  Juju GUI uses
nodejs-based development tools, so you will need ``nodejs`` from Chris
Lea's node PPA. You also need ImageMagick for sprite generation, lbox to
propose branches, python-sphinx and python-yaml to build docs, PyTZ to make
releases, python-shelltoolbox and python-selenium for browser tests, and
python-virtualenv to build the Google Closure linter tools locally::

  sudo add-apt-repository ppa:chris-lea/node.js
  sudo add-apt-repository ppa:gophers/go
  sudo apt-get update
  sudo apt-get install nodejs imagemagick lbox python-sphinx python-yaml \
    python-tz python-virtualenv python-shelltoolbox python-selenium \
    python-tornado python-gflags

See :ref:`Browser Testing <browser-testing>` if you are curious about the
reason for ``python-shelltoolbox`` and ``python-selenium``.

The jshint linter will be installed locally per branch, but if you want editor
integration, you may want to install ``jshint`` globally in your system.  More
importantly, to support testing from the command line, ``phantomjs`` and
``mocha-phantomjs`` should be installed globally.

::

  sudo npm install -g jshint@2.1.3 mocha-phantomjs@2.0.0 phantomjs@1.9.1-0

Note: Make sure to get the latest phantomjs from npm and not rely on an older
.deb packaged version. mocha-phantomjs will fail silently when running.

If you receive an error installing phantomjs, you can manually download and
unpack the archive and then arrange for the ``phantomjs`` executable to be
located on your path (e.g., by linking it into ``~/bin``).

The Juju GUI can now be installed and run with::

  bzr branch lp:juju-gui trunk
  cd trunk
  make devel

It may take a while for the server to start the first time as npm will
need to download packages.  When ready, the server will print::

  Server listening on 8888

You can then access the GUI at <http://localhost:8888/>.

If you receive an error like::

  fs.js:837
     throw errnoException(errno, 'watch');
           ^
  Error: watch ENOSPC

You can increase your watch limit by creating or editing::

  /etc/sysctl.d/10-inotify.conf

Add in the following::

  # expand inotify limit
  fs.inotify.max_user_watches=16384

Then::

  sudo sysctl -p
  cat /proc/sys/fs/inotify/max_user_watches

If it does not echo ``16384`` then you will need to restart.

Note that the Makefile supports ``make help`` to try to introduce some of the
more important targets.  Also note that if you use the "make prod" target
while using the PyJuju ``rapi-rollup`` improv script, the password you should
use is "admin," despite the help text you see.

Typical Bzr workflow
=====================

Bazaar allows you to work in a lot of different workflows. Here is one that
works well for our environemnt, if you are not already familiar with bzr.

To set up the environment::

  bzr init-repo juju-gui
  cd juju-gui
  bzr branch lp:juju-gui trunk
  mkdir yourUseName
  bzr branch trunk/{featureBranchName}

To link branch to ticket::

  bzr commit --fixes=lp:{ticketNumber}

To push code::

  bzr push lp:~{yourUserName}/juju-gui/{featureBranchName}

To submit for review::

  lbox propose -cr

After review, to merge into trunk::

  lbox submit

Working with a Real Juju
========================

The easiest way to work with a real Juju installation, as opposed to the
``improv`` script described above, is to use the Juju charm.  See
<http://jujucharms.com/~juju-gui/precise/juju-gui> or
<http://jujucharms.com/charms/precise/juju-gui> for details.

Alternatively, you can try the instructions below, but be warned that they
have bit-rotted and we have not felt the need to update them.  If you get them
to work, please update the docs and submit a branch for review (see below).

Bit-Rotted Instructions
-----------------------

You can use the GUI with any environment, but for development purposes, a
local environment works well. One environment option specific to this branch
is the ``api-port``. An appropriate sample configuration::

  default: dev
  environments:
    dev:
      type: local
      data-dir: /home/kapil/.juju/local
      admin-secret: b3a5dee4fb8c4fc9a4db04751e5936f4
      default-series: precise
      juju-origin: ppa
      api-port: 8081

Note that ``juju-origin`` is set to the PPA, the API server runs outside of
the container, and it is launched using whichever branch you are using.

Also note that the ``api-port`` should be set at ``8081``, which the GUI's
initial environment connection currently defaults to.

You will need to bootstrap the local environment, and deploy one service.
The API server needs access to the provisioning credentials which are
lazily initialized in Juju upon usage.

``Juju-gui`` and ``rapi-rollup`` can communicate via an encrypted WebSocket
connection: to enable it, add the following line to the config above::

  api-secure: true

You will also need to edit ``app/config-debug.js`` and ``app/config-prod.js``
replacing ``ws://localhost:8081/ws`` with ``wss://localhost:8081/ws``.

By default, ``rapi-rollup`` uses a self-signed certificate; because of that you
will need to visit the <https://localhost:8081/ws> WebSocket URL with your
browser and accept the included self-signed certificate, or the WebSocket
encrypted connection will not work.

In order to use a different certificate you add an ``api-keys`` option to the
config above: its value will be the path of the directory containing the
certificate and the private key, whose filenames will have to be respectively
``juju.crt`` and ``juju.key``.

After this, the GUI should be functional (it automatically polls the
API server for establishing a websocket).

Running Unit Tests
==================

``make test-prod`` or ``make test-debug`` will run the CLI based test
runner. If you need to debug a test in the browser, use ``make test-server``.

Running Lint
============

Run the linters with ``make lint``.  ``make beautify`` will use the Google
Closure tools to try and force the code to conform to some of the guidelines,
with variable success.  It can help, but we suggest you first commit your code
to your branch and only then run make beautify, so you can easily see and
evaluate the changes it made.

If you have done a large refactoring and the yuidoc linter complains about a
lot of code that no longer exists or has been moved or renamed, note that
``make undocumented`` can reproduce the undocumented file so as to quiet the
linter. If you need to do this, please make sure that the length (``wc -l``)
of the new "undocumented" file is the same or smaller than it was before.

.. _all-docs:

Documentation
=============

The ``make docs`` command generates the code and the project documentation
together. The ``make view-docs`` command does the above and also opens both
docs in the browser.

Code Documentation
------------------

Generated documentation for the JavaScript code is available in the ``yuidoc/``
directory.  You can build and view the docs by running::

  make view-code-doc

See the :ref:`style guide <embedded-docs>` document for details on how to
write the embedded documentation.

Project Documentation
---------------------

The project documentation is available in the ``docs/`` directory. As already
mentioned in the developer installation instructions above, it needs Sphinx
and Python-yaml.  To build and view the documentation, use these commands::

  make view-main-doc

Filing Bugs
===========

Please file bugs here:

https://bugs.launchpad.net/juju-gui/+filebug

Proposing Branches
==================

We use ``lbox`` to propose branches for review and submit them to the trunk.
Gustavo Niemeyer has `a helpful blogpost`_ about this tool.  See the
:ref:`Process document <preparing-reviews>` for a step-by-step checklist on how
to prepare branches for review.

.. _`a helpful blogpost`:
    http://blog.labix.org/2011/11/17/launchpad-rietveld-happycodereviews

Making Targets Quickly Without Bazaar
=====================================

Within a checkout, a lightweight checkout, or a branch, you may run make as
``NO_BZR=1 make [target]`` in order to prevent the Makefile from running any
Bazaar commands, all of which access the parent branch over the network. Where
Bazaar may have provided information such as the revno, sensible defaults are
used instead.  Because many of these Bazaar commands are used to populate
variables regardless of the target, defining NO_BZR will have an effect on all
targets, except ``dist``, which will refuse to complete.

Note that this allows one to run any make target from the working copy, even
if it is a lightweight checkout, by skipping steps that involve network access
through Bazaar.  Because of this, make will assume that the revno is
0 and that the branch is clean and up to date without checking that it is a
checkout of trunk.  The resulting tarball or build may be used to test
releases by hand or in the charm.

Making Releases
===============

See the :ref:`Process document <make-releases>` for step-by-step checklists to
make developer and stable releases.  The following is additional detail and an
overview.

To make a release, you must either be in a checkout of ``lp:juju-gui``
without uncommitted changes, or you must override one of the
`pertinent variable names`_ to force a release.

.. _`pertinent variable names`:
    `Potentially Useful Release-Oriented Makefile Variables`_

To make the release tarball use ``make distfile``.

In order to make and upload the release (``make dist``), you also need to have
a GPG key, and the ``python-pytz`` package installed (as well as
``launchpadlib``, but that is installed by default in Ubuntu).

Potentially Useful Release-Oriented Makefile Variables
------------------------------------------------------

The following is a list of pertinent Makefile variables.

``FINAL``
  Set ``FINAL`` to any non-empty value to make a final release. This will cause
  the ``bzr revno`` to be omitted from the tarball name, and (if you use the
  release target) will cause the release to be uploaded to the stable series
  rather than the trunk series. Example usage::

    FINAL=1 make dist

``PROD``
  By default, releases will be uploaded to ``staging.launchpad.net``, which is
  a separate version of Launchpad that uses a temporary database.  This can be
  convenient for trying out the release process in the Makefile without
  affecting our actual production releases.  Set ``PROD`` to any non-empty
  value to send uploads to ``launchpad.net``, the production version of
  Launchpad, when you are ready to make a real release.

  Note that you may need to ask the webops to turn off the two-factor
  authentication on your Launchpad staging account in order for the staging to
  work. Go to the ``#launchpad-ops`` channel on the Canonical IRC server and
  ask something like "webops, could you disable 2FA on my staging account?".

  Example usage::

    PROD=1 make dist

``IS_TRUNK_BRANCH``
  Set this to any non-empty value to force the Makefile to believe it is
  working with a trunk checkout. Example usage::

    IS_TRUNK_BRANCH=1 make dist

``BRANCH_IS_CLEAN``
  Set this to any non-empty value to force the Makefile to believe that the
  current code tree has no changes. Example usage::

    BRANCH_IS_CLEAN=1 make dist

``BRANCH_IS_GOOD``
  Set this to any non-empty value to force the Makefile to bypass checks of
  ``IS_TRUNK_BRANCH`` and ``BRANCH_IS_CLEAN``. Example usage::

    BRANCH_IS_GOOD=1 make dist

Updating the ``nodejs`` dependencies
====================================

The ranges of allowed versions for the ``nodejs`` dependency packages are
specified in the top-level ``package.json`` file. However, the actual installed
versions are frozen in the top-level ``npm-shrinkwap.json`` file, which
overrides the former.

The ``npm-shrinkwap.json`` file is generated by the ``npm shrinkwrap`` command
(see `shrinkwrap - Lock down dependency versions`_) on the basis of the
packages currently installed by any of the ``make build-[something]`` commands.

The procedure for updating the dependency versions is described in the
`Building shrinkwrapped packages`_ section of the aforementioned document. In
a nutshell:

1) review the ``package.json`` file and see whether any constraints may be
   updated, in order to allow using newer package versions;
2) delete the ``npm-shrinkwrap.json`` file;
3) run ``make``, getting all new dependencies;
4) check that everything works well;

If everything is fine, regenerate the ``npm-shrinkwap.json`` file by running
the ``npm shrinkwrap`` command.

If something is broken find the culprit, adjust the ``package.json`` file
accordingly, and go back to step #3.

Alternatively, you might use the ``npm outdated`` command to get the update
candidates, and do the job one step at a time rather than all at once.

.. _`shrinkwrap - Lock down dependency versions`:
    https://npmjs.org/doc/shrinkwrap.html
.. _`Building shrinkwrapped packages`:
    https://npmjs.org/doc/shrinkwrap.html#Building-shrinkwrapped-packages