diff --git a/deployment/data-streams/changeset/jd_distribute_llo_jobs.go b/deployment/data-streams/changeset/jd_distribute_llo_jobs.go index b7e7947a92a..406ce3c6e7e 100644 --- a/deployment/data-streams/changeset/jd_distribute_llo_jobs.go +++ b/deployment/data-streams/changeset/jd_distribute_llo_jobs.go @@ -116,6 +116,10 @@ func generateBootstrapProposals(ctx context.Context, e deployment.Environment, c Value: pointer.To(devenv.LabelNodeTypeValueBootstrap), Op: ptypes.SelectorOp_EQ, }, + { + Key: utils.DonIdentifier(cfg.Filter.DONID, cfg.Filter.DONName), + Op: ptypes.SelectorOp_EXIST, + }, }) if err != nil { return nil, fmt.Errorf("failed to get externalJobID: %w", err) @@ -124,6 +128,7 @@ func generateBootstrapProposals(ctx context.Context, e deployment.Environment, c bootstrapSpec := jobs.NewBootstrapSpec( cfg.ConfiguratorAddress, cfg.Filter.DONID, + cfg.Filter.DONName, jobs.RelayTypeEVM, jobs.RelayConfig{ ChainID: chainID, @@ -211,6 +216,10 @@ func generateOracleProposals(ctx context.Context, e deployment.Environment, cfg Value: pointer.To(devenv.LabelNodeTypeValuePlugin), Op: ptypes.SelectorOp_EQ, }, + { + Key: utils.DonIdentifier(cfg.Filter.DONID, cfg.Filter.DONName), + Op: ptypes.SelectorOp_EXIST, + }, }) if err != nil { return nil, fmt.Errorf("failed to get externalJobID: %w", err) diff --git a/deployment/data-streams/changeset/jd_distribute_llo_jobs_test.go b/deployment/data-streams/changeset/jd_distribute_llo_jobs_test.go index 20d41a0b1cf..7243a47f269 100644 --- a/deployment/data-streams/changeset/jd_distribute_llo_jobs_test.go +++ b/deployment/data-streams/changeset/jd_distribute_llo_jobs_test.go @@ -103,7 +103,7 @@ donID = 1 servers = {'mercury-pipeline-testnet-producer.TEST.cldev.cloud:1340' = '0000005187b1498c0ccb2e56d5ee8040a03a4955822ed208749b474058fc3f9c'} ` - bootstrapSpec := `name = 'bootstrap' + bootstrapSpec := `name = 'don | 1' type = 'bootstrap' schemaVersion = 1 contractID = '0x4170ed0880ac9a755fd29b2688956bd959f923f4' diff --git a/deployment/data-streams/jobs/bootstrap.go b/deployment/data-streams/jobs/bootstrap.go index 74d9e07a1c6..b3e3b016982 100644 --- a/deployment/data-streams/jobs/bootstrap.go +++ b/deployment/data-streams/jobs/bootstrap.go @@ -1,6 +1,8 @@ package jobs import ( + "fmt" + "github.com/google/uuid" "github.com/pelletier/go-toml/v2" ) @@ -37,13 +39,13 @@ type RelayConfig struct { FromBlock uint64 `toml:"fromBlock,omitempty"` } -func NewBootstrapSpec(contractID string, donID uint64, relay RelayType, relayConfig RelayConfig, externalJobID uuid.UUID) *BootstrapSpec { +func NewBootstrapSpec(contractID string, donID uint64, donName string, relay RelayType, relayConfig RelayConfig, externalJobID uuid.UUID) *BootstrapSpec { if externalJobID == uuid.Nil { externalJobID = uuid.New() } return &BootstrapSpec{ Base: Base{ - Name: "bootstrap", + Name: fmt.Sprintf("%s | %d", donName, donID), Type: JobSpecTypeBootstrap, SchemaVersion: 1, ExternalJobID: externalJobID, diff --git a/deployment/data-streams/jobs/bootstrap_test.go b/deployment/data-streams/jobs/bootstrap_test.go index 0a3f9eba3d6..a80dc73c63d 100644 --- a/deployment/data-streams/jobs/bootstrap_test.go +++ b/deployment/data-streams/jobs/bootstrap_test.go @@ -19,7 +19,63 @@ chainID = '42161' fromBlock = 283806260 ` -func Test_Bootstrap(t *testing.T) { +func TestNewBootstrapSpec(t *testing.T) { + t.Parallel() + + externalJobID := uuid.New() + + tests := []struct { + name string + contractID string + donID uint64 + donName string + relay RelayType + relayConfig RelayConfig + externalJobID uuid.UUID + want *BootstrapSpec + }{ + { + name: "success", + contractID: "0x01", + donID: 123, + donName: "don-123", + relay: RelayTypeEVM, + relayConfig: RelayConfig{ + ChainID: "234", + FromBlock: 345, + }, + externalJobID: externalJobID, + want: &BootstrapSpec{ + Base: Base{ + Name: "don-123 | 123", + Type: JobSpecTypeBootstrap, + SchemaVersion: 1, + ExternalJobID: externalJobID, + }, + ContractID: "0x01", + DonID: 123, + Relay: RelayTypeEVM, + RelayConfig: RelayConfig{ + ChainID: "234", + FromBlock: 345, + }}, + }, + } + + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := NewBootstrapSpec(tc.contractID, tc.donID, tc.donName, tc.relay, tc.relayConfig, tc.externalJobID) + if got == nil { + t.Fatal("got nil") + } + if *got != *tc.want { + t.Errorf("got %v, want %v", got, tc.want) + } + }) + } +} + +func TestMarshalTOML(t *testing.T) { t.Parallel() bootstrapSpec := BootstrapSpec{ diff --git a/deployment/data-streams/utils/identifiers.go b/deployment/data-streams/utils/identifiers.go index a9017ee542a..7e2a859a1f5 100644 --- a/deployment/data-streams/utils/identifiers.go +++ b/deployment/data-streams/utils/identifiers.go @@ -2,6 +2,7 @@ package utils import ( "fmt" + "regexp" ) const ( @@ -9,6 +10,9 @@ const ( ) // DonIdentifier generates a unique identifier for a DON based on its ID and name. +// All non-alphanumeric characters are replaced with underscores due to the limiting requirements of +// Job Distributor label keys. func DonIdentifier(donID uint64, donName string) string { - return fmt.Sprintf("don-%d-%s", donID, donName) + cleanDONName := regexp.MustCompile(`[^a-zA-Z0-9]+`).ReplaceAllString(donName, "_") + return fmt.Sprintf("don-%d-%s", donID, cleanDONName) } diff --git a/deployment/environment/devenv/don.go b/deployment/environment/devenv/don.go index 9c482283255..8fe4fc91e65 100644 --- a/deployment/environment/devenv/don.go +++ b/deployment/environment/devenv/don.go @@ -23,6 +23,18 @@ import ( "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/shared/ptypes" ) +// All label keys: +// * must be non-empty, +// * must be 63 characters or less, +// * must begin and end with an alphanumeric character ([a-z0-9A-Z]), +// * could contain dashes (-), underscores (_), dots (.), and alphanumerics between. +// +// All label values: +// * must be 63 characters or less (can be empty), +// * unless empty, must begin and end with an alphanumeric character ([a-z0-9A-Z]), +// * could contain dashes (-), underscores (_), dots (.), and alphanumerics between. +// +// Source: https://github.com/smartcontractkit/job-distributor/blob/main/pkg/entities/labels.go const ( LabelNodeTypeKey = "type" LabelNodeTypeValueBootstrap = "bootstrap"