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""" 

17OperationsService 

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

19 

20""" 

21 

22import logging 

23 

24import grpc 

25 

26from google.protobuf.empty_pb2 import Empty 

27 

28from buildgrid._exceptions import InvalidArgumentError 

29from buildgrid._protos.google.longrunning import operations_pb2_grpc, operations_pb2 

30from buildgrid.server._authentication import AuthContext, authorize 

31 

32 

33class OperationsService(operations_pb2_grpc.OperationsServicer): 

34 

35 def __init__(self, server): 

36 self.__logger = logging.getLogger(__name__) 

37 

38 self._instances = {} 

39 

40 operations_pb2_grpc.add_OperationsServicer_to_server(self, server) 

41 

42 # --- Public API --- 

43 

44 def add_instance(self, instance_name, instance): 

45 """Registers a new servicer instance. 

46 

47 Args: 

48 instance_name (str): The new instance's name. 

49 instance (OperationsInstance): The new instance itself. 

50 """ 

51 self._instances[instance_name] = instance 

52 

53 # --- Public API: Servicer --- 

54 

55 @authorize(AuthContext) 

56 def GetOperation(self, request, context): 

57 self.__logger.debug("GetOperation request from [%s]", context.peer()) 

58 

59 try: 

60 name = request.name 

61 

62 instance_name = self._parse_instance_name(name) 

63 instance = self._get_instance(instance_name) 

64 

65 operation_name = self._parse_operation_name(name) 

66 operation = instance.get_operation(operation_name) 

67 op = operations_pb2.Operation() 

68 op.CopyFrom(operation) 

69 op.name = name 

70 return op 

71 

72 except InvalidArgumentError as e: 

73 self.__logger.error(e) 

74 context.set_details(str(e)) 

75 context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

76 

77 return operations_pb2.Operation() 

78 

79 @authorize(AuthContext) 

80 def ListOperations(self, request, context): 

81 self.__logger.debug("ListOperations request from [%s]", context.peer()) 

82 

83 try: 

84 # The request name should be the collection name 

85 # In our case, this is just the instance_name 

86 instance_name = request.name 

87 instance = self._get_instance(instance_name) 

88 

89 result = instance.list_operations(request.filter, 

90 request.page_size, 

91 request.page_token) 

92 

93 for operation in result.operations: 

94 operation.name = "{}/{}".format(instance_name, operation.name) 

95 

96 return result 

97 

98 except InvalidArgumentError as e: 

99 self.__logger.error(e) 

100 context.set_details(str(e)) 

101 context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

102 

103 return operations_pb2.ListOperationsResponse() 

104 

105 @authorize(AuthContext) 

106 def DeleteOperation(self, request, context): 

107 self.__logger.debug("DeleteOperation request from [%s]", context.peer()) 

108 

109 try: 

110 name = request.name 

111 

112 instance_name = self._parse_instance_name(name) 

113 instance = self._get_instance(instance_name) 

114 

115 operation_name = self._parse_operation_name(name) 

116 instance.delete_operation(operation_name) 

117 

118 except InvalidArgumentError as e: 

119 self.__logger.error(e) 

120 context.set_details(str(e)) 

121 context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

122 

123 return Empty() 

124 

125 @authorize(AuthContext) 

126 def CancelOperation(self, request, context): 

127 self.__logger.debug("CancelOperation request from [%s]", context.peer()) 

128 

129 try: 

130 name = request.name 

131 

132 instance_name = self._parse_instance_name(name) 

133 instance = self._get_instance(instance_name) 

134 

135 operation_name = self._parse_operation_name(name) 

136 instance.cancel_operation(operation_name) 

137 

138 except InvalidArgumentError as e: 

139 self.__logger.error(e) 

140 context.set_details(str(e)) 

141 context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

142 

143 return Empty() 

144 

145 # --- Private API --- 

146 

147 def _parse_instance_name(self, name): 

148 """ If the instance name is not blank, 'name' will have the form 

149 {instance_name}/{operation_uuid}. Otherwise, it will just be 

150 {operation_uuid} """ 

151 names = name.split('/') 

152 return '/'.join(names[:-1]) if len(names) > 1 else '' 

153 

154 def _parse_operation_name(self, name): 

155 names = name.split('/') 

156 return names[-1] if len(names) > 1 else name 

157 

158 def _get_instance(self, name): 

159 try: 

160 return self._instances[name] 

161 

162 except KeyError: 

163 raise InvalidArgumentError("Instance doesn't exist on server: [{}]".format(name))