snapshot.py 8.55 KB
Newer Older
1 2 3
# -*- coding: utf-8 -*-
##############################################################################
#
4
# Copyright (c) 2010-2014 Vifib SARL and Contributors.
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
# All Rights Reserved.
#
# WARNING: This program as such is intended to be used by professional
# programmers who take the whole responsibility of assessing all potential
# consequences resulting from its eventual inadequacies and bugs
# End users who are looking for a ready-to-use solution with commercial
# guarantees and support are strongly adviced to contract a Free Software
# Service Company
#
# This program is Free Software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation; either version 2.1
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
#
##############################################################################

import psutil
import os
32
import subprocess
33 34 35 36 37 38
from temperature import collectComputerTemperature, \
                        launchTemperatureTest

from temperature.heating import get_contribution_ratio

MEASURE_INTERVAL = 5
39 40 41 42 43 44 45 46 47 48

class _Snapshot(object):
  def get(self, property, default=None):
    return getattr(self, property, default)

class ProcessSnapshot(_Snapshot):
  """ Take a snapshot from the running process
  """
  def __init__(self, process=None):
    assert type(process) is psutil.Process
49
    ui_counter_list = process.io_counters()
50
    self.username = process.username()
51
    self.process_object = process
52 53
    self.pid = process.pid 
    # Save full command line from the process.
54
    self.process = "%s-%s" % (process.pid, process.create_time())
55
    # CPU percentage, we will have to get actual absolute value
56
    self.cpu_percent = self.process_object.cpu_percent(None)
57
    # CPU Time
58
    self.cpu_time = sum(process.cpu_times())
59
    # Thread number, might not be really relevant
60
    self.cpu_num_threads = process.num_threads()
61
    # Memory percentage
62
    self.memory_percent = process.memory_percent()
63
    # Resident Set Size, virtual memory size is not accouned for
64
    self.memory_rss = process.memory_info()[0]
65 66 67 68 69
    # Byte count, Read and write. OSX NOT SUPPORTED
    self.io_rw_counter = ui_counter_list[2] + ui_counter_list[3]
    # Read + write IO cycles
    self.io_cycles_counter  = ui_counter_list[0] + ui_counter_list[1]

70
  def update_cpu_percent(self):
71 72
    if self.process_object.is_running():
      # CPU percentage, we will have to get actual absolute value
73
      self.cpu_percent = self.process_object.cpu_percent()
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
class FolderSizeSnapshot(_Snapshot):
  """Calculate partition folder size. 
  """
  def __init__(self, folder_path, pid_file=None, use_quota=False):
    # slapos computer partition size
    self.folder_path = folder_path
    self.pid_file = pid_file
    self.disk_usage = 0
    self.use_quota = use_quota

  def update_folder_size(self):
    """Return 0 if the process du is still running
    """
    if self.pid_file and os.path.exists(self.pid_file):
      with open(self.pid_file, 'r') as fpid:
        pid_str = fpid.read()
        if pid_str:
          pid = int(pid_str)
          try:
            os.kill(pid, 0)
          except OSError:
            pass
          else:
            return

    self.disk_usage = self._getSize(self.folder_path)
    # If extra disk added to partition
    data_dir = os.path.join(self.folder_path, 'DATA')
    if os.path.exists(data_dir):
      for filename in os.listdir(data_dir):
        extra_path = os.path.join(data_dir, filename)
        if os.path.islink(extra_path) and os.path.isdir('%s/' % extra_path):
          self.disk_usage += self._getSize('%s/' % extra_path)

  def _getSize(self, file_path):
    size = 0
111
    command = 'du -s %s' % file_path
112 113 114 115 116 117 118 119 120 121
    process = subprocess.Popen(command, stdout=subprocess.PIPE, 
                              stderr=subprocess.PIPE, shell=True)
    if self.pid_file:
      with open(self.pid_file, 'w') as fpid:
        pid = fpid.write(str(process.pid))
    result = process.communicate()[0]
    if process.returncode == 0:
      size, _  = result.strip().split()
    return float(size)

122 123 124
class SystemSnapshot(_Snapshot):
  """ Take a snapshot from current system usage
  """
125 126 127 128 129
  def __init__(self, interval=MEASURE_INTERVAL):

    cpu_idle_percentage = psutil.cpu_times_percent(interval=interval).idle
    load_percent = 100 - cpu_idle_percentage

