Merge lp:~blake-rouse/maas/maas-charms-initial into lp:~maas-committers/maas/maas-charms

Proposed by Blake Rouse
Status: Merged
Merged at revision: 2
Proposed branch: lp:~blake-rouse/maas/maas-charms-initial
Merge into: lp:~maas-committers/maas/maas-charms
Diff against target: 2178 lines (+2057/-0)
22 files modified
.bzrignore (+2/-0)
LICENSE (+676/-0)
Makefile (+26/-0)
README (+34/-0)
interfaces/maas-region-ha/interface.yaml (+4/-0)
interfaces/maas-region-ha/peers.py (+37/-0)
interfaces/maas-rpc/interface.yaml (+4/-0)
interfaces/maas-rpc/provides.py (+32/-0)
interfaces/maas-rpc/requires.py (+23/-0)
layers/maas-rack/config.yaml (+7/-0)
layers/maas-rack/icon.svg (+1/-0)
layers/maas-rack/layer.yaml (+5/-0)
layers/maas-rack/metadata.yaml (+12/-0)
layers/maas-rack/reactive/rack.py (+154/-0)
layers/maas-region/config.yaml (+150/-0)
layers/maas-region/icon.svg (+1/-0)
layers/maas-region/layer.yaml (+8/-0)
layers/maas-region/metadata.yaml (+18/-0)
layers/maas-region/reactive/region.py (+737/-0)
layers/maas-region/scripts/update_user.py (+26/-0)
layers/maas-region/templates/haproxy.cfg (+70/-0)
layers/maas-region/templates/keepalived.conf (+30/-0)
To merge this branch: bzr merge lp:~blake-rouse/maas/maas-charms-initial
Reviewer Review Type Date Requested Status
Blake Rouse (community) Approve
Review via email: mp+292582@code.launchpad.net

Commit message

Initial commit.

To post a comment you must log in.
2. By Blake Rouse

