Skip to content

Commit

Permalink
Add delete_unsynced option to targets
Browse files Browse the repository at this point in the history
  • Loading branch information
Julien Duchesne committed Jul 10, 2019
1 parent ea2c9e4 commit 11fd301
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 44 deletions.
38 changes: 16 additions & 22 deletions sync/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ import (

// Configuration represents the parsed configuration file given to the application
type Configuration struct {
Sources *credentials.SourcesConfiguration
StopOnError bool `mapstructure:"stop_on_error"`
TargetParallelism int `mapstructure:"target_parallelism"`
Targets *targets.Configuration
CredentialsToDelete []string `mapstructure:"credentials_to_delete"`
Sources *credentials.SourcesConfiguration `mapstructure:"sources"`
StopOnError bool `mapstructure:"stop_on_error"`
TargetParallelism int `mapstructure:"target_parallelism"`
Targets *targets.Configuration `mapstructure:"targets"`
}

// NewConfiguration creates a new configuration with default values
Expand Down Expand Up @@ -76,26 +77,19 @@ func initTarget(target targets.Target, creds []credentials.Credentials, channel
func syncCredentials(target targets.Target, credentialsList []credentials.Credentials, channel chan bool, panicOnError bool) {
defer func() { <-channel }()

credChannel := make(chan bool, 1)
filteredCredentials := []credentials.Credentials{}
for _, cred := range credentialsList {
credChannel <- true
go func(cred credentials.Credentials) {
defer func() { <-credChannel }()
if !cred.ShouldSync(target.GetName(), target.GetTags()) {
return
}
log.Infof("[%s] Syncing %s", target.GetName(), cred.GetID())
if err := target.UpdateCredentials(cred); err != nil {
message := fmt.Sprintf("Failed to send credential %s to %s: %v", cred.GetID(), target.GetName(), err)
if panicOnError {
log.Fatal(message)
}
log.Error(message)
}
}(cred)
if cred.ShouldSync(target.GetName(), target.GetTags()) {
filteredCredentials = append(filteredCredentials, cred)
}
}
for i := 0; i < cap(credChannel); i++ {
credChannel <- true

if err := targets.UpdateListOfCredentials(target, filteredCredentials); err != nil {
message := fmt.Sprintf("Failed to send credentials to %s: %v", target.GetName(), err)
if panicOnError {
log.Fatal(message)
}
log.Error(message)
}

log.Infof("Finished sync to %s", target.GetName())
Expand Down
35 changes: 16 additions & 19 deletions targets/jenkins.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,17 @@ func (jenkins *JenkinsTarget) Initialize(allCredentials []credentials.Credential
return err
}

// HasCredentials returns true if the given credentials exists on the Jenkins instance
func (jenkins *JenkinsTarget) HasCredentials(cred credentials.Credentials) bool {
for _, id := range jenkins.existingCredentials {
if cred.GetID() == id {
return true
}
}
return false
}

// ToString prints out a description of the Jenkins instance
func (jenkins *JenkinsTarget) ToString() string {
return fmt.Sprintf("%s (Jenkins) - %s", jenkins.BaseToString(), jenkins.URL)
}

// UpdateListOfCredentials syncs the given list of credentials to the Jenkins instance
func (jenkins *JenkinsTarget) UpdateListOfCredentials(listOfCredentials []credentials.Credentials) error {
for _, credentials := range listOfCredentials {
if err := jenkins.UpdateCredentials(credentials); err != nil {
return err
}
}
return nil
func (jenkins *JenkinsTarget) GetExistingCredentials() []string {
return jenkins.existingCredentials
}

func (jenkins *JenkinsTarget) DeleteCredentials(id string) error {
return jenkins.credentialsManager.Delete(credentialsDomain, id)
}

// UpdateCredentials syncs the given credentials to the Jenkins instance
Expand All @@ -96,7 +84,7 @@ func (jenkins *JenkinsTarget) UpdateCredentials(cred credentials.Credentials) er
if jenkinsCred == nil {
return fmt.Errorf("Unable to create jenkins credentials from %s", cred.GetID())
}
if jenkins.HasCredentials(cred) {
if jenkins.hasCredentials(cred) {
return jenkins.credentialsManager.Update(credentialsDomain, cred.GetID(), jenkinsCred)
}
return jenkins.credentialsManager.Add(credentialsDomain, jenkinsCred)
Expand All @@ -111,6 +99,15 @@ func (jenkins *JenkinsTarget) ValidateConfiguration() bool {
return true
}

func (jenkins *JenkinsTarget) hasCredentials(cred credentials.Credentials) bool {
for _, id := range jenkins.existingCredentials {
if cred.GetID() == id {
return true
}
}
return false
}

func toJenkinsCredential(creds credentials.Credentials) interface{} {
switch creds.(type) {
case *credentials.AmazonWebServicesCredentials:
Expand Down
58 changes: 55 additions & 3 deletions targets/targets.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,60 @@ import (

// Target represents an endpoint where credentials can be synced
type Target interface {
// Base
BaseValidateConfiguration() bool
GetName() string
GetTags() map[string]string
ShouldDeleteUnsynced() bool
ShouldTagUnsynced() bool

// To implement
GetExistingCredentials() []string
Initialize([]credentials.Credentials) error
ToString() string
UpdateListOfCredentials([]credentials.Credentials) error
DeleteCredentials(id string) error
UpdateCredentials(credentials.Credentials) error
ValidateConfiguration() bool
}

// UpdateListOfCredentials syncs the given list of credentials to the given target
func UpdateListOfCredentials(target Target, listOfCredentials []credentials.Credentials) error {
isSynced := func(id string) bool {
for _, credentials := range listOfCredentials {
if credentials.GetID() == id {
return true
}
}
return false
}

for _, credentials := range listOfCredentials {
log.Infof("[%s] Syncing %s", target.GetName(), credentials.GetID())
if err := target.UpdateCredentials(credentials); err != nil {
return err
}
}

if target.ShouldDeleteUnsynced() {
log.Debugf("Deleting unsynced credentials from %v", target.GetName())
for _, existingID := range target.GetExistingCredentials() {
if !isSynced(existingID) {
log.Infof("[%s] Deleting %s", target.GetName(), existingID)
if err := target.DeleteCredentials(existingID); err != nil {
return err
}
}
}
}
return nil
}

// Base contains attributes which are common to all targets
type Base struct {
Name string
Tags map[string]string
DeleteUnsynced bool `mapstructure:"delete_unsynced"`
TagUnsynced bool `mapstructure:"tag_unsynced"`
Name string `mapstructure:"name"`
Tags map[string]string `mapstructure:"tags"`
}

// BaseToString prints out the target fields common to all types of targets
Expand All @@ -41,6 +81,10 @@ func (targetBase *Base) BaseValidateConfiguration() bool {
log.Errorf("Every target need to define a name")
return false
}
if targetBase.DeleteUnsynced && targetBase.TagUnsynced {
log.Errorf("Cannot set both `tag_unsynced` and `delete_unsynced` on %v", targetBase.Name)
return false
}
return true
}

Expand All @@ -54,6 +98,14 @@ func (targetBase *Base) GetTags() map[string]string {
return targetBase.Tags
}

func (targetBase *Base) ShouldDeleteUnsynced() bool {
return targetBase.DeleteUnsynced
}

func (targetBase *Base) ShouldTagUnsynced() bool {
return targetBase.TagUnsynced
}

// Configuration contains all configured targets
type Configuration struct {
JenkinsTargets []*JenkinsTarget `mapstructure:"jenkins"`
Expand Down

0 comments on commit 11fd301

Please sign in to comment.