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

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

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

# Copyright (C) 2018 Bloomberg LP 

# 

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

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

# You may obtain a copy of the License at 

# 

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

# 

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

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

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

# See the License for the specific language governing permissions and 

# limitations under the License. 

 

 

""" 

OperationsService 

================= 

 

""" 

 

import logging 

 

import grpc 

 

from google.protobuf.empty_pb2 import Empty 

 

from buildgrid._exceptions import InvalidArgumentError 

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

from buildgrid.server._authentication import AuthContext, authorize 

 

 

class OperationsService(operations_pb2_grpc.OperationsServicer): 

 

def __init__(self, server): 

self.__logger = logging.getLogger(__name__) 

 

self._instances = {} 

 

operations_pb2_grpc.add_OperationsServicer_to_server(self, server) 

 

# --- Public API --- 

 

def add_instance(self, instance_name, instance): 

"""Registers a new servicer instance. 

 

Args: 

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

instance (OperationsInstance): The new instance itself. 

""" 

self._instances[instance_name] = instance 

 

# --- Public API: Servicer --- 

 

@authorize(AuthContext) 

def GetOperation(self, request, context): 

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

 

try: 

name = request.name 

 

instance_name = self._parse_instance_name(name) 

instance = self._get_instance(instance_name) 

 

operation_name = self._parse_operation_name(name) 

operation = instance.get_operation(operation_name) 

op = operations_pb2.Operation() 

op.CopyFrom(operation) 

op.name = name 

return op 

 

except InvalidArgumentError as e: 

self.__logger.error(e) 

context.set_details(str(e)) 

context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

 

return operations_pb2.Operation() 

 

@authorize(AuthContext) 

def ListOperations(self, request, context): 

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

 

try: 

# The request name should be the collection name 

# In our case, this is just the instance_name 

instance_name = request.name 

instance = self._get_instance(instance_name) 

 

result = instance.list_operations(request.filter, 

request.page_size, 

request.page_token) 

 

for operation in result.operations: 

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

 

return result 

 

except InvalidArgumentError as e: 

self.__logger.error(e) 

context.set_details(str(e)) 

context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

 

return operations_pb2.ListOperationsResponse() 

 

@authorize(AuthContext) 

def DeleteOperation(self, request, context): 

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

 

try: 

name = request.name 

 

instance_name = self._parse_instance_name(name) 

instance = self._get_instance(instance_name) 

 

operation_name = self._parse_operation_name(name) 

instance.delete_operation(operation_name) 

 

except InvalidArgumentError as e: 

self.__logger.error(e) 

context.set_details(str(e)) 

context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

 

return Empty() 

 

@authorize(AuthContext) 

def CancelOperation(self, request, context): 

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

 

try: 

name = request.name 

 

instance_name = self._parse_instance_name(name) 

instance = self._get_instance(instance_name) 

 

operation_name = self._parse_operation_name(name) 

instance.cancel_operation(operation_name) 

 

except InvalidArgumentError as e: 

self.__logger.error(e) 

context.set_details(str(e)) 

context.set_code(grpc.StatusCode.INVALID_ARGUMENT) 

 

return Empty() 

 

# --- Private API --- 

 

def _parse_instance_name(self, name): 

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

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

{operation_uuid} """ 

names = name.split('/') 

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

 

def _parse_operation_name(self, name): 

names = name.split('/') 

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

 

def _get_instance(self, name): 

try: 

return self._instances[name] 

 

except KeyError: 

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