Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Copyright (C) 2018 Bloomberg LP 

2# 

3# Licensed under the Apache License, Version 2.0 (the "License"); 

4# you may not use this file except in compliance with the License. 

5# You may obtain a copy of the License at 

6# 

7# <http://www.apache.org/licenses/LICENSE-2.0> 

8# 

9# Unless required by applicable law or agreed to in writing, software 

10# distributed under the License is distributed on an "AS IS" BASIS, 

11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

12# See the License for the specific language governing permissions and 

13# limitations under the License. 

14 

15 

16""" 

17Bot Session 

18=========== 

19 

20Allows connections 

21""" 

22import asyncio 

23import logging 

24import platform 

25import grpc 

26import os 

27 

28from buildgrid._enums import BotStatus, LeaseState 

29from buildgrid._protos.google.devtools.remoteworkers.v1test2 import bots_pb2 

30from buildgrid._protos.google.rpc import code_pb2 

31 

32from buildgrid._exceptions import FailedPreconditionError 

33 

34from .tenantmanager import TenantManager 

35 

36 

37class BotSession: 

38 def __init__(self, instance_name, bots_interface, hardware_interface, work, 

39 context=None): 

40 """ Unique bot ID within the farm used to identify this bot 

41 Needs to be human readable. 

42 All prior sessions with bot_id of same ID are invalidated. 

43 If a bot attempts to update an invalid session, it must be rejected and 

44 may be put in quarantine. 

45 """ 

46 self.__logger = logging.getLogger(__name__) 

47 

48 self._bots_interface = bots_interface 

49 self._hardware_interface = hardware_interface 

50 

51 self._status = BotStatus.OK.value 

52 self._tenant_manager = TenantManager() 

53 

54 self.__instance_name = instance_name 

55 self.__bot_id = f'{instance_name}.{platform.node()}.{os.getpid()}' 

56 self.__name = None 

57 

58 self._work = work 

59 self._context = context 

60 

61 self.__connected = False 

62 

63 @property 

64 def bot_id(self): 

65 return self.__bot_id 

66 

67 @property 

68 def connected(self): 

69 return self.__connected 

70 

71 async def run(self): 

72 interval = self._bots_interface.interval 

73 executing_interval = self._bots_interface.executing_interval 

74 try: 

75 while True: 

76 if not self.connected: 

77 self.create_bot_session() 

78 else: 

79 self.update_bot_session() 

80 

81 if not self.connected: 

82 await asyncio.sleep(interval) 

83 else: 

84 await self._tenant_manager.wait_on_tenants(executing_interval) 

85 except asyncio.CancelledError: 

86 pass 

87 

88 def create_bot_session(self): 

89 self.__logger.debug("Creating bot session") 

90 

91 session = self._bots_interface.create_bot_session(self.__instance_name, self.get_pb2()) 

92 if session in list(grpc.StatusCode): 

93 self.__connected = False 

94 return 

95 self.__connected = True 

96 self.__name = session.name 

97 

98 self.__logger.info(f"Created bot session with name: [{self.__name}]") 

99 

100 for lease in session.leases: 

101 self._register_lease(lease) 

102 

103 def update_bot_session(self): 

104 self.__logger.debug(f"Updating bot session: [{self.__bot_id}]") 

105 

106 session = self._bots_interface.update_bot_session(self.get_pb2()) 

107 if session in list(grpc.StatusCode): 

108 self.__connected = False 

109 return 

110 self.__connected = True 

111 server_ids = [] 

112 

113 for lease in session.leases: 

114 server_ids.append(lease.id) 

115 

116 lease_state = LeaseState(lease.state) 

117 if lease_state == LeaseState.PENDING: 

118 self._register_lease(lease) 

119 

120 elif lease_state == LeaseState.CANCELLED: 

121 self._tenant_manager.cancel_tenancy(lease.id) 

122 

123 closed_lease_ids = [x for x in self._tenant_manager.get_lease_ids() if x not in server_ids] 

124 

125 for lease_id in closed_lease_ids: 

126 self._tenant_manager.cancel_tenancy(lease_id) 

127 self._tenant_manager.remove_tenant(lease_id) 

128 

129 def get_pb2(self): 

130 return bots_pb2.BotSession(worker=self._hardware_interface.get_worker_pb2(), 

131 status=self._status, 

132 leases=self._tenant_manager.get_leases(), 

133 bot_id=self.__bot_id, 

134 name=self.__name) 

135 

136 def _register_lease(self, lease): 

137 lease_id = lease.id 

138 try: 

139 self._tenant_manager.create_tenancy(lease) 

140 

141 except KeyError as e: 

142 self.__logger.error(e) 

143 

144 else: 

145 try: 

146 self._hardware_interface.configure_hardware(lease.requirements) 

147 

148 except FailedPreconditionError as e: 

149 self.__logger.error(e) 

150 self._tenant_manager.complete_lease(lease_id, status=code_pb2.FailedPreconditionError) 

151 

152 else: 

153 self._tenant_manager.create_work(lease_id, self._work, self._context)