~ubuntu-branches/ubuntu/raring/maas/raring-updates

« back to all changes in this revision

Viewing changes to src/maasserver/management/commands/reconcile.py

  • Committer: Package Import Robot
  • Author(s): Andres Rodriguez
  • Date: 2012-07-03 17:42:37 UTC
  • mfrom: (1.1.13)
  • Revision ID: package-import@ubuntu.com-20120703174237-p8l0keuuznfg721k
Tags: 0.1+bzr709+dfsg-0ubuntu1
* New Upstream release
* debian/control:
  - Depends on python-celery, python-tempita, libjs-yui3-{full,min},
    libjs-raphael
* debian/maas.install:
  - Install apiclient, celeryconfig.py, maas-import-pxe-files, preseeds_v2.
  - Update to install various files from chroot, rather tha manually copy
    them from the source.
* debian/maas.links: symlink celeryconfig.py
* debian/maas.maas-celery.upstart: Add job.
* debian/rules:
  - Install celery upstart job.
  - Do not install jslibs as packages are now used.
  - Drop copying of maas_local_settings_sample.py as source now ships
    a maas_local_settings.py
* debian/patches:
  - 04-maas-http-fix.patch: Drop. Merged upstream.
  - 01-fix-database-settings.patch: Refreshed.
  - 99_enums_js.patch: Added until creation of enum.js / build process
    is fixed.
* debian/maas.postinst: Update bzr version to correctly handle upgrades.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2012 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
"""Reconcile MAAS's view of the world with the Provisioning Server's.
 
5
 
 
6
Both MAAS and the Provisioning Server will be examined. Missing nodes will be
 
7
copied in *both* directions. Nodes that exist in common will have their MAC
 
8
addresses reconciled in *both* directions. The result should be the union of
 
9
nodes in MAAS and nodes as the Provisioning Server sees them.
 
10
 
 
11
The Provisioning Server is currently stateless, so this actually implies
 
12
reconciling with Cobbler.
 
13
 
 
14
************************************************************************
 
15
**                DO NOT USE ON A PRODUCTION SYSTEM                   **
 
16
**            This is intended for use as a QA tool only              **
 
17
************************************************************************
 
18
"""
 
19
 
 
20
from __future__ import (
 
21
    absolute_import,
 
22
    print_function,
 
23
    unicode_literals,
 
24
    )
 
25
 
 
26
__metaclass__ = type
 
27
__all__ = [
 
28
    "Command",
 
29
    ]
 
30
 
 
31
from django.core.management.base import NoArgsCommand
 
32
from maasserver import provisioning
 
33
from maasserver.enum import ARCHITECTURE
 
34
from maasserver.models import Node
 
35
 
 
36
 
 
37
ARCHITECTURE_GUESSES = {
 
38
    "i386": ARCHITECTURE.i386,
 
39
    "amd64": ARCHITECTURE.amd64,
 
40
    "x86_64": ARCHITECTURE.amd64,
 
41
    }
 
42
 
 
43
 
 
44
def guess_architecture_from_profile(profile_name):
 
45
    """
 
46
    This attempts to obtain the architecture from a Cobbler profile name. The
 
47
    naming convention for profile names is "maas-${series}-${arch}".
 
48
    """
 
49
    for guess, architecture in ARCHITECTURE_GUESSES.items():
 
50
        if guess in profile_name:
 
51
            return architecture
 
52
    else:
 
53
        return None
 
54
 
 
55
 
 
56
def reconcile():
 
57
    papi = provisioning.get_provisioning_api_proxy()
 
58
    nodes_local = {node.system_id: node for node in Node.objects.all()}
 
59
    nodes_remote = papi.get_nodes()
 
60
 
 
61
    missing_local = set(nodes_remote).difference(nodes_local)
 
62
    missing_local.discard("default")
 
63
    for name in missing_local:
 
64
        print("remote:", name)
 
65
        remote_node = nodes_remote[name]
 
66
        local_node = Node(
 
67
            system_id=remote_node["name"],
 
68
            architecture=(
 
69
                guess_architecture_from_profile(remote_node["profile"])),
 
70
            power_type=remote_node["power_type"],
 
71
            hostname=remote_node["name"])
 
72
        local_node.save()
 
73
        for mac_address in remote_node["mac_addresses"]:
 
74
            local_node.add_mac_address(mac_address)
 
75
 
 
76
    missing_remote = set(nodes_local).difference(nodes_remote)
 
77
    for name in missing_remote:
 
78
        print("local:", name)
 
79
        local_node = nodes_local[name]
 
80
        provisioning.provision_post_save_Node(
 
81
            sender=None, instance=local_node, created=False)
 
82
 
 
83
    present_in_both = set(nodes_local).intersection(nodes_remote)
 
84
    for name in present_in_both:
 
85
        print("common:", name)
 
86
        node_local = nodes_local[name]
 
87
        node_remote = nodes_remote[name]
 
88
        # Check that MACs are the same.
 
89
        macs_local = {
 
90
            mac.mac_address
 
91
            for mac in node_local.macaddress_set.all()
 
92
            }
 
93
        print("- local macs:", " ".join(sorted(macs_local)))
 
94
        macs_remote = {
 
95
            mac for mac in node_remote["mac_addresses"]
 
96
            }
 
97
        print("- remote macs:", " ".join(sorted(macs_remote)))
 
98
        for mac in macs_remote - macs_local:
 
99
            node_local.add_mac_address(mac)
 
100
        if len(macs_local - macs_remote) != 0:
 
101
            provisioning.set_node_mac_addresses(node_local)
 
102
 
 
103
 
 
104
class Command(NoArgsCommand):
 
105
 
 
106
    help = __doc__
 
107
 
 
108
    def handle_noargs(self, **options):
 
109
        reconcile()