| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2014 The Swarming Authors. All rights reserved. | 2 # Copyright 2014 The Swarming Authors. All rights reserved. |
| 3 # Use of this source code is governed by the Apache v2.0 license that can be | 3 # Use of this source code is governed by the Apache v2.0 license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """OS specific utility functions. | 6 """OS specific utility functions. |
| 7 | 7 |
| 8 Includes code: | 8 Includes code: |
| 9 - to declare the current system this code is running under. | 9 - to declare the current system this code is running under. |
| 10 - to run a command on user login. | 10 - to run a command on user login. |
| 11 - to restart the host. | 11 - to restart the host. |
| 12 | 12 |
| 13 This file serves as an API to bot_config.py. bot_config.py can be replaced on | 13 This file serves as an API to bot_config.py. bot_config.py can be replaced on |
| 14 the server to allow additional server-specific functionality. | 14 the server to allow additional server-specific functionality. |
| 15 """ | 15 """ |
| 16 | 16 |
| 17 import ctypes | 17 import ctypes |
| 18 import getpass | 18 import getpass |
| 19 import glob | 19 import glob |
| 20 import hashlib |
| 20 import json | 21 import json |
| 21 import logging | 22 import logging |
| 22 import multiprocessing | 23 import multiprocessing |
| 23 import os | 24 import os |
| 24 import pipes | 25 import pipes |
| 25 import platform | 26 import platform |
| 26 import re | 27 import re |
| 27 import signal | 28 import signal |
| 28 import socket | 29 import socket |
| 29 import string | 30 import string |
| 30 import subprocess | 31 import subprocess |
| 31 import sys | 32 import sys |
| 32 import tempfile | 33 import tempfile |
| 33 import time | 34 import time |
| 34 import urllib2 | 35 import urllib2 |
| 35 | 36 |
| 37 import platforms |
| 36 from utils import file_path | 38 from utils import file_path |
| 37 from utils import tools | 39 from utils import tools |
| 38 from utils import zip_package | |
| 39 | |
| 40 | |
| 41 import platforms | |
| 42 | |
| 43 | |
| 44 THIS_FILE = os.path.abspath(zip_package.get_main_script_path() or __file__) | |
| 45 | 40 |
| 46 | 41 |
| 47 # https://cloud.google.com/compute/pricing#machinetype | 42 # https://cloud.google.com/compute/pricing#machinetype |
| 48 GCE_MACHINE_COST_HOUR_US = { | 43 GCE_MACHINE_COST_HOUR_US = { |
| 49 u'n1-standard-1': 0.063, | 44 u'n1-standard-1': 0.063, |
| 50 u'n1-standard-2': 0.126, | 45 u'n1-standard-2': 0.126, |
| 51 u'n1-standard-4': 0.252, | 46 u'n1-standard-4': 0.252, |
| 52 u'n1-standard-8': 0.504, | 47 u'n1-standard-8': 0.504, |
| 53 u'n1-standard-16': 1.008, | 48 u'n1-standard-16': 1.008, |
| 54 u'f1-micro': 0.012, | 49 u'f1-micro': 0.012, |
| (...skipping 657 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 token_info.Label.Sid, p_sid_size.contents.value - 1) | 707 token_info.Label.Sid, p_sid_size.contents.value - 1) |
| 713 value = res.contents.value | 708 value = res.contents.value |
| 714 return mapping.get(value) or u'0x%04x' % value | 709 return mapping.get(value) or u'0x%04x' % value |
| 715 finally: | 710 finally: |
| 716 ctypes.windll.kernel32.CloseHandle(token) | 711 ctypes.windll.kernel32.CloseHandle(token) |
| 717 | 712 |
| 718 | 713 |
| 719 ### Android. | 714 ### Android. |
| 720 | 715 |
| 721 | 716 |
| 717 def initialize_android(pub, priv): |
| 718 # TODO(maruel): Remove. |
| 719 return platforms.android.initialize(pub, priv) |
| 720 |
| 721 |
| 722 def get_dimensions_all_devices_android(devices): |
| 723 """Returns the default dimensions for an host with multiple android devices. |
| 724 """ |
| 725 dimensions = get_dimensions() |
| 726 if not devices: |
| 727 return dimensions |
| 728 |
| 729 # Pop a few dimensions otherwise there will be too many dimensions. |
| 730 del dimensions[u'cpu'] |
| 731 del dimensions[u'cores'] |
| 732 del dimensions[u'gpu'] |
| 733 dimensions.pop(u'machine_type') |
| 734 |
| 735 # Make sure all the devices use the same board. |
| 736 keys = (u'build.id', u'product.board') |
| 737 for key in keys: |
| 738 dimensions[key] = set() |
| 739 dimensions[u'android'] = [] |
| 740 for serial_number, cmd in devices.iteritems(): |
| 741 if cmd: |
| 742 properties = platforms.android.get_build_prop(cmd) |
| 743 if properties: |
| 744 for key in keys: |
| 745 dimensions[key].add(properties[u'ro.' + key]) |
| 746 dimensions[u'android'].append(serial_number) |
| 747 dimensions[u'android'].sort() |
| 748 for key in keys: |
| 749 if not dimensions[key]: |
| 750 del dimensions[key] |
| 751 else: |
| 752 dimensions[key] = sorted(dimensions[key]) |
| 753 nb_android = len(dimensions[u'android']) |
| 754 dimensions[u'android_devices'] = map( |
| 755 str, range(nb_android, max(0, nb_android-2), -1)) |
| 756 return dimensions |
| 757 |
| 758 |
| 759 def get_state_all_devices_android(devices): |
| 760 """Returns state information about all the devices connected to the host. |
| 761 """ |
| 762 state = get_state() |
| 763 if not devices: |
| 764 return state |
| 765 |
| 766 # Add a few values that were poped from dimensions. |
| 767 cpu_type = get_cpu_type() |
| 768 cpu_bitness = get_cpu_bitness() |
| 769 state[u'cpu'] = [ |
| 770 cpu_type, |
| 771 cpu_type + u'-' + cpu_bitness, |
| 772 ] |
| 773 state[u'cores'] = [unicode(get_num_processors())] |
| 774 state[u'gpu'] = get_gpu()[0] |
| 775 machine_type = get_machine_type() |
| 776 if machine_type: |
| 777 state[u'machine_type'] = [machine_type] |
| 778 |
| 779 keys = ( |
| 780 u'board.platform', u'product.cpu.abi', u'build.tags', u'build.type', |
| 781 u'build.version.sdk') |
| 782 state['devices'] = {} |
| 783 for serial_number, cmd in devices.iteritems(): |
| 784 if cmd: |
| 785 properties = platforms.android.get_build_prop(cmd) |
| 786 if properties: |
| 787 # TODO(maruel): uptime, diskstats, wifi, power, throttle, etc. |
| 788 device = { |
| 789 u'build': {key: properties[u'ro.'+key] for key in keys}, |
| 790 u'disk': platforms.android.get_disk(cmd), |
| 791 u'battery': platforms.android.get_battery(cmd), |
| 792 u'state': u'available', |
| 793 u'temp': platforms.android.get_temp(cmd), |
| 794 } |
| 795 else: |
| 796 device = {u'state': u'unavailable'} |
| 797 else: |
| 798 device = {u'state': 'unauthenticated'} |
| 799 state[u'devices'][serial_number] = device |
| 800 return state |
| 722 | 801 |
| 723 | 802 |
| 724 ### | 803 ### |
| 725 | 804 |
| 726 | 805 |
| 727 def get_dimensions(): | 806 def get_dimensions(): |
| 728 """Returns the default dimensions.""" | 807 """Returns the default dimensions.""" |
| 729 os_name = get_os_name() | 808 os_name = get_os_name() |
| 730 cpu_type = get_cpu_type() | 809 cpu_type = get_cpu_type() |
| 731 cpu_bitness = get_cpu_bitness() | 810 cpu_bitness = get_cpu_bitness() |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1044 os.remove(item) | 1123 os.remove(item) |
| 1045 for item in glob.iglob('%s.???' % name): | 1124 for item in glob.iglob('%s.???' % name): |
| 1046 os.remove(item) | 1125 os.remove(item) |
| 1047 except Exception as e: | 1126 except Exception as e: |
| 1048 logging.exception('trim_rolled_log(%s) failed: %s', name, e) | 1127 logging.exception('trim_rolled_log(%s) failed: %s', name, e) |
| 1049 | 1128 |
| 1050 | 1129 |
| 1051 def main(): | 1130 def main(): |
| 1052 """Prints out the output of get_dimensions() and get_state().""" | 1131 """Prints out the output of get_dimensions() and get_state().""" |
| 1053 # Pass an empty tag, so pop it up since it has no significance. | 1132 # Pass an empty tag, so pop it up since it has no significance. |
| 1054 data = { | 1133 devices = None |
| 1055 u'dimensions': get_dimensions(), | 1134 if sys.platform == 'linux2': |
| 1056 u'state': get_state(), | 1135 devices = platforms.android.get_devices() |
| 1057 } | 1136 if devices: |
| 1137 try: |
| 1138 data = { |
| 1139 u'dimensions': get_dimensions_all_devices_android(devices), |
| 1140 u'state': get_state_all_devices_android(devices), |
| 1141 } |
| 1142 finally: |
| 1143 platforms.android.close_devices(devices) |
| 1144 if not devices: |
| 1145 data = { |
| 1146 u'dimensions': get_dimensions(), |
| 1147 u'state': get_state(), |
| 1148 } |
| 1149 |
| 1058 json.dump(data, sys.stdout, indent=2, sort_keys=True, separators=(',', ': ')) | 1150 json.dump(data, sys.stdout, indent=2, sort_keys=True, separators=(',', ': ')) |
| 1059 print('') | 1151 print('') |
| 1060 return 0 | 1152 return 0 |
| 1061 | 1153 |
| 1062 | 1154 |
| 1063 if __name__ == '__main__': | 1155 if __name__ == '__main__': |
| 1064 sys.exit(main()) | 1156 sys.exit(main()) |
| OLD | NEW |