|
5 | 5 | import builtins |
6 | 6 | import importlib |
7 | 7 | import inspect |
| 8 | +import sys |
8 | 9 |
|
9 | 10 | import grpc |
10 | 11 | import crossplane.function.logging |
@@ -32,6 +33,12 @@ def __init__(self, debug=False): |
32 | 33 | self.logger = crossplane.function.logging.get_logger() |
33 | 34 | self.clazzes = {} |
34 | 35 |
|
| 36 | + def invalidate_module(self, module): |
| 37 | + self.clazzes.clear() |
| 38 | + if module in sys.modules: |
| 39 | + del sys.modules[module] |
| 40 | + importlib.invalidate_caches() |
| 41 | + |
35 | 42 | async def RunFunction( |
36 | 43 | self, request: fnv1.RunFunctionRequest, _: grpc.aio.ServicerContext |
37 | 44 | ) -> fnv1.RunFunctionResponse: |
@@ -70,52 +77,52 @@ async def RunFunction( |
70 | 77 | try: |
71 | 78 | exec(composite, module.__dict__) |
72 | 79 | except Exception as e: |
73 | | - crossplane.function.response.fatal(response, f"Exec exception: {e}") |
74 | 80 | logger.exception('Exec exception') |
| 81 | + crossplane.function.response.fatal(response, f"Exec exception: {e}") |
75 | 82 | return response |
76 | 83 | composite = ['<script>', 'Composite'] |
77 | 84 | else: |
78 | 85 | composite = composite.rsplit('.', 1) |
79 | 86 | if len(composite) == 1: |
80 | | - crossplane.function.response.fatal(response, f"Composite class name does not include module: {composite[0]}") |
81 | 87 | logger.error(f"Composite class name does not include module: {composite[0]}") |
| 88 | + crossplane.function.response.fatal(response, f"Composite class name does not include module: {composite[0]}") |
82 | 89 | return response |
83 | 90 | try: |
84 | 91 | module = importlib.import_module(composite[0]) |
85 | 92 | except Exception as e: |
| 93 | + logger.error(str(e)) |
86 | 94 | crossplane.function.response.fatal(response, f"Import module exception: {e}") |
87 | | - logger.exception('Import module exception') |
88 | 95 | return response |
89 | 96 | clazz = getattr(module, composite[1], None) |
90 | 97 | if not clazz: |
91 | | - crossplane.function.response.fatal(response, f"{composite[0]} did not define: {composite[1]}") |
92 | 98 | logger.error(f"{composite[0]} did not define: {composite[1]}") |
| 99 | + crossplane.function.response.fatal(response, f"{composite[0]} did not define: {composite[1]}") |
93 | 100 | return response |
94 | 101 | composite = '.'.join(composite) |
95 | 102 | if not inspect.isclass(clazz): |
96 | | - crossplane.function.response.fatal(response, f"{composite} is not a class") |
97 | 103 | logger.error(f"{composite} is not a class") |
| 104 | + crossplane.function.response.fatal(response, f"{composite} is not a class") |
98 | 105 | return response |
99 | 106 | if not issubclass(clazz, BaseComposite): |
100 | | - crossplane.function.response.fatal(response, f"{composite} is not a subclass of BaseComposite") |
101 | 107 | logger.error(f"{composite} is not a subclass of BaseComposite") |
| 108 | + crossplane.function.response.fatal(response, f"{composite} is not a subclass of BaseComposite") |
102 | 109 | return response |
103 | 110 | self.clazzes[composite] = clazz |
104 | 111 |
|
105 | 112 | try: |
106 | 113 | composite = clazz(request, response, logger) |
107 | 114 | except Exception as e: |
108 | | - crossplane.function.response.fatal(response, f"Instatiate exception: {e}") |
109 | 115 | logger.exception('Instatiate exception') |
| 116 | + crossplane.function.response.fatal(response, f"Instatiate exception: {e}") |
110 | 117 | return response |
111 | 118 |
|
112 | 119 | try: |
113 | 120 | result = composite.compose() |
114 | 121 | if asyncio.iscoroutine(result): |
115 | 122 | await result |
116 | 123 | except Exception as e: |
117 | | - crossplane.function.response.fatal(response, f"Compose exception: {e}") |
118 | 124 | logger.exception('Compose exception') |
| 125 | + crossplane.function.response.fatal(response, f"Compose exception: {e}") |
119 | 126 | return response |
120 | 127 |
|
121 | 128 | unknownResources = [] |
@@ -150,27 +157,36 @@ async def RunFunction( |
150 | 157 | resource.desired._patchUnknowns(resource.observed) |
151 | 158 | else: |
152 | 159 | del composite.resources[name] |
| 160 | + |
153 | 161 | if fatalResources: |
154 | | - if not self.debug: |
155 | | - logger.error('Observed resources with unknowns', resources=fatalResources) |
| 162 | + level = logger.error |
| 163 | + reason = 'FatalUnknowns' |
156 | 164 | message = f"Observed resources with unknowns: {','.join(fatalResources)}" |
157 | | - composite.conditions.NoUnknowns(False, 'FatalUnknowns', message) |
158 | | - composite.results.fatal(message, 'FatalUnknowns') |
159 | | - return response |
160 | | - if warningResources: |
161 | | - if not self.debug: |
162 | | - logger.warning('Observed resources with unknowns', resources=fatalResources) |
| 165 | + status = False |
| 166 | + event = composite.events.fatal |
| 167 | + elif warningResources: |
| 168 | + level = logger.warning |
| 169 | + reason = 'ObservedUnknowns' |
163 | 170 | message = f"Observed resources with unknowns: {','.join(warningResources)}" |
164 | | - composite.conditions.NoUnknowns(False, 'ObservedUnknowns', message) |
165 | | - composite.results.warning(message, 'ObservedUnknowns') |
| 171 | + status = False |
| 172 | + event = composite.events.warning |
166 | 173 | elif unknownResources: |
167 | | - if not self.debug: |
168 | | - logger.info('New resources with unknowns', resources=unknownResources) |
169 | | - message = f"New resources with unknowns: {','.join(unknownResources)}" |
170 | | - composite.conditions.NoUnknowns(False, 'NewUnknowns', message) |
171 | | - composite.results.info(message, 'NewUnknowns') |
| 174 | + level = logger.info |
| 175 | + reason = 'DesiredUnknowns' |
| 176 | + message = f"Desired resources with unknowns: {','.join(unknownResources)}" |
| 177 | + status = False |
| 178 | + event = composite.events.info |
172 | 179 | else: |
173 | | - composite.conditions.NoUnknowns(True, 'AllResolved', 'All resources are resolved') |
| 180 | + level = None |
| 181 | + reason = 'AllComposed' |
| 182 | + message = 'All resources are composed' |
| 183 | + status = True |
| 184 | + event = None |
| 185 | + if not self.debug and level: |
| 186 | + level(message) |
| 187 | + composite.conditions.ResourcesComposed(reason, message, status) |
| 188 | + if event: |
| 189 | + event(reason, message) |
174 | 190 |
|
175 | 191 | for name, resource in composite.resources: |
176 | 192 | if resource.autoReady or (resource.autoReady is None and composite.autoReady): |
|
0 commit comments