Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for helmfile in the apps model #6660

Closed
wants to merge 20 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
ce6ab1c
fix: add helper class for working with environment contexts
jstrachan Jan 29, 2020
3e540a9
fix: support helmfile/helm 3 with the app framework
jstrachan Jan 29, 2020
c441ae3
fix: lets resolve fully qualified charts for helmfile
jstrachan Jan 29, 2020
ab161fa
fix: add version defaulting from the version stream
jstrachan Jan 29, 2020
d9f504f
fix: improve handling of local charts in helmfile generation
jstrachan Jan 29, 2020
f05a967
fix: add version stream defaults for apps in helmfile
jstrachan Jan 29, 2020
2cd5171
fix: lets allow helmfile to be abled via env vars
jstrachan Jan 29, 2020
5ae4e0b
fix: rebased with latest jx
jstrachan Jan 29, 2020
8820ffa
chore: fix hound warnings
jstrachan Jan 29, 2020
a81936e
fix: add missing classifications
jstrachan Jan 29, 2020
4968833
chore: fix failing test broken due to rebase
jstrachan Jan 29, 2020
ca0939d
chore: regenerated
jstrachan Jan 29, 2020
3209fe7
chore: fix some tests broken due to rebase
jstrachan Jan 30, 2020
c7d0454
fix: refactor ApplicationConfig => AppConfig
jstrachan Jan 30, 2020
bce4142
fix: regression in `jx add app` when not using helmfile
jstrachan Jan 30, 2020
e213c49
fix: lets improve the EnvironmentContext API
jstrachan Jan 30, 2020
84c5288
fix: regression in `jx upgrade app`
jstrachan Jan 30, 2020
61a2300
fix: lets polish the code to be more clear on chart names
jstrachan Jan 30, 2020
b0ed159
fix: polish the code based on review
jstrachan Jan 30, 2020
272c3d5
fix: add the suggestions from @pmuir
jstrachan Jan 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pkg/applications/applications.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func (d Deployment) URL(kc kubernetes.Interface, a Application) string {
return url
}

// GetApplications fetches all Applications
// GetApplications fetches all Apps

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So GetApplication so far where the user's "applications" right? Now you want to call this "Apps" and unify this with the current Apps plugins and all become apps? We really are in a bit of a naming mess here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see https://github.com/jenkins-x/enhancements/tree/master/proposals/1 but I'm also hoping to submit a further enhancement to address the mess of jx get app v jx get applications but that would be another enhancement + PR etc...

