<commit_before>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package podsecuritypolicy

import (
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/apis/policy"
	"k8s.io/kubernetes/pkg/features"
)

// DropDisabledFields removes disabled fields from the pod security policy spec.
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a od security policy spec.
func DropDisabledFields(pspSpec, oldPSPSpec *policy.PodSecurityPolicySpec) {
	if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) && !allowedProcMountTypesInUse(oldPSPSpec) {
		pspSpec.AllowedProcMountTypes = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.RunAsGroup) && (oldPSPSpec == nil || oldPSPSpec.RunAsGroup == nil) {
		pspSpec.RunAsGroup = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) && !sysctlsInUse(oldPSPSpec) {
		pspSpec.AllowedUnsafeSysctls = nil
		pspSpec.ForbiddenSysctls = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
		pspSpec.AllowedCSIDrivers = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) &&
		(oldPSPSpec == nil || oldPSPSpec.RuntimeClass == nil) {
		pspSpec.RuntimeClass = nil
	}
}

func allowedProcMountTypesInUse(oldPSPSpec *policy.PodSecurityPolicySpec) bool {
	if oldPSPSpec == nil {
		return false
	}

	if oldPSPSpec.AllowedProcMountTypes != nil {
		return true
	}

	return false

}

func sysctlsInUse(oldPSPSpec *policy.PodSecurityPolicySpec) bool {
	if oldPSPSpec == nil {
		return false
	}
	if oldPSPSpec.AllowedUnsafeSysctls != nil || oldPSPSpec.ForbiddenSysctls != nil {
		return true
	}
	return false
}
<commit_msg>[pkg/api/podsecuritypolicy]: fixup typo<commit_after>/*
Copyright 2018 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package podsecuritypolicy

import (
	utilfeature "k8s.io/apiserver/pkg/util/feature"
	"k8s.io/kubernetes/pkg/apis/policy"
	"k8s.io/kubernetes/pkg/features"
)

// DropDisabledFields removes disabled fields from the pod security policy spec.
// This should be called from PrepareForCreate/PrepareForUpdate for all resources containing a pod security policy spec.
func DropDisabledFields(pspSpec, oldPSPSpec *policy.PodSecurityPolicySpec) {
	if !utilfeature.DefaultFeatureGate.Enabled(features.ProcMountType) && !allowedProcMountTypesInUse(oldPSPSpec) {
		pspSpec.AllowedProcMountTypes = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.RunAsGroup) && (oldPSPSpec == nil || oldPSPSpec.RunAsGroup == nil) {
		pspSpec.RunAsGroup = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.Sysctls) && !sysctlsInUse(oldPSPSpec) {
		pspSpec.AllowedUnsafeSysctls = nil
		pspSpec.ForbiddenSysctls = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.CSIInlineVolume) {
		pspSpec.AllowedCSIDrivers = nil
	}
	if !utilfeature.DefaultFeatureGate.Enabled(features.RuntimeClass) &&
		(oldPSPSpec == nil || oldPSPSpec.RuntimeClass == nil) {
		pspSpec.RuntimeClass = nil
	}
}

func allowedProcMountTypesInUse(oldPSPSpec *policy.PodSecurityPolicySpec) bool {
	if oldPSPSpec == nil {
		return false
	}

	if oldPSPSpec.AllowedProcMountTypes != nil {
		return true
	}

	return false

}

func sysctlsInUse(oldPSPSpec *policy.PodSecurityPolicySpec) bool {
	if oldPSPSpec == nil {
		return false
	}
	if oldPSPSpec.AllowedUnsafeSysctls != nil || oldPSPSpec.ForbiddenSysctls != nil {
		return true
	}
	return false
}
<|endoftext|>


<commit_before>package build

import (
	"fmt"

	"github.com/flant/werf/pkg/docker_registry"
	imagePkg "github.com/flant/werf/pkg/image"
	"github.com/flant/werf/pkg/lock"
	"github.com/flant/werf/pkg/logger"
	"github.com/flant/werf/pkg/tag_strategy"
	"github.com/flant/werf/pkg/util"
)

const RepoImageStageTagFormat = "image-stage-%s"

func NewPublishImagesPhase(imagesRepo string, opts PublishImagesOptions) *PublishImagesPhase {
	tagsByScheme := map[tag_strategy.TagStrategy][]string{
		tag_strategy.Custom:    opts.CustomTags,
		tag_strategy.GitBranch: opts.TagsByGitBranch,
		tag_strategy.GitTag:    opts.TagsByGitTag,
		tag_strategy.GitCommit: opts.TagsByGitCommit,
	}
	return &PublishImagesPhase{ImagesRepo: imagesRepo, TagsByScheme: tagsByScheme}
}

type PublishImagesPhase struct {
	WithStages   bool
	ImagesRepo   string
	TagsByScheme map[tag_strategy.TagStrategy][]string
}

func (p *PublishImagesPhase) Run(c *Conveyor) error {
	return logger.LogProcess("Publishing images", logger.LogProcessOptions{}, func() error {
		return p.run(c)
	})
}

func (p *PublishImagesPhase) run(c *Conveyor) error {
	// TODO: Push stages should occur on the BuildStagesPhase

	for _, image := range c.imagesInOrder {
		if err := logger.LogProcess(image.LogProcessName(), logger.LogProcessOptions{ColorizeMsgFunc: image.LogProcessColorizeFunc()}, func() error {
			if p.WithStages {
				err := logger.LogSecondaryProcess("Pushing stages cache", logger.LogProcessOptions{}, func() error {
					if err := p.pushImageStages(c, image); err != nil {
						return fmt.Errorf("unable to push image %s stages: %s", image.GetName(), err)
					}

					return nil
				})

				if err != nil {
					return err
				}
			}

			if !image.isArtifact {
				if err := p.pushImage(c, image); err != nil {
					return fmt.Errorf("unable to push image %s: %s", image.GetName(), err)
				}
			}

			return nil
		}); err != nil {
			return err
		}
	}

	return nil
}

func (p *PublishImagesPhase) pushImageStages(c *Conveyor, image *Image) error {
	stages := image.GetStages()

	existingStagesTags, err := docker_registry.ImageStagesTags(p.ImagesRepo)
	if err != nil {
		return fmt.Errorf("error fetching existing stages cache list %s: %s", p.ImagesRepo, err)
	}

	for _, stage := range stages {
		stageTagName := fmt.Sprintf(RepoImageStageTagFormat, stage.GetSignature())
		stageImageName := fmt.Sprintf("%s:%s", p.ImagesRepo, stageTagName)

		if util.IsStringsContainValue(existingStagesTags, stageTagName) {
			logger.LogHighlightLn(stage.Name())

			logger.LogInfoF("stages-repo: %s\n", p.ImagesRepo)
			logger.LogInfoF("      image: %s\n", stageImageName)

			logger.OptionalLnModeOn()

			continue
		}

		err := func() error {
			imageLockName := imagePkg.GetImageLockName(stageImageName)

			if err := lock.Lock(imageLockName, lock.LockOptions{}); err != nil {
				return fmt.Errorf("failed to lock %s: %s", imageLockName, err)
			}

			defer lock.Unlock(imageLockName)

			stageImage := c.GetStageImage(stage.GetImage().Name())

			infoSectionFunc := func(err error) {
				if err == nil {
					_ = logger.WithIndent(func() error {
						logger.LogInfoF("stages-repo: %s\n", p.ImagesRepo)
						logger.LogInfoF("      image: %s\n", stageImageName)

						return nil
					})
				}
			}

			logProcessOptions := logger.LogProcessOptions{InfoSectionFunc: infoSectionFunc}
			return logger.LogProcess(fmt.Sprintf("Publishing %s", stage.Name()), logProcessOptions, func() error {
				if err := stageImage.Export(stageImageName); err != nil {
					return fmt.Errorf("error pushing %s: %s", stageImageName, err)
				}

				return nil
			})
		}()

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *PublishImagesPhase) pushImage(c *Conveyor, image *Image) error {
	var imageRepository string
	if image.GetName() != "" {
		imageRepository = fmt.Sprintf("%s/%s", p.ImagesRepo, image.GetName())
	} else {
		imageRepository = p.ImagesRepo
	}

	existingTags, err := docker_registry.ImageTags(imageRepository)
	if err != nil {
		return fmt.Errorf("error fetch existing tags of image %s: %s", imageRepository, err)
	}

	stages := image.GetStages()
	lastStageImage := stages[len(stages)-1].GetImage()

	var nonEmptySchemeInOrder []tag_strategy.TagStrategy
	for strategy, tags := range p.TagsByScheme {
		if len(tags) == 0 {
			continue
		}

		nonEmptySchemeInOrder = append(nonEmptySchemeInOrder, strategy)
	}

	for _, strategy := range nonEmptySchemeInOrder {
		tags := p.TagsByScheme[strategy]

		if len(tags) == 0 {
			continue
		}

		err := logger.LogProcess(fmt.Sprintf("%s tagging strategy", string(strategy)), logger.LogProcessOptions{}, func() error {
		ProcessingTags:
			for _, tag := range tags {
				tagLogName := fmt.Sprintf("tag %s", tag)
				imageName := fmt.Sprintf("%s:%s", imageRepository, tag)

				if util.IsStringsContainValue(existingTags, tag) {
					parentID, err := docker_registry.ImageParentId(imageName)
					if err != nil {
						return fmt.Errorf("unable to get image %s parent id: %s", imageName, err)
					}

					if lastStageImage.ID() == parentID {
						logger.LogHighlightF("Tag %s is up-to-date\n", tag)
						_ = logger.WithIndent(func() error {
							logger.LogInfoF("images-repo: %s\n", imageRepository)
							logger.LogInfoF("      image: %s\n", imageName)

							return nil
						})

						logger.OptionalLnModeOn()

						continue ProcessingTags
					}
				}

				err := func() error {
					imageLockName := imagePkg.GetImageLockName(imageName)
					if err = lock.Lock(imageLockName, lock.LockOptions{}); err != nil {
						return fmt.Errorf("failed to lock %s: %s", imageLockName, err)
					}
					defer lock.Unlock(imageLockName)

					pushImage := imagePkg.NewImage(c.GetStageImage(lastStageImage.Name()), imageName)

					pushImage.Container().ServiceCommitChangeOptions().AddLabel(map[string]string{
						imagePkg.WerfDockerImageName:  imageName,
						imagePkg.WerfTagStrategyLabel: string(strategy),
						imagePkg.WerfImageLabel:       "true",
					})

					infoSectionFunc := func(err error) {
						if err == nil {
							_ = logger.WithIndent(func() error {
								logger.LogInfoF("images-repo: %s\n", imageRepository)
								logger.LogInfoF("      image: %s\n", imageName)

								return nil
							})
						}
					}
					logProcessOptions := logger.LogProcessOptions{InfoSectionFunc: infoSectionFunc}
					return logger.LogProcess(fmt.Sprintf("Publishing %s", tagLogName), logProcessOptions, func() error {
						if err := logger.LogSecondaryProcess("Building final image with meta information", logger.LogProcessOptions{}, func() error {
							if err := pushImage.Build(imagePkg.BuildOptions{}); err != nil {
								return fmt.Errorf("error building %s with tagging strategy '%s': %s", imageName, strategy, err)
							}

							return nil
						}); err != nil {
							return err
						}

						if err := pushImage.Export(); err != nil {
							return fmt.Errorf("error pushing %s: %s", imageName, err)
						}

						return nil
					})
				}()

				if err != nil {
					return err
				}
			}

			return nil
		})

		if err != nil {
			return err
		}
	}

	return nil
}
<commit_msg>Log publish docker registry requests<commit_after>package build

import (
	"fmt"

	"github.com/flant/werf/pkg/docker_registry"
	imagePkg "github.com/flant/werf/pkg/image"
	"github.com/flant/werf/pkg/lock"
	"github.com/flant/werf/pkg/logger"
	"github.com/flant/werf/pkg/tag_strategy"
	"github.com/flant/werf/pkg/util"
)

const RepoImageStageTagFormat = "image-stage-%s"

func NewPublishImagesPhase(imagesRepo string, opts PublishImagesOptions) *PublishImagesPhase {
	tagsByScheme := map[tag_strategy.TagStrategy][]string{
		tag_strategy.Custom:    opts.CustomTags,
		tag_strategy.GitBranch: opts.TagsByGitBranch,
		tag_strategy.GitTag:    opts.TagsByGitTag,
		tag_strategy.GitCommit: opts.TagsByGitCommit,
	}
	return &PublishImagesPhase{ImagesRepo: imagesRepo, TagsByScheme: tagsByScheme}
}

type PublishImagesPhase struct {
	WithStages   bool
	ImagesRepo   string
	TagsByScheme map[tag_strategy.TagStrategy][]string
}

func (p *PublishImagesPhase) Run(c *Conveyor) error {
	return logger.LogProcess("Publishing images", logger.LogProcessOptions{}, func() error {
		return p.run(c)
	})
}

func (p *PublishImagesPhase) run(c *Conveyor) error {
	// TODO: Push stages should occur on the BuildStagesPhase

	for _, image := range c.imagesInOrder {
		if err := logger.LogProcess(image.LogProcessName(), logger.LogProcessOptions{ColorizeMsgFunc: image.LogProcessColorizeFunc()}, func() error {
			if p.WithStages {
				err := logger.LogSecondaryProcess("Pushing stages cache", logger.LogProcessOptions{}, func() error {
					if err := p.pushImageStages(c, image); err != nil {
						return fmt.Errorf("unable to push image %s stages: %s", image.GetName(), err)
					}

					return nil
				})

				if err != nil {
					return err
				}
			}

			if !image.isArtifact {
				if err := p.pushImage(c, image); err != nil {
					return fmt.Errorf("unable to push image %s: %s", image.GetName(), err)
				}
			}

			return nil
		}); err != nil {
			return err
		}
	}

	return nil
}

func (p *PublishImagesPhase) pushImageStages(c *Conveyor, image *Image) error {
	stages := image.GetStages()

	existingStagesTags, err := docker_registry.ImageStagesTags(p.ImagesRepo)
	if err != nil {
		return fmt.Errorf("error fetching existing stages cache list %s: %s", p.ImagesRepo, err)
	}

	for _, stage := range stages {
		stageTagName := fmt.Sprintf(RepoImageStageTagFormat, stage.GetSignature())
		stageImageName := fmt.Sprintf("%s:%s", p.ImagesRepo, stageTagName)

		if util.IsStringsContainValue(existingStagesTags, stageTagName) {
			logger.LogHighlightLn(stage.Name())

			logger.LogInfoF("stages-repo: %s\n", p.ImagesRepo)
			logger.LogInfoF("      image: %s\n", stageImageName)

			logger.OptionalLnModeOn()

			continue
		}

		err := func() error {
			imageLockName := imagePkg.GetImageLockName(stageImageName)

			if err := lock.Lock(imageLockName, lock.LockOptions{}); err != nil {
				return fmt.Errorf("failed to lock %s: %s", imageLockName, err)
			}

			defer lock.Unlock(imageLockName)

			stageImage := c.GetStageImage(stage.GetImage().Name())

			infoSectionFunc := func(err error) {
				if err == nil {
					_ = logger.WithIndent(func() error {
						logger.LogInfoF("stages-repo: %s\n", p.ImagesRepo)
						logger.LogInfoF("      image: %s\n", stageImageName)

						return nil
					})
				}
			}

			logProcessOptions := logger.LogProcessOptions{InfoSectionFunc: infoSectionFunc}
			return logger.LogProcess(fmt.Sprintf("Publishing %s", stage.Name()), logProcessOptions, func() error {
				if err := stageImage.Export(stageImageName); err != nil {
					return fmt.Errorf("error pushing %s: %s", stageImageName, err)
				}

				return nil
			})
		}()

		if err != nil {
			return err
		}
	}

	return nil
}

func (p *PublishImagesPhase) pushImage(c *Conveyor, image *Image) error {
	var imageRepository string
	if image.GetName() != "" {
		imageRepository = fmt.Sprintf("%s/%s", p.ImagesRepo, image.GetName())
	} else {
		imageRepository = p.ImagesRepo
	}

	var existingTags []string
	var err error
	if err := logger.LogSecondaryProcessInline("Fetching existing image tags", func() error {
		existingTags, err = docker_registry.ImageTags(imageRepository)
		return err
	}); err != nil {
		return fmt.Errorf("error fetch existing tags of image %s: %s", imageRepository, err)
	}
	logger.OptionalLnModeOn()

	stages := image.GetStages()
	lastStageImage := stages[len(stages)-1].GetImage()

	var nonEmptySchemeInOrder []tag_strategy.TagStrategy
	for strategy, tags := range p.TagsByScheme {
		if len(tags) == 0 {
			continue
		}

		nonEmptySchemeInOrder = append(nonEmptySchemeInOrder, strategy)
	}

	for _, strategy := range nonEmptySchemeInOrder {
		tags := p.TagsByScheme[strategy]

		if len(tags) == 0 {
			continue
		}

		err := logger.LogProcess(fmt.Sprintf("%s tagging strategy", string(strategy)), logger.LogProcessOptions{}, func() error {
		ProcessingTags:
			for _, tag := range tags {
				tagLogName := fmt.Sprintf("tag %s", tag)
				imageName := fmt.Sprintf("%s:%s", imageRepository, tag)

				if util.IsStringsContainValue(existingTags, tag) {
					var parentID string
					var err error
					logProcessMsg := fmt.Sprintf("Getting existing tag %s parent id", tag)
					if err := logger.LogSecondaryProcessInline(logProcessMsg, func() error {
						parentID, err = docker_registry.ImageParentId(imageName)
						return err
					}); err != nil {
						return fmt.Errorf("unable to get image %s parent id: %s", imageName, err)
					}
					logger.OptionalLnModeOn()

					if lastStageImage.ID() == parentID {
						logger.LogHighlightF("Tag %s is up-to-date\n", tag)
						_ = logger.WithIndent(func() error {
							logger.LogInfoF("images-repo: %s\n", imageRepository)
							logger.LogInfoF("      image: %s\n", imageName)

							return nil
						})

						logger.OptionalLnModeOn()

						continue ProcessingTags
					}
				}

				err := func() error {
					imageLockName := imagePkg.GetImageLockName(imageName)
					if err = lock.Lock(imageLockName, lock.LockOptions{}); err != nil {
						return fmt.Errorf("failed to lock %s: %s", imageLockName, err)
					}
					defer lock.Unlock(imageLockName)

					pushImage := imagePkg.NewImage(c.GetStageImage(lastStageImage.Name()), imageName)

					pushImage.Container().ServiceCommitChangeOptions().AddLabel(map[string]string{
						imagePkg.WerfDockerImageName:  imageName,
						imagePkg.WerfTagStrategyLabel: string(strategy),
						imagePkg.WerfImageLabel:       "true",
					})

					infoSectionFunc := func(err error) {
						if err == nil {
							_ = logger.WithIndent(func() error {
								logger.LogInfoF("images-repo: %s\n", imageRepository)
								logger.LogInfoF("      image: %s\n", imageName)

								return nil
							})
						}
					}
					logProcessOptions := logger.LogProcessOptions{InfoSectionFunc: infoSectionFunc}
					return logger.LogProcess(fmt.Sprintf("Publishing %s", tagLogName), logProcessOptions, func() error {
						if err := logger.LogSecondaryProcess("Building final image with meta information", logger.LogProcessOptions{}, func() error {
							if err := pushImage.Build(imagePkg.BuildOptions{}); err != nil {
								return fmt.Errorf("error building %s with tagging strategy '%s': %s", imageName, strategy, err)
							}

							return nil
						}); err != nil {
							return err
						}

						if err := pushImage.Export(); err != nil {
							return fmt.Errorf("error pushing %s: %s", imageName, err)
						}

						return nil
					})
				}()

				if err != nil {
					return err
				}
			}

			return nil
		})

		if err != nil {
			return err
		}
	}

	return nil
}
<|endoftext|>


<commit_before>package social

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/org"

	"golang.org/x/oauth2"
	"gopkg.in/square/go-jose.v2/jwt"
)

type SocialAzureAD struct {
	*SocialBase
	allowedGroups    []string
	forceUseGraphAPI bool
}

type azureClaims struct {
	Email             string                 `json:"email"`
	PreferredUsername string                 `json:"preferred_username"`
	Roles             []string               `json:"roles"`
	Groups            []string               `json:"groups"`
	Name              string                 `json:"name"`
	ID                string                 `json:"oid"`
	ClaimNames        claimNames             `json:"_claim_names,omitempty"`
	ClaimSources      map[string]claimSource `json:"_claim_sources,omitempty"`
	TenantID          string                 `json:"tid,omitempty"`
}

type claimNames struct {
	Groups string `json:"groups"`
}

type claimSource struct {
	Endpoint string `json:"endpoint"`
}

type azureAccessClaims struct {
	TenantID string `json:"tid"`
}

func (s *SocialAzureAD) Type() int {
	return int(models.AZUREAD)
}

func (s *SocialAzureAD) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) {
	idToken := token.Extra("id_token")
	if idToken == nil {
		return nil, ErrIDTokenNotFound
	}

	parsedToken, err := jwt.ParseSigned(idToken.(string))
	if err != nil {
		return nil, fmt.Errorf("error parsing id token: %w", err)
	}

	var claims azureClaims
	if err := parsedToken.UnsafeClaimsWithoutVerification(&claims); err != nil {
		return nil, fmt.Errorf("error getting claims from id token: %w", err)
	}

	email := claims.extractEmail()
	if email == "" {
		return nil, ErrEmailNotFound
	}

	role, grafanaAdmin := s.extractRoleAndAdmin(&claims)
	if s.roleAttributeStrict && !role.IsValid() {
		return nil, &InvalidBasicRoleError{idP: "Azure", assignedRole: string(role)}
	}

	logger.Debug("AzureAD OAuth: extracted role", "email", email, "role", role)

	groups, err := s.extractGroups(client, claims, token)
	if err != nil {
		return nil, fmt.Errorf("failed to extract groups: %w", err)
	}

	logger.Debug("AzureAD OAuth: extracted groups", "email", email, "groups", fmt.Sprintf("%v", groups))
	if !s.IsGroupMember(groups) {
		return nil, errMissingGroupMembership
	}

	var isGrafanaAdmin *bool = nil
	if s.allowAssignGrafanaAdmin {
		isGrafanaAdmin = &grafanaAdmin
	}

	return &BasicUserInfo{
		Id:             claims.ID,
		Name:           claims.Name,
		Email:          email,
		Login:          email,
		Role:           role,
		IsGrafanaAdmin: isGrafanaAdmin,
		Groups:         groups,
	}, nil
}

func (s *SocialAzureAD) IsGroupMember(groups []string) bool {
	if len(s.allowedGroups) == 0 {
		return true
	}

	for _, allowedGroup := range s.allowedGroups {
		for _, group := range groups {
			if group == allowedGroup {
				return true
			}
		}
	}

	return false
}

func (claims *azureClaims) extractEmail() string {
	if claims.Email == "" {
		if claims.PreferredUsername != "" {
			return claims.PreferredUsername
		}
	}

	return claims.Email
}

// extractRoleAndAdmin extracts the role from the claims and returns the role and whether the user is a Grafana admin.
func (s *SocialAzureAD) extractRoleAndAdmin(claims *azureClaims) (org.RoleType, bool) {
	if len(claims.Roles) == 0 {
		return s.defaultRole(false), false
	}

	roleOrder := []org.RoleType{RoleGrafanaAdmin, org.RoleAdmin, org.RoleEditor, org.RoleViewer}
	for _, role := range roleOrder {
		if found := hasRole(claims.Roles, role); found {
			if role == RoleGrafanaAdmin {
				return org.RoleAdmin, true
			}

			return role, false
		}
	}

	return s.defaultRole(false), false
}

func hasRole(roles []string, role org.RoleType) bool {
	for _, item := range roles {
		if strings.EqualFold(item, string(role)) {
			return true
		}
	}

	return false
}

type getAzureGroupRequest struct {
	SecurityEnabledOnly bool `json:"securityEnabledOnly"`
}

type getAzureGroupResponse struct {
	Value []string `json:"value"`
}

// extractGroups retrieves groups from the claims.
// Note: If user groups exceeds 200 no groups will be found in claims and URL to target the Graph API will be
// given instead.
// See https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#groups-overage-claim
func (s *SocialAzureAD) extractGroups(client *http.Client, claims azureClaims, token *oauth2.Token) ([]string, error) {
	if !s.forceUseGraphAPI {
		logger.Debug("checking the claim for groups")
		if len(claims.Groups) > 0 {
			return claims.Groups, nil
		}

		if claims.ClaimNames.Groups == "" {
			return []string{}, nil
		}
	}

	// Fallback to the Graph API
	endpoint, errBuildGraphURI := groupsGraphAPIURL(claims, token)
	if errBuildGraphURI != nil {
		return nil, errBuildGraphURI
	}

	data, err := json.Marshal(&getAzureGroupRequest{SecurityEnabledOnly: false})
	if err != nil {
		return nil, err
	}

	res, err := client.Post(endpoint, "application/json", bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	defer func() {
		if err := res.Body.Close(); err != nil {
			logger.Warn("AzureAD OAuth: failed to close response body", "err", err)
		}
	}()

	if res.StatusCode != http.StatusOK {
		if res.StatusCode == http.StatusForbidden {
			logger.Warn("AzureAD OAuh: Token need GroupMember.Read.All permission to fetch all groups")
		} else {
			body, _ := io.ReadAll(res.Body)
			logger.Warn("AzureAD OAuh: could not fetch user groups", "code", res.StatusCode, "body", string(body))
		}
		return []string{}, nil
	}

	var body getAzureGroupResponse
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		return nil, err
	}

	return body.Value, nil
}

// groupsGraphAPIURL retrieves the Microsoft Graph API URL to fetch user groups from the _claim_sources if present
// otherwise it generates an handcrafted URL.
func groupsGraphAPIURL(claims azureClaims, token *oauth2.Token) (string, error) {
	var endpoint string
	// First check if an endpoint was specified in the claims
	if claims.ClaimNames.Groups != "" {
		endpoint = claims.ClaimSources[claims.ClaimNames.Groups].Endpoint
		logger.Debug(fmt.Sprintf("endpoint to fetch groups specified in the claims: %s", endpoint))
	}

	// If no endpoint was specified or if the endpoints provided in _claim_source is pointing to the deprecated
	// "graph.windows.net" api, use an handcrafted url to graph.microsoft.com
	// See https://docs.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview
	if endpoint == "" || strings.Contains(endpoint, "graph.windows.net") {
		tenantID := claims.TenantID
		// If tenantID wasn't found in the id_token, parse access token
		if tenantID == "" {
			parsedToken, err := jwt.ParseSigned(token.AccessToken)
			if err != nil {
				return "", fmt.Errorf("error parsing access token: %w", err)
			}

			var accessClaims azureAccessClaims
			if err := parsedToken.UnsafeClaimsWithoutVerification(&accessClaims); err != nil {
				return "", fmt.Errorf("error getting claims from access token: %w", err)
			}
			tenantID = accessClaims.TenantID
		}

		endpoint = fmt.Sprintf("https://graph.microsoft.com/v1.0/%s/users/%s/getMemberObjects", tenantID, claims.ID)
		logger.Debug(fmt.Sprintf("handcrafted endpoint to fetch groups: %s", endpoint))
	}
	return endpoint, nil
}
<commit_msg>Auth: Validate Azure ID token version on login is not v1 (#58088)<commit_after>package social

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"strings"

	"github.com/grafana/grafana/pkg/models"
	"github.com/grafana/grafana/pkg/services/org"

	"golang.org/x/oauth2"
	"gopkg.in/square/go-jose.v2/jwt"
)

type SocialAzureAD struct {
	*SocialBase
	allowedGroups    []string
	forceUseGraphAPI bool
}

type azureClaims struct {
	Email             string                 `json:"email"`
	PreferredUsername string                 `json:"preferred_username"`
	Roles             []string               `json:"roles"`
	Groups            []string               `json:"groups"`
	Name              string                 `json:"name"`
	ID                string                 `json:"oid"`
	ClaimNames        claimNames             `json:"_claim_names,omitempty"`
	ClaimSources      map[string]claimSource `json:"_claim_sources,omitempty"`
	TenantID          string                 `json:"tid,omitempty"`
	OAuthVersion      string                 `json:"ver,omitempty"`
}

type claimNames struct {
	Groups string `json:"groups"`
}

type claimSource struct {
	Endpoint string `json:"endpoint"`
}

type azureAccessClaims struct {
	TenantID string `json:"tid"`
}

func (s *SocialAzureAD) Type() int {
	return int(models.AZUREAD)
}

func (s *SocialAzureAD) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) {
	idToken := token.Extra("id_token")
	if idToken == nil {
		return nil, ErrIDTokenNotFound
	}

	parsedToken, err := jwt.ParseSigned(idToken.(string))
	if err != nil {
		return nil, fmt.Errorf("error parsing id token: %w", err)
	}

	var claims azureClaims
	if err := parsedToken.UnsafeClaimsWithoutVerification(&claims); err != nil {
		return nil, fmt.Errorf("error getting claims from id token: %w", err)
	}

	if claims.OAuthVersion == "1.0" {
		return nil, &Error{"AzureAD OAuth: version 1.0 is not supported. Please ensure the auth_url and token_url are set to the v2.0 endpoints."}
	}

	email := claims.extractEmail()
	if email == "" {
		return nil, ErrEmailNotFound
	}

	role, grafanaAdmin := s.extractRoleAndAdmin(&claims)
	if s.roleAttributeStrict && !role.IsValid() {
		return nil, &InvalidBasicRoleError{idP: "Azure", assignedRole: string(role)}
	}

	logger.Debug("AzureAD OAuth: extracted role", "email", email, "role", role)

	groups, err := s.extractGroups(client, claims, token)
	if err != nil {
		return nil, fmt.Errorf("failed to extract groups: %w", err)
	}

	logger.Debug("AzureAD OAuth: extracted groups", "email", email, "groups", fmt.Sprintf("%v", groups))
	if !s.IsGroupMember(groups) {
		return nil, errMissingGroupMembership
	}

	var isGrafanaAdmin *bool = nil
	if s.allowAssignGrafanaAdmin {
		isGrafanaAdmin = &grafanaAdmin
	}

	return &BasicUserInfo{
		Id:             claims.ID,
		Name:           claims.Name,
		Email:          email,
		Login:          email,
		Role:           role,
		IsGrafanaAdmin: isGrafanaAdmin,
		Groups:         groups,
	}, nil
}

func (s *SocialAzureAD) IsGroupMember(groups []string) bool {
	if len(s.allowedGroups) == 0 {
		return true
	}

	for _, allowedGroup := range s.allowedGroups {
		for _, group := range groups {
			if group == allowedGroup {
				return true
			}
		}
	}

	return false
}

func (claims *azureClaims) extractEmail() string {
	if claims.Email == "" {
		if claims.PreferredUsername != "" {
			return claims.PreferredUsername
		}
	}

	return claims.Email
}

// extractRoleAndAdmin extracts the role from the claims and returns the role and whether the user is a Grafana admin.
func (s *SocialAzureAD) extractRoleAndAdmin(claims *azureClaims) (org.RoleType, bool) {
	if len(claims.Roles) == 0 {
		return s.defaultRole(false), false
	}

	roleOrder := []org.RoleType{RoleGrafanaAdmin, org.RoleAdmin, org.RoleEditor, org.RoleViewer}
	for _, role := range roleOrder {
		if found := hasRole(claims.Roles, role); found {
			if role == RoleGrafanaAdmin {
				return org.RoleAdmin, true
			}

			return role, false
		}
	}

	return s.defaultRole(false), false
}

func hasRole(roles []string, role org.RoleType) bool {
	for _, item := range roles {
		if strings.EqualFold(item, string(role)) {
			return true
		}
	}

	return false
}

type getAzureGroupRequest struct {
	SecurityEnabledOnly bool `json:"securityEnabledOnly"`
}

type getAzureGroupResponse struct {
	Value []string `json:"value"`
}

// extractGroups retrieves groups from the claims.
// Note: If user groups exceeds 200 no groups will be found in claims and URL to target the Graph API will be
// given instead.
// See https://docs.microsoft.com/en-us/azure/active-directory/develop/id-tokens#groups-overage-claim
func (s *SocialAzureAD) extractGroups(client *http.Client, claims azureClaims, token *oauth2.Token) ([]string, error) {
	if !s.forceUseGraphAPI {
		logger.Debug("checking the claim for groups")
		if len(claims.Groups) > 0 {
			return claims.Groups, nil
		}

		if claims.ClaimNames.Groups == "" {
			return []string{}, nil
		}
	}

	// Fallback to the Graph API
	endpoint, errBuildGraphURI := groupsGraphAPIURL(claims, token)
	if errBuildGraphURI != nil {
		return nil, errBuildGraphURI
	}

	data, err := json.Marshal(&getAzureGroupRequest{SecurityEnabledOnly: false})
	if err != nil {
		return nil, err
	}

	res, err := client.Post(endpoint, "application/json", bytes.NewBuffer(data))
	if err != nil {
		return nil, err
	}

	defer func() {
		if err := res.Body.Close(); err != nil {
			logger.Warn("AzureAD OAuth: failed to close response body", "err", err)
		}
	}()

	if res.StatusCode != http.StatusOK {
		if res.StatusCode == http.StatusForbidden {
			logger.Warn("AzureAD OAuh: Token need GroupMember.Read.All permission to fetch all groups")
		} else {
			body, _ := io.ReadAll(res.Body)
			logger.Warn("AzureAD OAuh: could not fetch user groups", "code", res.StatusCode, "body", string(body))
		}
		return []string{}, nil
	}

	var body getAzureGroupResponse
	if err := json.NewDecoder(res.Body).Decode(&body); err != nil {
		return nil, err
	}

	return body.Value, nil
}

// groupsGraphAPIURL retrieves the Microsoft Graph API URL to fetch user groups from the _claim_sources if present
// otherwise it generates an handcrafted URL.
func groupsGraphAPIURL(claims azureClaims, token *oauth2.Token) (string, error) {
	var endpoint string
	// First check if an endpoint was specified in the claims
	if claims.ClaimNames.Groups != "" {
		endpoint = claims.ClaimSources[claims.ClaimNames.Groups].Endpoint
		logger.Debug(fmt.Sprintf("endpoint to fetch groups specified in the claims: %s", endpoint))
	}

	// If no endpoint was specified or if the endpoints provided in _claim_source is pointing to the deprecated
	// "graph.windows.net" api, use an handcrafted url to graph.microsoft.com
	// See https://docs.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview
	if endpoint == "" || strings.Contains(endpoint, "graph.windows.net") {
		tenantID := claims.TenantID
		// If tenantID wasn't found in the id_token, parse access token
		if tenantID == "" {
			parsedToken, err := jwt.ParseSigned(token.AccessToken)
			if err != nil {
				return "", fmt.Errorf("error parsing access token: %w", err)
			}

			var accessClaims azureAccessClaims
			if err := parsedToken.UnsafeClaimsWithoutVerification(&accessClaims); err != nil {
				return "", fmt.Errorf("error getting claims from access token: %w", err)
			}
			tenantID = accessClaims.TenantID
		}

		endpoint = fmt.Sprintf("https://graph.microsoft.com/v1.0/%s/users/%s/getMemberObjects", tenantID, claims.ID)
		logger.Debug(fmt.Sprintf("handcrafted endpoint to fetch groups: %s", endpoint))
	}
	return endpoint, nil
}
<|endoftext|>


<commit_before>package social

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/mail"
	"regexp"

	"github.com/grafana/grafana/pkg/models"

	"golang.org/x/oauth2"
)

type SocialGenericOAuth struct {
	*SocialBase
	allowedDomains       []string
	allowedOrganizations []string
	apiUrl               string
	allowSignup          bool
	emailAttributeName   string
	teamIds              []int
}

func (s *SocialGenericOAuth) Type() int {
	return int(models.GENERIC)
}

func (s *SocialGenericOAuth) IsEmailAllowed(email string) bool {
	return isEmailAllowed(email, s.allowedDomains)
}

func (s *SocialGenericOAuth) IsSignupAllowed() bool {
	return s.allowSignup
}

func (s *SocialGenericOAuth) IsTeamMember(client *http.Client) bool {
	if len(s.teamIds) == 0 {
		return true
	}

	teamMemberships, err := s.FetchTeamMemberships(client)
	if err != nil {
		return false
	}

	for _, teamId := range s.teamIds {
		for _, membershipId := range teamMemberships {
			if teamId == membershipId {
				return true
			}
		}
	}

	return false
}

func (s *SocialGenericOAuth) IsOrganizationMember(client *http.Client) bool {
	if len(s.allowedOrganizations) == 0 {
		return true
	}

	organizations, err := s.FetchOrganizations(client)
	if err != nil {
		return false
	}

	for _, allowedOrganization := range s.allowedOrganizations {
		for _, organization := range organizations {
			if organization == allowedOrganization {
				return true
			}
		}
	}

	return false
}

func (s *SocialGenericOAuth) FetchPrivateEmail(client *http.Client) (string, error) {
	type Record struct {
		Email       string `json:"email"`
		Primary     bool   `json:"primary"`
		IsPrimary   bool   `json:"is_primary"`
		Verified    bool   `json:"verified"`
		IsConfirmed bool   `json:"is_confirmed"`
	}

	response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/emails"))
	if err != nil {
		return "", fmt.Errorf("Error getting email address: %s", err)
	}

	var records []Record

	err = json.Unmarshal(response.Body, &records)
	if err != nil {
		var data struct {
			Values []Record `json:"values"`
		}

		err = json.Unmarshal(response.Body, &data)
		if err != nil {
			return "", fmt.Errorf("Error getting email address: %s", err)
		}

		records = data.Values
	}

	var email = ""
	for _, record := range records {
		if record.Primary || record.IsPrimary {
			email = record.Email
			break
		}
	}

	return email, nil
}

func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, error) {
	type Record struct {
		Id int `json:"id"`
	}

	response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/teams"))
	if err != nil {
		return nil, fmt.Errorf("Error getting team memberships: %s", err)
	}

	var records []Record

	err = json.Unmarshal(response.Body, &records)
	if err != nil {
		return nil, fmt.Errorf("Error getting team memberships: %s", err)
	}

	var ids = make([]int, len(records))
	for i, record := range records {
		ids[i] = record.Id
	}

	return ids, nil
}

func (s *SocialGenericOAuth) FetchOrganizations(client *http.Client) ([]string, error) {
	type Record struct {
		Login string `json:"login"`
	}

	response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/orgs"))
	if err != nil {
		return nil, fmt.Errorf("Error getting organizations: %s", err)
	}

	var records []Record

	err = json.Unmarshal(response.Body, &records)
	if err != nil {
		return nil, fmt.Errorf("Error getting organizations: %s", err)
	}

	var logins = make([]string, len(records))
	for i, record := range records {
		logins[i] = record.Login
	}

	return logins, nil
}

type UserInfoJson struct {
	Name        string              `json:"name"`
	DisplayName string              `json:"display_name"`
	Login       string              `json:"login"`
	Username    string              `json:"username"`
	Email       string              `json:"email"`
	Upn         string              `json:"upn"`
	Attributes  map[string][]string `json:"attributes"`
}

func (s *SocialGenericOAuth) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) {
	var data UserInfoJson
	var err error

	if !s.extractToken(&data, token) {
		response, err := HttpGet(client, s.apiUrl)
		if err != nil {
			return nil, fmt.Errorf("Error getting user info: %s", err)
		}

		err = json.Unmarshal(response.Body, &data)
		if err != nil {
			return nil, fmt.Errorf("Error decoding user info JSON: %s", err)
		}
	}

	name := s.extractName(&data)

	email := s.extractEmail(&data)
	if email == "" {
		email, err = s.FetchPrivateEmail(client)
		if err != nil {
			return nil, err
		}
	}

	login := s.extractLogin(&data, email)

	userInfo := &BasicUserInfo{
		Name:  name,
		Login: login,
		Email: email,
	}

	if !s.IsTeamMember(client) {
		return nil, errors.New("User not a member of one of the required teams")
	}

	if !s.IsOrganizationMember(client) {
		return nil, errors.New("User not a member of one of the required organizations")
	}

	return userInfo, nil
}

func (s *SocialGenericOAuth) extractToken(data *UserInfoJson, token *oauth2.Token) bool {
	idToken := token.Extra("id_token")
	if idToken == nil {
		s.log.Debug("No id_token found", "token", token)
		return false
	}

	jwtRegexp := regexp.MustCompile("^([-_a-zA-Z0-9]+)[.]([-_a-zA-Z0-9]+)[.]([-_a-zA-Z0-9]+)$")
	matched := jwtRegexp.FindStringSubmatch(idToken.(string))
	if matched == nil {
		s.log.Debug("id_token is not in JWT format", "id_token", idToken.(string))
		return false
	}

	payload, err := base64.RawURLEncoding.DecodeString(matched[2])
	if err != nil {
		s.log.Error("Error base64 decoding id_token", "raw_payload", matched[2], "err", err)
		return false
	}

	err = json.Unmarshal(payload, data)
	if err != nil {
		s.log.Error("Error decoding id_token JSON", "payload", string(payload), "err", err)
		return false
	}

	email := s.extractEmail(data)
	if email == "" {
		s.log.Debug("No email found in id_token", "json", string(payload), "data", data)
		return false
	}

	s.log.Debug("Received id_token", "json", string(payload), "data", data)
	return true
}

func (s *SocialGenericOAuth) extractEmail(data *UserInfoJson) string {
	if data.Email != "" {
		return data.Email
	}

	emails, ok := data.Attributes[s.emailAttributeName]
	if ok && len(emails) != 0 {
		return emails[0]
	}

	if data.Upn != "" {
		emailAddr, emailErr := mail.ParseAddress(data.Upn)
		if emailErr == nil {
			return emailAddr.Address
		}
	}

	return ""
}

func (s *SocialGenericOAuth) extractLogin(data *UserInfoJson, email string) string {
	if data.Login != "" {
		return data.Login
	}

	if data.Username != "" {
		return data.Username
	}

	return email
}

func (s *SocialGenericOAuth) extractName(data *UserInfoJson) string {
	if data.Name != "" {
		return data.Name
	}

	if data.DisplayName != "" {
		return data.DisplayName
	}

	return ""
}
<commit_msg>Update jwt regexp to include = (#16521)<commit_after>package social

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"net/http"
	"net/mail"
	"regexp"

	"github.com/grafana/grafana/pkg/models"

	"golang.org/x/oauth2"
)

type SocialGenericOAuth struct {
	*SocialBase
	allowedDomains       []string
	allowedOrganizations []string
	apiUrl               string
	allowSignup          bool
	emailAttributeName   string
	teamIds              []int
}

func (s *SocialGenericOAuth) Type() int {
	return int(models.GENERIC)
}

func (s *SocialGenericOAuth) IsEmailAllowed(email string) bool {
	return isEmailAllowed(email, s.allowedDomains)
}

func (s *SocialGenericOAuth) IsSignupAllowed() bool {
	return s.allowSignup
}

func (s *SocialGenericOAuth) IsTeamMember(client *http.Client) bool {
	if len(s.teamIds) == 0 {
		return true
	}

	teamMemberships, err := s.FetchTeamMemberships(client)
	if err != nil {
		return false
	}

	for _, teamId := range s.teamIds {
		for _, membershipId := range teamMemberships {
			if teamId == membershipId {
				return true
			}
		}
	}

	return false
}

func (s *SocialGenericOAuth) IsOrganizationMember(client *http.Client) bool {
	if len(s.allowedOrganizations) == 0 {
		return true
	}

	organizations, err := s.FetchOrganizations(client)
	if err != nil {
		return false
	}

	for _, allowedOrganization := range s.allowedOrganizations {
		for _, organization := range organizations {
			if organization == allowedOrganization {
				return true
			}
		}
	}

	return false
}

func (s *SocialGenericOAuth) FetchPrivateEmail(client *http.Client) (string, error) {
	type Record struct {
		Email       string `json:"email"`
		Primary     bool   `json:"primary"`
		IsPrimary   bool   `json:"is_primary"`
		Verified    bool   `json:"verified"`
		IsConfirmed bool   `json:"is_confirmed"`
	}

	response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/emails"))
	if err != nil {
		return "", fmt.Errorf("Error getting email address: %s", err)
	}

	var records []Record

	err = json.Unmarshal(response.Body, &records)
	if err != nil {
		var data struct {
			Values []Record `json:"values"`
		}

		err = json.Unmarshal(response.Body, &data)
		if err != nil {
			return "", fmt.Errorf("Error getting email address: %s", err)
		}

		records = data.Values
	}

	var email = ""
	for _, record := range records {
		if record.Primary || record.IsPrimary {
			email = record.Email
			break
		}
	}

	return email, nil
}

func (s *SocialGenericOAuth) FetchTeamMemberships(client *http.Client) ([]int, error) {
	type Record struct {
		Id int `json:"id"`
	}

	response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/teams"))
	if err != nil {
		return nil, fmt.Errorf("Error getting team memberships: %s", err)
	}

	var records []Record

	err = json.Unmarshal(response.Body, &records)
	if err != nil {
		return nil, fmt.Errorf("Error getting team memberships: %s", err)
	}

	var ids = make([]int, len(records))
	for i, record := range records {
		ids[i] = record.Id
	}

	return ids, nil
}

func (s *SocialGenericOAuth) FetchOrganizations(client *http.Client) ([]string, error) {
	type Record struct {
		Login string `json:"login"`
	}

	response, err := HttpGet(client, fmt.Sprintf(s.apiUrl+"/orgs"))
	if err != nil {
		return nil, fmt.Errorf("Error getting organizations: %s", err)
	}

	var records []Record

	err = json.Unmarshal(response.Body, &records)
	if err != nil {
		return nil, fmt.Errorf("Error getting organizations: %s", err)
	}

	var logins = make([]string, len(records))
	for i, record := range records {
		logins[i] = record.Login
	}

	return logins, nil
}

type UserInfoJson struct {
	Name        string              `json:"name"`
	DisplayName string              `json:"display_name"`
	Login       string              `json:"login"`
	Username    string              `json:"username"`
	Email       string              `json:"email"`
	Upn         string              `json:"upn"`
	Attributes  map[string][]string `json:"attributes"`
}

func (s *SocialGenericOAuth) UserInfo(client *http.Client, token *oauth2.Token) (*BasicUserInfo, error) {
	var data UserInfoJson
	var err error

	if !s.extractToken(&data, token) {
		response, err := HttpGet(client, s.apiUrl)
		if err != nil {
			return nil, fmt.Errorf("Error getting user info: %s", err)
		}

		err = json.Unmarshal(response.Body, &data)
		if err != nil {
			return nil, fmt.Errorf("Error decoding user info JSON: %s", err)
		}
	}

	name := s.extractName(&data)

	email := s.extractEmail(&data)
	if email == "" {
		email, err = s.FetchPrivateEmail(client)
		if err != nil {
			return nil, err
		}
	}

	login := s.extractLogin(&data, email)

	userInfo := &BasicUserInfo{
		Name:  name,
		Login: login,
		Email: email,
	}

	if !s.IsTeamMember(client) {
		return nil, errors.New("User not a member of one of the required teams")
	}

	if !s.IsOrganizationMember(client) {
		return nil, errors.New("User not a member of one of the required organizations")
	}

	return userInfo, nil
}

func (s *SocialGenericOAuth) extractToken(data *UserInfoJson, token *oauth2.Token) bool {
	idToken := token.Extra("id_token")
	if idToken == nil {
		s.log.Debug("No id_token found", "token", token)
		return false
	}

	jwtRegexp := regexp.MustCompile("^([-_a-zA-Z0-9=]+)[.]([-_a-zA-Z0-9=]+)[.]([-_a-zA-Z0-9=]+)$")
	matched := jwtRegexp.FindStringSubmatch(idToken.(string))
	if matched == nil {
		s.log.Debug("id_token is not in JWT format", "id_token", idToken.(string))
		return false
	}

	payload, err := base64.RawURLEncoding.DecodeString(matched[2])
	if err != nil {
		s.log.Error("Error base64 decoding id_token", "raw_payload", matched[2], "err", err)
		return false
	}

	err = json.Unmarshal(payload, data)
	if err != nil {
		s.log.Error("Error decoding id_token JSON", "payload", string(payload), "err", err)
		return false
	}

	email := s.extractEmail(data)
	if email == "" {
		s.log.Debug("No email found in id_token", "json", string(payload), "data", data)
		return false
	}

	s.log.Debug("Received id_token", "json", string(payload), "data", data)
	return true
}

func (s *SocialGenericOAuth) extractEmail(data *UserInfoJson) string {
	if data.Email != "" {
		return data.Email
	}

	emails, ok := data.Attributes[s.emailAttributeName]
	if ok && len(emails) != 0 {
		return emails[0]
	}

	if data.Upn != "" {
		emailAddr, emailErr := mail.ParseAddress(data.Upn)
		if emailErr == nil {
			return emailAddr.Address
		}
	}

	return ""
}

func (s *SocialGenericOAuth) extractLogin(data *UserInfoJson, email string) string {
	if data.Login != "" {
		return data.Login
	}

	if data.Username != "" {
		return data.Username
	}

	return email
}

func (s *SocialGenericOAuth) extractName(data *UserInfoJson) string {
	if data.Name != "" {
		return data.Name
	}

	if data.DisplayName != "" {
		return data.DisplayName
	}

	return ""
}
<|endoftext|>


<commit_before>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package flocker

import (
	"testing"

	flockerClient "github.com/ClusterHQ/flocker-go"
	"github.com/stretchr/testify/assert"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/volume"
)

const pluginName = "kubernetes.io/flocker"

func newInitializedVolumePlugMgr() volume.VolumePluginMgr {
	plugMgr := volume.VolumePluginMgr{}
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost("/foo/bar", nil, nil))
	return plugMgr
}

func TestGetByName(t *testing.T) {
	assert := assert.New(t)
	plugMgr := newInitializedVolumePlugMgr()

	plug, err := plugMgr.FindPluginByName(pluginName)
	assert.NotNil(plug, "Can't find the plugin by name")
	assert.NoError(err)
}

func TestCanSupport(t *testing.T) {
	assert := assert.New(t)
	plugMgr := newInitializedVolumePlugMgr()

	plug, err := plugMgr.FindPluginByName(pluginName)
	assert.NoError(err)

	specs := map[*volume.Spec]bool{
		&volume.Spec{
			Volume: &api.Volume{
				VolumeSource: api.VolumeSource{
					Flocker: &api.FlockerVolumeSource{},
				},
			},
		}: true,
		&volume.Spec{
			PersistentVolume: &api.PersistentVolume{
				Spec: api.PersistentVolumeSpec{
					PersistentVolumeSource: api.PersistentVolumeSource{
						Flocker: &api.FlockerVolumeSource{},
					},
				},
			},
		}: true,
		&volume.Spec{
			Volume: &api.Volume{
				VolumeSource: api.VolumeSource{},
			},
		}: false,
	}

	for spec, expected := range specs {
		actual := plug.CanSupport(spec)
		assert.Equal(expected, actual)
	}
}

func TestGetFlockerVolumeSource(t *testing.T) {
	assert := assert.New(t)

	p := flockerPlugin{}

	spec := &volume.Spec{
		Volume: &api.Volume{
			VolumeSource: api.VolumeSource{
				Flocker: &api.FlockerVolumeSource{},
			},
		},
	}
	vs, ro := p.getFlockerVolumeSource(spec)
	assert.False(ro)
	assert.Equal(spec.Volume.Flocker, vs)

	spec = &volume.Spec{
		PersistentVolume: &api.PersistentVolume{
			Spec: api.PersistentVolumeSpec{
				PersistentVolumeSource: api.PersistentVolumeSource{
					Flocker: &api.FlockerVolumeSource{},
				},
			},
		},
	}
	vs, ro = p.getFlockerVolumeSource(spec)
	assert.False(ro)
	assert.Equal(spec.PersistentVolume.Spec.Flocker, vs)
}

func TestNewBuilder(t *testing.T) {
	assert := assert.New(t)

	plugMgr := newInitializedVolumePlugMgr()
	plug, err := plugMgr.FindPluginByName(pluginName)
	assert.NoError(err)

	spec := &volume.Spec{
		Volume: &api.Volume{
			VolumeSource: api.VolumeSource{
				Flocker: &api.FlockerVolumeSource{
					DatasetName: "something",
				},
			},
		},
	}

	_, err = plug.NewBuilder(spec, &api.Pod{}, volume.VolumeOptions{})
	assert.NoError(err)
}

func TestNewCleaner(t *testing.T) {
	assert := assert.New(t)

	p := flockerPlugin{}

	cleaner, err := p.NewCleaner("", types.UID(""))
	assert.Nil(cleaner)
	assert.NoError(err)
}

func TestIsReadOnly(t *testing.T) {
	b := flockerBuilder{readOnly: true}
	assert.True(t, b.IsReadOnly())
}

func TestGetPath(t *testing.T) {
	const expectedPath = "/flocker/expected"

	assert := assert.New(t)

	b := flockerBuilder{flocker: &flocker{path: expectedPath}}
	assert.Equal(expectedPath, b.GetPath())
}

type mockFlockerClient struct {
	datasetID, primaryUUID, path string
	datasetState                 *flockerClient.DatasetState
}

func newMockFlockerClient(mockDatasetID, mockPrimaryUUID, mockPath string) *mockFlockerClient {
	return &mockFlockerClient{
		datasetID:   mockDatasetID,
		primaryUUID: mockPrimaryUUID,
		path:        mockPath,
		datasetState: &flockerClient.DatasetState{
			Path:      mockPath,
			DatasetID: mockDatasetID,
			Primary:   mockPrimaryUUID,
		},
	}
}

func (m mockFlockerClient) CreateDataset(metaName string) (*flockerClient.DatasetState, error) {
	return m.datasetState, nil
}
func (m mockFlockerClient) GetDatasetState(datasetID string) (*flockerClient.DatasetState, error) {
	return m.datasetState, nil
}
func (m mockFlockerClient) GetDatasetID(metaName string) (string, error) {
	return m.datasetID, nil
}
func (m mockFlockerClient) GetPrimaryUUID() (string, error) {
	return m.primaryUUID, nil
}
func (m mockFlockerClient) UpdatePrimaryForDataset(primaryUUID, datasetID string) (*flockerClient.DatasetState, error) {
	return m.datasetState, nil
}

func TestSetUpAtInternal(t *testing.T) {
	const dir = "dir"
	mockPath := "expected-to-be-set-properly" // package var
	expectedPath := mockPath

	assert := assert.New(t)

	plugMgr := newInitializedVolumePlugMgr()
	plug, err := plugMgr.FindPluginByName(flockerPluginName)
	assert.NoError(err)

	pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
	b := flockerBuilder{flocker: &flocker{pod: pod, plugin: plug.(*flockerPlugin)}}
	b.client = newMockFlockerClient("dataset-id", "primary-uid", mockPath)

	assert.NoError(b.SetUpAt(dir))
	assert.Equal(expectedPath, b.flocker.path)
}
<commit_msg>flocker unit test should clean up after itself<commit_after>/*
Copyright 2015 The Kubernetes Authors All rights reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package flocker

import (
	"io/ioutil"
	"os"
	"testing"

	flockerClient "github.com/ClusterHQ/flocker-go"
	"github.com/stretchr/testify/assert"
	"k8s.io/kubernetes/pkg/api"
	"k8s.io/kubernetes/pkg/types"
	"k8s.io/kubernetes/pkg/volume"
)

const pluginName = "kubernetes.io/flocker"

func newInitializedVolumePlugMgr(t *testing.T) (volume.VolumePluginMgr, string) {
	plugMgr := volume.VolumePluginMgr{}
	dir, err := ioutil.TempDir("", "flocker")
	assert.NoError(t, err)
	plugMgr.InitPlugins(ProbeVolumePlugins(), volume.NewFakeVolumeHost(dir, nil, nil))
	return plugMgr, dir
}

func TestGetByName(t *testing.T) {
	assert := assert.New(t)
	plugMgr, _ := newInitializedVolumePlugMgr(t)

	plug, err := plugMgr.FindPluginByName(pluginName)
	assert.NotNil(plug, "Can't find the plugin by name")
	assert.NoError(err)
}

func TestCanSupport(t *testing.T) {
	assert := assert.New(t)
	plugMgr, _ := newInitializedVolumePlugMgr(t)

	plug, err := plugMgr.FindPluginByName(pluginName)
	assert.NoError(err)

	specs := map[*volume.Spec]bool{
		&volume.Spec{
			Volume: &api.Volume{
				VolumeSource: api.VolumeSource{
					Flocker: &api.FlockerVolumeSource{},
				},
			},
		}: true,
		&volume.Spec{
			PersistentVolume: &api.PersistentVolume{
				Spec: api.PersistentVolumeSpec{
					PersistentVolumeSource: api.PersistentVolumeSource{
						Flocker: &api.FlockerVolumeSource{},
					},
				},
			},
		}: true,
		&volume.Spec{
			Volume: &api.Volume{
				VolumeSource: api.VolumeSource{},
			},
		}: false,
	}

	for spec, expected := range specs {
		actual := plug.CanSupport(spec)
		assert.Equal(expected, actual)
	}
}

func TestGetFlockerVolumeSource(t *testing.T) {
	assert := assert.New(t)

	p := flockerPlugin{}

	spec := &volume.Spec{
		Volume: &api.Volume{
			VolumeSource: api.VolumeSource{
				Flocker: &api.FlockerVolumeSource{},
			},
		},
	}
	vs, ro := p.getFlockerVolumeSource(spec)
	assert.False(ro)
	assert.Equal(spec.Volume.Flocker, vs)

	spec = &volume.Spec{
		PersistentVolume: &api.PersistentVolume{
			Spec: api.PersistentVolumeSpec{
				PersistentVolumeSource: api.PersistentVolumeSource{
					Flocker: &api.FlockerVolumeSource{},
				},
			},
		},
	}
	vs, ro = p.getFlockerVolumeSource(spec)
	assert.False(ro)
	assert.Equal(spec.PersistentVolume.Spec.Flocker, vs)
}

func TestNewBuilder(t *testing.T) {
	assert := assert.New(t)

	plugMgr, _ := newInitializedVolumePlugMgr(t)
	plug, err := plugMgr.FindPluginByName(pluginName)
	assert.NoError(err)

	spec := &volume.Spec{
		Volume: &api.Volume{
			VolumeSource: api.VolumeSource{
				Flocker: &api.FlockerVolumeSource{
					DatasetName: "something",
				},
			},
		},
	}

	_, err = plug.NewBuilder(spec, &api.Pod{}, volume.VolumeOptions{})
	assert.NoError(err)
}

func TestNewCleaner(t *testing.T) {
	assert := assert.New(t)

	p := flockerPlugin{}

	cleaner, err := p.NewCleaner("", types.UID(""))
	assert.Nil(cleaner)
	assert.NoError(err)
}

func TestIsReadOnly(t *testing.T) {
	b := flockerBuilder{readOnly: true}
	assert.True(t, b.IsReadOnly())
}

func TestGetPath(t *testing.T) {
	const expectedPath = "/flocker/expected"

	assert := assert.New(t)

	b := flockerBuilder{flocker: &flocker{path: expectedPath}}
	assert.Equal(expectedPath, b.GetPath())
}

type mockFlockerClient struct {
	datasetID, primaryUUID, path string
	datasetState                 *flockerClient.DatasetState
}

func newMockFlockerClient(mockDatasetID, mockPrimaryUUID, mockPath string) *mockFlockerClient {
	return &mockFlockerClient{
		datasetID:   mockDatasetID,
		primaryUUID: mockPrimaryUUID,
		path:        mockPath,
		datasetState: &flockerClient.DatasetState{
			Path:      mockPath,
			DatasetID: mockDatasetID,
			Primary:   mockPrimaryUUID,
		},
	}
}

func (m mockFlockerClient) CreateDataset(metaName string) (*flockerClient.DatasetState, error) {
	return m.datasetState, nil
}
func (m mockFlockerClient) GetDatasetState(datasetID string) (*flockerClient.DatasetState, error) {
	return m.datasetState, nil
}
func (m mockFlockerClient) GetDatasetID(metaName string) (string, error) {
	return m.datasetID, nil
}
func (m mockFlockerClient) GetPrimaryUUID() (string, error) {
	return m.primaryUUID, nil
}
func (m mockFlockerClient) UpdatePrimaryForDataset(primaryUUID, datasetID string) (*flockerClient.DatasetState, error) {
	return m.datasetState, nil
}

func TestSetUpAtInternal(t *testing.T) {
	const dir = "dir"
	mockPath := "expected-to-be-set-properly" // package var
	expectedPath := mockPath

	assert := assert.New(t)

	plugMgr, rootDir := newInitializedVolumePlugMgr(t)
	if rootDir != "" {
		defer os.RemoveAll(rootDir)
	}
	plug, err := plugMgr.FindPluginByName(flockerPluginName)
	assert.NoError(err)

	pod := &api.Pod{ObjectMeta: api.ObjectMeta{UID: types.UID("poduid")}}
	b := flockerBuilder{flocker: &flocker{pod: pod, plugin: plug.(*flockerPlugin)}}
	b.client = newMockFlockerClient("dataset-id", "primary-uid", mockPath)

	assert.NoError(b.SetUpAt(dir))
	assert.Equal(expectedPath, b.flocker.path)
}
<|endoftext|>


<commit_before>// Copyright 2017 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"os"

	"github.com/docker/machine/libmachine/drivers/plugin/localbinary"
	"github.com/tsuru/tsuru-client/tsuru/admin"
	"github.com/tsuru/tsuru-client/tsuru/client"
	"github.com/tsuru/tsuru-client/tsuru/installer"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/iaas/dockermachine"
	_ "github.com/tsuru/tsuru/provision/docker/cmds"
)

const (
	version = "1.9.6"
	header  = "Supported-Tsuru"
)

func buildManager(name string) *cmd.Manager {
	lookup := func(context *cmd.Context) error {
		return client.RunPlugin(context)
	}
	m := cmd.BuildBaseManager(name, version, header, lookup)
	m.Register(&client.AppRun{})
	m.Register(&client.AppInfo{})
	m.Register(&client.AppCreate{})
	m.Register(&client.AppRemove{})
	m.Register(&client.AppUpdate{})
	m.Register(&client.UnitAdd{})
	m.Register(&client.UnitRemove{})
	m.Register(&client.UnitSet{})
	m.Register(&client.AppList{})
	m.Register(&client.AppLog{})
	m.Register(&client.AppGrant{})
	m.Register(&client.AppRevoke{})
	m.Register(&client.AppRestart{})
	m.Register(&client.AppStart{})
	m.Register(&client.AppStop{})
	m.Register(&client.Init{})
	m.Register(&admin.AppLockDelete{})
	m.Register(&client.CertificateSet{})
	m.Register(&client.CertificateUnset{})
	m.Register(&client.CertificateList{})
	m.Register(&client.CnameAdd{})
	m.Register(&client.CnameRemove{})
	m.Register(&client.EnvGet{})
	m.Register(&client.EnvSet{})
	m.Register(&client.EnvUnset{})
	m.Register(client.ServiceList{})
	m.Register(&client.ServiceInstanceAdd{})
	m.Register(&client.ServiceInstanceUpdate{})
	m.Register(&client.ServiceInstanceRemove{})
	m.Register(&client.ServiceInfo{})
	m.Register(&client.ServicePlanList{})
	m.Register(&client.ServiceInstanceGrant{})
	m.Register(&client.ServiceInstanceRevoke{})
	m.Register(&client.ServiceInstanceBind{})
	m.Register(&client.ServiceInstanceUnbind{})
	m.Register(&admin.PlatformList{})
	m.Register(&admin.PlatformAdd{})
	m.Register(&admin.PlatformUpdate{})
	m.Register(&admin.PlatformRemove{})
	m.Register(&admin.PlatformInfo{})
	m.Register(&client.PluginInstall{})
	m.Register(&client.PluginRemove{})
	m.Register(&client.PluginList{})
	m.Register(&client.AppSwap{})
	m.Register(&client.AppDeploy{})
	m.Register(&client.AppBuild{})
	m.Register(&client.PlanList{})
	m.Register(&client.UserCreate{})
	m.Register(&client.ResetPassword{})
	m.Register(&client.UserRemove{})
	m.Register(&client.ListUsers{})
	m.Register(&client.TeamCreate{})
	m.Register(&client.TeamUpdate{})
	m.Register(&client.TeamRemove{})
	m.Register(&client.TeamList{})
	m.Register(&client.TeamInfo{})
	m.Register(&client.ChangePassword{})
	m.Register(&client.ShowAPIToken{})
	m.Register(&client.RegenerateAPIToken{})
	m.Register(&client.AppDeployList{})
	m.Register(&client.AppDeployRollback{})
	m.Register(&client.AppDeployRollbackUpdate{})
	m.Register(&client.AppDeployRebuild{})
	m.Register(&cmd.ShellToContainerCmd{})
	m.Register(&client.PoolList{})
	m.Register(&client.PermissionList{})
	m.Register(&client.RoleAdd{})
	m.Register(&client.RoleUpdate{})
	m.Register(&client.RoleRemove{})
	m.Register(&client.RoleList{})
	m.Register(&client.RoleInfo{})
	m.Register(&client.RolePermissionAdd{})
	m.Register(&client.RolePermissionRemove{})
	m.Register(&client.RoleAssign{})
	m.Register(&client.RoleDissociate{})
	m.Register(&client.RoleDefaultAdd{})
	m.Register(&client.RoleDefaultList{})
	m.Register(&client.RoleDefaultRemove{})
	m.Register(&installer.Install{})
	m.Register(&installer.Uninstall{})
	m.Register(&installer.InstallHostList{})
	m.Register(&installer.InstallSSH{})
	m.Register(&installer.InstallConfigInit{})
	m.Register(&admin.AddPoolToSchedulerCmd{})
	m.Register(&client.EventList{})
	m.Register(&client.EventInfo{})
	m.Register(&client.EventCancel{})
	m.Register(&client.RoutersList{})
	m.Register(&client.RouterAdd{})
	m.Register(&client.RouterUpdate{})
	m.Register(&client.RouterRemove{})
	m.Register(&client.RouterInfo{})
	m.Register(&admin.TemplateList{})
	m.Register(&admin.TemplateAdd{})
	m.Register(&admin.TemplateRemove{})
	m.Register(&admin.MachineList{})
	m.Register(&admin.MachineDestroy{})
	m.Register(&admin.TemplateUpdate{})
	m.Register(&admin.TemplateCopy{})
	m.Register(&admin.PlanCreate{})
	m.Register(&admin.PlanRemove{})
	m.Register(&admin.UpdatePoolToSchedulerCmd{})
	m.Register(&admin.RemovePoolFromSchedulerCmd{})
	m.Register(&admin.ServiceCreate{})
	m.Register(&admin.ServiceDestroy{})
	m.Register(&admin.ServiceUpdate{})
	m.Register(&admin.ServiceDocGet{})
	m.Register(&admin.ServiceDocAdd{})
	m.Register(&admin.ServiceTemplate{})
	m.Register(&admin.UserQuotaView{})
	m.Register(&admin.UserChangeQuota{})
	m.Register(&admin.AppQuotaView{})
	m.Register(&admin.AppQuotaChange{})
	m.Register(&admin.AppRoutesRebuild{})
	m.Register(&admin.PoolConstraintList{})
	m.Register(&admin.PoolConstraintSet{})
	m.Register(&admin.EventBlockList{})
	m.Register(&admin.EventBlockAdd{})
	m.Register(&admin.EventBlockRemove{})
	m.Register(&client.TagList{})
	m.Register(&admin.NodeContainerList{})
	m.Register(&admin.NodeContainerAdd{})
	m.Register(&admin.NodeContainerInfo{})
	m.Register(&admin.NodeContainerUpdate{})
	m.Register(&admin.NodeContainerDelete{})
	m.Register(&admin.NodeContainerUpgrade{})
	m.Register(&admin.ClusterAdd{})
	m.Register(&admin.ClusterUpdate{})
	m.Register(&admin.ClusterRemove{})
	m.Register(&admin.ClusterList{})
	m.Register(&client.VolumeCreate{})
	m.Register(&client.VolumeUpdate{})
	m.Register(&client.VolumeList{})
	m.Register(&client.VolumePlansList{})
	m.Register(&client.VolumeDelete{})
	m.Register(&client.VolumeInfo{})
	m.Register(&client.VolumeBind{})
	m.Register(&client.VolumeUnbind{})
	m.Register(&client.AppRoutersList{})
	m.Register(&client.AppRoutersAdd{})
	m.Register(&client.AppRoutersRemove{})
	m.Register(&client.AppRoutersUpdate{})
	m.Register(&admin.InfoNodeCmd{})
	m.Register(&client.TokenCreateCmd{})
	m.Register(&client.TokenUpdateCmd{})
	m.Register(&client.TokenListCmd{})
	m.Register(&client.TokenDeleteCmd{})
	m.Register(&client.TokenInfoCmd{})
	m.Register(&client.WebhookList{})
	m.Register(&client.WebhookCreate{})
	m.Register(&client.WebhookUpdate{})
	m.Register(&client.WebhookDelete{})
	m.Register(&admin.BrokerList{})
	m.Register(&admin.BrokerAdd{})
	m.Register(&admin.BrokerUpdate{})
	m.Register(&admin.BrokerDelete{})
	m.Register(&admin.ProvisionerList{})
	m.Register(&admin.ProvisionerInfo{})
	m.Register(&client.AppVersionRouterAdd{})
	m.Register(&client.AppVersionRouterRemove{})
	m.Register(client.UserInfo{})
	m.Register(&client.AutoScaleSet{})
	m.Register(&client.AutoScaleUnset{})
	m.Register(&client.MetadataSet{})
	m.Register(&client.MetadataUnset{})
	m.Register(&client.MetadataGet{})
	m.Register(&admin.AddNodeCmd{})
	m.Register(&admin.RemoveNodeCmd{})
	m.Register(&admin.UpdateNodeCmd{})
	m.Register(&admin.ListNodesCmd{})
	m.Register(&admin.DeleteNodeHealingConfigCmd{})
	m.Register(&admin.GetNodeHealingConfigCmd{})
	m.Register(&admin.SetNodeHealingConfigCmd{})
	m.Register(&admin.DeleteNodeHealingConfigCmd{})
	m.Register(&admin.RebalanceNodeCmd{})
	m.Register(&admin.AutoScaleRunCmd{})
	m.Register(&admin.ListAutoScaleHistoryCmd{})
	m.Register(&admin.AutoScaleInfoCmd{})
	m.Register(&admin.AutoScaleSetRuleCmd{})
	m.Register(&admin.AutoScaleDeleteRuleCmd{})
	m.Register(&admin.ListHealingHistoryCmd{})
	m.Register(client.ServiceInstanceInfo{})
	registerExtraCommands(m)
	return m
}

func registerExtraCommands(m *cmd.Manager) {
	for _, c := range cmd.ExtraCmds() {
		m.Register(c)
	}
}

func inDockerMachineDriverMode() bool {
	return os.Getenv(localbinary.PluginEnvKey) == localbinary.PluginEnvVal
}

func main() {
	if inDockerMachineDriverMode() {
		err := dockermachine.RunDriver(os.Getenv(localbinary.PluginEnvDriverName))
		if err != nil {
			log.Fatalf("Error running driver: %s", err)
		}
	} else {
		localbinary.CurrentBinaryIsDockerMachine = true
		name := cmd.ExtractProgramName(os.Args[0])
		m := buildManager(name)
		m.Run(os.Args[1:])
	}
}
<commit_msg>Remove duplicated command<commit_after>// Copyright 2017 tsuru-client authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"log"
	"os"

	"github.com/docker/machine/libmachine/drivers/plugin/localbinary"
	"github.com/tsuru/tsuru-client/tsuru/admin"
	"github.com/tsuru/tsuru-client/tsuru/client"
	"github.com/tsuru/tsuru-client/tsuru/installer"
	"github.com/tsuru/tsuru/cmd"
	"github.com/tsuru/tsuru/iaas/dockermachine"
	_ "github.com/tsuru/tsuru/provision/docker/cmds"
)

const (
	version = "1.9.6"
	header  = "Supported-Tsuru"
)

func buildManager(name string) *cmd.Manager {
	lookup := func(context *cmd.Context) error {
		return client.RunPlugin(context)
	}
	m := cmd.BuildBaseManager(name, version, header, lookup)
	m.Register(&client.AppRun{})
	m.Register(&client.AppInfo{})
	m.Register(&client.AppCreate{})
	m.Register(&client.AppRemove{})
	m.Register(&client.AppUpdate{})
	m.Register(&client.UnitAdd{})
	m.Register(&client.UnitRemove{})
	m.Register(&client.UnitSet{})
	m.Register(&client.AppList{})
	m.Register(&client.AppLog{})
	m.Register(&client.AppGrant{})
	m.Register(&client.AppRevoke{})
	m.Register(&client.AppRestart{})
	m.Register(&client.AppStart{})
	m.Register(&client.AppStop{})
	m.Register(&client.Init{})
	m.Register(&admin.AppLockDelete{})
	m.Register(&client.CertificateSet{})
	m.Register(&client.CertificateUnset{})
	m.Register(&client.CertificateList{})
	m.Register(&client.CnameAdd{})
	m.Register(&client.CnameRemove{})
	m.Register(&client.EnvGet{})
	m.Register(&client.EnvSet{})
	m.Register(&client.EnvUnset{})
	m.Register(client.ServiceList{})
	m.Register(&client.ServiceInstanceAdd{})
	m.Register(&client.ServiceInstanceUpdate{})
	m.Register(&client.ServiceInstanceRemove{})
	m.Register(&client.ServiceInfo{})
	m.Register(&client.ServicePlanList{})
	m.Register(&client.ServiceInstanceGrant{})
	m.Register(&client.ServiceInstanceRevoke{})
	m.Register(&client.ServiceInstanceBind{})
	m.Register(&client.ServiceInstanceUnbind{})
	m.Register(&admin.PlatformList{})
	m.Register(&admin.PlatformAdd{})
	m.Register(&admin.PlatformUpdate{})
	m.Register(&admin.PlatformRemove{})
	m.Register(&admin.PlatformInfo{})
	m.Register(&client.PluginInstall{})
	m.Register(&client.PluginRemove{})
	m.Register(&client.PluginList{})
	m.Register(&client.AppSwap{})
	m.Register(&client.AppDeploy{})
	m.Register(&client.AppBuild{})
	m.Register(&client.PlanList{})
	m.Register(&client.UserCreate{})
	m.Register(&client.ResetPassword{})
	m.Register(&client.UserRemove{})
	m.Register(&client.ListUsers{})
	m.Register(&client.TeamCreate{})
	m.Register(&client.TeamUpdate{})
	m.Register(&client.TeamRemove{})
	m.Register(&client.TeamList{})
	m.Register(&client.TeamInfo{})
	m.Register(&client.ChangePassword{})
	m.Register(&client.ShowAPIToken{})
	m.Register(&client.RegenerateAPIToken{})
	m.Register(&client.AppDeployList{})
	m.Register(&client.AppDeployRollback{})
	m.Register(&client.AppDeployRollbackUpdate{})
	m.Register(&client.AppDeployRebuild{})
	m.Register(&cmd.ShellToContainerCmd{})
	m.Register(&client.PoolList{})
	m.Register(&client.PermissionList{})
	m.Register(&client.RoleAdd{})
	m.Register(&client.RoleUpdate{})
	m.Register(&client.RoleRemove{})
	m.Register(&client.RoleList{})
	m.Register(&client.RoleInfo{})
	m.Register(&client.RolePermissionAdd{})
	m.Register(&client.RolePermissionRemove{})
	m.Register(&client.RoleAssign{})
	m.Register(&client.RoleDissociate{})
	m.Register(&client.RoleDefaultAdd{})
	m.Register(&client.RoleDefaultList{})
	m.Register(&client.RoleDefaultRemove{})
	m.Register(&installer.Install{})
	m.Register(&installer.Uninstall{})
	m.Register(&installer.InstallHostList{})
	m.Register(&installer.InstallSSH{})
	m.Register(&installer.InstallConfigInit{})
	m.Register(&admin.AddPoolToSchedulerCmd{})
	m.Register(&client.EventList{})
	m.Register(&client.EventInfo{})
	m.Register(&client.EventCancel{})
	m.Register(&client.RoutersList{})
	m.Register(&client.RouterAdd{})
	m.Register(&client.RouterUpdate{})
	m.Register(&client.RouterRemove{})
	m.Register(&client.RouterInfo{})
	m.Register(&admin.TemplateList{})
	m.Register(&admin.TemplateAdd{})
	m.Register(&admin.TemplateRemove{})
	m.Register(&admin.MachineList{})
	m.Register(&admin.MachineDestroy{})
	m.Register(&admin.TemplateUpdate{})
	m.Register(&admin.TemplateCopy{})
	m.Register(&admin.PlanCreate{})
	m.Register(&admin.PlanRemove{})
	m.Register(&admin.UpdatePoolToSchedulerCmd{})
	m.Register(&admin.RemovePoolFromSchedulerCmd{})
	m.Register(&admin.ServiceCreate{})
	m.Register(&admin.ServiceDestroy{})
	m.Register(&admin.ServiceUpdate{})
	m.Register(&admin.ServiceDocGet{})
	m.Register(&admin.ServiceDocAdd{})
	m.Register(&admin.ServiceTemplate{})
	m.Register(&admin.UserQuotaView{})
	m.Register(&admin.UserChangeQuota{})
	m.Register(&admin.AppQuotaView{})
	m.Register(&admin.AppQuotaChange{})
	m.Register(&admin.AppRoutesRebuild{})
	m.Register(&admin.PoolConstraintList{})
	m.Register(&admin.PoolConstraintSet{})
	m.Register(&admin.EventBlockList{})
	m.Register(&admin.EventBlockAdd{})
	m.Register(&admin.EventBlockRemove{})
	m.Register(&client.TagList{})
	m.Register(&admin.NodeContainerList{})
	m.Register(&admin.NodeContainerAdd{})
	m.Register(&admin.NodeContainerInfo{})
	m.Register(&admin.NodeContainerUpdate{})
	m.Register(&admin.NodeContainerDelete{})
	m.Register(&admin.NodeContainerUpgrade{})
	m.Register(&admin.ClusterAdd{})
	m.Register(&admin.ClusterUpdate{})
	m.Register(&admin.ClusterRemove{})
	m.Register(&admin.ClusterList{})
	m.Register(&client.VolumeCreate{})
	m.Register(&client.VolumeUpdate{})
	m.Register(&client.VolumeList{})
	m.Register(&client.VolumePlansList{})
	m.Register(&client.VolumeDelete{})
	m.Register(&client.VolumeInfo{})
	m.Register(&client.VolumeBind{})
	m.Register(&client.VolumeUnbind{})
	m.Register(&client.AppRoutersList{})
	m.Register(&client.AppRoutersAdd{})
	m.Register(&client.AppRoutersRemove{})
	m.Register(&client.AppRoutersUpdate{})
	m.Register(&admin.InfoNodeCmd{})
	m.Register(&client.TokenCreateCmd{})
	m.Register(&client.TokenUpdateCmd{})
	m.Register(&client.TokenListCmd{})
	m.Register(&client.TokenDeleteCmd{})
	m.Register(&client.TokenInfoCmd{})
	m.Register(&client.WebhookList{})
	m.Register(&client.WebhookCreate{})
	m.Register(&client.WebhookUpdate{})
	m.Register(&client.WebhookDelete{})
	m.Register(&admin.BrokerList{})
	m.Register(&admin.BrokerAdd{})
	m.Register(&admin.BrokerUpdate{})
	m.Register(&admin.BrokerDelete{})
	m.Register(&admin.ProvisionerList{})
	m.Register(&admin.ProvisionerInfo{})
	m.Register(&client.AppVersionRouterAdd{})
	m.Register(&client.AppVersionRouterRemove{})
	m.Register(client.UserInfo{})
	m.Register(&client.AutoScaleSet{})
	m.Register(&client.AutoScaleUnset{})
	m.Register(&client.MetadataSet{})
	m.Register(&client.MetadataUnset{})
	m.Register(&client.MetadataGet{})
	m.Register(&admin.AddNodeCmd{})
	m.Register(&admin.RemoveNodeCmd{})
	m.Register(&admin.UpdateNodeCmd{})
	m.Register(&admin.ListNodesCmd{})
	m.Register(&admin.GetNodeHealingConfigCmd{})
	m.Register(&admin.SetNodeHealingConfigCmd{})
	m.Register(&admin.DeleteNodeHealingConfigCmd{})
	m.Register(&admin.RebalanceNodeCmd{})
	m.Register(&admin.AutoScaleRunCmd{})
	m.Register(&admin.ListAutoScaleHistoryCmd{})
	m.Register(&admin.AutoScaleInfoCmd{})
	m.Register(&admin.AutoScaleSetRuleCmd{})
	m.Register(&admin.AutoScaleDeleteRuleCmd{})
	m.Register(&admin.ListHealingHistoryCmd{})
	m.Register(client.ServiceInstanceInfo{})
	registerExtraCommands(m)
	return m
}

func registerExtraCommands(m *cmd.Manager) {
	for _, c := range cmd.ExtraCmds() {
		m.Register(c)
	}
}

func inDockerMachineDriverMode() bool {
	return os.Getenv(localbinary.PluginEnvKey) == localbinary.PluginEnvVal
}

func main() {
	if inDockerMachineDriverMode() {
		err := dockermachine.RunDriver(os.Getenv(localbinary.PluginEnvDriverName))
		if err != nil {
			log.Fatalf("Error running driver: %s", err)
		}
	} else {
		localbinary.CurrentBinaryIsDockerMachine = true
		name := cmd.ExtractProgramName(os.Args[0])
		m := buildManager(name)
		m.Run(os.Args[1:])
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

// safeWriter transactionalizes writes of manifest, lock, and vendor dir, both
// individually and in any combination, into a pseudo-atomic action with
// transactional rollback.
//
// It is not impervious to errors (writing to disk is hard), but it should
// guard against non-arcane failure conditions.
type safeWriter struct {
	root          string
	nm            *manifest // the new manifest to write
	lock          *lock     // the old lock, if any
	nl            gps.Lock  // the new lock to write, if desired
	sm            gps.SourceManager
	mpath, vendor string
}

// writeAllSafe writes out some combination of config yaml, lock, and a vendor
// tree, to a temp dir, then moves them into place if and only if all the write
// operations succeeded. It also does its best to roll back if any moves fail.
//
// This mostly guarantees that dep cannot terminate with a partial write,
// resulting in an undefined disk state.
//
// - If a gw.conf is provided, it will be written to the standard manifest file
// name beneath gw.pr
// - If gw.lock is provided without a gw.nl, it will be written to
//   `glide.lock` in the parent dir of gw.vendor
// - If gw.lock and gw.nl are both provided and are not equivalent,
//   the nl will be written to the same location as above, and a vendor
//   tree will be written to gw.vendor
// - If gw.nl is provided and gw.lock is not, it will write both a lock
//   and vendor dir in the same way
//
// Any of the conf, lock, or result can be omitted; the grouped write operation
// will continue for whichever inputs are present.
func (gw safeWriter) writeAllSafe() error {
	// Decide which writes we need to do
	var writeM, writeL, writeV bool

	if gw.nm != nil {
		writeM = true
	}

	if gw.nl != nil {
		if gw.lock == nil {
			writeL, writeV = true, true
		} else {
			rlf := lockFromInterface(gw.nl)
			if !locksAreEquivalent(rlf, gw.lock) {
				writeL, writeV = true, true
			}
		}
	} else if gw.lock != nil {
		writeL = true
	}

	if !writeM && !writeL && !writeV {
		// nothing to do
		return nil
	}

	if writeM && gw.mpath == "" {
		return fmt.Errorf("Must provide a path if writing out a config yaml.")
	}

	if (writeL || writeV) && gw.vendor == "" {
		return fmt.Errorf("Must provide a vendor dir if writing out a lock or vendor dir.")
	}

	if writeV && gw.sm == nil {
		return fmt.Errorf("Must provide a SourceManager if writing out a vendor dir.")
	}

	td, err := ioutil.TempDir(os.TempDir(), "dep")
	if err != nil {
		return errors.Wrap(err, "error while creating temp dir for writing manifest/lock/vendor")
	}
	defer os.RemoveAll(td)

	if writeM {
		if err := writeFile(filepath.Join(td, manifestName), gw.nm); err != nil {
			return errors.Wrap(err, "failed to write manifest file to temp dir")
		}
	}

	if writeL {
		if gw.nl == nil {
			// the new lock is nil but the flag is on, so we must be writing
			// the other one
			if err := writeFile(filepath.Join(td, lockName), gw.lock); err != nil {
				return errors.Wrap(err, "failed to write lock file to temp dir")
			}
		} else {
			rlf := lockFromInterface(gw.nl)
			// As with above, this case really shouldn't get hit unless there's
			// a bug in gps, or guarantees change
			if err != nil {
				return err
			}
			if err := writeFile(filepath.Join(td, lockName), rlf); err != nil {
				return errors.Wrap(err, "failed to write lock file to temp dir")
			}
		}
	}

	if writeV {
		err = gps.WriteDepTree(filepath.Join(td, "vendor"), gw.nl, gw.sm, true)
		if err != nil {
			return fmt.Errorf("Error while generating vendor tree: %s", err)
		}
	}

	// Move the existing files and dirs to the temp dir while we put the new
	// ones in, to provide insurance against errors for as long as possible
	var fail bool
	var failerr error
	type pathpair struct {
		from, to string
	}
	var restore []pathpair

	if writeM {
		if _, err := os.Stat(gw.mpath); err == nil {
			// move out the old one
			tmploc := filepath.Join(td, manifestName+".orig")
			failerr = os.Rename(gw.mpath, tmploc)
			if failerr != nil {
				fail = true
			} else {
				restore = append(restore, pathpair{from: tmploc, to: gw.mpath})
			}
		}

		// move in the new one
		failerr = os.Rename(filepath.Join(td, manifestName), gw.mpath)
		if failerr != nil {
			fail = true
		}
	}

	if !fail && writeL {
		tgt := filepath.Join(filepath.Dir(gw.vendor), lockName)
		if _, err := os.Stat(tgt); err == nil {
			// move out the old one
			tmploc := filepath.Join(td, lockName+".orig")

			failerr = os.Rename(tgt, tmploc)
			if failerr != nil {
				fail = true
			} else {
				restore = append(restore, pathpair{from: tmploc, to: tgt})
			}
		}

		// move in the new one
		failerr = renameElseCopy(filepath.Join(td, lockName), tgt)
		if failerr != nil {
			fail = true
		}
	}

	// have to declare out here so it's present later
	var vendorbak string
	if !fail && writeV {
		if _, err := os.Stat(gw.vendor); err == nil {
			// move out the old vendor dir. just do it into an adjacent dir, to
			// try to mitigate the possibility of a pointless cross-filesystem
			// move with a temp dir
			vendorbak = gw.vendor + ".orig"
			if _, err := os.Stat(vendorbak); err == nil {
				// If that does already exist bite the bullet and use a proper
				// tempdir
				vendorbak = filepath.Join(td, "vendor.orig")
			}

			failerr = renameElseCopy(gw.vendor, vendorbak)
			if failerr != nil {
				fail = true
			} else {
				restore = append(restore, pathpair{from: vendorbak, to: gw.vendor})
			}
		}

		// move in the new one
		failerr = renameElseCopy(filepath.Join(td, "vendor"), gw.vendor)
		if failerr != nil {
			fail = true
		}
	}

	// If we failed at any point, move all the things back into place, then bail
	if fail {
		for _, pair := range restore {
			// Nothing we can do on err here, we're already in recovery mode
			renameElseCopy(pair.from, pair.to)
		}
		return failerr
	}

	// Renames all went smoothly. The deferred os.RemoveAll will get the temp
	// dir, but if we wrote vendor, we have to clean that up directly

	if writeV {
		// Again, kinda nothing we can do about an error at this point
		os.RemoveAll(vendorbak)
	}

	return nil
}
<commit_msg>Remove extra err check<commit_after>// Copyright 2016 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"

	"github.com/pkg/errors"
	"github.com/sdboyer/gps"
)

// safeWriter transactionalizes writes of manifest, lock, and vendor dir, both
// individually and in any combination, into a pseudo-atomic action with
// transactional rollback.
//
// It is not impervious to errors (writing to disk is hard), but it should
// guard against non-arcane failure conditions.
type safeWriter struct {
	root          string
	nm            *manifest // the new manifest to write
	lock          *lock     // the old lock, if any
	nl            gps.Lock  // the new lock to write, if desired
	sm            gps.SourceManager
	mpath, vendor string
}

// writeAllSafe writes out some combination of config yaml, lock, and a vendor
// tree, to a temp dir, then moves them into place if and only if all the write
// operations succeeded. It also does its best to roll back if any moves fail.
//
// This mostly guarantees that dep cannot terminate with a partial write,
// resulting in an undefined disk state.
//
// - If a gw.conf is provided, it will be written to the standard manifest file
// name beneath gw.pr
// - If gw.lock is provided without a gw.nl, it will be written to
//   `glide.lock` in the parent dir of gw.vendor
// - If gw.lock and gw.nl are both provided and are not equivalent,
//   the nl will be written to the same location as above, and a vendor
//   tree will be written to gw.vendor
// - If gw.nl is provided and gw.lock is not, it will write both a lock
//   and vendor dir in the same way
//
// Any of the conf, lock, or result can be omitted; the grouped write operation
// will continue for whichever inputs are present.
func (gw safeWriter) writeAllSafe() error {
	// Decide which writes we need to do
	var writeM, writeL, writeV bool

	if gw.nm != nil {
		writeM = true
	}

	if gw.nl != nil {
		if gw.lock == nil {
			writeL, writeV = true, true
		} else {
			rlf := lockFromInterface(gw.nl)
			if !locksAreEquivalent(rlf, gw.lock) {
				writeL, writeV = true, true
			}
		}
	} else if gw.lock != nil {
		writeL = true
	}

	if !writeM && !writeL && !writeV {
		// nothing to do
		return nil
	}

	if writeM && gw.mpath == "" {
		return fmt.Errorf("Must provide a path if writing out a config yaml.")
	}

	if (writeL || writeV) && gw.vendor == "" {
		return fmt.Errorf("Must provide a vendor dir if writing out a lock or vendor dir.")
	}

	if writeV && gw.sm == nil {
		return fmt.Errorf("Must provide a SourceManager if writing out a vendor dir.")
	}

	td, err := ioutil.TempDir(os.TempDir(), "dep")
	if err != nil {
		return errors.Wrap(err, "error while creating temp dir for writing manifest/lock/vendor")
	}
	defer os.RemoveAll(td)

	if writeM {
		if err := writeFile(filepath.Join(td, manifestName), gw.nm); err != nil {
			return errors.Wrap(err, "failed to write manifest file to temp dir")
		}
	}

	if writeL {
		if gw.nl == nil {
			// the new lock is nil but the flag is on, so we must be writing
			// the other one
			if err := writeFile(filepath.Join(td, lockName), gw.lock); err != nil {
				return errors.Wrap(err, "failed to write lock file to temp dir")
			}
		} else {
			rlf := lockFromInterface(gw.nl)
			if err := writeFile(filepath.Join(td, lockName), rlf); err != nil {
				return errors.Wrap(err, "failed to write lock file to temp dir")
			}
		}
	}

	if writeV {
		err = gps.WriteDepTree(filepath.Join(td, "vendor"), gw.nl, gw.sm, true)
		if err != nil {
			return fmt.Errorf("Error while generating vendor tree: %s", err)
		}
	}

	// Move the existing files and dirs to the temp dir while we put the new
	// ones in, to provide insurance against errors for as long as possible
	var fail bool
	var failerr error
	type pathpair struct {
		from, to string
	}
	var restore []pathpair

	if writeM {
		if _, err := os.Stat(gw.mpath); err == nil {
			// move out the old one
			tmploc := filepath.Join(td, manifestName+".orig")
			failerr = os.Rename(gw.mpath, tmploc)
			if failerr != nil {
				fail = true
			} else {
				restore = append(restore, pathpair{from: tmploc, to: gw.mpath})
			}
		}

		// move in the new one
		failerr = os.Rename(filepath.Join(td, manifestName), gw.mpath)
		if failerr != nil {
			fail = true
		}
	}

	if !fail && writeL {
		tgt := filepath.Join(filepath.Dir(gw.vendor), lockName)
		if _, err := os.Stat(tgt); err == nil {
			// move out the old one
			tmploc := filepath.Join(td, lockName+".orig")

			failerr = os.Rename(tgt, tmploc)
			if failerr != nil {
				fail = true
			} else {
				restore = append(restore, pathpair{from: tmploc, to: tgt})
			}
		}

		// move in the new one
		failerr = renameElseCopy(filepath.Join(td, lockName), tgt)
		if failerr != nil {
			fail = true
		}
	}

	// have to declare out here so it's present later
	var vendorbak string
	if !fail && writeV {
		if _, err := os.Stat(gw.vendor); err == nil {
			// move out the old vendor dir. just do it into an adjacent dir, to
			// try to mitigate the possibility of a pointless cross-filesystem
			// move with a temp dir
			vendorbak = gw.vendor + ".orig"
			if _, err := os.Stat(vendorbak); err == nil {
				// If that does already exist bite the bullet and use a proper
				// tempdir
				vendorbak = filepath.Join(td, "vendor.orig")
			}

			failerr = renameElseCopy(gw.vendor, vendorbak)
			if failerr != nil {
				fail = true
			} else {
				restore = append(restore, pathpair{from: vendorbak, to: gw.vendor})
			}
		}

		// move in the new one
		failerr = renameElseCopy(filepath.Join(td, "vendor"), gw.vendor)
		if failerr != nil {
			fail = true
		}
	}

	// If we failed at any point, move all the things back into place, then bail
	if fail {
		for _, pair := range restore {
			// Nothing we can do on err here, we're already in recovery mode
			renameElseCopy(pair.from, pair.to)
		}
		return failerr
	}

	// Renames all went smoothly. The deferred os.RemoveAll will get the temp
	// dir, but if we wrote vendor, we have to clean that up directly

	if writeV {
		// Again, kinda nothing we can do about an error at this point
		os.RemoveAll(vendorbak)
	}

	return nil
}
<|endoftext|>