aboutsummaryrefslogtreecommitdiffstats
path: root/yardstick/benchmark/scenarios/energy/energy.py
blob: 7440835be2f3b539aa3a03039c746bc483e5710e (plain)
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
##############################################################################
# Copyright (c) 2019 Lenovo Group Limited Co.,Ltd and others.
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
##############################################################################

from __future__ import print_function
from __future__ import absolute_import
import logging
import requests
import json
from yardstick.benchmark.scenarios import base

LOG = logging.getLogger(__name__)
logging.captureWarnings(True)


class Energy(base.Scenario):
    """Get current energy consumption of target host

    This scenario sends a REDFISH request to a host BMC
    to request current energy consumption.
    The response returns a number of Watts.
    Usually this is an average of a rolling windows
    taken from server internal sensor.
    This is dependant of the server provider.

    This scenario should be used with node context

    As this scenario usually run background with other scenarios,
    error of api query or data parse will not terminate task runner.
    If any error occured, energy consumption will be set to -1.

    Parameters
        None
    """

    __scenario_type__ = "Energy"

    def __init__(self, scenario_cfg, context_cfg):
        self.scenario_cfg = scenario_cfg
        self.context_cfg = context_cfg
        self.target = self.context_cfg['target']
        self.setup_done = False
        self.get_response = False

    def _send_request(self, url):
        LOG.info("Send request to %s", url)
        pod_auth = (self.target["redfish_user"], self.target["redfish_pwd"])
        response = requests.get(url, auth=pod_auth, verify=False)
        return response

    def setup(self):
        url = "https://{}/redfish/v1/".format(self.target["redfish_ip"])
        response = self._send_request(url)
        if response.status_code != 200:
            LOG.info("Don't get right response from %s", url)
            self.get_response = False
        else:
            LOG.info("Get response from %s", url)
            self.get_response = True

        self.setup_done = True

    def load_chassis_list(self):
        chassis_list = []

        # Get Chassis list
        request_url = "https://" + self.target["redfish_ip"]
        request_url += "/redfish/v1/Chassis/"
        response = self._send_request(request_url)
        if response.status_code != 200:
            LOG.info("Do not get proper response from %s", request_url)
            return chassis_list

        try:
            chassis_data = json.loads(response.text)
        except(TypeError, ValueError) as e:
            LOG.info("Invalid response data, %s", e)
            return chassis_list

        try:
            for chassis in chassis_data['Members']:
                chassis_list.append(chassis["@odata.id"])
        except KeyError as e:
            LOG.info("Error data format of chassis data or invalid key.")

        return chassis_list

    def get_power(self, chassis_uri):
        """Get PowerMetter values from Redfish API."""
        if chassis_uri[-1:] != '/':
            chassis_uri += '/'
        request_url = "https://" + self.target['redfish_ip']
        request_url += chassis_uri
        request_url += "Power/"
        response = self._send_request(request_url)
        if response.status_code != 200:
            LOG.info("Do not get proper response from %s", request_url)
            power = -1
            return power

        try:
            power_metrics = json.loads(response.text)
        except(TypeError, ValueError) as e:
            LOG.info("Invalid response data, %s", e)
            power = -1
            return power

        try:
            power = power_metrics["PowerControl"][0]["PowerConsumedWatts"]
        except KeyError as e:
            LOG.info("Error data format of power metrics or invalid key.")
            power = -1

        return power

    def run(self, result):
        """execute the benchmark"""
        if not self.setup_done:
            self.setup()
        chassis_list = self.load_chassis_list()
        if not self.get_response or not chassis_list:
            power = -1
            data = {
                "power": power,
            }
            result.update(data)
        else:
            power = 0
            for chassis in chassis_list:
                power += self.get_power(chassis)
            data = {
                "power": power,
            }
            result.update(data)