File: load_generator.py

package info (click to toggle)
vitrage 15.0.1-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 6,908 kB
  • sloc: python: 35,107; sh: 405; makefile: 64
file content (157 lines) | stat: -rw-r--r-- 5,389 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# Copyright 2017 - Nokia
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import sys

import cotyledon
from futurist import periodics
from futurist import ThreadPoolExecutor

from oslo_config import cfg
from oslo_log import log
import oslo_messaging
from tools.load_generator.notification_info import COMPUTE_INSTANCE_CREATE_END
from tools.load_generator.notification_info import PORT_CREATE_END
from tools.load_generator.notification_info import VOLUME_ATTACH_END
from tools.load_generator.notification_info import VOLUME_CREATE_END

from vitrage.common import config
from vitrage.messaging import get_transport


CONF = cfg.CONF
LOG = log.getLogger(__name__)

EXISTING_COMPUTES_NUM = 64
VMS_PER_COMPUTE = 2
NET_ID = '59fec1a4-7ab2-4bc6-8792-0ddf54b15dfe'
RUN_EVERY_X_SECONDS = 600

"""
Stress Notifications Tool:

Following service runs a timed action every X seconds.
Action will send mock bus notifications, as configured in the constants above.
Sends mock notifications for:
    VM create
    Port create
    volume create
    volume attach

1. To use this, place computes.yaml at /etc/vitrage/static_datasources/
   and restart vitrage-graph.
2. EXISTING_COMPUTES_NUM should match the computes defined in computes.yaml
3. Configure NET_ID to an existing network (this tool doesnt create networks)
4. Run 'python load_generator.py'

Number of vms = VMS_PER_COMPUTE * EXISTING_COMPUTES_NUM
Number of ports = VMS_PER_COMPUTE * EXISTING_COMPUTES_NUM
Number of volumes = VMS_PER_COMPUTE * EXISTING_COMPUTES_NUM

Notifications are sent repeatedly every RUN_EVERY_X_SECONDS, this is
to avoid Vitrage consistency deleting the created resources.

* Folder /templates also includes templates to create load on the evaluator

"""


class StressNotificationsService(cotyledon.Service):
    def __init__(self, worker_id):
        super(StressNotificationsService, self).__init__(worker_id)
        self.oslo_notifier = None
        topics = CONF.datasources.notification_topics
        self.oslo_notifier = oslo_messaging.Notifier(
            get_transport(),
            driver='messagingv2',
            publisher_id='vitrage.stress',
            topics=topics)
        self.periodic = periodics.PeriodicWorker.create(
            [], executor_factory=lambda: ThreadPoolExecutor(max_workers=10))

    def run(self):
        LOG.info("StressNotificationsService - Started!")
        self.periodic.add(self.stress_notifications)
        self.periodic.start()

    def terminate(self):
        self.periodic.stop()
        LOG.info("StressNotificationsService - Stopped!")

    @periodics.periodic(spacing=RUN_EVERY_X_SECONDS)
    def stress_notifications(self):
        notifications = []
        for i in range(EXISTING_COMPUTES_NUM * VMS_PER_COMPUTE):
            vm = create_vm(i, i % EXISTING_COMPUTES_NUM)
            port = create_port(i, vm[0][1]['instance_id'], vm[0][1]['host'],
                               NET_ID)
            storage = create_storage(i, vm[0][1]['instance_id'])
            notifications.extend(vm)
            notifications.extend(port)
            notifications.extend(storage)

        LOG.info("Notifications Created - " + str(len(notifications)))
        LOG.info("Sending...")
        for n in notifications:
            self._send(*n)
        LOG.info("Sent!")

    def _send(self, notification_type, payload):
        try:
            self.oslo_notifier.info(
                {},
                notification_type,
                payload)
        except Exception:
            LOG.exception('Cannot notify - %s', notification_type)


def create_port(port_num, instance_id, host_id, net_id):
    payload = copy.deepcopy(PORT_CREATE_END)
    payload['port']['id'] = 'StressPort-' + str(port_num)
    payload['port']['device_id'] = instance_id
    payload['port']['binding:host_id'] = host_id
    payload['port']['network_id'] = net_id
    return [('port.create.end', payload)]


def create_storage(volume_num, instance_id):
    payload_1 = copy.deepcopy(VOLUME_CREATE_END)
    payload_1['volume_id'] = 'StressVolume-' + str(volume_num)

    payload_2 = copy.deepcopy(VOLUME_ATTACH_END)
    payload_2['volume_id'] = payload_1['volume_id']
    payload_2['volume_attachment'][0]['volume']['id'] = payload_1['volume_id']
    payload_2['volume_attachment'][0]['instance_uuid'] = instance_id

    return [('volume.create.end', payload_1),
            ('volume.attach.end', payload_2)]


def create_vm(instance_num, compute_num):
    payload = copy.deepcopy(COMPUTE_INSTANCE_CREATE_END)
    payload['instance_id'] = 'StressVM-' + str(instance_num)
    payload['node'] = payload['host'] = "compute-0-" + str(compute_num)
    return [('compute.instance.create.end', payload)]


def main():
    config.parse_config(sys.argv)
    sm = cotyledon.ServiceManager()
    sm.add(StressNotificationsService)
    sm.run()


if __name__ == "__main__":
    sys.exit(main())