Skip to content

Commit

Permalink
Merge pull request kubernetes#22988 from mpherman2/multi-tenancy
Browse files Browse the repository at this point in the history
Add ProwJobDefault config with TenantID
  • Loading branch information
k8s-ci-robot authored Aug 5, 2021
2 parents ba5b5fc + 94d22c9 commit d15451c
Show file tree
Hide file tree
Showing 8 changed files with 944 additions and 3 deletions.
30 changes: 30 additions & 0 deletions prow/apis/prowjobs/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,10 @@ type ProwJobSpec struct {
// Presubmits and Postsubmits can also be set to hidden by
// adding their repository in Decks `hidden_repo` setting.
Hidden bool `json:"hidden,omitempty"`

// ProwJobDefault holds configuration options provided as defaults
// in the Prow config
ProwJobDefault *ProwJobDefault `json:"prowjob_defaults,omitempty"`
}

type GitHubTeamSlug struct {
Expand Down Expand Up @@ -353,6 +357,12 @@ func (d *Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.Duration.String())
}

// ProwJobDefault is used for Prowjob fields we want to set as defaults
// in Prow config
type ProwJobDefault struct {
TenantID string `json:"tenant_id,omitempty"`
}

// DecorationConfig specifies how to augment pods.
//
// This is primarily used to provide automatic integration with gubernator
Expand Down Expand Up @@ -517,6 +527,26 @@ type OauthTokenSecret struct {
Key string `json:"key,omitempty"`
}

func (d *ProwJobDefault) ApplyDefault(def *ProwJobDefault) *ProwJobDefault {
if d == nil && def == nil {
return nil
}
var merged ProwJobDefault
if d != nil {
merged = *d.DeepCopy()
} else {
merged = *def.DeepCopy()
}
if d == nil || def == nil {
return &merged
}
if merged.TenantID == "" {
merged.TenantID = def.TenantID
}

return &merged
}

// ApplyDefault applies the defaults for the ProwJob decoration. If a field has a zero value, it
// replaces that with the value set in def.
func (d *DecorationConfig) ApplyDefault(def *DecorationConfig) *DecorationConfig {
Expand Down
59 changes: 59 additions & 0 deletions prow/apis/prowjobs/v1/types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,65 @@ func pStr(str string) *string {
return &str
}

// TODO(mpherman): Add more tests when ProwJobDefaults have more than 1 field
func TestProwJobDefaulting(t *testing.T) {
var testCases = []struct {
name string
provided *ProwJobDefault
def *ProwJobDefault
expected *ProwJobDefault
}{
{
name: "nothing provided",
provided: &ProwJobDefault{},
def: &ProwJobDefault{},
expected: &ProwJobDefault{},
},
{
name: "TenantID provided, no default",
provided: &ProwJobDefault{
TenantID: "Provided",
},
def: &ProwJobDefault{},
expected: &ProwJobDefault{
TenantID: "Provided",
},
},
{
name: "TenantID provided, No Override",
provided: &ProwJobDefault{
TenantID: "Provided",
},
def: &ProwJobDefault{
TenantID: "Default",
},
expected: &ProwJobDefault{
TenantID: "Provided",
},
},
{
name: "TenantID not Provided, Uses default",
provided: &ProwJobDefault{},
def: &ProwJobDefault{
TenantID: "Default",
},
expected: &ProwJobDefault{
TenantID: "Default",
},
},
}
for _, testCase := range testCases {
tc := testCase
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
actual := tc.provided.ApplyDefault(tc.def)
if diff := cmp.Diff(actual, tc.expected, cmpopts.EquateEmpty()); diff != "" {
t.Errorf("expected defaulted config but got diff %v", diff)
}
})
}
}