130
    memory = psutil.virtual_memory()
131 132 133 134 135
    net_io = psutil.net_io_counters()
    
    self.memory_used = memory.used
    self.memory_free = memory.free
    self.memory_percent = memory.percent
136 137
    #self.cpu_percent = psutil.cpu_percent()
    self.cpu_percent = load_percent
138 139 140 141 142 143 144 145
    self.load = os.getloadavg()[0]
    self.net_in_bytes = net_io.bytes_recv
    self.net_in_errors = net_io.errin
    self.net_in_dropped = net_io.dropin
    self.net_out_bytes = net_io.bytes_sent
    self.net_out_errors = net_io.errout
    self.net_out_dropped = net_io.dropout

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
class TemperatureSnapshot(_Snapshot):
  """ Take a snapshot from the current temperature on 
      all available sensors
  """
  def __init__(self, sensor_id, temperature, alarm):
    self.sensor_id = sensor_id
    self.temperature = temperature
    self.alarm = alarm

class HeatingContributionSnapshot(_Snapshot):

  def __init__(self, sensor_id, model_id):
    self.initial_temperature = None
    
    result = launchTemperatureTest(sensor_id)
    if result is None:
      print "Impossible to test sensor: %s " % sensor_id
      

    initial_temperature, final_temperature, duration = result 
    
    self.initial_temperature = initial_temperature
    self.final_temperature = final_temperature
    self.delta_time = duration
    self.model_id = model_id
    self.sensor_id = sensor_id
    self.zero_emission_ratio = self._get_contribution_ratio()

  def _get_contribution_ratio(self):
    delta_temperature = (self.final_temperature-self.initial_temperature)
    contribution_value = delta_temperature/self.delta_time
    return get_contribution_ratio(self.model_id, contribution_value)

  def _get_uptime(self):
    # Linux only
    if os.path.exists('/proc/uptime'):
      with open('/proc/uptime', 'r') as f:
        return float(f.readline().split()[0])

    return -1


188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
class DiskPartitionSnapshot(_Snapshot):
  """ Take Snapshot from general disk partitions 
      usage 
  """
  def __init__(self, partition, mountpoint):
    self.partition = partition
    self.mountpoint_list = [ mountpoint ]
    disk = psutil.disk_usage(mountpoint)
    disk_io = psutil.disk_io_counters()

    self.disk_size_used = disk.used
    self.disk_size_free = disk.free
    self.disk_size_percent = disk.percent

class ComputerSnapshot(_Snapshot):
  """ Take a snapshot from computer informations
  """
205
  def __init__(self, model_id=None, sensor_id=None, test_heating=False):
206
    self.cpu_num_core = psutil.cpu_count()
207 208
    self.cpu_frequency = 0
    self.cpu_type = 0
209
    self.memory_size = psutil.virtual_memory().total
210 211 212 213 214 215 216
    self.memory_type = 0

    #
    # Include a SystemSnapshot and a list DiskPartitionSnapshot
    # on a Computer Snapshot
    #
    self.system_snapshot = SystemSnapshot()
217
    self.temperature_snapshot_list = self._get_temperature_snapshot_list()
218 219 220
    self.disk_snapshot_list = []
    self.partition_list = self._get_physical_disk_info()

221 222 223 224 225 226 227 228 229 230 231 232
    if test_heating and model_id is not None \
                    and sensor_id is not None:
      self.heating_contribution_snapshot = HeatingContributionSnapshot(sensor_id, model_id)

  def _get_temperature_snapshot_list(self):
    temperature_snapshot_list = []
    for sensor_entry in collectComputerTemperature():
      sensor_id, temperature, maximal, critical, alarm = sensor_entry
      temperature_snapshot_list.append(
          TemperatureSnapshot(sensor_id, temperature, alarm))
    return temperature_snapshot_list

233 234 235 236 237 238 239 240 241 242 243 244
  def _get_physical_disk_info(self):
    partition_dict = {}

    for partition in psutil.disk_partitions():
      if partition.device not in partition_dict:
        usage = psutil.disk_usage(partition.mountpoint)
        partition_dict[partition.device] = usage.total
        self.disk_snapshot_list.append(
          DiskPartitionSnapshot(partition.device, 
                                partition.mountpoint))

    return [(k, v) for k, v in partition_dict.iteritems()]
245

246