Revision 0e1f3323

b/snf-cyclades-gtools/synnefo/ganeti/eventd.py
56 56
from signal import signal, SIGINT, SIGTERM
57 57
import setproctitle
58 58

  
59
from ganeti import utils
60
from ganeti import jqueue
61
from ganeti import constants
62
from ganeti import serializer
59
from ganeti import utils, jqueue, constants, serializer, cli
63 60
from ganeti.ssconf import SimpleConfigReader
64 61

  
65 62

  
......
67 64
from synnefo.lib.amqp import AMQPClient
68 65

  
69 66

  
70

  
71 67
def get_time_from_status(op, job):
72 68
    """Generate a unique message identifier for a ganeti job.
73 69

  
......
97 93
    raise InvalidBackendStatus(status, job)
98 94

  
99 95

  
96
def get_instance_nics(instance, logger):
97
    """Query Ganeti to a get the instance's NICs.
98

  
99
    @type instance: string
100
    @param instance: the name of the instance
101
    @rtype: List of dicts
102
    @retrun: Dictionary containing the instance's NICs. Each dictionary
103
             contains the following keys: 'network', 'ip', 'mac', 'mode',
104
             'link' and 'firewall'
105

  
106
    """
107
    fields = ["nic.networks", "nic.ips", "nic.macs", "nic.modes", "nic.links",
108
              "tags"]
109
    # Get Ganeti client
110
    client = cli.GetClient()
111
    info = client.QueryInstances([instance], fields, use_locking=False)
112
    networks, ips, macs, modes, links, tags = info[0]
113
    nic_keys = ["network", "ip", "mac", "mode", "link"]
114
    nics = zip(networks, ips, macs, modes, links)
115
    nics = map(lambda x: dict(zip(nic_keys, x)), nics)
116
    # Get firewall from instance Tags
117
    # Tags are of the form synnefo:network:N:firewall_mode
118
    for tag in tags:
119
        t = tag.split(":")
120
        if t[0:2] == ["synnefo", "network"]:
121
            if len(t) != 4:
122
                logger.error("Malformed synefo tag %s", tag)
123
                continue
124
            try:
125
                index = int(t[2])
126
                nics[index]['firewall'] = t[3]
127
            except ValueError:
128
                logger.error("Malformed synnefo tag %s", tag)
129
            except IndexError:
130
                logger.error("Found tag %s for non-existent NIC %d",
131
                             tag, index)
132
    return nics
133

  
134

  
100 135
class InvalidBackendStatus(Exception):
101 136
    def __init__(self, status, job):
102 137
        self.status = status
......
192 227
                        "logmsg": logmsg,
193 228
                        "jobId": job_id})
194 229

  
230
            if op_id in ["OP_INSTANCE_CREATE", "OP_INSTANCE_SET_PARAMS",
231
                         "OP_INSTANCE_STARTUP"]:
232
                if op.status == "success":
233
                    nics = get_instance_nics(msg["instance"], self.logger)
234
                    msg["nics"] = nics
235

  
195 236
            msg = json.dumps(msg)
196 237
            self.logger.debug("Delivering msg: %s (key=%s)", msg, routekey)
197 238

  
b/snf-cyclades-gtools/test/synnefo.ganeti_unittest.py
1 1
#!/usr/bin/env python
2
#
3 2
# -*- coding: utf-8 -*-
4 3
#
5
# Copyright 2011 GRNET S.A. All rights reserved.
4
# Copyright 2013 GRNET S.A. All rights reserved.
6 5
#
7 6
# Redistribution and use in source and binary forms, with or
8 7
# without modification, are permitted provided that the following
......
35 34
# interpreted as representing official policies, either expressed
36 35
# or implied, of GRNET S.A.
37 36
#
38
#
39

  
40
"""Unit Tests for the Ganeti-specific interfaces in synnefo.ganeti
41

  
42
Provides unit tests for the code implementing
43
the Ganeti notification daemon and the Ganeti hook in Synnefo.
44

  
45
"""
46

  
47
# This assumes a test-specific configuration file
48
# is in the same directory as the unit test script
49
import os
50
os.environ["SYNNEFO_CONFIG_DIR"] = os.path.dirname(__file__)
51 37

  
38
import sys
52 39
import logging
53
import unittest
40
from synnefo.ganeti.eventd import get_instance_nics
41
from mock import patch
54 42

  
55
from synnefo.ganeti.hook import ganeti_net_status
43
log = logging.getLogger()
56 44

  
45
# Use backported unittest functionality if Python < 2.7
46
try:
47
    import unittest2 as unittest
48
except ImportError:
49
    if sys.version_info < (2, 7):
50
        raise Exception("The unittest2 package is required for Python < 2.7")
51
    import unittest
57 52

  
58
class GanetiHookTestCase(unittest.TestCase):
59 53

  
60
    def setUp(self):
61
        # Example Ganeti environment, based on from
62
        # http://docs.ganeti.org/ganeti/master/html/hooks.html?highlight=hooks#examples
63
        self.env = {
64
            'GANETI_CLUSTER': 'cluster1.example.com',
65
            'GANETI_DATA_DIR': '/var/lib/ganeti',
66
            'GANETI_FORCE': 'False',
67
            'GANETI_HOOKS_PATH': 'instance-start',
68
            'GANETI_HOOKS_PHASE': 'post',
69
            'GANETI_HOOKS_VERSION': '2',
70
            'GANETI_INSTANCE_DISK0_MODE': 'rw',
71
            'GANETI_INSTANCE_DISK0_SIZE': '128',
72
            'GANETI_INSTANCE_DISK_COUNT': '1',
73
            'GANETI_INSTANCE_DISK_TEMPLATE': 'drbd',
74
            'GANETI_INSTANCE_MEMORY': '128',
75
            'GANETI_INSTANCE_TAGS': 'tag1 synnefo:network:0:protected tag2',
76
            'GANETI_INSTANCE_NAME': 'instance2.example.com',
77
            'GANETI_INSTANCE_NIC0_BRIDGE': 'xen-br0',
78
            'GANETI_INSTANCE_NIC0_IP': '147.102.3.1',
79
            'GANETI_INSTANCE_NIC0_MAC': '00:01:de:ad:be:ef',
80
            'GANETI_INSTANCE_NIC1_MAC': '00:01:de:ad:ba:be',
81
            'GANETI_INSTANCE_NIC2_MAC': '00:01:02:03:04:05',
82
            'GANETI_INSTANCE_NIC2_IP': '147.102.3.98',
83
            'GANETI_INSTANCE_NIC_COUNT': '3',
84
            'GANETI_INSTANCE_OS_TYPE': 'debootstrap',
85
            'GANETI_INSTANCE_PRIMARY': 'node3.example.com',
86
            'GANETI_INSTANCE_SECONDARY': 'node5.example.com',
87
            'GANETI_INSTANCE_STATUS': 'down',
88
            'GANETI_INSTANCE_VCPUS': '1',
89
            'GANETI_MASTER': 'node1.example.com',
90
            'GANETI_OBJECT_TYPE': 'INSTANCE',
91
            'GANETI_OP_CODE': 'OP_INSTANCE_STARTUP',
92
            'GANETI_OP_TARGET': 'instance2.example.com'
93
        }
54
@patch("ganeti.cli.GetClient")
55
class GanetiNICTestCase(unittest.TestCase):
56
    def test_no_nics(self, client):
57
        ret = [[[], [], [], [], [], []]]
58
        client.return_value.QueryInstances.return_value = ret
59
        self.assertEqual(get_instance_nics('test', log), [])
94 60

  
95
    def test_ganeti_net_status(self):
96
        e = self.env
97
        expected = {
98
            'type': 'ganeti-net-status',
99
            'instance': 'instance2.example.com',
100
            'nics': [
101
                {
102
                    'ip': '147.102.3.1', 'mac': '00:01:de:ad:be:ef',
103
                    'link': 'xen-br0', 'ipv6': '2001:db8::201:deff:fead:beef',
104
                    'firewall': 'protected'
105
                },
106
                { 'mac': '00:01:de:ad:ba:be' },
107
                { 'ip': '147.102.3.98', 'mac': '00:01:02:03:04:05' }
108
            ]
109
        }
61
    def test_one_nic(self, client):
62
        ret = [[["network"], ["ip"], ["mac"], ["mode"], ["link"],
63
                ["tag1", "tag2"]]]
64
        client.return_value.QueryInstances.return_value = ret
65
        nics0 = get_instance_nics("test", log)
66
        nics1 = [{"network": "network",
67
                  "ip": "ip",
68
                  "mac": "mac",
69
                  "mode": "mode",
70
                  "link": "link"}]
71
        self.assertEqual(nics0, nics1)
110 72

  
111
        self.assertEqual(ganeti_net_status(logging, e), expected)
73
    def test_two_nics(self, client):
74
        ret = [[["network1", "network2"], ["ip1", "ip2"], ["mac1", "mac2"],
75
                ["mode1", "mode2"], ["link1", "link2"], ["tag1", "tag2"]]]
76
        client.return_value.QueryInstances.return_value = ret
77
        nics0 = get_instance_nics("test", log)
78
        nics1 = [{"network": "network1",
79
                  "ip": "ip1",
80
                  "mac": "mac1",
81
                  "mode": "mode1",
82
                  "link": "link1"},
83
                  {"network": "network2",
84
                   "ip": "ip2",
85
                   "mac": "mac2",
86
                   "mode": "mode2",
87
                   "link": "link2"}]
88
        self.assertEqual(nics0, nics1)
89

  
90
    def test_firewall(self, client):
91
        ret = [[["network"], ["ip"], ["mac"], ["mode"], ["link"],
92
            ["tag1", "synnefo:network:0:protected"]]]
93
        client.return_value.QueryInstances.return_value = ret
94
        nics0 = get_instance_nics("test", log)
95
        nics1 = [{"network": "network",
96
                  "ip": "ip",
97
                  "mac": "mac",
98
                  "mode": "mode",
99
                  "link": "link",
100
                  "firewall": "protected"}]
101
        self.assertEqual(nics0, nics1)
112 102

  
113 103

  
114 104
if __name__ == '__main__':
115 105
    unittest.main()
116

  

Also available in: Unified diff