@@ -77,22 +77,39 @@ func (CsDistributeLLOJobSpecs) Apply(e cldf.Environment, cfg CsDistributeLLOJobS
7777 if err != nil {
7878 return cldf.ChangesetOutput {}, fmt .Errorf ("failed to generate bootstrap proposals: %w" , err )
7979 }
80- oracleProposals , err := generateOracleProposals (ctx , e , cfg , chainID , cfg .Labels )
80+ // These will be empty when we send only oracle jobs. In that case we'll fetch the bootstrappers by the don
81+ // identifier label.
82+ boostrapNodeIDs := make ([]string , 0 , len (bootstrapProposals ))
83+ for _ , p := range bootstrapProposals {
84+ boostrapNodeIDs = append (boostrapNodeIDs , p .NodeId )
85+ }
86+ oracleProposals , err := generateOracleProposals (ctx , e , cfg , chainID , cfg .Labels , boostrapNodeIDs )
8187 if err != nil {
8288 return cldf.ChangesetOutput {}, fmt .Errorf ("failed to generate oracle proposals: %w" , err )
8389 }
84-
85- proposedJobs , err := proposeAllOrNothing (ctx , e .Offchain , append ( bootstrapProposals , oracleProposals ... ) )
90+ allProposals := append ( bootstrapProposals , oracleProposals ... ) //nolint: gocritic // ignore a silly rule
91+ proposedJobs , err := proposeAllOrNothing (ctx , e .Offchain , allProposals )
8692 if err != nil {
8793 return cldf.ChangesetOutput {}, fmt .Errorf ("failed to propose all jobs: %w" , err )
8894 }
8995
96+ err = labelNodesForProposals (e .GetContext (), e .Offchain , allProposals , utils .DonIdentifier (cfg .Filter .DONID , cfg .Filter .DONName ))
97+ if err != nil {
98+ return cldf.ChangesetOutput {}, fmt .Errorf ("failed to label nodes for proposals: %w" , err )
99+ }
100+
90101 return cldf.ChangesetOutput {
91102 Jobs : proposedJobs ,
92103 }, nil
93104}
94105
95- func generateBootstrapProposals (ctx context.Context , e cldf.Environment , cfg CsDistributeLLOJobSpecsConfig , chainID string , labels []* ptypes.Label ) ([]* jobv1.ProposeJobRequest , error ) {
106+ func generateBootstrapProposals (
107+ ctx context.Context ,
108+ e cldf.Environment ,
109+ cfg CsDistributeLLOJobSpecsConfig ,
110+ chainID string ,
111+ labels []* ptypes.Label ,
112+ ) ([]* jobv1.ProposeJobRequest , error ) {
96113 bootstrapNodes , err := jd .FetchDONBootstrappersFromJD (ctx , e .Offchain , cfg .Filter , cfg .NodeNames )
97114 if err != nil {
98115 return nil , fmt .Errorf ("failed to get bootstrap nodes: %w" , err )
@@ -153,7 +170,14 @@ func generateBootstrapProposals(ctx context.Context, e cldf.Environment, cfg CsD
153170 return proposals , nil
154171}
155172
156- func generateOracleProposals (ctx context.Context , e cldf.Environment , cfg CsDistributeLLOJobSpecsConfig , chainID string , labels []* ptypes.Label ) ([]* jobv1.ProposeJobRequest , error ) {
173+ func generateOracleProposals (
174+ ctx context.Context ,
175+ e cldf.Environment ,
176+ cfg CsDistributeLLOJobSpecsConfig ,
177+ chainID string ,
178+ labels []* ptypes.Label ,
179+ boostrapNodeIDs []string ,
180+ ) ([]* jobv1.ProposeJobRequest , error ) {
157181 // nils will be filled out later with n-specific values:
158182 lloSpec := & jobs.LLOJobSpec {
159183 Base : jobs.Base {
@@ -193,7 +217,7 @@ func generateOracleProposals(ctx context.Context, e cldf.Environment, cfg CsDist
193217 return nil , fmt .Errorf ("failed to get node chain configs: %w" , err )
194218 }
195219
196- bootstrapMultiaddr , err := getBootstrapMultiAddr (ctx , e , cfg )
220+ bootstrapMultiaddr , err := getBootstrapMultiAddr (ctx , e , cfg , boostrapNodeIDs )
197221 if err != nil {
198222 return nil , fmt .Errorf ("failed to get bootstrap bootstrapMultiaddr: %w" , err )
199223 }
@@ -276,45 +300,53 @@ func chainConfigs(ctx context.Context, e cldf.Environment, chainID string, nodes
276300}
277301
278302// getBootstrapMultiAddr fetches the bootstrap node from Job Distributor and returns its multiaddr.
279- func getBootstrapMultiAddr (ctx context.Context , e cldf.Environment , cfg CsDistributeLLOJobSpecsConfig ) (string , error ) {
280- // Get all bootstrap nodes for this DON.
281- // We fetch these with a custom filter because the filter in the config defines which nodes need to be sent jobs
282- // and this might not cover any bootstrap nodes.
283- respBoots , err := e .Offchain .ListNodes (ctx , & node.ListNodesRequest {
284- Filter : & node.ListNodesRequest_Filter {
285- Selectors : []* ptypes.Selector {
286- {
287- Key : utils .DonIdentifier (cfg .Filter .DONID , cfg .Filter .DONName ),
288- Op : ptypes .SelectorOp_EXIST ,
289- },
290- {
291- Key : devenv .LabelNodeTypeKey ,
292- Op : ptypes .SelectorOp_EQ ,
293- Value : pointer .To (devenv .LabelNodeTypeValueBootstrap ),
294- },
295- {
296- Key : devenv .LabelEnvironmentKey ,
297- Op : ptypes .SelectorOp_EQ ,
298- Value : & cfg .Filter .EnvLabel ,
299- },
300- {
301- Key : devenv .LabelProductKey ,
302- Op : ptypes .SelectorOp_EQ ,
303- Value : pointer .To (utils .ProductLabel ),
303+ // If boostrapNodeIDs is empty, it will return the first bootstrap node found for this DON.
304+ func getBootstrapMultiAddr (ctx context.Context , e cldf.Environment , cfg CsDistributeLLOJobSpecsConfig , boostrapNodeIDs []string ) (string , error ) {
305+ if len (boostrapNodeIDs ) == 0 {
306+ // Get all bootstrap nodes for this DON.
307+ // We fetch these with a custom filter because the filter in the config defines which nodes need to be sent jobs
308+ // and this might not cover any bootstrap nodes.
309+ respBoots , err := e .Offchain .ListNodes (ctx , & node.ListNodesRequest {
310+ Filter : & node.ListNodesRequest_Filter {
311+ Selectors : []* ptypes.Selector {
312+ // We can afford to filter by DonIdentifier here because if the caller didn't provide any bootstrap node IDs,
313+ // then they are updating an existing job spec and the bootstrap nodes are already labeled with the DON ID.
314+ {
315+ Key : utils .DonIdentifier (cfg .Filter .DONID , cfg .Filter .DONName ),
316+ Op : ptypes .SelectorOp_EXIST ,
317+ },
318+ {
319+ Key : devenv .LabelNodeTypeKey ,
320+ Op : ptypes .SelectorOp_EQ ,
321+ Value : pointer .To (devenv .LabelNodeTypeValueBootstrap ),
322+ },
323+ {
324+ Key : devenv .LabelEnvironmentKey ,
325+ Op : ptypes .SelectorOp_EQ ,
326+ Value : & cfg .Filter .EnvLabel ,
327+ },
328+ {
329+ Key : devenv .LabelProductKey ,
330+ Op : ptypes .SelectorOp_EQ ,
331+ Value : pointer .To (utils .ProductLabel ),
332+ },
304333 },
305334 },
306- },
307- })
308- if err != nil {
309- return "" , fmt .Errorf ("failed to list bootstrap nodes for DON %d - %s: %w" , cfg .Filter .DONID , cfg .Filter .DONName , err )
335+ })
336+ if err != nil {
337+ return "" , fmt .Errorf ("failed to list bootstrap nodes for DON %d - %s: %w" , cfg .Filter .DONID , cfg .Filter .DONName , err )
338+ }
339+ if len (respBoots .Nodes ) == 0 {
340+ return "" , errors .New ("no bootstrap nodes found" )
341+ }
342+ for _ , n := range respBoots .Nodes {
343+ boostrapNodeIDs = append (boostrapNodeIDs , n .Id )
344+ }
310345 }
311346
312- if len (respBoots .Nodes ) == 0 {
313- return "" , errors .New ("no bootstrap nodes found" )
314- }
315347 resp , err := e .Offchain .ListNodeChainConfigs (ctx , & node.ListNodeChainConfigsRequest {
316348 Filter : & node.ListNodeChainConfigsRequest_Filter {
317- NodeIds : [] string { respBoots . Nodes [ 0 ]. Id } ,
349+ NodeIds : boostrapNodeIDs ,
318350 },
319351 })
320352 if err != nil {
@@ -348,3 +380,27 @@ func (f CsDistributeLLOJobSpecs) VerifyPreconditions(_ cldf.Environment, config
348380
349381 return nil
350382}
383+
384+ // labelNodesForProposals adds a DON Identifier label to the nodes for the given proposals.
385+ func labelNodesForProposals (ctx context.Context , jd cldf.OffchainClient , props []* jobv1.ProposeJobRequest , donIdentifier string ) error {
386+ for _ , p := range props {
387+ nodeResp , err := jd .GetNode (ctx , & node.GetNodeRequest {Id : p .NodeId })
388+ if err != nil {
389+ return fmt .Errorf ("failed to get node %s: %w" , p .NodeId , err )
390+ }
391+ newLabels := append (nodeResp .Node .Labels , & ptypes.Label { //nolint: gocritic // local copy
392+ Key : donIdentifier ,
393+ })
394+
395+ _ , err = jd .UpdateNode (ctx , & node.UpdateNodeRequest {
396+ Id : p .NodeId ,
397+ Name : nodeResp .Node .Name ,
398+ PublicKey : nodeResp .Node .PublicKey ,
399+ Labels : newLabels ,
400+ })
401+ if err != nil {
402+ return fmt .Errorf ("failed to label node %s: %w" , p .NodeId , err )
403+ }
404+ }
405+ return nil
406+ }
0 commit comments