func GetApplications(factory clients.Factory) (List, error) {
list := List{
Items: make([]Application, 0),
Expand Down
61 changes: 57 additions & 4 deletions pkg/apps/gitops.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"os"
"path/filepath"

"github.com/jenkins-x/jx/pkg/config"
"github.com/jenkins-x/jx/pkg/gits"
"github.com/jenkins-x/jx/pkg/kube/naming"

"github.com/jenkins-x/jx/pkg/helm"
"github.com/jenkins-x/jx/pkg/util"
Expand All @@ -28,7 +30,7 @@ type GitOpsOptions struct {
}

// AddApp adds the app with version rooted in dir from the repository. An alias can be specified.
func (o *GitOpsOptions) AddApp(app string, dir string, version string, repository string, alias string, autoMerge bool) error {
func (o *GitOpsOptions) AddApp(app string, fullChartName string, dir string, version string, repository string, alias string, autoMerge bool) error {
details := gits.PullRequestDetails{
BranchName: "add-app-" + app + "-" + version,
Title: fmt.Sprintf("Add %s %s", app, version),
Expand All @@ -39,7 +41,8 @@ func (o *GitOpsOptions) AddApp(app string, dir string, version string, repositor
Gitter: o.Gitter,
ModifyChartFn: environments.CreateAddRequirementFn(app, alias, version,
repository, o.valuesFiles, dir, o.Verbose, o.Helmer),
GitProvider: o.GitProvider,
ModifyAppsFn: environments.CreateAddAppConfigFn(fullChartName, version, repository),
GitProvider: o.GitProvider,
}

info, err := options.Create(o.DevEnv, o.EnvironmentCloneDir, &details, nil, "", autoMerge)
Expand Down Expand Up @@ -102,7 +105,8 @@ func (o *GitOpsOptions) UpgradeApp(app string, version string, repository string
Gitter: o.Gitter,
ModifyChartFn: environments.CreateUpgradeRequirementsFn(all, app, alias, version, username, password,
o.Helmer, inspectChartFunc, o.Verbose, o.valuesFiles),
GitProvider: o.GitProvider,
ModifyAppsFn: environments.CreateUpgradeAppConfigFn(all, app, version),
GitProvider: o.GitProvider,
}

_, err = options.Create(o.DevEnv, o.EnvironmentCloneDir, &details, nil, app, autoMerge)
Expand Down Expand Up @@ -145,6 +149,26 @@ func (o *GitOpsOptions) DeleteApp(app string, alias string, autoMerge bool) erro
}
return nil
}
modifyAppsFn := func(appsConfig *config.AppConfig, dir string, pullRequestDetails *gits.PullRequestDetails) error {
// See if the app already exists in requirements
found := false
for i, d := range appsConfig.Apps {
if d.Name == app {
found = true
appsConfig.Apps = append(appsConfig.Apps[:i], appsConfig.Apps[i+1:]...)
}
}

// If app not found, add it
if !found {
a := app
if alias != "" {
a = fmt.Sprintf("%s with alias %s", a, alias)
}
return fmt.Errorf("unable to delete app %s as not installed", app)
}
return nil
}
details := gits.PullRequestDetails{
BranchName: "delete-app-" + app,
Title: fmt.Sprintf("Delete %s", app),
Expand All @@ -154,6 +178,7 @@ func (o *GitOpsOptions) DeleteApp(app string, alias string, autoMerge bool) erro
options := environments.EnvironmentPullRequestOptions{
Gitter: o.Gitter,
ModifyChartFn: modifyChartFn,
ModifyAppsFn: modifyAppsFn,
GitProvider: o.GitProvider,
}

Expand Down Expand Up @@ -200,6 +225,35 @@ func (o *GitOpsOptions) GetApps(appNames map[string]bool, expandFn func([]string
return nil, errors.Wrapf(err, "failed to checkout %s to dir %s", o.DevEnv.Spec.Source.Ref, dir)
}

appsList := v1.AppList{}

// lets check if we are using a `jx-apps.yml` file
appsConfig, fileName, err := config.LoadAppConfig(dir)
if err != nil {
return nil, errors.Wrapf(err, "failed to load applications config in environment clone of %s", cloneUrl)
}
if fileName != "" {
// lets use the jx-apps.yml file
for _, a := range appsConfig.Apps {
app := v1.App{}
app.Name = naming.ToValidName(a.Name)
app.Namespace = a.Namespace
if app.Namespace == "" {
app.Namespace = o.DevEnv.Namespace
}
app.Labels = map[string]string{
helm.LabelAppName: a.Name,
helm.LabelAppVersion: a.Version,
}
app.Annotations = map[string]string{
helm.AnnotationAppDescription: a.Description,
helm.AnnotationAppRepository: a.Repository,
}
appsList.Items = append(appsList.Items, app)
}
return &appsList, nil
}

envDir := filepath.Join(dir, helm.DefaultEnvironmentChartDir)
if err != nil {
return nil, err
Expand All @@ -223,7 +277,6 @@ func (o *GitOpsOptions) GetApps(appNames map[string]bool, expandFn func([]string
return nil, errors.Wrap(err, "couldn't unmarshal the environment's requirements.yaml file")
}

appsList := v1.AppList{}
for _, d := range reqs.Dependencies {
if appNames[d.Name] == true || len(appNames) == 0 {
//Make sure we ignore the jenkins-x-platform requirement
Expand Down
40 changes: 23 additions & 17 deletions pkg/apps/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,28 +10,29 @@ import (
"strings"
"time"

"github.com/jenkins-x/jx/pkg/kube/naming"
rbacv1 "k8s.io/api/rbac/v1"

corev1 "k8s.io/api/core/v1"

"github.com/jenkins-x/jx/pkg/kube"
rbacv1 "k8s.io/api/rbac/v1"

"github.com/pborman/uuid"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

jenkinsv1 "github.com/jenkins-x/jx/pkg/apis/jenkins.io/v1"
"github.com/jenkins-x/jx/pkg/client/clientset/versioned"
"github.com/jenkins-x/jx/pkg/envctx"
"github.com/jenkins-x/jx/pkg/environments"
"github.com/jenkins-x/jx/pkg/gits"
"github.com/jenkins-x/jx/pkg/vault"
"k8s.io/client-go/kubernetes"

"github.com/jenkins-x/jx/pkg/helm"
"github.com/jenkins-x/jx/pkg/kube"
"github.com/jenkins-x/jx/pkg/kube/naming"
"github.com/jenkins-x/jx/pkg/log"
"github.com/jenkins-x/jx/pkg/util"
"github.com/jenkins-x/jx/pkg/vault"
"github.com/jenkins-x/jx/pkg/versionstream"

"github.com/pkg/errors"

"k8s.io/client-go/kubernetes"
)

// InstallOptions are shared options for installing, removing or upgrading apps for either GitOps or HelmOps
Expand All @@ -54,6 +55,7 @@ type InstallOptions struct {
VaultClient vault.Client
AutoMerge bool
SecretsScheme string
VersionResolver *versionstream.VersionResolver

valuesFiles *environments.ValuesFiles // internal variable used to track, most be passed in
}
Expand All @@ -62,9 +64,11 @@ type InstallOptions struct {
// or latest if not specified) from the repository with username and password. A releaseName can be specified.
// Values can be passed with in files or as a slice of name=value pairs. An alias can be specified.
// GitOps or HelmOps will be automatically chosen based on the o.GitOps flag
func (o *InstallOptions) AddApp(app string, version string, repository string, username string, password string,
func (o *InstallOptions) AddApp(details *envctx.ChartDetails, version string, username string, password string,
releaseName string, valuesFiles []string, setValues []string, alias string, helmUpdate bool) error {

repository := details.Repository
app := details.LocalName
o.valuesFiles = &environments.ValuesFiles{
Items: valuesFiles,
}
Expand All @@ -79,18 +83,20 @@ func (o *InstallOptions) AddApp(app string, version string, repository string, u
return errors.Wrapf(err, "adding helm repo")
}

chartName, err := o.resolvePrefixesAgainstRepos(repository, app)
if err != nil {
return errors.WithStack(err)
if details.Name == details.LocalName {
details.Name, err = o.resolvePrefixesAgainstRepos(repository, details.LocalName)
if err != nil {
return errors.WithStack(err)
}
}

chartName := details.Name
if chartName == "" {
return errors.Errorf("unable to find %s in %s", app, repository)
}

// The chart inspector allows us to operate on the unpacked chart.
// We need to ask questions then as we have access to the schema, and can add secrets.
interrogateChartFn := o.createInterrogateChartFn(version, chartName, repository, username, password, alias, true)
interrogateChartFn := o.createInterrogateChartFn(version, details.LocalName, repository, username, password, alias, true)

// Called whilst the chart is unpacked and modifiable
installAppFunc := func(dir string) error {
Expand All @@ -104,7 +110,7 @@ func (o *InstallOptions) AddApp(app string, version string, repository string, u
opts := GitOpsOptions{
InstallOptions: o,
}
err = opts.AddApp(chartDetails.Name, dir, chartDetails.Version, repository, alias, o.AutoMerge)
err = opts.AddApp(details.LocalName, details.Name, dir, chartDetails.Version, repository, alias, o.AutoMerge)
if err != nil {
return errors.Wrapf(err, "adding app %s version %s with alias %s using gitops", chartName, version, alias)
}
Expand All @@ -122,7 +128,7 @@ func (o *InstallOptions) AddApp(app string, version string, repository string, u
return errors.Wrapf(err, "building dependencies for %s", chartName)
}
}
err = opts.AddApp(chartName, dir, chartDetails.Name, chartDetails.Version, chartDetails.Values, repository,
err = opts.AddApp(details.Name, dir, chartDetails.Name, chartDetails.Version, chartDetails.Values, repository,
username, password,
releaseName,
setValues,
Expand All @@ -140,7 +146,7 @@ func (o *InstallOptions) AddApp(app string, version string, repository string, u
}

// Do the actual work
return helm.InspectChart(chartName, version, repository, username, password, o.Helmer, installAppFunc)
return helm.InspectChart(details.LocalName, version, repository, username, password, o.Helmer, installAppFunc)
}

//GetApps gets a list of installed apps
Expand Down
35 changes: 19 additions & 16 deletions pkg/cmd/add/add_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"fmt"

"github.com/jenkins-x/jx/pkg/cmd/helper"

"github.com/jenkins-x/jx/pkg/cmd/opts"
"github.com/jenkins-x/jx/pkg/cmd/templates"

Expand Down Expand Up @@ -61,6 +60,9 @@ var (
# Add an app
jx add app jx-app-jacoco

# Add an app using a chart repository prefix from the version stream 'charts/repositories.yml' file

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here things get confusing for me. So far this command is documented as being responsible for installing "apps" which are similar to "addons". So without any further context, I read this as "install an addon from a chart repository prefix from the version stream 'charts/repositories.yml' file". And not sure what the second part really means.

Do you have a plan how we get out of this naming mess?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

jx add app flagger/flagger

# Add an app from a local path
jx add app .`)
)
Expand Down Expand Up @@ -116,14 +118,12 @@ func (o *AddAppOptions) addFlags(cmd *cobra.Command, defaultNamespace string) {

// Run implements this command
func (o *AddAppOptions) Run() error {
o.GitOps, o.DevEnv = o.GetDevEnv()
if o.Repo == "" {
o.Repo = o.DevEnv.Spec.TeamSettings.AppsRepository
}
if o.Repo == "" {
o.Repo = kube.DefaultChartMuseumURL
ec, err := o.EnvironmentContext(".", false)
if err != nil {
return err
}

o.GitOps = ec.GitOps
o.DevEnv = ec.DevEnv
jxClient, ns, err := o.JXClientAndDevNamespace()
if err != nil {
return errors.Wrapf(err, "getting jx client")
Expand All @@ -135,6 +135,7 @@ func (o *AddAppOptions) Run() error {
if o.Namespace == "" {
o.Namespace = ns
}

installOpts := apps.InstallOptions{
IOFileHandles: o.GetIOFileHandles(),
DevEnv: o.DevEnv,
Expand All @@ -150,6 +151,7 @@ func (o *AddAppOptions) Run() error {
JxClient: jxClient,
InstallTimeout: opts.DefaultInstallTimeout,
EnvironmentCloneDir: o.CloneDir,
VersionResolver: ec.VersionResolver,
}

if o.GitOps {
Expand Down Expand Up @@ -214,16 +216,17 @@ func (o *AddAppOptions) Run() error {
return o.Cmd.Help()
}

if o.Repo == "" {
return fmt.Errorf("must specify a repository")
}
app := args[0]

var version string
if o.Version != "" {
version = o.Version
details, err := ec.ChartDetails(app, o.Repo)
if err != nil {
return err
}
app := args[0]
return installOpts.AddApp(app, version, o.Repo, o.Username, o.Password, o.ReleaseName, o.ValuesFiles, o.SetValues,
if details.Repository == "" {
return fmt.Errorf("must specify a repository or use a repository prefix in the chart name %s", details.Name)
}
o.Repo = details.Repository
return installOpts.AddApp(details, o.Version, o.Username, o.Password, o.ReleaseName, o.ValuesFiles, o.SetValues,
o.Alias, o.HelmUpdate)
}

Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func NewJXCommand(f clients.Factory, in terminal.FileReader, out terminal.FileWr
},
},
{
Message: "Working with Applications:",
Message: "Working with Apps:",
Commands: []*cobra.Command{
NewCmdConsole(commonOpts),
NewCmdLogs(commonOpts),
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/create/create_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func NewCmdCreateEnv(commonOpts *opts.CommonOptions) *cobra.Command {

cmd := &cobra.Command{
Use: "environment",
Short: "Create a new Environment which is used to promote your Team's Applications via Continuous Delivery",
Short: "Create a new Environment which is used to promote your Team's Apps via Continuous Delivery",
Aliases: []string{"env"},
Long: create_env_long,
Example: create_env_example,
Expand Down
8 changes: 7 additions & 1 deletion pkg/cmd/deletecmd/delete_app.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,12 @@ func NewCmdDeleteApp(commonOpts *opts.CommonOptions) *cobra.Command {

// Run implements this command
func (o *DeleteAppOptions) Run() error {
o.GitOps, o.DevEnv = o.GetDevEnv()
ec, err := o.EnvironmentContext(".", false)
if err != nil {
return err
}
o.GitOps = ec.GitOps
o.DevEnv = ec.DevEnv

installOptions := apps.InstallOptions{
IOFileHandles: o.GetIOFileHandles(),
Expand All @@ -95,6 +100,7 @@ func (o *DeleteAppOptions) Run() error {
Helmer: o.Helm(),
AutoMerge: o.AutoMerge,
EnvironmentCloneDir: o.CloneDir,
VersionResolver: ec.VersionResolver,
}

if o.GitOps {
Expand Down
Loading