Coverage for /builds/BuildGrid/buildgrid/buildgrid/server/actioncache/caches/action_cache_abc.py: 74.58%

59 statements  

« prev     ^ index     » next       coverage.py v6.4.1, created at 2022-06-22 21:04 +0000

1# Copyright (C) 2020 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 

16from abc import ABC, abstractmethod 

17import logging 

18 

19from buildgrid._protos.build.bazel.remote.execution.v2.remote_execution_pb2 import ( 

20 ActionResult, 

21 Digest, 

22 Tree 

23) 

24from buildgrid.utils import get_hash_type 

25 

26 

27class ActionCacheABC(ABC): 

28 

29 def __init__(self, allow_updates=False, storage=None): 

30 self._logger = logging.getLogger(__name__) 

31 self._instance_name = None 

32 self._allow_updates = allow_updates 

33 self._storage = storage 

34 

35 @property 

36 def instance_name(self): 

37 return self._instance_name 

38 

39 @instance_name.setter 

40 def instance_name(self, instance_name): 

41 self._instance_name = instance_name 

42 

43 @property 

44 def allow_updates(self): 

45 return self._allow_updates 

46 

47 def hash_type(self): 

48 return get_hash_type() 

49 

50 def setup_grpc(self): 

51 if self._storage is not None: 

52 self._storage.setup_grpc() 

53 

54 # NOTE: This method exists for compatibility reasons. Ideally it should never 

55 # be used with an up-to-date configuration. 

56 def register_instance_with_server(self, instance_name, server): 

57 """Names and registers the action-cache instance with a given server.""" 

58 if hasattr(self, '_logger'): 

59 self._logger.warning( 

60 "Cache instances should be defined in a 'caches' list and passed " 

61 "to an ActionCache service, rather than defined in the 'services' " 

62 "list themselves.") 

63 if self._instance_name is None: 

64 server.add_action_cache_instance(self, instance_name) 

65 

66 self._instance_name = instance_name 

67 

68 else: 

69 raise AssertionError("Instance already registered") 

70 

71 @abstractmethod 

72 def get_action_result(self, action_digest: Digest) -> ActionResult: 

73 raise NotImplementedError() 

74 

75 @abstractmethod 

76 def update_action_result(self, action_digest: Digest, 

77 action_result: ActionResult) -> None: 

78 raise NotImplementedError() 

79 

80 def _action_result_blobs_still_exist(self, action_result: ActionResult) -> bool: 

81 """Checks CAS for ActionResult output blobs existence. 

82 

83 Args: 

84 action_result (ActionResult): ActionResult to search referenced 

85 output blobs for. 

86 

87 Returns: 

88 True if all referenced blobs are present in CAS, False otherwise. 

89 """ 

90 if not self._storage: 

91 return True 

92 blobs_needed = [] 

93 

94 for output_file in action_result.output_files: 

95 blobs_needed.append(output_file.digest) 

96 

97 for output_directory in action_result.output_directories: 

98 blobs_needed.append(output_directory.tree_digest) 

99 tree = self._storage.get_message(output_directory.tree_digest, Tree) 

100 if tree is None: 

101 return False 

102 

103 for file_node in tree.root.files: 

104 blobs_needed.append(file_node.digest) 

105 

106 for child in tree.children: 

107 for file_node in child.files: 

108 blobs_needed.append(file_node.digest) 

109 

110 if action_result.stdout_digest.hash and not action_result.stdout_raw: 

111 blobs_needed.append(action_result.stdout_digest) 

112 

113 if action_result.stderr_digest.hash and not action_result.stderr_raw: 

114 blobs_needed.append(action_result.stderr_digest) 

115 

116 missing = self._storage.missing_blobs(blobs_needed) 

117 if len(missing) != 0: 

118 self._logger.debug(f"Missing {len(missing)}/{len(blobs_needed)} blobs") 

119 return False 

120 return True