Coverage for n2vc/utils.py: 76%

70 statements  

« prev     ^ index     » next       coverage.py v7.6.12, created at 2025-05-07 06:04 +0000

1# Copyright 2020 Canonical Ltd. 

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 

15import base64 

16import re 

17import binascii 

18import yaml 

19import string 

20import secrets 

21from enum import Enum 

22from juju.machine import Machine 

23from juju.application import Application 

24from juju.action import Action 

25from juju.unit import Unit 

26from n2vc.exceptions import N2VCInvalidCertificate 

27from typing import Tuple 

28 

29 

30def base64_to_cacert(b64string): 

31 """Convert the base64-encoded string containing the VCA CACERT. 

32 

33 The input string.... 

34 

35 """ 

36 try: 

37 cacert = base64.b64decode(b64string).decode("utf-8") 

38 

39 cacert = re.sub( 

40 r"\\n", 

41 r"\n", 

42 cacert, 

43 ) 

44 except binascii.Error as e: 

45 raise N2VCInvalidCertificate(message="Invalid CA Certificate: {}".format(e)) 

46 

47 return cacert 

48 

49 

50class N2VCDeploymentStatus(Enum): 

51 PENDING = "pending" 

52 RUNNING = "running" 

53 COMPLETED = "completed" 

54 FAILED = "failed" 

55 UNKNOWN = "unknown" 

56 

57 

58class Dict(dict): 

59 """ 

60 Dict class that allows to access the keys like attributes 

61 """ 

62 

63 def __getattribute__(self, name): 

64 if name in self: 

65 return self[name] 

66 

67 

68class EntityType(Enum): 

69 MACHINE = Machine 

70 APPLICATION = Application 

71 ACTION = Action 

72 UNIT = Unit 

73 

74 @classmethod 

75 def has_value(cls, value): 

76 return value in cls._value2member_map_ # pylint: disable=E1101 

77 

78 @classmethod 

79 def get_entity(cls, value): 

80 return ( 

81 cls._value2member_map_[value] # pylint: disable=E1101 

82 if value in cls._value2member_map_ # pylint: disable=E1101 

83 else None # pylint: disable=E1101 

84 ) 

85 

86 @classmethod 

87 def get_entity_from_delta(cls, delta_entity: str): 

88 """ 

89 Get Value from delta entity 

90 

91 :param: delta_entity: Possible values are "machine", "application", "unit", "action" 

92 """ 

93 for v in cls._value2member_map_: # pylint: disable=E1101 

94 if v.__name__.lower() == delta_entity: 

95 return cls.get_entity(v) 

96 

97 

98JujuStatusToOSM = { 

99 "machine": { 

100 "pending": N2VCDeploymentStatus.PENDING, 

101 "started": N2VCDeploymentStatus.COMPLETED, 

102 }, 

103 "application": { 

104 "waiting": N2VCDeploymentStatus.RUNNING, 

105 "maintenance": N2VCDeploymentStatus.RUNNING, 

106 "blocked": N2VCDeploymentStatus.RUNNING, 

107 "error": N2VCDeploymentStatus.FAILED, 

108 "active": N2VCDeploymentStatus.COMPLETED, 

109 }, 

110 "action": { 

111 "pending": N2VCDeploymentStatus.PENDING, 

112 "running": N2VCDeploymentStatus.RUNNING, 

113 "completed": N2VCDeploymentStatus.COMPLETED, 

114 }, 

115 "unit": { 

116 "waiting": N2VCDeploymentStatus.RUNNING, 

117 "maintenance": N2VCDeploymentStatus.RUNNING, 

118 "blocked": N2VCDeploymentStatus.RUNNING, 

119 "error": N2VCDeploymentStatus.FAILED, 

120 "active": N2VCDeploymentStatus.COMPLETED, 

121 }, 

122} 

123 

124 

125def obj_to_yaml(obj: object) -> str: 

126 """ 

127 Converts object to yaml format 

128 :return: yaml data 

129 """ 

130 # dump to yaml 

131 dump_text = yaml.dump(obj, default_flow_style=False, indent=2) 

132 # split lines 

133 lines = dump_text.splitlines() 

134 # remove !!python/object tags 

135 yaml_text = "" 

136 for line in lines: 

137 index = line.find("!!python/object") 

138 if index >= 0: 

139 line = line[:index] 

140 yaml_text += line + "\n" 

141 return yaml_text 

142 

143 

144def obj_to_dict(obj: object) -> dict: 

145 """ 

146 Converts object to dictionary format 

147 :return: dict data 

148 """ 

149 # convert obj to yaml 

150 yaml_text = obj_to_yaml(obj) 

151 # parse to dict 

152 return yaml.load(yaml_text, Loader=yaml.SafeLoader) 

153 

154 

155def get_ee_id_components(ee_id: str) -> Tuple[str, str, str]: 

156 """ 

157 Get model, application and machine components from an execution environment id 

158 :param ee_id: 

159 :return: model_name, application_name, machine_id 

160 """ 

161 parts = ee_id.split(".") 

162 if len(parts) != 3: 

163 raise Exception("invalid ee id.") 

164 model_name = parts[0] 

165 application_name = parts[1] 

166 machine_id = parts[2] 

167 return model_name, application_name, machine_id 

168 

169 

170def generate_random_alfanum_string(size: int) -> str: 

171 """ 

172 Generate random alfa-numeric string with a size given by argument 

173 :param size: 

174 :return: random generated string 

175 """ 

176 

177 return "".join( 

178 secrets.choice(string.ascii_letters + string.digits) for i in range(size) 

179 )