Add copyright on python files.

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

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file '.bzrignore'
2--- .bzrignore 1970-01-01 00:00:00 +0000
3+++ .bzrignore 2016-04-21 20:17:50 +0000
4@@ -0,0 +1,2 @@
5+deps/
6+xenial/
7
8=== added file 'LICENSE'
9--- LICENSE 1970-01-01 00:00:00 +0000
10+++ LICENSE 2016-04-21 20:17:50 +0000
11@@ -0,0 +1,676 @@
12+MAAS charms is Copyright 2016 Canonical Ltd.
13+
14+Canonical Ltd ("Canonical") distributes the MAAS charms source code
15+under the GNU Affero General Public License, version 3 ("AGPLv3").
16+The full text of this licence is given below.
17+
18+Third-party copyright in this distribution is noted where applicable.
19+
20+All rights not expressly granted are reserved.
21+
22+=========================================================================
23+
24+ GNU AFFERO GENERAL PUBLIC LICENSE
25+ Version 3, 19 November 2007
26+ (http://www.gnu.org/licenses/agpl.html)
27+
28+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
29+ Everyone is permitted to copy and distribute verbatim copies
30+ of this license document, but changing it is not allowed.
31+
32+ Preamble
33+
34+ The GNU Affero General Public License is a free, copyleft license for
35+software and other kinds of works, specifically designed to ensure
36+cooperation with the community in the case of network server software.
37+
38+ The licenses for most software and other practical works are designed
39+to take away your freedom to share and change the works. By contrast,
40+our General Public Licenses are intended to guarantee your freedom to
41+share and change all versions of a program--to make sure it remains free
42+software for all its users.
43+
44+ When we speak of free software, we are referring to freedom, not
45+price. Our General Public Licenses are designed to make sure that you
46+have the freedom to distribute copies of free software (and charge for
47+them if you wish), that you receive source code or can get it if you
48+want it, that you can change the software or use pieces of it in new
49+free programs, and that you know you can do these things.
50+
51+ Developers that use our General Public Licenses protect your rights
52+with two steps: (1) assert copyright on the software, and (2) offer
53+you this License which gives you legal permission to copy, distribute
54+and/or modify the software.
55+
56+ A secondary benefit of defending all users' freedom is that
57+improvements made in alternate versions of the program, if they
58+receive widespread use, become available for other developers to
59+incorporate. Many developers of free software are heartened and
60+encouraged by the resulting cooperation. However, in the case of
61+software used on network servers, this result may fail to come about.
62+The GNU General Public License permits making a modified version and
63+letting the public access it on a server without ever releasing its
64+source code to the public.
65+
66+ The GNU Affero General Public License is designed specifically to
67+ensure that, in such cases, the modified source code becomes available
68+to the community. It requires the operator of a network server to
69+provide the source code of the modified version running there to the
70+users of that server. Therefore, public use of a modified version, on
71+a publicly accessible server, gives the public access to the source
72+code of the modified version.
73+
74+ An older license, called the Affero General Public License and
75+published by Affero, was designed to accomplish similar goals. This is
76+a different license, not a version of the Affero GPL, but Affero has
77+released a new version of the Affero GPL which permits relicensing under
78+this license.
79+
80+ The precise terms and conditions for copying, distribution and
81+modification follow.
82+
83+ TERMS AND CONDITIONS
84+
85+ 0. Definitions.
86+
87+ "This License" refers to version 3 of the GNU Affero General Public License.
88+
89+ "Copyright" also means copyright-like laws that apply to other kinds of
90+works, such as semiconductor masks.
91+
92+ "The Program" refers to any copyrightable work licensed under this
93+License. Each licensee is addressed as "you". "Licensees" and
94+"recipients" may be individuals or organizations.
95+
96+ To "modify" a work means to copy from or adapt all or part of the work
97+in a fashion requiring copyright permission, other than the making of an
98+exact copy. The resulting work is called a "modified version" of the
99+earlier work or a work "based on" the earlier work.
100+
101+ A "covered work" means either the unmodified Program or a work based
102+on the Program.
103+
104+ To "propagate" a work means to do anything with it that, without
105+permission, would make you directly or secondarily liable for
106+infringement under applicable copyright law, except executing it on a
107+computer or modifying a private copy. Propagation includes copying,
108+distribution (with or without modification), making available to the
109+public, and in some countries other activities as well.
110+
111+ To "convey" a work means any kind of propagation that enables other
112+parties to make or receive copies. Mere interaction with a user through
113+a computer network, with no transfer of a copy, is not conveying.
114+
115+ An interactive user interface displays "Appropriate Legal Notices"
116+to the extent that it includes a convenient and prominently visible
117+feature that (1) displays an appropriate copyright notice, and (2)
118+tells the user that there is no warranty for the work (except to the
119+extent that warranties are provided), that licensees may convey the
120+work under this License, and how to view a copy of this License. If
121+the interface presents a list of user commands or options, such as a
122+menu, a prominent item in the list meets this criterion.
123+
124+ 1. Source Code.
125+
126+ The "source code" for a work means the preferred form of the work
127+for making modifications to it. "Object code" means any non-source
128+form of a work.
129+
130+ A "Standard Interface" means an interface that either is an official
131+standard defined by a recognized standards body, or, in the case of
132+interfaces specified for a particular programming language, one that
133+is widely used among developers working in that language.
134+
135+ The "System Libraries" of an executable work include anything, other
136+than the work as a whole, that (a) is included in the normal form of
137+packaging a Major Component, but which is not part of that Major
138+Component, and (b) serves only to enable use of the work with that
139+Major Component, or to implement a Standard Interface for which an
140+implementation is available to the public in source code form. A
141+"Major Component", in this context, means a major essential component
142+(kernel, window system, and so on) of the specific operating system
143+(if any) on which the executable work runs, or a compiler used to
144+produce the work, or an object code interpreter used to run it.
145+
146+ The "Corresponding Source" for a work in object code form means all
147+the source code needed to generate, install, and (for an executable
148+work) run the object code and to modify the work, including scripts to
149+control those activities. However, it does not include the work's
150+System Libraries, or general-purpose tools or generally available free
151+programs which are used unmodified in performing those activities but
152+which are not part of the work. For example, Corresponding Source
153+includes interface definition files associated with source files for
154+the work, and the source code for shared libraries and dynamically
155+linked subprograms that the work is specifically designed to require,
156+such as by intimate data communication or control flow between those
157+subprograms and other parts of the work.
158+
159+ The Corresponding Source need not include anything that users
160+can regenerate automatically from other parts of the Corresponding
161+Source.
162+
163+ The Corresponding Source for a work in source code form is that
164+same work.
165+
166+ 2. Basic Permissions.
167+
168+ All rights granted under this License are granted for the term of
169+copyright on the Program, and are irrevocable provided the stated
170+conditions are met. This License explicitly affirms your unlimited
171+permission to run the unmodified Program. The output from running a
172+covered work is covered by this License only if the output, given its
173+content, constitutes a covered work. This License acknowledges your
174+rights of fair use or other equivalent, as provided by copyright law.
175+
176+ You may make, run and propagate covered works that you do not
177+convey, without conditions so long as your license otherwise remains
178+in force. You may convey covered works to others for the sole purpose
179+of having them make modifications exclusively for you, or provide you
180+with facilities for running those works, provided that you comply with
181+the terms of this License in conveying all material for which you do
182+not control copyright. Those thus making or running the covered works
183+for you must do so exclusively on your behalf, under your direction
184+and control, on terms that prohibit them from making any copies of
185+your copyrighted material outside their relationship with you.
186+
187+ Conveying under any other circumstances is permitted solely under
188+the conditions stated below. Sublicensing is not allowed; section 10
189+makes it unnecessary.
190+
191+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
192+
193+ No covered work shall be deemed part of an effective technological
194+measure under any applicable law fulfilling obligations under article
195+11 of the WIPO copyright treaty adopted on 20 December 1996, or
196+similar laws prohibiting or restricting circumvention of such
197+measures.
198+
199+ When you convey a covered work, you waive any legal power to forbid
200+circumvention of technological measures to the extent such circumvention
201+is effected by exercising rights under this License with respect to
202+the covered work, and you disclaim any intention to limit operation or
203+modification of the work as a means of enforcing, against the work's
204+users, your or third parties' legal rights to forbid circumvention of
205+technological measures.
206+
207+ 4. Conveying Verbatim Copies.
208+
209+ You may convey verbatim copies of the Program's source code as you
210+receive it, in any medium, provided that you conspicuously and
211+appropriately publish on each copy an appropriate copyright notice;
212+keep intact all notices stating that this License and any
213+non-permissive terms added in accord with section 7 apply to the code;
214+keep intact all notices of the absence of any warranty; and give all
215+recipients a copy of this License along with the Program.
216+
217+ You may charge any price or no price for each copy that you convey,
218+and you may offer support or warranty protection for a fee.
219+
220+ 5. Conveying Modified Source Versions.
221+
222+ You may convey a work based on the Program, or the modifications to
223+produce it from the Program, in the form of source code under the
224+terms of section 4, provided that you also meet all of these conditions:
225+
226+ a) The work must carry prominent notices stating that you modified
227+ it, and giving a relevant date.
228+
229+ b) The work must carry prominent notices stating that it is
230+ released under this License and any conditions added under section
231+ 7. This requirement modifies the requirement in section 4 to
232+ "keep intact all notices".
233+
234+ c) You must license the entire work, as a whole, under this
235+ License to anyone who comes into possession of a copy. This
236+ License will therefore apply, along with any applicable section 7
237+ additional terms, to the whole of the work, and all its parts,
238+ regardless of how they are packaged. This License gives no
239+ permission to license the work in any other way, but it does not
240+ invalidate such permission if you have separately received it.
241+
242+ d) If the work has interactive user interfaces, each must display
243+ Appropriate Legal Notices; however, if the Program has interactive
244+ interfaces that do not display Appropriate Legal Notices, your
245+ work need not make them do so.
246+
247+ A compilation of a covered work with other separate and independent
248+works, which are not by their nature extensions of the covered work,
249+and which are not combined with it such as to form a larger program,
250+in or on a volume of a storage or distribution medium, is called an
251+"aggregate" if the compilation and its resulting copyright are not
252+used to limit the access or legal rights of the compilation's users
253+beyond what the individual works permit. Inclusion of a covered work
254+in an aggregate does not cause this License to apply to the other
255+parts of the aggregate.
256+
257+ 6. Conveying Non-Source Forms.
258+
259+ You may convey a covered work in object code form under the terms
260+of sections 4 and 5, provided that you also convey the
261+machine-readable Corresponding Source under the terms of this License,
262+in one of these ways:
263+
264+ a) Convey the object code in, or embodied in, a physical product
265+ (including a physical distribution medium), accompanied by the
266+ Corresponding Source fixed on a durable physical medium
267+ customarily used for software interchange.
268+
269+ b) Convey the object code in, or embodied in, a physical product
270+ (including a physical distribution medium), accompanied by a
271+ written offer, valid for at least three years and valid for as
272+ long as you offer spare parts or customer support for that product
273+ model, to give anyone who possesses the object code either (1) a
274+ copy of the Corresponding Source for all the software in the
275+ product that is covered by this License, on a durable physical
276+ medium customarily used for software interchange, for a price no
277+ more than your reasonable cost of physically performing this
278+ conveying of source, or (2) access to copy the
279+ Corresponding Source from a network server at no charge.
280+
281+ c) Convey individual copies of the object code with a copy of the
282+ written offer to provide the Corresponding Source. This
283+ alternative is allowed only occasionally and noncommercially, and
284+ only if you received the object code with such an offer, in accord
285+ with subsection 6b.
286+
287+ d) Convey the object code by offering access from a designated
288+ place (gratis or for a charge), and offer equivalent access to the
289+ Corresponding Source in the same way through the same place at no
290+ further charge. You need not require recipients to copy the
291+ Corresponding Source along with the object code. If the place to
292+ copy the object code is a network server, the Corresponding Source
293+ may be on a different server (operated by you or a third party)
294+ that supports equivalent copying facilities, provided you maintain
295+ clear directions next to the object code saying where to find the
296+ Corresponding Source. Regardless of what server hosts the
297+ Corresponding Source, you remain obligated to ensure that it is
298+ available for as long as needed to satisfy these requirements.
299+
300+ e) Convey the object code using peer-to-peer transmission, provided
301+ you inform other peers where the object code and Corresponding
302+ Source of the work are being offered to the general public at no
303+ charge under subsection 6d.
304+
305+ A separable portion of the object code, whose source code is excluded
306+from the Corresponding Source as a System Library, need not be
307+included in conveying the object code work.
308+
309+ A "User Product" is either (1) a "consumer product", which means any
310+tangible personal property which is normally used for personal, family,
311+or household purposes, or (2) anything designed or sold for incorporation
312+into a dwelling. In determining whether a product is a consumer product,
313+doubtful cases shall be resolved in favor of coverage. For a particular
314+product received by a particular user, "normally used" refers to a
315+typical or common use of that class of product, regardless of the status
316+of the particular user or of the way in which the particular user
317+actually uses, or expects or is expected to use, the product. A product
318+is a consumer product regardless of whether the product has substantial
319+commercial, industrial or non-consumer uses, unless such uses represent
320+the only significant mode of use of the product.
321+
322+ "Installation Information" for a User Product means any methods,
323+procedures, authorization keys, or other information required to install
324+and execute modified versions of a covered work in that User Product from
325+a modified version of its Corresponding Source. The information must
326+suffice to ensure that the continued functioning of the modified object
327+code is in no case prevented or interfered with solely because
328+modification has been made.
329+
330+ If you convey an object code work under this section in, or with, or
331+specifically for use in, a User Product, and the conveying occurs as
332+part of a transaction in which the right of possession and use of the
333+User Product is transferred to the recipient in perpetuity or for a
334+fixed term (regardless of how the transaction is characterized), the
335+Corresponding Source conveyed under this section must be accompanied
336+by the Installation Information. But this requirement does not apply
337+if neither you nor any third party retains the ability to install
338+modified object code on the User Product (for example, the work has
339+been installed in ROM).
340+
341+ The requirement to provide Installation Information does not include a
342+requirement to continue to provide support service, warranty, or updates
343+for a work that has been modified or installed by the recipient, or for
344+the User Product in which it has been modified or installed. Access to a
345+network may be denied when the modification itself materially and
346+adversely affects the operation of the network or violates the rules and
347+protocols for communication across the network.
348+
349+ Corresponding Source conveyed, and Installation Information provided,
350+in accord with this section must be in a format that is publicly
351+documented (and with an implementation available to the public in
352+source code form), and must require no special password or key for
353+unpacking, reading or copying.
354+
355+ 7. Additional Terms.
356+
357+ "Additional permissions" are terms that supplement the terms of this
358+License by making exceptions from one or more of its conditions.
359+Additional permissions that are applicable to the entire Program shall
360+be treated as though they were included in this License, to the extent
361+that they are valid under applicable law. If additional permissions
362+apply only to part of the Program, that part may be used separately
363+under those permissions, but the entire Program remains governed by
364+this License without regard to the additional permissions.
365+
366+ When you convey a copy of a covered work, you may at your option
367+remove any additional permissions from that copy, or from any part of
368+it. (Additional permissions may be written to require their own
369+removal in certain cases when you modify the work.) You may place
370+additional permissions on material, added by you to a covered work,
371+for which you have or can give appropriate copyright permission.
372+
373+ Notwithstanding any other provision of this License, for material you
374+add to a covered work, you may (if authorized by the copyright holders of
375+that material) supplement the terms of this License with terms:
376+
377+ a) Disclaiming warranty or limiting liability differently from the
378+ terms of sections 15 and 16 of this License; or
379+
380+ b) Requiring preservation of specified reasonable legal notices or
381+ author attributions in that material or in the Appropriate Legal
382+ Notices displayed by works containing it; or
383+
384+ c) Prohibiting misrepresentation of the origin of that material, or
385+ requiring that modified versions of such material be marked in
386+ reasonable ways as different from the original version; or
387+
388+ d) Limiting the use for publicity purposes of names of licensors or
389+ authors of the material; or
390+
391+ e) Declining to grant rights under trademark law for use of some
392+ trade names, trademarks, or service marks; or
393+
394+ f) Requiring indemnification of licensors and authors of that
395+ material by anyone who conveys the material (or modified versions of
396+ it) with contractual assumptions of liability to the recipient, for
397+ any liability that these contractual assumptions directly impose on
398+ those licensors and authors.
399+
400+ All other non-permissive additional terms are considered "further
401+restrictions" within the meaning of section 10. If the Program as you
402+received it, or any part of it, contains a notice stating that it is
403+governed by this License along with a term that is a further
404+restriction, you may remove that term. If a license document contains
405+a further restriction but permits relicensing or conveying under this
406+License, you may add to a covered work material governed by the terms
407+of that license document, provided that the further restriction does
408+not survive such relicensing or conveying.
409+
410+ If you add terms to a covered work in accord with this section, you
411+must place, in the relevant source files, a statement of the
412+additional terms that apply to those files, or a notice indicating
413+where to find the applicable terms.
414+
415+ Additional terms, permissive or non-permissive, may be stated in the
416+form of a separately written license, or stated as exceptions;
417+the above requirements apply either way.
418+
419+ 8. Termination.
420+
421+ You may not propagate or modify a covered work except as expressly
422+provided under this License. Any attempt otherwise to propagate or
423+modify it is void, and will automatically terminate your rights under
424+this License (including any patent licenses granted under the third
425+paragraph of section 11).
426+
427+ However, if you cease all violation of this License, then your
428+license from a particular copyright holder is reinstated (a)
429+provisionally, unless and until the copyright holder explicitly and
430+finally terminates your license, and (b) permanently, if the copyright
431+holder fails to notify you of the violation by some reasonable means
432+prior to 60 days after the cessation.
433+
434+ Moreover, your license from a particular copyright holder is
435+reinstated permanently if the copyright holder notifies you of the
436+violation by some reasonable means, this is the first time you have
437+received notice of violation of this License (for any work) from that
438+copyright holder, and you cure the violation prior to 30 days after
439+your receipt of the notice.
440+
441+ Termination of your rights under this section does not terminate the
442+licenses of parties who have received copies or rights from you under
443+this License. If your rights have been terminated and not permanently
444+reinstated, you do not qualify to receive new licenses for the same
445+material under section 10.
446+
447+ 9. Acceptance Not Required for Having Copies.
448+
449+ You are not required to accept this License in order to receive or
450+run a copy of the Program. Ancillary propagation of a covered work
451+occurring solely as a consequence of using peer-to-peer transmission
452+to receive a copy likewise does not require acceptance. However,
453+nothing other than this License grants you permission to propagate or
454+modify any covered work. These actions infringe copyright if you do
455+not accept this License. Therefore, by modifying or propagating a
456+covered work, you indicate your acceptance of this License to do so.
457+
458+ 10. Automatic Licensing of Downstream Recipients.
459+
460+ Each time you convey a covered work, the recipient automatically
461+receives a license from the original licensors, to run, modify and
462+propagate that work, subject to this License. You are not responsible
463+for enforcing compliance by third parties with this License.
464+
465+ An "entity transaction" is a transaction transferring control of an
466+organization, or substantially all assets of one, or subdividing an
467+organization, or merging organizations. If propagation of a covered
468+work results from an entity transaction, each party to that
469+transaction who receives a copy of the work also receives whatever
470+licenses to the work the party's predecessor in interest had or could
471+give under the previous paragraph, plus a right to possession of the
472+Corresponding Source of the work from the predecessor in interest, if
473+the predecessor has it or can get it with reasonable efforts.
474+
475+ You may not impose any further restrictions on the exercise of the
476+rights granted or affirmed under this License. For example, you may
477+not impose a license fee, royalty, or other charge for exercise of
478+rights granted under this License, and you may not initiate litigation
479+(including a cross-claim or counterclaim in a lawsuit) alleging that
480+any patent claim is infringed by making, using, selling, offering for
481+sale, or importing the Program or any portion of it.
482+
483+ 11. Patents.
484+
485+ A "contributor" is a copyright holder who authorizes use under this
486+License of the Program or a work on which the Program is based. The
487+work thus licensed is called the contributor's "contributor version".
488+
489+ A contributor's "essential patent claims" are all patent claims
490+owned or controlled by the contributor, whether already acquired or
491+hereafter acquired, that would be infringed by some manner, permitted
492+by this License, of making, using, or selling its contributor version,
493+but do not include claims that would be infringed only as a
494+consequence of further modification of the contributor version. For
495+purposes of this definition, "control" includes the right to grant
496+patent sublicenses in a manner consistent with the requirements of
497+this License.
498+
499+ Each contributor grants you a non-exclusive, worldwide, royalty-free
500+patent license under the contributor's essential patent claims, to
501+make, use, sell, offer for sale, import and otherwise run, modify and
502+propagate the contents of its contributor version.
503+
504+ In the following three paragraphs, a "patent license" is any express
505+agreement or commitment, however denominated, not to enforce a patent
506+(such as an express permission to practice a patent or covenant not to
507+sue for patent infringement). To "grant" such a patent license to a
508+party means to make such an agreement or commitment not to enforce a
509+patent against the party.
510+
511+ If you convey a covered work, knowingly relying on a patent license,
512+and the Corresponding Source of the work is not available for anyone
513+to copy, free of charge and under the terms of this License, through a
514+publicly available network server or other readily accessible means,
515+then you must either (1) cause the Corresponding Source to be so
516+available, or (2) arrange to deprive yourself of the benefit of the
517+patent license for this particular work, or (3) arrange, in a manner
518+consistent with the requirements of this License, to extend the patent
519+license to downstream recipients. "Knowingly relying" means you have
520+actual knowledge that, but for the patent license, your conveying the
521+covered work in a country, or your recipient's use of the covered work
522+in a country, would infringe one or more identifiable patents in that
523+country that you have reason to believe are valid.
524+
525+ If, pursuant to or in connection with a single transaction or
526+arrangement, you convey, or propagate by procuring conveyance of, a
527+covered work, and grant a patent license to some of the parties
528+receiving the covered work authorizing them to use, propagate, modify
529+or convey a specific copy of the covered work, then the patent license
530+you grant is automatically extended to all recipients of the covered
531+work and works based on it.
532+
533+ A patent license is "discriminatory" if it does not include within
534+the scope of its coverage, prohibits the exercise of, or is
535+conditioned on the non-exercise of one or more of the rights that are
536+specifically granted under this License. You may not convey a covered
537+work if you are a party to an arrangement with a third party that is
538+in the business of distributing software, under which you make payment
539+to the third party based on the extent of your activity of conveying
540+the work, and under which the third party grants, to any of the
541+parties who would receive the covered work from you, a discriminatory
542+patent license (a) in connection with copies of the covered work
543+conveyed by you (or copies made from those copies), or (b) primarily
544+for and in connection with specific products or compilations that
545+contain the covered work, unless you entered into that arrangement,
546+or that patent license was granted, prior to 28 March 2007.
547+
548+ Nothing in this License shall be construed as excluding or limiting
549+any implied license or other defenses to infringement that may
550+otherwise be available to you under applicable patent law.
551+
552+ 12. No Surrender of Others' Freedom.
553+
554+ If conditions are imposed on you (whether by court order, agreement or
555+otherwise) that contradict the conditions of this License, they do not
556+excuse you from the conditions of this License. If you cannot convey a
557+covered work so as to satisfy simultaneously your obligations under this
558+License and any other pertinent obligations, then as a consequence you may
559+not convey it at all. For example, if you agree to terms that obligate you
560+to collect a royalty for further conveying from those to whom you convey
561+the Program, the only way you could satisfy both those terms and this
562+License would be to refrain entirely from conveying the Program.
563+
564+ 13. Remote Network Interaction; Use with the GNU General Public License.
565+
566+ Notwithstanding any other provision of this License, if you modify the
567+Program, your modified version must prominently offer all users
568+interacting with it remotely through a computer network (if your version
569+supports such interaction) an opportunity to receive the Corresponding
570+Source of your version by providing access to the Corresponding Source
571+from a network server at no charge, through some standard or customary
572+means of facilitating copying of software. This Corresponding Source
573+shall include the Corresponding Source for any work covered by version 3
574+of the GNU General Public License that is incorporated pursuant to the
575+following paragraph.
576+
577+ Notwithstanding any other provision of this License, you have
578+permission to link or combine any covered work with a work licensed
579+under version 3 of the GNU General Public License into a single
580+combined work, and to convey the resulting work. The terms of this
581+License will continue to apply to the part which is the covered work,
582+but the work with which it is combined will remain governed by version
583+3 of the GNU General Public License.
584+
585+ 14. Revised Versions of this License.
586+
587+ The Free Software Foundation may publish revised and/or new versions of
588+the GNU Affero General Public License from time to time. Such new versions
589+will be similar in spirit to the present version, but may differ in detail to
590+address new problems or concerns.
591+
592+ Each version is given a distinguishing version number. If the
593+Program specifies that a certain numbered version of the GNU Affero General
594+Public License "or any later version" applies to it, you have the
595+option of following the terms and conditions either of that numbered
596+version or of any later version published by the Free Software
597+Foundation. If the Program does not specify a version number of the
598+GNU Affero General Public License, you may choose any version ever published
599+by the Free Software Foundation.
600+
601+ If the Program specifies that a proxy can decide which future
602+versions of the GNU Affero General Public License can be used, that proxy's
603+public statement of acceptance of a version permanently authorizes you
604+to choose that version for the Program.
605+
606+ Later license versions may give you additional or different
607+permissions. However, no additional obligations are imposed on any
608+author or copyright holder as a result of your choosing to follow a
609+later version.
610+
611+ 15. Disclaimer of Warranty.
612+
613+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
614+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
615+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
616+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
617+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
618+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
619+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
620+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
621+
622+ 16. Limitation of Liability.
623+
624+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
625+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
626+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
627+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
628+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
629+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
630+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
631+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
632+SUCH DAMAGES.
633+
634+ 17. Interpretation of Sections 15 and 16.
635+
636+ If the disclaimer of warranty and limitation of liability provided
637+above cannot be given local legal effect according to their terms,
638+reviewing courts shall apply local law that most closely approximates
639+an absolute waiver of all civil liability in connection with the
640+Program, unless a warranty or assumption of liability accompanies a
641+copy of the Program in return for a fee.
642+
643+ END OF TERMS AND CONDITIONS
644+
645+ How to Apply These Terms to Your New Programs
646+
647+ If you develop a new program, and you want it to be of the greatest
648+possible use to the public, the best way to achieve this is to make it
649+free software which everyone can redistribute and change under these terms.
650+
651+ To do so, attach the following notices to the program. It is safest
652+to attach them to the start of each source file to most effectively
653+state the exclusion of warranty; and each file should have at least
654+the "copyright" line and a pointer to where the full notice is found.
655+
656+ <one line to give the program's name and a brief idea of what it does.>
657+ Copyright (C) <year> <name of author>
658+
659+ This program is free software: you can redistribute it and/or modify
660+ it under the terms of the GNU Affero General Public License as published by
661+ the Free Software Foundation, either version 3 of the License, or
662+ (at your option) any later version.
663+
664+ This program is distributed in the hope that it will be useful,
665+ but WITHOUT ANY WARRANTY; without even the implied warranty of
666+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
667+ GNU Affero General Public License for more details.
668+
669+ You should have received a copy of the GNU Affero General Public License
670+ along with this program. If not, see <http://www.gnu.org/licenses/>.
671+
672+Also add information on how to contact you by electronic and paper mail.
673+
674+ If your software can interact with users remotely through a computer
675+network, you should also make sure that it provides a way for users to
676+get its source. For example, if your program is a web application, its
677+interface could display a "Source" link that leads users to an archive
678+of the code. There are many ways you could offer source, and different
679+solutions will be better for different programs; see section 13 for the
680+specific requirements.
681+
682+ You should also get your employer (if you work as a programmer) or school,
683+if any, to sign a "copyright disclaimer" for the program, if necessary.
684+For more information on this, and how to apply and follow the GNU AGPL, see
685+<http://www.gnu.org/licenses/>.
686+
687+=========================================================================
688
689=== added file 'Makefile'
690--- Makefile 1970-01-01 00:00:00 +0000
691+++ Makefile 2016-04-21 20:17:50 +0000
692@@ -0,0 +1,26 @@
693+# `charm build` needs the paths to INTERFACES and LAYERS.
694+export INTERFACE_PATH := $(CURDIR)/interfaces
695+export LAYER_PATH := $(CURDIR)/layers
696+
697+all: build
698+
699+install-dependencies:
700+ sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
701+ --no-install-recommends install charm-tools
702+
703+build: maas-region maas-rack
704+
705+
706+maas-region:
707+ charm build -s xenial maas-region -o .
708+
709+maas-rack:
710+ charm build -s xenial maas-rack -o .
711+
712+test: build test-maas-region test-maas-rack
713+
714+test-maas-region:
715+ charm proof xenial/maas-region
716+
717+test-maas-rack:
718+ charm proof xenial/maas-rack
719
720=== added file 'README'
721--- README 1970-01-01 00:00:00 +0000
722+++ README 2016-04-21 20:17:50 +0000
723@@ -0,0 +1,34 @@
724+.. -*- mode: rst -*-
725+
726+********************************
727+MAAS (Metal as a Service) Charms
728+********************************
729+
730+Juju charms that allow deploying both the MAAS region controller and
731+MAAS rack controller.
732+
733+The MAAS region controller is the main communication point for MAAS.
734+Users and tools communicate over the API and UI frontend to control
735+machines and devices. The following services are installed and
736+setup with the maas-region charm:
737+
738+ * bind9
739+ * haproxy
740+ * keepalived (only with vip config is set)
741+ * maas-proxy
742+ * maas-regiond
743+
744+The MAAS rack controller is where BMC's for machines are controller
745+where the machines PXE boot, download images, and contact for DHCP.
746+The following services are installed and setup with the maas-rack
747+charm:
748+
749+ * maas-dhcpd
750+ * maas-dhcpd6
751+ * maas-rackd
752+ * tgtd
753+
754+For more information see `MAAS`_.
755+
756+.. _MAAS: https://maas.io/
757+
758
759=== added directory 'interfaces'
760=== added directory 'interfaces/maas-region-ha'
761=== added file 'interfaces/maas-region-ha/interface.yaml'
762--- interfaces/maas-region-ha/interface.yaml 1970-01-01 00:00:00 +0000
763+++ interfaces/maas-region-ha/interface.yaml 2016-04-21 20:17:50 +0000
764@@ -0,0 +1,4 @@
765+name: maas-region-ha
766+summary: Interface used by MAAS region units
767+version: 1
768+maintainer: "MAAS Maintainers <maas-devel@canonical.com>"
769
770=== added file 'interfaces/maas-region-ha/peers.py'
771--- interfaces/maas-region-ha/peers.py 1970-01-01 00:00:00 +0000
772+++ interfaces/maas-region-ha/peers.py 2016-04-21 20:17:50 +0000
773@@ -0,0 +1,37 @@
774+# Copyright 2016 Canonical Ltd. This software is licensed under the
775+# GNU Affero General Public License version 3 (see the file LICENSE).
776+
777+from subprocess import CalledProcessError
778+
779+from charms.reactive import (
780+ hook,
781+ RelationBase,
782+ scopes,
783+)
784+
785+
786+class MAASRegionPeers(RelationBase):
787+ scope = scopes.UNIT
788+
789+ @hook('{peers:maas-region-ha}-relation-joined')
790+ def joined(self):
791+ conv = self.conversation()
792+ conv.remove_state('{relation_name}.departed')
793+ conv.set_state('{relation_name}.joined')
794+
795+ @hook('{peers:maas-region-ha}-relation-departed')
796+ def departed(self):
797+ conv = self.conversation()
798+ conv.remove_state('{relation_name}.joined')
799+ conv.set_state('{relation_name}.departed')
800+
801+ def get_units(self):
802+ try:
803+ return {
804+ conv.scope: conv.get_remote('private-address')
805+ for conv in self.conversations()
806+ }
807+ except CalledProcessError:
808+ # Possible that when remove the service that self.conversations
809+ # raises this exception.
810+ return {}
811
812=== added directory 'interfaces/maas-rpc'
813=== added file 'interfaces/maas-rpc/interface.yaml'
814--- interfaces/maas-rpc/interface.yaml 1970-01-01 00:00:00 +0000
815+++ interfaces/maas-rpc/interface.yaml 2016-04-21 20:17:50 +0000
816@@ -0,0 +1,4 @@
817+name: maas-rpc
818+summary: Interface used by for maas-rack can connect to maas-region.
819+version: 1
820+maintainer: "MAAS Maintainers <maas-devel@canonical.com>"
821
822=== added file 'interfaces/maas-rpc/provides.py'
823--- interfaces/maas-rpc/provides.py 1970-01-01 00:00:00 +0000
824+++ interfaces/maas-rpc/provides.py 2016-04-21 20:17:50 +0000
825@@ -0,0 +1,32 @@
826+# Copyright 2016 Canonical Ltd. This software is licensed under the
827+# GNU Affero General Public License version 3 (see the file LICENSE).
828+
829+from charms.reactive import RelationBase
830+from charms.reactive import scopes
831+from charms.reactive import hook
832+from charms.reactive import not_unless
833+
834+
835+class MAASRPC(RelationBase):
836+ scope = scopes.GLOBAL
837+
838+ @hook('{provides:maas-rpc}-relation-{changed,joined}')
839+ def changed_joined(self):
840+ self.set_state('{relation_name}.rpc.requested')
841+
842+ @hook('{provides:maas-rpc}-relation-{departed,broken}')
843+ def departed_broken(self):
844+ self.remove_state('{relation_name}.rpc.requested')
845+
846+ @not_unless('{provides:maas-rpc}.rpc.requested')
847+ def set_connection_info(self, maas_url, secret):
848+ """
849+ Set the connection information.
850+
851+ :param str maas_url: The MAAS URL the rack controller should use to
852+ connect.
853+ :param str secret: The secret that should be used to authenticate
854+ the RPC connection.
855+ """
856+ self.set_remote(maas_url=maas_url, secret=secret)
857+ self.remove_state('{relation_name}.rpc.requested')
858
859=== added file 'interfaces/maas-rpc/requires.py'
860--- interfaces/maas-rpc/requires.py 1970-01-01 00:00:00 +0000
861+++ interfaces/maas-rpc/requires.py 2016-04-21 20:17:50 +0000
862@@ -0,0 +1,23 @@
863+# Copyright 2016 Canonical Ltd. This software is licensed under the
864+# GNU Affero General Public License version 3 (see the file LICENSE).
865+
866+from charms.reactive import RelationBase
867+from charms.reactive import hook
868+from charms.reactive import scopes
869+
870+
871+class MAASRPCClient(RelationBase):
872+ scope = scopes.GLOBAL
873+
874+ # These remote data fields will be automatically mapped to accessors
875+ # with a basic documentation string provided.
876+ auto_accessors = ['maas_url', 'secret']
877+
878+ @hook('{requires:maas-rpc}-relation-{changed,joined}')
879+ def changed_joined(self):
880+ if all([self.maas_url(), self.secret()]):
881+ self.set_state('{relation_name}.rpc.available')
882+
883+ @hook('{provides:maas-rpc}-relation-{departed,broken}')
884+ def departed_broken(self):
885+ self.remove_state('{relation_name}.rpc.available')
886
887=== added directory 'layers'
888=== added directory 'layers/maas-rack'
889=== added file 'layers/maas-rack/config.yaml'
890--- layers/maas-rack/config.yaml 1970-01-01 00:00:00 +0000
891+++ layers/maas-rack/config.yaml 2016-04-21 20:17:50 +0000
892@@ -0,0 +1,7 @@
893+options:
894+ ppa:
895+ type: string
896+ default: ''
897+ description: |
898+ PPA to added before installing MAAS. This needs to be set before during
899+ deployment. Changing after initial deployment has no affect.
900
901=== added file 'layers/maas-rack/icon.svg'
902--- layers/maas-rack/icon.svg 1970-01-01 00:00:00 +0000
903+++ layers/maas-rack/icon.svg 2016-04-21 20:17:50 +0000
904@@ -0,0 +1,1 @@
905+<svg xmlns="http://www.w3.org/2000/svg" width="354.331" height="354.331"><g><path d="M326.627 176.777c0 82.76-67.09 149.85-149.85 149.85-82.76 0-149.85-67.09-149.85-149.85 0-82.76 67.09-149.85 149.85-149.85 82.76 0 149.85 67.09 149.85 149.85z" opacity=".597" fill="#333" fill-opacity="0"/><path d="M237.057 181.242c0 46.758-26.955 84.663-60.205 84.663S116.647 228 116.647 181.242c0-46.758 26.955-84.663 60.205-84.663s60.205 37.904 60.205 84.662z" opacity=".597" fill="#dd4814" fill-opacity="0"/><path d="M267.786 221.692c0 15.413-25.13 27.907-56.128 27.907-31 0-56.13-12.495-56.13-27.908 0-15.413 25.13-27.908 56.13-27.908 31 0 56.128 12.495 56.128 27.908z" opacity=".597" fill="#dd4814" fill-opacity="0"/><path d="M321.81 176.228c0 79.71-64.618 144.328-144.328 144.328-79.71 0-144.328-64.618-144.328-144.328 0-79.71 64.618-144.328 144.328-144.328 79.71 0 144.328 64.618 144.328 144.328z" fill="#dd4814"/><g fill="#fff" stroke="#fff" stroke-width=".798"><path d="M164.915 229.485c-18.342.033-50.34.346-63.057 2.305-6.876 1.09-6.34 5.642-6.54 9.397v.067c.2 3.756-.336 8.31 6.54 9.398 16.935 2.61 68.054 2.305 75.58 2.304h.055c7.525 0 58.644.305 75.58-2.304 6.875-1.09 6.368-5.642 6.567-9.398-.21-3.767.348-8.37-6.568-9.464-16.935-2.61-68.054-2.305-75.58-2.305-1.858 0-6.463-.01-12.577 0z"/><path d="M164.915 99.493c-18.342.033-50.34.346-63.057 2.305-6.876 1.09-6.34 5.642-6.54 9.397v.067c.2 3.755-.336 8.308 6.54 9.397 16.935 2.608 68.054 2.305 75.58 2.304h.055c7.525 0 58.644.304 75.58-2.305 6.875-1.09 6.368-5.643 6.567-9.398-.21-3.767.348-8.37-6.568-9.464-16.935-2.61-68.054-2.306-75.58-2.305-1.858 0-6.463-.01-12.577 0z"/><path d="M164.915 186.155c-18.342.032-50.34.345-63.057 2.304-6.876 1.088-6.34 5.64-6.54 9.396v.069c.2 3.755-.336 8.308 6.54 9.397 16.935 2.61 68.054 2.306 75.58 2.305h.055c7.525 0 58.644.305 75.58-2.304 6.875-1.088 6.368-5.64 6.567-9.396-.21-3.768.348-8.37-6.568-9.465-16.935-2.61-68.054-2.306-75.58-2.305-1.858 0-6.463-.01-12.577 0z"/><path d="M164.915 142.824c-18.342.032-50.34.346-63.057 2.304-6.876 1.09-6.34 5.642-6.54 9.398v.068c.2 3.755-.336 8.308 6.54 9.397 16.935 2.61 68.054 2.305 75.58 2.305h.055c7.525 0 58.644.304 75.58-2.305 6.875-1.09 6.368-5.642 6.567-9.397-.21-3.768.348-8.37-6.568-9.465-16.935-2.608-68.054-2.305-75.58-2.304-1.858 0-6.463-.01-12.577 0z"/></g></g></svg>
906\ No newline at end of file
907
908=== added file 'layers/maas-rack/layer.yaml'
909--- layers/maas-rack/layer.yaml 1970-01-01 00:00:00 +0000
910+++ layers/maas-rack/layer.yaml 2016-04-21 20:17:50 +0000
911@@ -0,0 +1,5 @@
912+includes: [
913+ 'layer:basic',
914+ 'interface:maas-rpc',
915+]
916+repo: https://code.launchpad.net/~maas-committers/maas/maas-charms
917
918=== added file 'layers/maas-rack/metadata.yaml'
919--- layers/maas-rack/metadata.yaml 1970-01-01 00:00:00 +0000
920+++ layers/maas-rack/metadata.yaml 2016-04-21 20:17:50 +0000
921@@ -0,0 +1,12 @@
922+name: maas-rack
923+summary: Rack controller for MAAS.
924+maintainer: MAAS Maintainers <maas-devel@canonical.com>
925+description: |
926+ MAAS runs a software-defined data centre - it turns a collection of physical
927+ servers and switches into a bare metal cloud with full open source IP address
928+ management (IPAM) and instant provisioning on demand.
929+tags:
930+ - network
931+requires:
932+ rpc:
933+ interface: maas-rpc
934
935=== added directory 'layers/maas-rack/reactive'
936=== added file 'layers/maas-rack/reactive/rack.py'
937--- layers/maas-rack/reactive/rack.py 1970-01-01 00:00:00 +0000
938+++ layers/maas-rack/reactive/rack.py 2016-04-21 20:17:50 +0000
939@@ -0,0 +1,154 @@
940+# Copyright 2016 Canonical Ltd. This software is licensed under the
941+# GNU Affero General Public License version 3 (see the file LICENSE).
942+
943+import os
944+from subprocess import (
945+ check_call,
946+ check_output,
947+)
948+
949+from charmhelpers import fetch
950+from charmhelpers.core import (
951+ hookenv,
952+ host,
953+ unitdata,
954+)
955+from charms.reactive import (
956+ hook,
957+ when,
958+ when_not,
959+)
960+
961+
962+# Presistent unit data.
963+unit_db = unitdata.kv()
964+
965+
966+# Ports to mark as open when in ready state.
967+ports = [
968+ # DHCP
969+ (67, 'UDP'),
970+ (68, 'UDP'),
971+ # TFTP
972+ (69, 'TCP'),
973+ (69, 'UDP'),
974+ # HTTP
975+ (5248, 'TCP'),
976+ # ISCSI
977+ (860, 'TCP'),
978+ (3260, 'TCP'),
979+]
980+
981+
982+def open_ports():
983+ """Tells Juju about the open ports."""
984+ ports_opened = unit_db.get('ports_opened', False)
985+ if ports_opened:
986+ return
987+ for port, protocol in ports:
988+ hookenv.open_port(port, protocol)
989+ unit_db.set('ports_opened', True)
990+
991+
992+def close_ports():
993+ """Removes opened ports from Juju."""
994+ ports_opened = unit_db.get('ports_opened', False)
995+ if not ports_opened:
996+ return
997+ for port, protocol in ports:
998+ hookenv.close_port(port, protocol)
999+ unit_db.unset('ports_opened')
1000+
1001+
1002+@hook('install')
1003+def install_rack():
1004+ # Place in maintenance.
1005+ hookenv.status_set('maintenance', '')
1006+
1007+ # Add the ppa source if provided in config.
1008+ ppa_source = hookenv.config('ppa')
1009+ if ppa_source:
1010+ hookenv.status_set('maintenance', 'Enabling PPA')
1011+ fetch.add_source(ppa_source)
1012+
1013+ # Update the sources and install the required packages.
1014+ hookenv.status_set('maintenance', 'Installing packages')
1015+ fetch.apt_update()
1016+ fetch.apt_install([
1017+ 'maas-dhcp',
1018+ 'maas-rack-controller'])
1019+
1020+ # Possible re-install remove rackd.conf.
1021+ if os.path.exists('/etc/maas/rackd.conf'):
1022+ os.remove('/etc/maas/rackd.conf')
1023+
1024+ # Install should have rackd off.
1025+ host.service_stop('maas-rackd')
1026+
1027+
1028+@when('rpc.rpc.available')
1029+def update_rackd_config(rpc):
1030+ maas_url = unit_db.get('maas_url')
1031+ rpc_maas_url = rpc.maas_url()
1032+ if rpc_maas_url is None:
1033+ rpc_maas_url = ''
1034+ if maas_url is None or maas_url != rpc_maas_url:
1035+ hookenv.status_set('maintenance', 'Writing maas_url into rackd.conf')
1036+ check_call(['maas-rack', 'config', '--region-url', rpc_maas_url])
1037+ unit_db.set('maas_url', rpc_maas_url)
1038+ secret = unit_db.get('secret')
1039+ rpc_secret = rpc.secret()
1040+ if rpc_secret is None:
1041+ rpc_secret = ''
1042+ if secret is None or secret != rpc_secret:
1043+ hookenv.status_set('maintenance', 'Writing secret into /var/lib/maas/')
1044+ check_output(
1045+ ['maas-rack', 'install-shared-secret'],
1046+ input=rpc_secret.encode('ascii'))
1047+ unit_db.set('secret', rpc_secret)
1048+ if rpc_maas_url:
1049+ # Valid maas_url then we are running.
1050+ if not host.service_running('maas-rackd'):
1051+ host.service_restart('maas-rackd')
1052+ else:
1053+ # maas-rackd will acutally pick this up automatically and does not
1054+ # needs to be reloaded or restarted.
1055+ pass
1056+ open_ports()
1057+ unit_db.set('running', True)
1058+ update_status()
1059+ else:
1060+ # Invalid maas_url so we are no longer running.
1061+ stop_rackd()
1062+
1063+
1064+@when_not('rpc.rpc.available')
1065+def stop_rackd():
1066+ hookenv.status_set('waiting', 'Waiting on relation to maas-region')
1067+ host.service_stop('maas-rackd')
1068+ close_ports()
1069+ unit_db.unset('running')
1070+
1071+
1072+@hook('update-status')
1073+def update_status():
1074+ """Called by Juju to update the status of the service."""
1075+ # Only update the status if running. The reset of the time the other hooks
1076+ # set the correct state.
1077+ running = unit_db.get('running', False)
1078+ if running:
1079+ # Keep rackd running.
1080+ if not host.service_running('maas-rackd'):
1081+ host.service_restart('maas-rackd')
1082+
1083+ # Update status using the dhcpd services.
1084+ dhcpd_running = host.service_running('maas-dhcpd')
1085+ dhcpd6_running = host.service_running('maas-dhcpd6')
1086+ if dhcpd_running and dhcpd6_running:
1087+ hookenv.status_set('active', 'Providing DHCPv4 and DHCPv6')
1088+ elif dhcpd_running:
1089+ hookenv.status_set('active', 'Providing DHCPv4')
1090+ elif dhcpd6_running:
1091+ hookenv.status_set('active', 'Providing DHCPv6')
1092+ else:
1093+ hookenv.status_set('active', 'Ready')
1094
1095=== added directory 'layers/maas-region'
1096=== added file 'layers/maas-region/config.yaml'
1097--- layers/maas-region/config.yaml 1970-01-01 00:00:00 +0000
1098+++ layers/maas-region/config.yaml 2016-04-21 20:17:50 +0000
1099@@ -0,0 +1,150 @@
1100+options:
1101+ ppa:
1102+ type: string
1103+ default: ''
1104+ description: |
1105+ PPA to added before installing MAAS. This needs to be set before during
1106+ deployment. Changing after initial deployment has no affect.
1107+ dbname:
1108+ type: string
1109+ default: maas
1110+ description: Name of the database to use when related to PostgreSQL.
1111+ maas-url:
1112+ type: string
1113+ default: ''
1114+ description: |
1115+ URL that rack controllers connect get RPC information and deploying
1116+ machines use for metadata, APT proxy, and DNS.
1117+ .
1118+ It is recommended to leave this unset. In a multi unit deployment the
1119+ maas_url in the regiond.conf will be set to the leader unit for the
1120+ service unless this is set to override that value.
1121+ vip:
1122+ type: string
1123+ default: ''
1124+ description: |
1125+ IP address deploying machines will use to access their metadata,
1126+ proxy, and DNS. (Recommended in multi unit deployments; overrides the
1127+ maas-url config.)
1128+ .
1129+ The virtual IP address will be placed on the primary maas-region unit for
1130+ deploying machines to communicate to for metadata, APT proxy, and DNS.
1131+ .
1132+ For metadata and APT proxy this will be the load balancer on the
1133+ maas-region unit balancing the requests to all active maas-region units.
1134+ DNS will only be resolved the primary maas-region unit.
1135+ .
1136+ Keepalived is used to keep the virtual IP address on the primary unit.
1137+ admin-username:
1138+ type: string
1139+ default: admin
1140+ description: Username for the initial admin user.
1141+ admin-email:
1142+ type: string
1143+ default: noreply@maas
1144+ description: Email for the initial admin user.
1145+ admin-password:
1146+ type: string
1147+ default: ''
1148+ description: |
1149+ Password for the initial admin user. If not set admin user will not be
1150+ created.
1151+ maas-name:
1152+ type: string
1153+ default: juju-maas
1154+ description: Name to identify this MAAS deployment.
1155+ main-archive:
1156+ type: string
1157+ default: http://archive.ubuntu.com/ubuntu
1158+ description: |
1159+ Ubuntu archive used by machines to retrieve packages for Intel
1160+ architectures.
1161+ ports-archive:
1162+ type: string
1163+ default: http://ports.ubuntu.com/ubuntu-ports
1164+ description: |
1165+ Ubuntu archive used by machines to retrieve packages for non-Intel
1166+ architectures.
1167+ enable-http-proxy:
1168+ type: boolean
1169+ default: True
1170+ description: |
1171+ Enable the use of an APT and HTTP/HTTPS proxy.
1172+ .
1173+ Provision machines to use the built-in HTTP proxy (or user specified
1174+ proxy) for APT. MAAS also uses the proxy for downloading boot images.
1175+ http-proxy:
1176+ type: string
1177+ default: ''
1178+ description: |
1179+ Proxy for APT and HTTP/HTTPS.
1180+ .
1181+ This will be passed onto provisioned machines to use as a proxy for APT
1182+ traffic. MAAS also uses the proxy for downloading boot images. If no
1183+ URL is provided, the built-in MAAS proxy will be used.
1184+ upstream-dns:
1185+ type: string
1186+ default: ''
1187+ description: |
1188+ Upstream DNS used to resolve domains not managed by this MAAS
1189+ (space-separated IP addresses).
1190+ dnssec-validation:
1191+ type: string
1192+ default: auto
1193+ description: |
1194+ Enable DNSSEC validation of upstream zones.
1195+ .
1196+ Only used when MAAS is running its own DNS server. This value is used as
1197+ the value of 'dnssec_validation' in the DNS server config.
1198+ ntp-server:
1199+ type: string
1200+ default: ntp.ubuntu.com
1201+ description: |
1202+ Address of NTP server for machines.
1203+ .
1204+ NTP server address passed to machines via a DHCP response.
1205+ default-storage-layout:
1206+ type: string
1207+ default: flat
1208+ description: |
1209+ Storage layout that is applied to a machine when it is commissioned.
1210+ (Supports: flat, vlm, or bcache).
1211+ enable-disk-erasing-on-release:
1212+ type: boolean
1213+ default: False
1214+ description: |
1215+ Erase machines' disks prior to releasing.
1216+ curtin-verbose:
1217+ type: boolean
1218+ default: False
1219+ description: |
1220+ Turn on curtin verbose logging when a machine is being deployed.
1221+ Installation log for the deployed or failed deployed machine will contain
1222+ detailed log information to aid in bug reporting and development.
1223+ haproxy-stats-enabled:
1224+ type: boolean
1225+ default: False
1226+ description: Enable the stats endpoint on the haproxy.
1227+ haproxy-stats-uri:
1228+ type: string
1229+ default: '/haproxy?stats'
1230+ description: URI for the stats endpoint.
1231+ haproxy-stats-auth:
1232+ type: string
1233+ default: 'ubuntu:ubuntu'
1234+ description: |
1235+ HTTP authentication to access the stats endpoint.
1236+ .
1237+ Accepts a multiple user password combinations. Each user password
1238+ combination should be seperated by a ';'. Example:
1239+ .
1240+ ubuntu:ubuntu;ubuntu1:ubuntu1
1241+ .
1242+ Setting to an empty string will result in no authentication.
1243+ keepalived-router-id:
1244+ type: int
1245+ default: 50
1246+ description: |
1247+ Virtual router ID to use for the keepalived configuration. This needs
1248+ to be unique for the entire network where the deployment exists. (Only
1249+ used when a VIP is set.)
1250
1251=== added file 'layers/maas-region/icon.svg'
1252--- layers/maas-region/icon.svg 1970-01-01 00:00:00 +0000
1253+++ layers/maas-region/icon.svg 2016-04-21 20:17:50 +0000
1254@@ -0,0 +1,1 @@
1255+<svg xmlns="http://www.w3.org/2000/svg" width="354.331" height="354.331"><g><path d="M326.627 176.777c0 82.76-67.09 149.85-149.85 149.85-82.76 0-149.85-67.09-149.85-149.85 0-82.76 67.09-149.85 149.85-149.85 82.76 0 149.85 67.09 149.85 149.85z" opacity=".597" fill="#333" fill-opacity="0"/><path d="M237.057 181.242c0 46.758-26.955 84.663-60.205 84.663S116.647 228 116.647 181.242c0-46.758 26.955-84.663 60.205-84.663s60.205 37.904 60.205 84.662z" opacity=".597" fill="#dd4814" fill-opacity="0"/><path d="M267.786 221.692c0 15.413-25.13 27.907-56.128 27.907-31 0-56.13-12.495-56.13-27.908 0-15.413 25.13-27.908 56.13-27.908 31 0 56.128 12.495 56.128 27.908z" opacity=".597" fill="#dd4814" fill-opacity="0"/><path d="M321.81 176.228c0 79.71-64.618 144.328-144.328 144.328-79.71 0-144.328-64.618-144.328-144.328 0-79.71 64.618-144.328 144.328-144.328 79.71 0 144.328 64.618 144.328 144.328z" fill="#dd4814"/><g fill="#fff" stroke="#fff" stroke-width=".798"><path d="M164.915 229.485c-18.342.033-50.34.346-63.057 2.305-6.876 1.09-6.34 5.642-6.54 9.397v.067c.2 3.756-.336 8.31 6.54 9.398 16.935 2.61 68.054 2.305 75.58 2.304h.055c7.525 0 58.644.305 75.58-2.304 6.875-1.09 6.368-5.642 6.567-9.398-.21-3.767.348-8.37-6.568-9.464-16.935-2.61-68.054-2.305-75.58-2.305-1.858 0-6.463-.01-12.577 0z"/><path d="M164.915 99.493c-18.342.033-50.34.346-63.057 2.305-6.876 1.09-6.34 5.642-6.54 9.397v.067c.2 3.755-.336 8.308 6.54 9.397 16.935 2.608 68.054 2.305 75.58 2.304h.055c7.525 0 58.644.304 75.58-2.305 6.875-1.09 6.368-5.643 6.567-9.398-.21-3.767.348-8.37-6.568-9.464-16.935-2.61-68.054-2.306-75.58-2.305-1.858 0-6.463-.01-12.577 0z"/><path d="M164.915 186.155c-18.342.032-50.34.345-63.057 2.304-6.876 1.088-6.34 5.64-6.54 9.396v.069c.2 3.755-.336 8.308 6.54 9.397 16.935 2.61 68.054 2.306 75.58 2.305h.055c7.525 0 58.644.305 75.58-2.304 6.875-1.088 6.368-5.64 6.567-9.396-.21-3.768.348-8.37-6.568-9.465-16.935-2.61-68.054-2.306-75.58-2.305-1.858 0-6.463-.01-12.577 0z"/><path d="M164.915 142.824c-18.342.032-50.34.346-63.057 2.304-6.876 1.09-6.34 5.642-6.54 9.398v.068c.2 3.755-.336 8.308 6.54 9.397 16.935 2.61 68.054 2.305 75.58 2.305h.055c7.525 0 58.644.304 75.58-2.305 6.875-1.09 6.368-5.642 6.567-9.397-.21-3.768.348-8.37-6.568-9.465-16.935-2.608-68.054-2.305-75.58-2.304-1.858 0-6.463-.01-12.577 0z"/></g></g></svg>
1256\ No newline at end of file
1257
1258=== added file 'layers/maas-region/layer.yaml'
1259--- layers/maas-region/layer.yaml 1970-01-01 00:00:00 +0000
1260+++ layers/maas-region/layer.yaml 2016-04-21 20:17:50 +0000
1261@@ -0,0 +1,8 @@
1262+includes: [
1263+ 'layer:basic',
1264+ 'layer:leadership',
1265+ 'interface:maas-region-ha',
1266+ 'interface:maas-rpc',
1267+ 'interface:pgsql',
1268+]
1269+repo: https://code.launchpad.net/~maas-committers/maas/maas-charms
1270
1271=== added file 'layers/maas-region/metadata.yaml'
1272--- layers/maas-region/metadata.yaml 1970-01-01 00:00:00 +0000
1273+++ layers/maas-region/metadata.yaml 2016-04-21 20:17:50 +0000
1274@@ -0,0 +1,18 @@
1275+name: maas-region
1276+summary: Region controller for MAAS.
1277+maintainer: MAAS Maintainers <maas-devel@canonical.com>
1278+description: |
1279+ MAAS runs a software-defined data centre - it turns a collection of physical
1280+ servers and switches into a bare metal cloud with full open source IP address
1281+ management (IPAM) and instant provisioning on demand.
1282+tags:
1283+ - network
1284+peers:
1285+ ha:
1286+ interface: maas-region-ha
1287+provides:
1288+ rpc:
1289+ interface: maas-rpc
1290+requires:
1291+ db:
1292+ interface: pgsql
1293
1294=== added directory 'layers/maas-region/reactive'
1295=== added file 'layers/maas-region/reactive/region.py'
1296--- layers/maas-region/reactive/region.py 1970-01-01 00:00:00 +0000
1297+++ layers/maas-region/reactive/region.py 2016-04-21 20:17:50 +0000
1298@@ -0,0 +1,737 @@
1299+# Copyright 2016 Canonical Ltd. This software is licensed under the
1300+# GNU Affero General Public License version 3 (see the file LICENSE).
1301+
1302+import ipaddress
1303+import json
1304+import os
1305+from functools import partial
1306+from subprocess import (
1307+ CalledProcessError,
1308+ check_call,
1309+ check_output,
1310+)
1311+import yaml
1312+
1313+from charmhelpers import fetch
1314+from charmhelpers.core import (
1315+ hookenv,
1316+ host,
1317+ sysctl,
1318+ templating,
1319+ unitdata,
1320+)
1321+from charms import leadership
1322+from charms.reactive import (
1323+ hook,
1324+ when,
1325+ when_any,
1326+ when_not,
1327+ when_file_changed,
1328+ set_state,
1329+ remove_state,
1330+)
1331+
1332+
1333+# Presistent unit data.
1334+unit_db = unitdata.kv()
1335+
1336+# Global config options
1337+global_configs = [
1338+ ('maas-name', 'maas_name', 'string'),
1339+ ('main-archive', 'main_archive', 'string'),
1340+ ('ports-archive', 'ports_archive', 'string'),
1341+ ('enable-http-proxy', 'enable_http_proxy', 'boolean'),
1342+ ('http-proxy', 'http_proxy', 'string'),
1343+ ('upstream-dns', 'upstream_dns', 'string'),
1344+ ('dnssec-validation', 'dnssec_validation', 'string'),
1345+ ('ntp-server', 'ntp_server', 'string'),
1346+ ('default-storage-layout', 'default_storage_layout', 'string'),
1347+ (
1348+ 'enable-disk-erasing-on-release',
1349+ 'enable_disk_erasing_on_release', 'boolean'),
1350+ ('curtin-verbose', 'curtin_verbose', 'boolean'),
1351+]
1352+
1353+# Ports to mark as open when in ready state.
1354+ports = [
1355+ # DNS
1356+ (53, 'TCP'),
1357+ (53, 'UDP'),
1358+ # API and WebUI
1359+ (80, 'TCP'),
1360+ # RPC
1361+ (5250, 'TCP'),
1362+ (5251, 'TCP'),
1363+ (5252, 'TCP'),
1364+ (5253, 'TCP'),
1365+ # Proxy
1366+ (8000, 'TCP'),
1367+]
1368+
1369+
1370+def is_valid_ip(ip):
1371+ """Return True if `ip` is valid."""
1372+ try:
1373+ ipaddress.ip_address(ip)
1374+ except ValueError:
1375+ return False
1376+ else:
1377+ return True
1378+
1379+
1380+def get_ip_version(ip):
1381+ """Return the IP version of the `ip`."""
1382+ return ipaddress.ip_address(ip).version
1383+
1384+
1385+def allows_ip_nonlocal_bind(ip_version):
1386+ """Return True if `ip_nonlocal_bind` for the IP version is allowed."""
1387+ with open('/proc/sys/net/ipv%d/ip_nonlocal_bind' % ip_version, 'r') as fp:
1388+ return int(fp.read().strip()) == 1
1389+
1390+
1391+def is_in_container():
1392+ """Return True if running in container."""
1393+ try:
1394+ check_call(['systemd-detect-virt', '-c', '-q'])
1395+ except CalledProcessError:
1396+ return False
1397+ else:
1398+ return True
1399+
1400+
1401+def get_filtered_ip_addr():
1402+ """Return filtered ip addr information."""
1403+ # python3-maas-provisioningserver will be installed before this function
1404+ # is called.
1405+ from provisioningserver.utils.ipaddr import get_ip_addr
1406+ return {
1407+ name: ipaddr
1408+ for name, ipaddr in get_ip_addr().items()
1409+ if (ipaddr['type'] not in ['loopback', 'ipip'] and
1410+ not ipaddr['type'].startswith('unknown-'))
1411+ }
1412+
1413+
1414+def get_interface_for_ip(ip_address):
1415+ """Return the name of the interface that has a subnet that `ip_address`
1416+ belongs."""
1417+ ip_version = get_ip_version(ip_address)
1418+ ip_address = ipaddress.ip_address(ip_address)
1419+ inet = "inet"
1420+ if ip_version == 6:
1421+ inet = "inet6"
1422+ ipaddr_info = get_filtered_ip_addr()
1423+ for name, ipaddr in ipaddr_info.items():
1424+ for address in ipaddr.get(inet, []):
1425+ if ip_address in ipaddress.ip_network(address, strict=False):
1426+ hookenv.log(
1427+ "Found interface %s for VIP %s." % (name, ip_address))
1428+ return name
1429+ sorted_interfaces = sorted(ipaddr_info.keys())
1430+ if len(sorted_interfaces) > 0:
1431+ hookenv.log(
1432+ "Unable to find specific interface for VIP %s; "
1433+ "selected %s instead." % (ip_address, sorted_interfaces[0]))
1434+ return sorted_interfaces[0]
1435+ else:
1436+ raise ValueError(
1437+ "Unable to identify interface for VIP %s." % ip_address)
1438+
1439+
1440+def unit_has_ip(ip_address):
1441+ """Return True if the unit has the `ip_address` on any interface."""
1442+ ip_version = get_ip_version(ip_address)
1443+ ip_address = ipaddress.ip_address(ip_address)
1444+ inet = "inet"
1445+ if ip_version == 6:
1446+ inet = "inet6"
1447+ ipaddr_info = get_filtered_ip_addr()
1448+ for name, ipaddr in ipaddr_info.items():
1449+ for address in ipaddr.get(inet, []):
1450+ if '/' in address:
1451+ address = address.split('/')[0]
1452+ if ip_address == ipaddress.ip_address(address):
1453+ return True
1454+ return False
1455+
1456+
1457+def lsmod():
1458+ """Return a list of loaded kernel modules."""
1459+ output = check_output(['lsmod']).decode('utf-8')
1460+ return [
1461+ line.split()[0]
1462+ for line in output.splitlines()
1463+ ]
1464+
1465+
1466+def is_module_loaded(module):
1467+ """Return True if module is loaded."""
1468+ modules = lsmod()
1469+ return module in modules
1470+
1471+
1472+def is_blocked_by_missing_module(module):
1473+ """Check if blocked by the fact 'ip_vs' module is not loaded and also
1474+ running in a container."""
1475+ return not is_module_loaded(module) and is_in_container()
1476+
1477+
1478+def get_regiond_config_value(name):
1479+ """Return the configuration value for `name`."""
1480+ arg_name = name.replace('_', '-')
1481+ conf_settings = json.loads(
1482+ check_output([
1483+ 'maas-region', 'local_config_get',
1484+ '--json', '--%s' % arg_name]).decode('ascii'))
1485+ return conf_settings.get(name)
1486+
1487+
1488+def regiond_ready_to_run():
1489+ """Return True if database_pass set in regiond.conf."""
1490+ dbpass = get_regiond_config_value('database_pass')
1491+ return (
1492+ dbpass is not None and
1493+ len(dbpass) > 0 and
1494+ not dbpass.isspace())
1495+
1496+
1497+def get_maas_secret():
1498+ """Return the MAAS secret value."""
1499+ with open('/var/lib/maas/secret', 'r') as fp:
1500+ return fp.read().strip()
1501+
1502+
1503+def get_apikey():
1504+ """Return the API key for the admin user."""
1505+ apikey = leadership.leader_get('apikey')
1506+ if not apikey:
1507+ apikey = check_output([
1508+ 'maas-region', 'apikey',
1509+ '--username', leadership.leader_get('admin_username')])
1510+ apikey = apikey.decode('ascii').strip()
1511+ leadership.leader_set(apikey=apikey)
1512+ return apikey
1513+
1514+
1515+def update_config_value(charm_name, maas_name, value_type="string"):
1516+ """Update the global config values."""
1517+ if not hookenv.is_leader():
1518+ # Only the leader updates config values.
1519+ return
1520+ admin_username = leadership.leader_get('admin_username')
1521+ if not admin_username:
1522+ # Value can only be set once an administrator has been created.
1523+ return
1524+
1525+ # Ensure logged into API.
1526+ check_call([
1527+ 'maas', 'login', 'juju-admin',
1528+ 'http://localhost:5240/MAAS', get_apikey()])
1529+
1530+ # Get the current value.
1531+ result = check_output([
1532+ 'maas', 'juju-admin', 'maas', 'get-config', 'name=%s' % maas_name])
1533+ result = result.decode("utf-8")
1534+ if value_type == "boolean":
1535+ if result == "true":
1536+ result = True
1537+ else:
1538+ result = False
1539+
1540+ # Update the value if its different.
1541+ new_value = hookenv.config(charm_name)
1542+ if result != new_value:
1543+ check_call([
1544+ 'maas', 'juju-admin', 'maas',
1545+ 'set-config', 'name=%s' % maas_name, 'value=%s' % new_value])
1546+
1547+
1548+def set_all_global_configs():
1549+ """Set all global configs.
1550+
1551+ Called after the administrator is first created.
1552+ """
1553+ hookenv.status_set('maintenance', 'Setting all global config options')
1554+ for charm_name, maas_name, value_type in global_configs:
1555+ update_config_value(charm_name, maas_name, value_type)
1556+
1557+
1558+def update_admin(old_username, username, email, password):
1559+ env = os.environ.copy()
1560+ env['DJANGO_SETTINGS_MODULE'] = 'maas.settings'
1561+ env['PYTHONPATH'] = '/usr/share/maas'
1562+ check_call([
1563+ 'python3', 'scripts/update_user.py',
1564+ '--old-username', old_username,
1565+ '--username', username,
1566+ '--email', email,
1567+ '--password', password], env=env)
1568+
1569+
1570+def is_vip_valid():
1571+ vip = hookenv.config('vip')
1572+ if not vip:
1573+ return True
1574+ elif is_valid_ip(vip):
1575+ ip_version = get_ip_version(vip)
1576+ if is_blocked_by_missing_module('ip_vs'):
1577+ hookenv.status_set(
1578+ 'blocked',
1579+ 'Kernel module ip_vs is not loaded and cannot be loaded when '
1580+ 'in a container')
1581+ return False
1582+ else:
1583+ return True
1584+ else:
1585+ hookenv.status_set(
1586+ 'blocked', 'Config vip invalid; not valid IP address')
1587+ host.service_stop('maas-regiond')
1588+ close_ports()
1589+ return False
1590+
1591+
1592+def open_ports():
1593+ """Tells Juju about the open ports."""
1594+ ports_opened = unit_db.get('ports_opened', False)
1595+ if ports_opened:
1596+ return
1597+ for port, protocol in ports:
1598+ hookenv.open_port(port, protocol)
1599+ unit_db.set('ports_opened', True)
1600+
1601+
1602+def close_ports():
1603+ """Removes opened ports from Juju."""
1604+ ports_opened = unit_db.get('ports_opened', False)
1605+ if not ports_opened:
1606+ return
1607+ for port, protocol in ports:
1608+ hookenv.close_port(port, protocol)
1609+ unit_db.unset('ports_opened')
1610+
1611+
1612+@hook('install')
1613+def install_region():
1614+ # Place in maintenance.
1615+ hookenv.status_set('maintenance', '')
1616+
1617+ # Add the ppa source if provided in config.
1618+ ppa_source = hookenv.config('ppa')
1619+ if ppa_source:
1620+ hookenv.status_set('maintenance', 'Enabling PPA')
1621+ fetch.add_source(ppa_source)
1622+
1623+ # Update the sources and install the required packages.
1624+ hookenv.status_set('maintenance', 'Installing packages')
1625+ fetch.apt_update()
1626+ fetch.apt_install([
1627+ 'haproxy',
1628+ 'maas-cli',
1629+ 'maas-dns',
1630+ 'maas-region-api'])
1631+
1632+ # Stop and disable apache2. Charm uses haproxy.
1633+ # maas-region-api should not depend on apache2.
1634+ host.service_stop('apache2')
1635+ host.service('disable', 'apache2')
1636+
1637+ # Possible re-install remove regiond.conf.
1638+ if os.path.exists('/etc/maas/regiond.conf'):
1639+ os.remove('/etc/maas/regiond.conf')
1640+
1641+ # Install should have regiond off.
1642+ host.service_stop('maas-regiond')
1643+
1644+ # Configure haproxy.
1645+ configure_haproxy()
1646+
1647+
1648+@hook('config-changed')
1649+def update_global_configs():
1650+ config = hookenv.config()
1651+ for charm_name, maas_name, value_type in global_configs:
1652+ if config.changed(charm_name):
1653+ update_config_value(charm_name, maas_name, value_type)
1654+
1655+
1656+@hook('db-relation-joined')
1657+def db_joined(pgsql):
1658+ # psql layer does not handle departing correctly. We set
1659+ # db_joined so the write_db_config is not skipped.
1660+ unit_db.set('db_joined', True)
1661+ hookenv.status_set('waiting', 'Requesting database from PostgreSQL')
1662+ pgsql.change_database_name(hookenv.config('dbname'))
1663+
1664+
1665+@hook('db-relation-departed')
1666+def db_departed(pgsql):
1667+ # psql layer does not handle departing correctly. We clear
1668+ # db_joined so the write_db_config is skipped.
1669+ unit_db.unset('db_joined')
1670+ unit_db.unset('dbhost')
1671+ unit_db.unset('dbdb')
1672+ unit_db.unset('dbuser')
1673+ unit_db.unset('dbpass')
1674+ check_call([
1675+ 'maas-region', 'local_config_set',
1676+ '--database-host', '',
1677+ '--database-name', '',
1678+ '--database-user', '',
1679+ '--database-pass', '',
1680+ ])
1681+ close_ports()
1682+ host.service_stop('maas-regiond')
1683+ hookenv.status_set('waiting', 'Waiting on relation to PostgreSQL')
1684+
1685+
1686+@when_any('config.changed.maas-url', 'config.changed.vip')
1687+def write_maas_url():
1688+ hookenv.status_set('maintenance', 'Writing maas_url into regiond.conf')
1689+ vip = hookenv.config('vip')
1690+ maas_url = hookenv.config('maas-url')
1691+ if vip:
1692+ if not is_valid_ip(vip):
1693+ url = ''
1694+ else:
1695+ url = 'http://%s/MAAS' % vip
1696+ elif maas_url:
1697+ url = maas_url
1698+ else:
1699+ url = 'http://localhost/MAAS'
1700+ check_call([
1701+ 'maas-region', 'local_config_set',
1702+ '--maas-url', url,
1703+ ])
1704+ start_regiond_when_ready()
1705+
1706+
1707+@when_not('db.database.available')
1708+def missing_postgresql():
1709+ close_ports()
1710+ host.service_stop('maas-regiond')
1711+ hookenv.status_set('waiting', 'Waiting on relation to PostgreSQL')
1712+
1713+
1714+@when('db.database.available')
1715+def write_db_config(pgsql):
1716+ # Do nothing if not db joined.
1717+ if not unit_db.get('db_joined', False):
1718+ return
1719+
1720+ # Update the database configuration only if any of the configuration
1721+ # values have changed. Nothing needs to be done if nothing has changed.
1722+ dbhost = pgsql.host()
1723+ dbdb = pgsql.database()
1724+ dbuser = pgsql.user()
1725+ dbpass = pgsql.password()
1726+ has_changed = (
1727+ unit_db.get('dbhost') != dbhost or
1728+ unit_db.get('dbdb') != dbdb or
1729+ unit_db.get('dbuser') != dbuser or
1730+ unit_db.get('dbpass') != dbpass)
1731+ if has_changed:
1732+ unit_db.set('dbhost', dbhost)
1733+ unit_db.set('dbdb', dbdb)
1734+ unit_db.set('dbuser', dbuser)
1735+ unit_db.set('dbpass', dbpass)
1736+ hookenv.status_set(
1737+ 'maintenance', 'Writing db configuration into regiond.conf')
1738+
1739+ check_call([
1740+ 'maas-region', 'local_config_set',
1741+ '--database-host', dbhost if dbhost else '',
1742+ '--database-name', dbdb if dbdb else '',
1743+ '--database-user', dbuser if dbuser else '',
1744+ '--database-pass', dbpass if dbpass else '',
1745+ ])
1746+ if all([dbhost, dbdb, dbuser, dbpass]):
1747+ start_regiond_when_ready()
1748+ else:
1749+ host.service_stop('maas-regiond')
1750+ hookenv.status_set('waiting', 'Waiting on relation to PostgreSQL')
1751+
1752+
1753+@when_any(
1754+ 'config.changed.haproxy-stats-enabled',
1755+ 'config.changed.haproxy-stats-uri',
1756+ 'config.changed.haproxy-stats-auth')
1757+def configure_haproxy():
1758+ """Write /etc/haproxy/haproxy.conf and reload haproxy."""
1759+ ha_units = unit_db.get('ha_units')
1760+ if ha_units is None:
1761+ ha_units = {}
1762+ templating.render('haproxy.cfg', '/etc/haproxy/haproxy.cfg', {
1763+ 'stats_enabled': hookenv.config('haproxy-stats-enabled'),
1764+ 'stats_uri': hookenv.config('haproxy-stats-uri'),
1765+ 'stats_auth': hookenv.config('haproxy-stats-auth'),
1766+ 'unit_name': hookenv.local_unit(),
1767+ 'unit_address': hookenv.unit_private_ip(),
1768+ 'ha_units': ha_units,
1769+ })
1770+
1771+
1772+@when_any(
1773+ 'config.changed.admin-username',
1774+ 'config.changed.admin-email',
1775+ 'config.changed.admin-password')
1776+def configure_admin_user():
1777+ """Configure administrator user."""
1778+ if hookenv.is_leader():
1779+ username = hookenv.config('admin-username')
1780+ email = hookenv.config('admin-email')
1781+ password = hookenv.config('admin-password')
1782+ if username and email and password:
1783+ admin_username = leadership.leader_get('admin_username')
1784+ if admin_username:
1785+ # Change the admin username, email, and password.
1786+ hookenv.status_set('maintenance', 'Leader: updating admin')
1787+ update_admin(admin_username, username, email, password)
1788+ leadership.leader_set(admin_username=username)
1789+ else:
1790+ # Create the admin user.
1791+ hookenv.status_set('maintenance', 'Leader: creating admin')
1792+ check_call([
1793+ 'maas-region', 'createadmin',
1794+ '--username', username,
1795+ '--email', email,
1796+ '--password', password,
1797+ ])
1798+ leadership.leader_set(admin_username=username)
1799+
1800+ # Update the state.
1801+ update_state()
1802+
1803+
1804+@when('ha.joined')
1805+def ha_unit_joined(ha):
1806+ unit_db.set('ha_units', ha.get_units())
1807+ configure_haproxy()
1808+
1809+
1810+@when('ha.departed')
1811+def ha_unit_departed(ha):
1812+ unit_db.set('ha_units', ha.get_units())
1813+ configure_haproxy()
1814+
1815+
1816+@when('leadership.changed.running_migrations')
1817+@when_file_changed('/etc/maas/regiond.conf')
1818+def start_regiond_when_ready():
1819+ # Prevent regiond from running if vip is invalid.
1820+ if not is_vip_valid():
1821+ return
1822+
1823+ # Only start regiond if migrations are not running and regiond
1824+ # is ready to run.
1825+ running_migrations = leadership.leader_get('running_migrations')
1826+ running_migrations = running_migrations == 'True'
1827+ if running_migrations:
1828+ if not hookenv.is_leader():
1829+ hookenv.status_set(
1830+ 'waiting', 'Waiting for leader to finish migrations')
1831+ host.service_stop('maas-regiond')
1832+ elif regiond_ready_to_run():
1833+ if hookenv.is_leader():
1834+ # Leader of the service and run migrations if needed.
1835+ migrations_ran = leadership.leader_get('migrations_ran')
1836+ migrations_ran = migrations_ran == 'True'
1837+ if not migrations_ran:
1838+ # XXX 2016-04-18 blake_r: Should detect if a new version of
1839+ # MAAS requires migrations to be ran again.
1840+ hookenv.status_set('maintenance', 'Leader: running migrations')
1841+ host.service_stop('maas-regiond')
1842+ leadership.leader_set(running_migrations='True')
1843+ check_call(['maas-region', 'dbupgrade'])
1844+ leadership.leader_set(
1845+ running_migrations='', migrations_ran='True')
1846+ else:
1847+ # Not the leader and migrations aren't being run, regiond
1848+ # can start.
1849+ hookenv.status_set('maintenance', 'Restarting regiond')
1850+
1851+ # Update any RPC relations with the new maas_url.
1852+ maas_url = get_regiond_config_value('maas_url')
1853+ if maas_url and maas_url != unit_db.get('rpc_maas_url', None):
1854+ send_maas_url = maas_url
1855+ if maas_url == "http://localhost/MAAS" and hookenv.is_leader():
1856+ # MAAS url on the region is set to localhost so we tell the
1857+ # rack to connect over the private address.
1858+ send_maas_url = "http://%s/MAAS" % hookenv.unit_private_ip()
1859+ for relation_id in hookenv.relation_ids('rpc'):
1860+ hookenv.relation_set(relation_id, {'maas_url': send_maas_url})
1861+ unit_db.set('rpc_maas_url', maas_url)
1862+
1863+ # Restart regiond so its has the latest configuration.
1864+ host.service_restart('maas-regiond')
1865+ update_state()
1866+
1867+
1868+@when_file_changed('/etc/haproxy/haproxy.conf')
1869+def reload_haproxy():
1870+ if host.service_running('haproxy'):
1871+ hookenv.status_set(
1872+ 'maintenance', 'Reloading haproxy')
1873+ host.service_reload('haproxy')
1874+ else:
1875+ hookenv.status_set(
1876+ 'maintenance', 'Starting haproxy')
1877+ host.service_restart('haproxy')
1878+ update_state()
1879+
1880+
1881+@when_any(
1882+ 'config.changed.vip',
1883+ 'leadership.changed.admin_username')
1884+def update_state():
1885+ # If VIP is set it needs to be correct before doing anything else.
1886+ if not is_vip_valid():
1887+ close_ports()
1888+ return
1889+
1890+ # We need to have a working haproxy and regiond before going forward.
1891+ running_migrations = leadership.leader_get('running_migrations')
1892+ running_migrations = running_migrations == 'True'
1893+ if (running_migrations or
1894+ not regiond_ready_to_run() or
1895+ not host.service_running('maas-regiond') or
1896+ not host.service_running('haproxy')):
1897+ close_ports()
1898+ return
1899+
1900+ # The DNS options need to be migrated before continuing.
1901+ dns_migrated = unit_db.get('dns_migrated', False)
1902+ if not dns_migrated:
1903+ hookenv.status_set('maintenance', 'Migrating DNS options')
1904+ check_call([
1905+ 'maas-region', 'edit_named_options',
1906+ '--migrate-conflicting-options'])
1907+ host.service_restart('bind9')
1908+ unit_db.set('dns_migrated', True)
1909+
1910+ # Make sure that administrator user has been created.
1911+ admin_username = leadership.leader_get('admin_username')
1912+ if not admin_username:
1913+ if hookenv.is_leader():
1914+ hookenv.status_set(
1915+ 'blocked', 'Missing admin config')
1916+ else:
1917+ hookenv.status_set(
1918+ 'waiting', 'Waiting for leader to configure admin account')
1919+ return
1920+
1921+ # Set all global configs if never done.
1922+ if hookenv.is_leader():
1923+ set_global_configs = leadership.leader_get('set_global_configs')
1924+ set_global_configs = set_global_configs == 'True'
1925+ if not set_global_configs:
1926+ set_all_global_configs()
1927+ leadership.leader_set(set_global_configs='True')
1928+
1929+ # Mark that the ports are open.
1930+ open_ports()
1931+
1932+ # If not VIP is set then the leader unit is the primary.
1933+ vip = hookenv.config('vip')
1934+ if vip:
1935+ # Determine leader by looking for VIP.
1936+ if unit_has_ip(vip):
1937+ hookenv.status_set(
1938+ 'active', 'Primary DNS and balancing HTTP (VIP: %s)' % vip)
1939+ else:
1940+ hookenv.status_set('active', 'Secondary DNS and balancing HTTP')
1941+ else:
1942+ # Leader is determined by Juju.
1943+ if hookenv.is_leader():
1944+ hookenv.status_set('active', 'Primary DNS and balancing HTTP')
1945+ else:
1946+ hookenv.status_set('active', 'Secondary DNS and balancing HTTP')
1947+
1948+
1949+@when_any(
1950+ 'config.changed.vip',
1951+ 'config.changed.keepalived-router-id',
1952+ 'leadership.changed.keepalived_pass')
1953+def update_vip_config():
1954+ vip = hookenv.config('vip')
1955+ if vip:
1956+ # If VIP is invalid and keepalived was running stop it and remove
1957+ # the configuration.
1958+ if not is_vip_valid() and unit_db.get('keepalived_running', False):
1959+ host.service_stop('keepalived')
1960+ if os.path.exists('/etc/keepalived/keepalived.conf'):
1961+ os.remove('/etc/keepalived/keepalived.conf')
1962+ return
1963+
1964+ # Using VIP configuration; setup keepalived.
1965+ keepalived_installed = unit_db.get('keepalived_installed', False)
1966+ if not keepalived_installed:
1967+ # Check to see if keepalived needs to be installed.
1968+ packages = fetch.filter_installed_packages(['keepalived'])
1969+ if len(packages) > 0:
1970+ fetch.apt_update()
1971+ fetch.apt_install(packages)
1972+ unit_db.set('keepalived_installed', True)
1973+
1974+ # Load the ip_vs module if needed.
1975+ module_loaded = False
1976+ if not is_module_loaded('ip_vs') and not is_in_container():
1977+ check_call(['modprobe', 'ip_vs'])
1978+ module_loaded = True
1979+
1980+ # Enable ip_nonlocal_bind if needed.
1981+ ip_version = get_ip_version(vip)
1982+ if not allows_ip_nonlocal_bind(ip_version):
1983+ sysctl.create(yaml.dump({
1984+ "net.ipv%s.ip_nonlocal_bind" % ip_version: 1
1985+ }), "/etc/sysctl.d/50-maas-region-nonlocal.conf")
1986+ host.service_start("procps")
1987+
1988+ # Get the keepalived password.
1989+ keepalived_pass = leadership.leader_get('keepalived_pass')
1990+ if not keepalived_pass:
1991+ if hookenv.is_leader():
1992+ keepalived_pass = host.pwgen()
1993+ leadership.leader_set(keepalived_pass=keepalived_pass)
1994+ else:
1995+ hookenv.status_set(
1996+ 'waiting',
1997+ 'Waiting on leader for keepalived authentication password')
1998+ return
1999+
2000+ # Get the interface that should be used for the VIP.
2001+ interface = get_interface_for_ip(vip)
2002+
2003+ # Write the keepalived.conf.
2004+ templating.render(
2005+ 'keepalived.conf', '/etc/keepalived/keepalived.conf', {
2006+ 'interface': interface,
2007+ 'priority': hookenv.local_unit().split('/')[1],
2008+ 'virtual_router_id': hookenv.config('keepalived-router-id'),
2009+ 'auth_pass': keepalived_pass,
2010+ 'vip': vip,
2011+ })
2012+
2013+ # Restart keepalived if stopped or the kernel module was loaded,
2014+ # otherwise just reload the config.
2015+ if host.service_running('keepalived') and not module_loaded:
2016+ host.service_reload('keepalived')
2017+ else:
2018+ host.service_restart('keepalived')
2019+ unit_db.set('keepalived_running', True)
2020+
2021+ elif unit_db.get('keepalived_running', False):
2022+ # Keepalived is running stop it and remove the config.
2023+ host.service_stop('keepalived')
2024+ os.remove('/etc/keepalived/keepalived.conf')
2025+
2026+ update_state()
2027+
2028+
2029+@when('rpc.rpc.requested')
2030+def rpc_requested(rpc):
2031+ if regiond_ready_to_run():
2032+ maas_url = get_regiond_config_value('maas_url')
2033+ unit_db.set('rpc_maas_url', maas_url)
2034+ rpc.set_connection_info(
2035+ maas_url, get_maas_secret())
2036
2037=== added directory 'layers/maas-region/scripts'
2038=== added file 'layers/maas-region/scripts/update_user.py'
2039--- layers/maas-region/scripts/update_user.py 1970-01-01 00:00:00 +0000
2040+++ layers/maas-region/scripts/update_user.py 2016-04-21 20:17:50 +0000
2041@@ -0,0 +1,26 @@
2042+# Copyright 2016 Canonical Ltd. This software is licensed under the
2043+# GNU Affero General Public License version 3 (see the file LICENSE).
2044+
2045+import argparse
2046+import os
2047+
2048+from django.contrib.auth.models import User
2049+
2050+
2051+def main():
2052+ parser = argparse.ArgumentParser()
2053+ parser.add_argument('--old-username', required=True)
2054+ parser.add_argument('--username', required=True)
2055+ parser.add_argument('--password', required=True)
2056+ parser.add_argument('--email', required=True)
2057+
2058+ args = parser.parse_args()
2059+ user = User.objects.get(username=args.old_username)
2060+ user.username = args.username
2061+ user.email = args.email
2062+ user.set_password(args.password)
2063+ user.save()
2064+
2065+
2066+if __name__ == "__main__":
2067+ main()
2068
2069=== added directory 'layers/maas-region/templates'
2070=== added file 'layers/maas-region/templates/haproxy.cfg'
2071--- layers/maas-region/templates/haproxy.cfg 1970-01-01 00:00:00 +0000
2072+++ layers/maas-region/templates/haproxy.cfg 2016-04-21 20:17:50 +0000
2073@@ -0,0 +1,70 @@
2074+global
2075+ log /dev/log local0
2076+ log /dev/log local1 notice
2077+ chroot /var/lib/haproxy
2078+ stats socket /run/haproxy/admin.sock mode 660 level admin
2079+ stats timeout 30s
2080+ user haproxy
2081+ group haproxy
2082+ daemon
2083+
2084+ # Default SSL material locations
2085+ ca-base /etc/ssl/certs
2086+ crt-base /etc/ssl/private
2087+
2088+ # Default ciphers to use on SSL-enabled listening sockets.
2089+ # For more information, see ciphers(1SSL). This list is from:
2090+ # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/
2091+ ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS
2092+ ssl-default-bind-options no-sslv3
2093+
2094+defaults
2095+ log global
2096+ mode http
2097+ option httplog
2098+ option dontlognull
2099+ retries 3
2100+ option redispatch
2101+ option http-server-close
2102+ timeout connect 5000
2103+ timeout client 50000
2104+ timeout server 50000
2105+ errorfile 400 /etc/haproxy/errors/400.http
2106+ errorfile 403 /etc/haproxy/errors/403.http
2107+ errorfile 408 /etc/haproxy/errors/408.http
2108+ errorfile 500 /etc/haproxy/errors/500.http
2109+ errorfile 502 /etc/haproxy/errors/502.http
2110+ errorfile 503 /etc/haproxy/errors/503.http
2111+ errorfile 504 /etc/haproxy/errors/504.http
2112+
2113+frontend maas
2114+ bind *:80
2115+ default_backend maas
2116+ {% if stats_enabled -%}
2117+ stats enable
2118+ stats uri {{ stats_uri }}
2119+ stats realm Haproxy\ Statistics
2120+ {% for auth in stats_auth.split(';') -%}
2121+ stats auth {{ auth }}
2122+ {%- endfor %}
2123+ {%- endif %}
2124+
2125+backend maas
2126+ timeout server 30s
2127+ balance roundrobin
2128+ server {{unit_name.replace('/', '-')}} {{unit_address}}:5240 check
2129+ {% for ha_name, ha_address in ha_units.items() -%}
2130+ server {{ha_name.replace('/', '-')}} {{ha_address}}:5240 check
2131+ {%- endfor %}
2132+
2133+frontend maas-proxy
2134+ bind *:8000
2135+ default_backend maas-proxy
2136+
2137+backend maas-proxy
2138+ timeout server 30s
2139+ balance roundrobin
2140+ server {{unit_name.replace('/', '-')}} {{unit_address}}:5240 check
2141+ {% for ha_name, ha_address in ha_units.items() -%}
2142+ server {{ha_name.replace('/', '-')}} {{ha_address}}:5240 check
2143+ {% endfor %}
2144
2145=== added file 'layers/maas-region/templates/keepalived.conf'
2146--- layers/maas-region/templates/keepalived.conf 1970-01-01 00:00:00 +0000
2147+++ layers/maas-region/templates/keepalived.conf 2016-04-21 20:17:50 +0000
2148@@ -0,0 +1,30 @@
2149+vrrp_script chk_haproxy {
2150+ script "killall -0 haproxy"
2151+ interval 2
2152+}
2153+
2154+vrrp_script chk_named {
2155+ script "killall -0 named"
2156+ interval 2
2157+}
2158+
2159+vrrp_instance maas_region {
2160+ state MASTER
2161+ interface {{ interface }}
2162+ priority {{ priority }}
2163+ virtual_router_id {{ virtual_router_id }}
2164+
2165+ authentication {
2166+ auth_type PASS
2167+ auth_pass {{ auth_pass }}
2168+ }
2169+
2170+ track_script {
2171+ chk_haproxy
2172+ chk_named
2173+ }
2174+
2175+ virtual_ipaddress {
2176+ {{ vip }}
2177+ }
2178+}

Subscribers

People subscribed via source and target branches

to all changes: