Skip to content

Commit

Permalink
Forward git credentials to config management plugins. Closes argoproj…
Browse files Browse the repository at this point in the history
  • Loading branch information
alexec committed Jun 7, 2019
1 parent 893f142 commit b73cad7
Show file tree
Hide file tree
Showing 14 changed files with 178 additions and 56 deletions.
6 changes: 6 additions & 0 deletions controller/appcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,6 +972,7 @@ func (ctrl *ApplicationController) watchSettings(ctx context.Context) {
prevAppLabelKey := ctrl.settings.GetAppInstanceLabelKey()
prevResourceExclusions := ctrl.settings.ResourceExclusions
prevResourceInclusions := ctrl.settings.ResourceInclusions
prevConfigManagementPlugins := ctrl.settings.ConfigManagementPlugins
done := false
for !done {
select {
Expand All @@ -993,6 +994,11 @@ func (ctrl *ApplicationController) watchSettings(ctx context.Context) {
ctrl.stateCache.Invalidate()
prevResourceInclusions = newSettings.ResourceInclusions
}
if !reflect.DeepEqual(prevConfigManagementPlugins, newSettings.ConfigManagementPlugins) {
log.WithFields(log.Fields{"prevConfigManagementPlugins": prevConfigManagementPlugins, "newConfigManagementPlugins": newSettings.ConfigManagementPlugins}).Info("config management plugins modified")
ctrl.stateCache.Invalidate()
prevConfigManagementPlugins = newSettings.ConfigManagementPlugins
}
case <-ctx.Done():
done = true
}
Expand Down
21 changes: 14 additions & 7 deletions reposerver/repository/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
"github.com/TomOnTime/utfutil"
argoexec "github.com/argoproj/pkg/exec"
"github.com/ghodss/yaml"
jsonnet "github.com/google/go-jsonnet"
"github.com/google/go-jsonnet"
log "github.com/sirupsen/logrus"
"golang.org/x/sync/semaphore"
"google.golang.org/grpc/codes"
Expand Down Expand Up @@ -191,6 +191,7 @@ func GenerateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, e
var dest *v1alpha1.ApplicationDestination

appSourceType, err := GetAppSourceType(q.ApplicationSource, appPath)
creds := newCreds(q.Repo)
switch appSourceType {
case v1alpha1.ApplicationSourceTypeKsonnet:
targetObjs, dest, err = ksShow(q.AppLabelKey, appPath, q.ApplicationSource.Ksonnet)
Expand All @@ -216,10 +217,10 @@ func GenerateManifests(appPath string, q *ManifestRequest) (*ManifestResponse, e
}
}
case v1alpha1.ApplicationSourceTypeKustomize:
k := kustomize.NewKustomizeApp(appPath, kustomizeCredentials(q.Repo))
k := kustomize.NewKustomizeApp(appPath, creds)
targetObjs, _, _, err = k.Build(q.ApplicationSource.Kustomize)
case v1alpha1.ApplicationSourceTypePlugin:
targetObjs, err = runConfigManagementPlugin(appPath, q, q.Plugins)
targetObjs, err = runConfigManagementPlugin(appPath, q, creds, q.Plugins)
case v1alpha1.ApplicationSourceTypeDirectory:
var directory *v1alpha1.ApplicationSourceDirectory
if directory = q.ApplicationSource.Directory; directory == nil {
Expand Down Expand Up @@ -511,7 +512,7 @@ func runCommand(command v1alpha1.Command, path string, env []string) (string, er
return argoexec.RunCommandExt(cmd)
}

func runConfigManagementPlugin(appPath string, q *ManifestRequest, plugins []*v1alpha1.ConfigManagementPlugin) ([]*unstructured.Unstructured, error) {
func runConfigManagementPlugin(appPath string, q *ManifestRequest, creds *git.Creds, plugins []*v1alpha1.ConfigManagementPlugin) ([]*unstructured.Unstructured, error) {
var plugin *v1alpha1.ConfigManagementPlugin
for i := range plugins {
if plugins[i].Name == q.ApplicationSource.Plugin.Name {
Expand All @@ -523,6 +524,12 @@ func runConfigManagementPlugin(appPath string, q *ManifestRequest, plugins []*v1
return nil, fmt.Errorf("Config management plugin with name '%s' is not supported.", q.ApplicationSource.Plugin.Name)
}
env := append(os.Environ(), fmt.Sprintf("%s=%s", PluginEnvAppName, q.AppLabelValue), fmt.Sprintf("%s=%s", PluginEnvAppNamespace, q.Namespace))
if creds != nil {
env = append(env,
"GIT_ASKPASS=git-ask-pass.sh",
fmt.Sprintf("GIT_USERNAME=%s", creds.Username),
fmt.Sprintf("GIT_PASSWORD=%s", creds.Password))
}
if plugin.Init != nil {
_, err := runCommand(*plugin.Init, appPath, env)
if err != nil {
Expand Down Expand Up @@ -641,7 +648,7 @@ func (s *Service) GetAppDetails(ctx context.Context, q *RepoServerAppDetailsQuer
case v1alpha1.ApplicationSourceTypeKustomize:
res.Kustomize = &KustomizeAppSpec{}
res.Kustomize.Path = q.Path
k := kustomize.NewKustomizeApp(appPath, kustomizeCredentials(q.Repo))
k := kustomize.NewKustomizeApp(appPath, newCreds(q.Repo))
_, imageTags, images, err := k.Build(nil)
if err != nil {
return nil, err
Expand All @@ -667,11 +674,11 @@ func (q *RepoServerAppDetailsQuery) valueFiles() []string {
return q.Helm.ValueFiles
}

func kustomizeCredentials(repo *v1alpha1.Repository) *kustomize.GitCredentials {
func newCreds(repo *v1alpha1.Repository) *git.Creds {
if repo == nil || repo.Password == "" {
return nil
}
return &kustomize.GitCredentials{
return &git.Creds{
Username: repo.Username,
Password: repo.Password,
}
Expand Down
8 changes: 7 additions & 1 deletion reposerver/repository/repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,12 @@ func TestRunCustomTool(t *testing.T) {
Name: "test",
Generate: argoappv1.Command{
Command: []string{"sh", "-c"},
Args: []string{`echo "{\"kind\": \"FakeObject\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\"}}"`},
Args: []string{`echo "{\"kind\": \"FakeObject\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GIT_ASKPASS\": \"$GIT_ASKPASS\", \"GIT_USERNAME\": \"$GIT_USERNAME\", \"GIT_PASSWORD\": \"$GIT_PASSWORD\"}}}"`},
},
}},
Repo: &argoappv1.Repository{
Username: "foo", Password: "bar",
},
})

assert.Nil(t, err)
Expand All @@ -173,6 +176,9 @@ func TestRunCustomTool(t *testing.T) {

assert.Equal(t, obj.GetName(), "test-app")
assert.Equal(t, obj.GetNamespace(), "test-namespace")
assert.Equal(t, "git-ask-pass.sh", obj.GetAnnotations()["GIT_ASKPASS"])
assert.Equal(t, "foo", obj.GetAnnotations()["GIT_USERNAME"])
assert.Equal(t, "bar", obj.GetAnnotations()["GIT_PASSWORD"])
}

func TestGenerateFromUTF16(t *testing.T) {
Expand Down
20 changes: 3 additions & 17 deletions test/e2e/app_management_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -284,16 +284,9 @@ func TestResourceDiffing(t *testing.T) {
And(func(app *Application) {
diffOutput, _ := fixture.RunCli("app", "diff", app.Name, "--local", "testdata/guestbook")
assert.Contains(t, diffOutput, fmt.Sprintf("===== apps/Deployment %s/guestbook-ui ======", fixture.DeploymentNamespace()))

// Update settings to ignore image difference
settings, err := fixture.SettingsManager.GetSettings()
assert.NoError(t, err)
settings.ResourceOverrides = map[string]ResourceOverride{
"apps/Deployment": {IgnoreDifferences: ` jsonPointers: ["/spec/template/spec/containers/0/image"]`},
}
err = fixture.SettingsManager.SaveSettings(settings)
assert.NoError(t, err)
}).
Given().
ResourceOverrides(map[string]ResourceOverride{"apps/Deployment": {IgnoreDifferences: ` jsonPointers: ["/spec/template/spec/containers/0/image"]`}}).
When().
Refresh(RefreshTypeNormal).
Then().
Expand Down Expand Up @@ -389,14 +382,7 @@ definitions:
func TestResourceAction(t *testing.T) {
Given(t).
Path(guestbookPath).
And(func() {
settings, err := fixture.SettingsManager.GetSettings()
assert.NoError(t, err)

settings.ResourceOverrides = map[string]ResourceOverride{"apps/Deployment": {Actions: actionsConfig}}
err = fixture.SettingsManager.SaveSettings(settings)
assert.NoError(t, err)
}).
ResourceOverrides(map[string]ResourceOverride{"apps/Deployment": {Actions: actionsConfig}}).
When().
Create().
Sync().
Expand Down
53 changes: 53 additions & 0 deletions test/e2e/custom_tool_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package e2e

import (
"testing"

"github.com/stretchr/testify/assert"

. "github.com/argoproj/argo-cd/errors"
. "github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
. "github.com/argoproj/argo-cd/test/e2e/fixture"
. "github.com/argoproj/argo-cd/test/e2e/fixture/app"
)

// make sure we can echo back the Git creds
func TestCustomToolWithGitCreds(t *testing.T) {
Given(t).
// path does not matter, we ignore it
ConfigManagementPlugin(
ConfigManagementPlugin{
Name: Name(),
Generate: Command{
Command: []string{"sh", "-c"},
Args: []string{`echo "{\"kind\": \"ConfigMap\", \"apiVersion\": \"v1\", \"metadata\": { \"name\": \"$ARGOCD_APP_NAME\", \"namespace\": \"$ARGOCD_APP_NAMESPACE\", \"annotations\": {\"GitAskpass\": \"$GIT_ASKPASS\", \"GitUsername\": \"$GIT_USERNAME\", \"GitPassword\": \"$GIT_PASSWORD\"}}}"`},
},
},
).
// add the private repo
And(func() {
FailOnErr(RunCli("repo", "add", repoUrl, "--username", "blah", "--password", accessToken))
}).
Repo(repoUrl).
Path(appPath).
When().
Create().
Sync().
Then().
Expect(OperationPhaseIs(OperationSucceeded)).
And(func(app *Application) {
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitAskpass}")
assert.NoError(t, err)
assert.Equal(t, "git-ask-pass.sh", output)
}).
And(func(app *Application) {
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitUsername}")
assert.NoError(t, err)
assert.Equal(t, "blah", output)
}).
And(func(app *Application) {
output, err := Run("", "kubectl", "-n", DeploymentNamespace(), "get", "cm", Name(), "-o", "jsonpath={.metadata.annotations.GitPassword}")
assert.NoError(t, err)
assert.Equal(t, accessToken, output)
})
}
4 changes: 4 additions & 0 deletions test/e2e/fixture/app/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ func (a *Actions) Create() *Actions {
args = append(args, "--nameprefix", a.context.namePrefix)
}

if a.context.configManagementPlugin != "" {
args = append(args, "--config-management-plugin", a.context.configManagementPlugin)
}

a.runCli(args...)

return a
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/fixture/app/consequences.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ func (c *Consequences) And(block func(app *Application)) *Consequences {
return c
}

func (c *Consequences) Given() *Context {
return c.context
}

func (c *Consequences) When() *Actions {
return c.actions
}
Expand Down
32 changes: 23 additions & 9 deletions test/e2e/fixture/app/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,22 @@ import (
"testing"

. "github.com/argoproj/argo-cd/common"
"github.com/argoproj/argo-cd/pkg/apis/application/v1alpha1"
"github.com/argoproj/argo-cd/test/e2e/fixture"
)

// this implements the "given" part of given/when/then
type Context struct {
t *testing.T
path string
name string
destServer string
env string
parameters []string
namePrefix string
resource string
prune bool
t *testing.T
path string
name string
destServer string
env string
parameters []string
namePrefix string
resource string
prune bool
configManagementPlugin string
}

func Given(t *testing.T) *Context {
Expand Down Expand Up @@ -61,6 +63,18 @@ func (c *Context) NamePrefix(namePrefix string) *Context {
return c
}

func (c *Context) ResourceOverrides(overrides map[string]v1alpha1.ResourceOverride) *Context {
fixture.SetResourceOverrides(overrides)
return c
}

// this both configures the plugin, but forces use of it
func (c *Context) ConfigManagementPlugin(plugin v1alpha1.ConfigManagementPlugin) *Context {
fixture.SetConfigManagementPlugin(plugin)
c.configManagementPlugin = plugin.Name
return c
}

func (c *Context) And(block func()) *Context {
block()
return c
Expand Down
Loading

0 comments on commit b73cad7

Please sign in to comment.