func TestDecorationDefaultingDoesntOverwrite(t *testing.T) {
truth := true
lies := false
Expand Down
21 changes: 21 additions & 0 deletions prow/apis/prowjobs/v1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions prow/cmd/deck/static/api/prow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ export interface ProwJobSpec {
reporter_config?: object;
rerun_auth_config?: object;
hidden?: boolean;
prowjob_default?: object;
}

// ProwJobStatus provides runtime metadata, such as when it finished, whether it is running, etc.
Expand Down
79 changes: 76 additions & 3 deletions prow/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,13 @@ type ProwConfig struct {
// ManagedWebhooks contains information about all github repositories and organizations which are using
// non-global Hmac token.
ManagedWebhooks ManagedWebhooks `json:"managed_webhooks,omitempty"`

// ProwJobDefaultEntries holds a list of defaults for specific values
// Each entry in the slice specifies Repo and CLuster regexp filter fields to
// match against the jobs and a corresponding ProwJobDefault . All entries that
// match a job are used. Later matching entries override the fields of earlier
// matching entires.
ProwJobDefaultEntries []*ProwJobDefaultEntry `json:"prowjob_default_entries,omitempty"`
}

type InRepoConfig struct {
Expand Down Expand Up @@ -540,6 +547,26 @@ type Plank struct {
BuildClusterStatusFile string `json:"build_cluster_status_file,omitempty"`
}

type ProwJobDefaultEntry struct {
// Matching/filtering fields. All filters must match for an entry to match.

// OrgRepo matches against the "org" or "org/repo" that the presubmit or postsubmit
// is associated with. If the job is a periodic, extra_refs[0] is used. If the
// job is a periodic without extra_refs, the empty string will be used.
// If this field is omitted all jobs will match.
OrgRepo string `json:"repo,omitempty"`
// Cluster matches against the cluster alias of the build cluster that the
// ProwJob is configured to run on. Recall that ProwJobs default to running on
// the "default" build cluster if they omit the "cluster" field in config.
Cluster string `json:"cluster,omitempty"`

// Config is the ProwJobDefault to apply if the filter fields all match the
// ProwJob. Note that when multiple entries match a ProwJob they are all used
// by sequentially merging with later entries overriding fields from earlier
// entries.
Config *prowapi.ProwJobDefault `json:"config,omitempty"`
}

// DefaultDecorationConfigEntry contains a DecorationConfig and a set of
// filters to use to determine if the config should be used as a default for a
// given ProwJob. When multiple of these entries match a ProwJob, they are all
Expand All @@ -564,11 +591,38 @@ type DefaultDecorationConfigEntry struct {
Config *prowapi.DecorationConfig `json:"config,omitempty"`
}

// TODO(mpherman): Make a Matcher struct embedded in both ProwJobDefaultEntry and DefaultDecorationConfigEntry
func matches(orgRepo, givenCluster, repo, cluster string) bool {
repoMatch := orgRepo == "" || orgRepo == "*" || orgRepo == repo || orgRepo == strings.Split(repo, "/")[0]
clusterMatch := givenCluster == "" || givenCluster == "*" || givenCluster == cluster
return repoMatch && clusterMatch
}

// matches returns true iff all the filters for the entry match a job.
func (d *ProwJobDefaultEntry) matches(repo, cluster string) bool {
return matches(d.OrgRepo, d.Cluster, repo, cluster)
}

// matches returns true iff all the filters for the entry match a job.
func (d *DefaultDecorationConfigEntry) matches(repo, cluster string) bool {
repoMatch := d.OrgRepo == "" || d.OrgRepo == "*" || d.OrgRepo == repo || d.OrgRepo == strings.Split(repo, "/")[0]
clusterMatch := d.Cluster == "" || d.Cluster == "*" || d.Cluster == cluster
return repoMatch && clusterMatch
return matches(d.OrgRepo, d.Cluster, repo, cluster)
}

// mergeProwJobDefault finds all matching ProwJobDefaultEntry
// for a job and merges them sequentially before merging into the job's own
// PrwoJobDefault. Configs merged later override values from earlier configs.
func (pc *ProwConfig) mergeProwJobDefault(repo, cluster string, jobDefault *prowapi.ProwJobDefault) *prowapi.ProwJobDefault {
var merged *prowapi.ProwJobDefault
for _, entry := range pc.ProwJobDefaultEntries {
if entry.matches(repo, cluster) {
merged = entry.Config.ApplyDefault(merged)
}
}
merged = jobDefault.ApplyDefault(merged)
if merged == nil {
merged = &prowapi.ProwJobDefault{}
}
return merged
}

// mergeDefaultDecorationConfig finds all matching DefaultDecorationConfigEntry
Expand Down Expand Up @@ -1493,6 +1547,22 @@ func shouldDecorate(c *JobConfig, util *UtilityConfig) bool {
return c.DecorateAllJobs
}

func setPresubmitProwJobDefaults(c *Config, ps *Presubmit, repo string) {
ps.ProwJobDefault = c.mergeProwJobDefault(repo, ps.Cluster, ps.ProwJobDefault)
}

func setPostsubmitProwJobDefaults(c *Config, ps *Postsubmit, repo string) {
ps.ProwJobDefault = c.mergeProwJobDefault(repo, ps.Cluster, ps.ProwJobDefault)
}

func setPeriodicProwJobDefaults(c *Config, ps *Periodic) {
var repo string
if len(ps.UtilityConfig.ExtraRefs) > 0 {
repo = fmt.Sprintf("%s/%s", ps.UtilityConfig.ExtraRefs[0].Org, ps.UtilityConfig.ExtraRefs[0].Repo)
}

ps.ProwJobDefault = c.mergeProwJobDefault(repo, ps.Cluster, ps.ProwJobDefault)
}
func setPresubmitDecorationDefaults(c *Config, ps *Presubmit, repo string) {
if shouldDecorate(&c.JobConfig, &ps.JobBase.UtilityConfig) {
ps.DecorationConfig = c.Plank.mergeDefaultDecorationConfig(repo, ps.Cluster, ps.DecorationConfig)
Expand Down Expand Up @@ -1522,6 +1592,7 @@ func defaultPresubmits(presubmits []Presubmit, additionalPresets []Preset, c *Co
var errs []error
for idx, ps := range presubmits {
setPresubmitDecorationDefaults(c, &presubmits[idx], repo)
setPresubmitProwJobDefaults(c, &presubmits[idx], repo)
if err := resolvePresets(ps.Name, ps.Labels, ps.Spec, append(c.Presets, additionalPresets...)); err != nil {
errs = append(errs, err)
}
Expand All @@ -1539,6 +1610,7 @@ func defaultPostsubmits(postsubmits []Postsubmit, additionalPresets []Preset, c
var errs []error
for idx, ps := range postsubmits {
setPostsubmitDecorationDefaults(c, &postsubmits[idx], repo)
setPostsubmitProwJobDefaults(c, &postsubmits[idx], repo)
if err := resolvePresets(ps.Name, ps.Labels, ps.Spec, append(c.Presets, additionalPresets...)); err != nil {
errs = append(errs, err)
}
Expand All @@ -1555,6 +1627,7 @@ func defaultPeriodics(c *Config) error {
var errs []error
for i := range c.Periodics {
setPeriodicDecorationDefaults(c, &c.Periodics[i])
setPeriodicProwJobDefaults(c, &c.Periodics[i])
if err := resolvePresets(c.Periodics[i].Name, c.Periodics[i].Labels, c.Periodics[i].Spec, c.Presets); err != nil {
errs = append(errs, err)
}
Expand Down
Loading

0 comments on commit d15451c

Please sign in to comment.