@@ -99,7 +99,7 @@ async def run_function(self, request):
9999 return self .fatal (request , logger , 'Instantiate' , e )
100100
101101 step = composite .context ._pythonic [step ]
102- iteration = (step .iteration or 0 ) + 1
102+ iteration = int (step .iteration ) + 1
103103 step .iteration = iteration
104104 composite .context .iteration = iteration
105105 logger .debug (f"Starting compose, { ordinal (len (composite .context ._pythonic ))} step, { ordinal (iteration )} pass" )
@@ -111,7 +111,40 @@ async def run_function(self, request):
111111 except Exception as e :
112112 return self .fatal (request , logger , 'Compose' , e )
113113
114- requested = []
114+ if requireds := self .get_requireds (step , composite ):
115+ logger .info (f"Requireds requested: { ',' .join (requireds )} " )
116+ else :
117+ self .process_usages (composite )
118+ self .process_unknowns (composite )
119+ self .process_auto_readies (composite )
120+ logger .info ('Completed compose' )
121+
122+ return composite .response ._message
123+
124+ def fatal (self , request , logger , message , exception = None ):
125+ if exception :
126+ message += ' exceptiion'
127+ logger .exception (message )
128+ m = str (exception )
129+ if not m :
130+ m = exception .__class__ .__name__
131+ message += ': ' + m
132+ else :
133+ logger .error (message )
134+ return fnv1 .RunFunctionResponse (
135+ meta = fnv1 .ResponseMeta (
136+ tag = request .meta .tag ,
137+ ),
138+ results = [
139+ fnv1 .Result (
140+ severity = fnv1 .SEVERITY_FATAL ,
141+ message = message ,
142+ )
143+ ]
144+ )
145+
146+ def get_requireds (self , step , composite ):
147+ requireds = []
115148 for name , required in composite .requireds :
116149 if required .apiVersion and required .kind :
117150 r = pythonic .Map (apiVersion = required .apiVersion , kind = required .kind )
@@ -123,11 +156,84 @@ async def run_function(self, request):
123156 r .matchLabels [key ] = value
124157 if r != step .requireds [name ]:
125158 step .requireds [name ] = r
126- requested .append (name )
127- if requested :
128- logger .info (f"Requireds requested: { ',' .join (requested )} " )
129- return composite .response ._message
159+ requireds .append (name )
160+ return requireds
161+
162+ def process_usages (self , composite ):
163+ for _ , resource in sorted (entry for entry in composite .resources ):
164+ dependencies = resource .desired ._getDependencies
165+ if dependencies :
166+ if self .debug :
167+ for destination , source in sorted (dependencies .items ()):
168+ destination = self .trimFullName (destination )
169+ source = self .trimFullName (source )
170+ logger .debug (f"Dependency: { destination } = { source } " )
171+ if resource .usages or (resource .usages is None and composite .usages ):
172+ resources = {}
173+ requireds = {}
174+ for destination , source in sorted (dependencies .items ()):
175+ name = source .split ('.' )
176+ if (len (name ) > 5 and
177+ name [0 ] == 'request' and
178+ name [1 ] == 'observed' and
179+ name [2 ] == 'resources' and
180+ name [4 ] == 'resource'
181+ ):
182+ if name [3 ] not in resources :
183+ resources [name [3 ]] = []
184+ resources [name [3 ]].append (f"{ '.' .join (destination .split ('.' )[5 :])} = { '.' .join (name [5 :])} " )
185+ elif (len (name ) > 5 and
186+ name [0 ] == 'request' and
187+ name [1 ] == 'extra_resources' and
188+ name [3 ].startswith ('items[' ) and name [3 ][- 1 ] == ']' and
189+ name [4 ] == 'resource'
190+ ):
191+ key = (name [2 ], int (name [3 ][6 :- 1 ]))
192+ if key not in requireds :
193+ requireds [key ] = []
194+ requireds [key ].append (f"{ '.' .join (destination .split ('.' )[5 :])} = [{ key [1 ]} ]{ '.' .join (name [5 :])} " )
195+ for name , dependencies in resources .items ():
196+ source = composite .resources [name ]
197+ name = [resource .name , str (source .kind )]
198+ if source .metadata .namespace :
199+ name .append (str (source .metadata .namespace ))
200+ name .append (str (source .observed .metadata .name ))
201+ usage = composite .resources ['_' .join (name )]('apiextensions.crossplane.io/v1beta1' , 'Usage' )
202+ #usage = composite.resources['_'.join(name)]('protection.crossplane.io/v1beta1', 'Usage')
203+ if resource .metadata .namespace :
204+ usage .metadata .namespace = resource .metadata .namespace
205+ usage .spec .reason = '\n ' .join (dependencies )
206+ usage .spec .replayDeletion = True
207+ usage .spec .by .apiVersion = resource .apiVersion
208+ usage .spec .by .kind = resource .kind
209+ usage .spec .by .resourceRef .name = resource .observed .metadata .name
210+ usage .spec .of .apiVersion = source .apiVersion
211+ usage .spec .of .kind = source .kind
212+ if source .metadata .namespace :
213+ usage .spec .of .resourceRef .namespace = source .metadata .namespace
214+ usage .spec .of .resourceRef .name = source .observed .metadata .name
215+ for key , dependencies in requireds .items ():
216+ source = composite .requireds [key [0 ]][key [1 ]]
217+ name = [resource .name , str (source .kind )]
218+ if source .metadata .namespace :
219+ name .append (str (source .metadata .namespace ))
220+ name .append (str (source .metadata .name ))
221+ usage = composite .resources ['_' .join (name )]('apiextensions.crossplane.io/v1beta1' , 'Usage' )
222+ #usage = composite.resources['_'.join(name)]('protection.crossplane.io/v1beta1', 'Usage')
223+ if resource .metadata .namespace :
224+ usage .metadata .namespace = resource .metadata .namespace
225+ usage .spec .reason = '\n ' .join (dependencies )
226+ usage .spec .replayDeletion = True
227+ usage .spec .by .apiVersion = resource .apiVersion
228+ usage .spec .by .kind = resource .kind
229+ usage .spec .by .resourceRef .name = resource .observed .metadata .name
230+ usage .spec .of .apiVersion = source .apiVersion
231+ usage .spec .of .kind = source .kind
232+ if source .metadata .namespace :
233+ usage .spec .of .resourceRef .namespace = source .metadata .namespace
234+ usage .spec .of .resourceRef .name = source .observed .metadata .name
130235
236+ def process_unknowns (self , composite ):
131237 unknownResources = []
132238 warningResources = []
133239 fatalResources = []
@@ -190,42 +296,19 @@ async def run_function(self, request):
190296 if event :
191297 event (reason , message )
192298
299+ def process_auto_readies (self , composite ):
193300 for name , resource in composite .resources :
194301 if resource .autoReady or (resource .autoReady is None and composite .autoReady ):
195302 if resource .ready is None :
196303 if resource .conditions .Ready .status :
197304 resource .ready = True
198305
199- logger .info ('Completed compose' )
200- return composite .response ._message
201-
202- def fatal (self , request , logger , message , exception = None ):
203- if exception :
204- message += ' exceptiion'
205- logger .exception (message )
206- m = str (exception )
207- if not m :
208- m = exception .__class__ .__name__
209- message += ': ' + m
210- else :
211- logger .error (message )
212- return fnv1 .RunFunctionResponse (
213- meta = fnv1 .ResponseMeta (
214- tag = request .meta .tag ,
215- ),
216- results = [
217- fnv1 .Result (
218- severity = fnv1 .SEVERITY_FATAL ,
219- message = message ,
220- )
221- ]
222- )
223-
224306 def trimFullName (self , name ):
225307 name = name .split ('.' )
226308 for values in (
309+ ('request' , 'observed' , 'composite' , 'resource' ),
227310 ('request' , 'observed' , 'resources' , None , 'resource' ),
228- ('request' , 'extra_resources' , None , 'items' , 'resource' ),
311+ ('request' , 'extra_resources' , None , 'items' , None , 'resource' ),
229312 ('response' , 'desired' , 'resources' , None , 'resource' ),
230313 ):
231314 if len (values ) < len (name ):
0 commit comments