Skip to content
This repository has been archived by the owner on Nov 1, 2022. It is now read-only.

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
dimitropoulos committed Mar 19, 2019
1 parent 267e011 commit 27b86d4
Show file tree
Hide file tree
Showing 17 changed files with 279 additions and 80 deletions.
3 changes: 2 additions & 1 deletion chart/flux/README.md
Expand Up @@ -164,7 +164,8 @@ fluxctl identity
In order to sync your cluster state with GitHub you need to copy the public key and
create a deploy key with write access on your GitHub repository.
Go to _Settings > Deploy keys_ click on _Add deploy key_, check
_Allow write access_, paste the Flux public key and click _Add key_.
_Allow write access_, paste the Flux public key and click _Add key_ if you want Flux to have write access to your repo.
If you are using the `--git-readonly=true` option, you can leave this box unchecked.

### Uninstalling the Chart

Expand Down
2 changes: 2 additions & 0 deletions chart/flux/templates/deployment.yaml
Expand Up @@ -115,12 +115,14 @@ spec:
- --ssh-keygen-dir=/var/fluxd/keygen
- --k8s-secret-name={{ .Values.git.secretName | default (printf "%s-git-deploy" (include "flux.fullname" .)) }}
- --memcached-hostname={{ template "flux.fullname" . }}-memcached
- --flux-state-mode={{ .Values.state.mode }}
{{- if .Values.memcached.createClusterIP }}
- --memcached-service=
{{- end }}
- --git-url={{ .Values.git.url }}
- --git-branch={{ .Values.git.branch }}
- --git-path={{ .Values.git.path }}
- --git-readonly={{ .Values.git.readonly }}
- --git-user={{ .Values.git.user }}
- --git-email={{ .Values.git.email }}
{{- if .Values.gpgKeys.secretName }}
Expand Down
7 changes: 7 additions & 0 deletions chart/flux/values.yaml
Expand Up @@ -99,13 +99,20 @@ gpgKeys:
# These keys will be imported into GPG in the Flux container.
secretName: ""

state:
# use `mode: Native` to store flux's state in a native kubernetes resource (instead of a git tag)
mode: GitTag

git:
# URL of git repo with Kubernetes manifests; e.g. git.url=ssh://git@github.com/weaveworks/flux-get-started
url: ""
# Branch of git repo to use for Kubernetes manifests
branch: "master"
# Path within git repo to locate Kubernetes manifests (relative path)
path: ""
# use if you want to Flux to be aware that you intend for Flux to not be able to push changes to git.
# Also configure state.mode to `Native` since storing state in a git tag will no longer be possible.
readonly: false
# Username to use as git committer
user: "Weave Flux"
# Email to use as git committer
Expand Down
54 changes: 52 additions & 2 deletions cmd/fluxd/main.go
Expand Up @@ -36,12 +36,14 @@ import (
"github.com/weaveworks/flux/image"
integrations "github.com/weaveworks/flux/integrations/client/clientset/versioned"
"github.com/weaveworks/flux/job"
nativestate "github.com/weaveworks/flux/nativestate"
"github.com/weaveworks/flux/registry"
"github.com/weaveworks/flux/registry/cache"
registryMemcache "github.com/weaveworks/flux/registry/cache/memcached"
registryMiddleware "github.com/weaveworks/flux/registry/middleware"
"github.com/weaveworks/flux/remote"
"github.com/weaveworks/flux/ssh"
fluxsync "github.com/weaveworks/flux/sync"
)

var version = "unversioned"
Expand Down Expand Up @@ -87,6 +89,7 @@ func main() {
gitURL = fs.String("git-url", "", "URL of git repo with Kubernetes manifests; e.g., git@github.com:weaveworks/flux-get-started")
gitBranch = fs.String("git-branch", "master", "branch of git repo to use for Kubernetes manifests")
gitPath = fs.StringSlice("git-path", []string{}, "relative paths within the git repo to locate Kubernetes manifests")
gitReadonly = fs.Bool("git-readonly", false, "use to prevnent Flux from pushing changes to git")
gitUser = fs.String("git-user", "Weave Flux", "username to use as git committer")
gitEmail = fs.String("git-email", "support@weave.works", "email to use as git committer")
gitSetAuthor = fs.Bool("git-set-author", false, "if set, the author of git commits will reflect the user who initiated the commit and will differ from the git committer.")
Expand Down Expand Up @@ -125,6 +128,9 @@ func main() {
registryAWSAccountIDs = fs.StringSlice("registry-ecr-include-id", nil, "restrict ECR scanning to these AWS account IDs; if empty, all account IDs that aren't excluded may be scanned")
registryAWSBlockAccountIDs = fs.StringSlice("registry-ecr-exclude-id", []string{registry.EKS_SYSTEM_ACCOUNT}, "do not scan ECR for images in these AWS account IDs; the default is to exclude the EKS system account")

// Flux state
fluxStateMode = fs.String("flux-state-mode", fluxsync.GitTagStateMode, "method used by flux for storing state")

// k8s-secret backed ssh keyring configuration
k8sSecretName = fs.String("k8s-secret-name", "flux-git-deploy", "name of the k8s secret used to store the private SSH key")
k8sSecretVolumeMountPath = fs.String("k8s-secret-volume-mount-path", "/etc/fluxd/ssh", "mount location of the k8s secret storing the private SSH key")
Expand Down Expand Up @@ -181,6 +187,31 @@ func main() {

// Argument validation

if *gitReadonly && *fluxStateMode != fluxsync.NativeStateMode {
logger.Log("warning", "to use readonly mode, you must use --flux-state-mode="+fluxsync.NativeStateMode+". instead you configured flux to use --flux-state-mode="+*fluxStateMode+". overriding to use --flux-state-mode="+fluxsync.NativeStateMode)
*fluxStateMode = fluxsync.NativeStateMode
}

// check whether the user is configuring things only used for git access at the same time as configuring Flux to run without touching git
gitRelatedFlags := []string{
"git-user",
"git-email",
"git-sync-tag",
"git-set-author",
"git-ci-skip",
"git-ci-skip-message",
}
var changedGitRelatedFlags []string
for _, gitRelatedFlag := range gitRelatedFlags {
if fs.Changed(gitRelatedFlag) {
changedGitRelatedFlags = append(changedGitRelatedFlags, gitRelatedFlag)
}
}
if *gitReadonly && len(changedGitRelatedFlags) > 0 {
flags := strings.Join(changedGitRelatedFlags, ", ")
logger.Log("warning", "configuring "+flags+" has no effect when either (A) using --git-readonly=true or when (B) using --flux-state-mode="+fluxsync.NativeStateMode)
}

// Sort out values for the git tag and notes ref. There are
// running deployments that assume the defaults as given, so don't
// mess with those unless explicitly told.
Expand Down Expand Up @@ -441,7 +472,6 @@ func main() {
gitConfig := git.Config{
Paths: *gitPath,
Branch: *gitBranch,
SyncTag: *gitSyncTag,
NotesRef: *gitNotesRef,
UserName: *gitUser,
UserEmail: *gitEmail,
Expand All @@ -450,7 +480,7 @@ func main() {
SkipMessage: *gitSkipMessage,
}

repo := git.NewRepo(gitRemote, git.PollInterval(*gitPollInterval), git.Timeout(*gitTimeout))
repo := git.NewRepo(gitRemote, git.PollInterval(*gitPollInterval), git.Timeout(*gitTimeout), git.SetReadOnly(*gitReadonly))
{
shutdownWg.Add(1)
go func() {
Expand All @@ -467,6 +497,8 @@ func main() {
"email", *gitEmail,
"signing-key", *gitSigningKey,
"sync-tag", *gitSyncTag,
"flux-state-mode", *fluxStateMode,
"readonly", *gitReadonly,
"notes-ref", *gitNotesRef,
"set-author", *gitSetAuthor,
)
Expand All @@ -476,6 +508,23 @@ func main() {
jobs = job.NewQueue(shutdown, shutdownWg)
}

var syncProvider fluxsync.SyncProvider
switch *fluxStateMode {
case fluxsync.NativeStateMode:
// reminder: this code assumes that if we are in readonly mode the *fluxStateMode has already been forced to NativeStateMode
syncProvider = nativestate.NewNativeSyncProvider()

case fluxsync.GitTagStateMode:
syncProvider = git.NewGitTagSyncProvider(
repo,
*gitSyncTag,
*gitURL,
*gitSigningKey,
*gitUser,
*gitEmail,
)
}

daemon := &daemon.Daemon{
V: version,
Cluster: k8s,
Expand All @@ -485,6 +534,7 @@ func main() {
Repo: repo,
GitConfig: gitConfig,
Jobs: jobs,
SyncProvider: syncProvider,
JobStatusCache: &job.StatusCache{Size: 100},
Logger: log.With(logger, "component", "daemon"),
LoopVars: &daemon.LoopVars{
Expand Down
9 changes: 8 additions & 1 deletion daemon/daemon.go
Expand Up @@ -27,6 +27,7 @@ import (
"github.com/weaveworks/flux/registry"
"github.com/weaveworks/flux/release"
"github.com/weaveworks/flux/resource"
fluxsync "github.com/weaveworks/flux/sync"
"github.com/weaveworks/flux/update"
)

Expand All @@ -53,6 +54,7 @@ type Daemon struct {
JobStatusCache *job.StatusCache
EventWriter event.EventWriter
Logger log.Logger
SyncProvider fluxsync.SyncProvider
// bookkeeping
*LoopVars
}
Expand Down Expand Up @@ -567,7 +569,12 @@ func (d *Daemon) JobStatus(ctx context.Context, jobID job.ID) (job.Status, error
// you'll get all the commits yet to be applied. If you send a hash
// and it's applied at or _past_ it, you'll get an empty list.
func (d *Daemon) SyncStatus(ctx context.Context, commitRef string) ([]string, error) {
commits, err := d.Repo.CommitsBetween(ctx, d.GitConfig.SyncTag, commitRef, d.GitConfig.Paths...)
syncMarkerRevision, err := d.SyncProvider.GetRevision(ctx)
if err != nil {
return nil, err
}

commits, err := d.Repo.CommitsBetween(ctx, syncMarkerRevision, commitRef, d.GitConfig.Paths...)
if err != nil {
return nil, err
}
Expand Down
44 changes: 24 additions & 20 deletions daemon/loop.go
Expand Up @@ -61,8 +61,8 @@ func (d *Daemon) Loop(stop chan struct{}, wg *sync.WaitGroup, logger log.Logger)

for {
var (
lastKnownSyncTagRev string
warnedAboutSyncTagChange bool
lastKnownSyncMarkerRev string
warnedAboutSyncMarkerChange bool
)
select {
case <-stop:
Expand All @@ -86,7 +86,7 @@ func (d *Daemon) Loop(stop chan struct{}, wg *sync.WaitGroup, logger log.Logger)
default:
}
}
if err := d.doSync(logger, &lastKnownSyncTagRev, &warnedAboutSyncTagChange); err != nil {
if err := d.doSync(logger, &lastKnownSyncMarkerRev, &warnedAboutSyncMarkerChange); err != nil {
logger.Log("err", err)
}
syncTimer.Reset(d.SyncInterval)
Expand Down Expand Up @@ -152,7 +152,7 @@ func (d *LoopVars) AskForImagePoll() {

// -- extra bits the loop needs

func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAboutSyncTagChange *bool) (retErr error) {
func (d *Daemon) doSync(logger log.Logger, lastKnownSyncMarkerRev *string, warnedAboutSyncMarkerChange *bool) (retErr error) {
started := time.Now().UTC()
defer func() {
syncDuration.With(
Expand Down Expand Up @@ -181,20 +181,21 @@ func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAb
}

// For comparison later.
oldTagRev, err := working.SyncRevision(ctx)
oldSyncMarkerRev, err := d.SyncProvider.GetRevision(ctx)

if err != nil && !isUnknownRevision(err) {
return err
}
// Check if something other than the current instance of fluxd changed the sync tag.
// This is likely to be caused by another fluxd instance using the same tag.
// Having multiple instances fighting for the same tag can lead to fluxd missing manifest changes.
if *lastKnownSyncTagRev != "" && oldTagRev != *lastKnownSyncTagRev && !*warnedAboutSyncTagChange {
if *lastKnownSyncMarkerRev != "" && oldSyncMarkerRev != *lastKnownSyncMarkerRev && !*warnedAboutSyncMarkerChange {
logger.Log("warning",
"detected external change in git sync tag; the sync tag should not be shared by fluxd instances")
*warnedAboutSyncTagChange = true
*warnedAboutSyncMarkerChange = true
}

newTagRev, err := working.HeadRevision(ctx)
headRev, err := working.HeadRevision(ctx)
if err != nil {
return err
}
Expand Down Expand Up @@ -229,11 +230,11 @@ func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAb
{
var err error
ctx, cancel := context.WithTimeout(ctx, d.GitOpTimeout)
if oldTagRev != "" {
commits, err = d.Repo.CommitsBetween(ctx, oldTagRev, newTagRev, d.GitConfig.Paths...)
if oldSyncMarkerRev != "" {
commits, err = d.Repo.CommitsBetween(ctx, oldSyncMarkerRev, headRev, d.GitConfig.Paths...)
} else {
initialSync = true
commits, err = d.Repo.CommitsBefore(ctx, newTagRev, d.GitConfig.Paths...)
commits, err = d.Repo.CommitsBefore(ctx, headRev, d.GitConfig.Paths...)
}
cancel()
if err != nil {
Expand All @@ -245,11 +246,11 @@ func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAb
changedResources := map[string]resource.Resource{}

if initialSync {
// no synctag, We are syncing everything from scratch
// no SyncMarker, We are syncing everything from scratch
changedResources = allResources
} else {
ctx, cancel := context.WithTimeout(ctx, d.GitOpTimeout)
changedFiles, err := working.ChangedFiles(ctx, oldTagRev)
changedFiles, err := working.ChangedFiles(ctx, oldSyncMarkerRev)
if err == nil && len(changedFiles) > 0 {
// We had some changed files, we're syncing a diff
// FIXME(michael): this won't be accurate when a file can have more than one resource
Expand Down Expand Up @@ -334,7 +335,7 @@ func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAb
Error: n.Result.Error(),
},
Spec: event.ReleaseSpec{
Type: event.ReleaseContainersSpecType,
Type: event.ReleaseContainersSpecType,
ReleaseContainersSpec: &spec,
},
Cause: n.Spec.Cause,
Expand Down Expand Up @@ -424,21 +425,24 @@ func (d *Daemon) doSync(logger log.Logger, lastKnownSyncTagRev *string, warnedAb
}

// Move the tag and push it so we know how far we've gotten.
if oldTagRev != newTagRev {
if oldSyncMarkerRev != headRev {
{
ctx, cancel := context.WithTimeout(ctx, d.GitOpTimeout)
tagAction := git.TagAction{
Revision: newTagRev,
syncMarkerAction := fluxsync.SyncMarkerAction{
Revision: headRev,
Message: "Sync pointer",
}
err := working.MoveSyncTagAndPush(ctx, tagAction)
err := d.SyncProvider.UpdateMarker(ctx, syncMarkerAction)
cancel()
if err != nil {
return err
}
*lastKnownSyncTagRev = newTagRev
*lastKnownSyncMarkerRev = headRev
}
logger.Log("tag", d.GitConfig.SyncTag, "old", oldTagRev, "new", newTagRev)
logger.Log(
"old", oldSyncMarkerRev,
"new", headRev,
)
{
ctx, cancel := context.WithTimeout(ctx, d.GitOpTimeout)
err := d.Repo.Refresh(ctx)
Expand Down
6 changes: 6 additions & 0 deletions deploy/flux-deployment.yaml
Expand Up @@ -106,6 +106,12 @@ spec:
- --git-url=git@github.com:weaveworks/flux-get-started
- --git-branch=master

# give flux readonly access to the repo (defalut false)
# - --git-readonly=true # requires `--flux-state-mode=Native`

# instruct flux where to store state (default "GitTag")
# - --flux-state-mode=Native

# include these next two to connect to an "upstream" service
# (e.g., Weave Cloud). The token is particular to the service.
# - --connect=wss://cloud.weave.works/api/flux
Expand Down
3 changes: 2 additions & 1 deletion git/errors.go
Expand Up @@ -114,7 +114,8 @@ create a new deploy key. To create a new one, use
fluxctl identity --regenerate
The public key this outputs can then be given to GitHub; make sure you
check the box to allow write access.
check the box to allow write access unless you're using the
--git-readonly=true option.
`,
}
Expand Down
26 changes: 7 additions & 19 deletions git/operations.go
Expand Up @@ -82,7 +82,13 @@ func checkPush(ctx context.Context, workingDir, upstream string) error {
if err := execGitCmd(ctx, args, gitCmdConfig{dir: workingDir}); err != nil {
return errors.Wrap(err, "attempt to push tag")
}
args = []string{"push", "--delete", upstream, "tag", CheckPushTag}
return deleteTag(ctx, workingDir, upstream, CheckPushTag)
}

// deleteTag deletes the given git tag
// See https://git-scm.com/docs/git-tag and https://git-scm.com/docs/git-push for more info.
func deleteTag(ctx context.Context, workingDir string, upstream string, tag string) error {
args := []string{"push", "--delete", upstream, "tag", tag}
return execGitCmd(ctx, args, gitCmdConfig{dir: workingDir})
}

Expand Down Expand Up @@ -232,24 +238,6 @@ func splitList(s string) []string {
return strings.Split(outStr, "\n")
}

// Move the tag to the ref given and push that tag upstream
func moveTagAndPush(ctx context.Context, workingDir, tag, upstream string, tagAction TagAction) error {
args := []string{"tag", "--force", "-a", "-m", tagAction.Message}
var env []string
if tagAction.SigningKey != "" {
args = append(args, fmt.Sprintf("--local-user=%s", tagAction.SigningKey))
}
args = append(args, tag, tagAction.Revision)
if err := execGitCmd(ctx, args, gitCmdConfig{dir: workingDir, env: env}); err != nil {
return errors.Wrap(err, "moving tag "+tag)
}
args = []string{"push", "--force", upstream, "tag", tag}
if err := execGitCmd(ctx, args, gitCmdConfig{dir: workingDir}); err != nil {
return errors.Wrap(err, "pushing tag to origin")
}
return nil
}

func verifyTag(ctx context.Context, workingDir, tag string) error {
var env []string
args := []string{"verify-tag", tag}
Expand Down
7 changes: 5 additions & 2 deletions git/repo.go
Expand Up @@ -83,8 +83,11 @@ func (t Timeout) apply(r *Repo) {
r.timeout = time.Duration(t)
}

var ReadOnly optionFunc = func(r *Repo) {
r.readonly = true
// SetReadOnly sets the repo to be notated as being readonly
type SetReadOnly bool

func (r SetReadOnly) apply(repo *Repo) {
repo.readonly = bool(r)
}

// NewRepo constructs a repo mirror which will sync itself.
Expand Down

0 comments on commit 27b86d4

Please sign in to comment.