Skip to content

Commit

Permalink
Release v0.7.0 (#108)
Browse files Browse the repository at this point in the history
* Change to new (unreleased) version

* Order cookbook files and add a new config option

* Fix a logical error causing issues using both Github and Gitlab

Namely when using the same organization and group names when using both Github and Gitlab, the old setup could not handle that properly.
  • Loading branch information
Sander van Harmelen committed Sep 8, 2016
1 parent 804e740 commit 77c3374
Show file tree
Hide file tree
Showing 14 changed files with 329 additions and 250 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Chef-Guard CHANGELOG
====================

0.7.0
-----
- Fixed a logical error which prevented the use of the same Github or Gitlab organization and/or group names. The fix for this contains a **backwards incompatible** change to the config file (GH-108)
- Order the files that are changed or missing before returning an error (GH-106)
- Add a `devenvironment` config option; no dependency checks will be done for this environment

0.6.2
-----
- Do not log empty error messages but instead try to capture a more useful message based on the given error
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.6.2
0.7.0
6 changes: 3 additions & 3 deletions changes.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func processChange(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Req
return
}

if getEffectiveConfig("ValidateChanges", cg.Organization).(string) == "enforced" &&
if getEffectiveConfig("ValidateChanges", cg.ChefOrg).(string) == "enforced" &&
r.Method != "DELETE" {
if errCode, err := cg.validateConstraints(reqBody); err != nil {
errorHandler(w, err.Error(), errCode)
Expand All @@ -76,7 +76,7 @@ func processChange(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Req
// 1. If we don't want to commit any changes, just return here.
// 2. If we do want to commit the changes, but we are a node updating itself also return
// here unless this is a client or node creation as we do want to see those ones.
if getEffectiveConfig("CommitChanges", cg.Organization).(bool) == false ||
if getEffectiveConfig("CommitChanges", cg.ChefOrg).(bool) == false ||
strings.HasPrefix(r.Header.Get("User-Agent"), "Chef Client") &&
r.Header.Get("X-Ops-Request-Source") != "web" &&
!((mux.Vars(r)["type"] == "clients" || mux.Vars(r)["type"] == "nodes") && r.Method == "POST") {
Expand Down Expand Up @@ -135,7 +135,7 @@ func processChange(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Req
go cg.syncedGitUpdate(r.Method, reqBody)
}

if getEffectiveConfig("ValidateChanges", cg.Organization).(string) == "permissive" &&
if getEffectiveConfig("ValidateChanges", cg.ChefOrg).(string) == "permissive" &&
r.Method != "DELETE" {
if errCode, err := cg.validateConstraints(reqBody); err != nil {
errorHandler(w, err.Error(), errCode)
Expand Down
4 changes: 2 additions & 2 deletions checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (

func (cg *ChefGuard) executeChecks() (int, error) {
if cfg.Tests.Foodcritic != "" {
if errCode, err := runFoodcritic(cg.Organization, cg.CookbookPath); err != nil {
if errCode, err := runFoodcritic(cg.ChefOrg, cg.CookbookPath); err != nil {
if errCode == http.StatusBadGateway || !cg.continueAfterFailedCheck("foodcritic") {
return errCode, err
}
Expand All @@ -43,7 +43,7 @@ func (cg *ChefGuard) executeChecks() (int, error) {

func (cg *ChefGuard) continueAfterFailedCheck(check string) bool {
WARNING.Printf("%s errors when uploading cookbook '%s' for '%s'\n", strings.Title(check), cg.Cookbook.Name, cg.User)
if getEffectiveConfig("Mode", cg.Organization).(string) == "permissive" && cg.ForcedUpload {
if getEffectiveConfig("Mode", cg.ChefOrg).(string) == "permissive" && cg.ForcedUpload {
return true
}
return false
Expand Down
33 changes: 25 additions & 8 deletions chef-guard.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"crypto/tls"
"flag"
"fmt"
"io/ioutil"
"log"
"net"
"net/http"
Expand All @@ -37,7 +38,9 @@ import (
)

// VERSION holds the current version
const VERSION = "0.6.2"
const VERSION = "0.7.0"

var chefKey string

var insecureTransport = &http.Transport{
Proxy: http.ProxyFromEnvironment,
Expand All @@ -56,8 +59,8 @@ type ChefGuard struct {
gitClient git.Git
User string
Repo string
Organization string
OrganizationID *string
ChefOrg string
ChefOrgID *string
Cookbook *chef.CookbookVersion
CookbookPath string
SourceCookbook *SourceCookbook
Expand All @@ -72,25 +75,39 @@ type ChefGuard struct {
func newChefGuard(r *http.Request) (*ChefGuard, error) {
cg := &ChefGuard{
User: r.Header.Get("X-Ops-Userid"),
Organization: getOrgFromRequest(r),
ChefOrg: getChefOrgFromRequest(r),
ForcedUpload: dropForce(r),
}

// Set the repo dependend on the Organization (could become a configurable in the future)
if cg.Organization != "" {
cg.Repo = cg.Organization
if cg.ChefOrg != "" {
cg.Repo = cg.ChefOrg
} else {
cg.Repo = "config"
}

// Initialize map for the file hashes
cg.FileHashes = map[string][16]byte{}

// Load the Chef key
if chefKey == "" {
key, err := ioutil.ReadFile(cfg.Chef.Key)
if err != nil {
return nil, fmt.Errorf("Failed to read Chef key: %s", err)
}

chefKey = string(key)
}

// Setup chefClient
var err error
cg.chefClient, err = chef.ConnectBuilder(cfg.Chef.Server, cfg.Chef.Port, "", cfg.Chef.User, cfg.Chef.Key, cg.Organization)
cg.chefClient, err = chef.ConnectBuilder(cfg.Chef.Server, cfg.Chef.Port, "", cfg.Chef.User, chefKey, cg.ChefOrg)
if err != nil {
return nil, fmt.Errorf("Failed to create new Chef API connection: %s", err)
}

cg.chefClient.SSLNoVerify = cfg.Chef.SSLNoVerify

return cg, nil
}

Expand Down Expand Up @@ -216,7 +233,7 @@ func errorHandler(w http.ResponseWriter, err string, statusCode int) {
http.Error(w, err, statusCode)
}

func getOrgFromRequest(r *http.Request) string {
func getChefOrgFromRequest(r *http.Request) string {
if cfg.Chef.Type != "enterprise" {
return ""
}
Expand Down
86 changes: 46 additions & 40 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,49 +24,52 @@ import (
"regexp"
"strings"

"gopkg.in/gcfg.v1"
"github.com/mitchellh/osext"
"github.com/xanzy/chef-guard/git"
"gopkg.in/gcfg.v1"
)

// Config represents the Chef-Guard configuration
type Config struct {
Default struct {
ListenIP string
ListenPort int
Logfile string
Tempdir string
Mode string
MailDomain string
MailServer string
MailPort int
MailSendBy string
MailRecipient string
ValidateChanges string
CommitChanges bool
MailChanges bool
SearchGit bool
PublishCookbook bool
Blacklist string
GitOrganization string
GitCookbookOrgs string
IncludeFCs string
ExcludeFCs string
ListenIP string
ListenPort int
Logfile string
Tempdir string
Mode string
MailDomain string
MailServer string
MailPort int
MailSendBy string
MailRecipient string
ValidateChanges string
CommitChanges bool
MailChanges bool
SearchGit bool
PublishCookbook bool
Blacklist string
DevEnvironment string
GitConfig string
GitCookbookConfigs string
IncludeFCs string
ExcludeFCs string
}
Customer map[string]*struct {
Mode *string
MailDomain *string
MailServer *string
MailPort *int
MailSendBy *string
MailRecipient *string
ValidateChanges *string
CommitChanges *bool
MailChanges *bool
SearchGit *bool
PublishCookbook *bool
Blacklist *string
GitCookbookOrgs *string
ExcludeFCs *string
Mode *string
MailDomain *string
MailServer *string
MailPort *int
MailSendBy *string
MailRecipient *string
ValidateChanges *string
CommitChanges *bool
MailChanges *bool
SearchGit *bool
PublishCookbook *bool
Blacklist *string
DevEnvironment *string
GitCookbookConfigs *string
ExcludeFCs *string
}
Chef struct {
Type string
Expand Down Expand Up @@ -165,11 +168,11 @@ func verifyRequiredFields(c *Config) error {
}

if c.Default.CommitChanges {
r["Default->GitOrganization"] = c.Default.GitOrganization
r["Default->GitConfig"] = c.Default.GitConfig
}

if c.Default.SearchGit {
r["Default->GitCookbookOrgs"] = c.Default.GitCookbookOrgs
r["Default->GitCookbookConfigs"] = c.Default.GitCookbookConfigs
}

if c.Default.PublishCookbook {
Expand Down Expand Up @@ -206,11 +209,14 @@ func verifyChefConfig(c *Config) error {

func verifyGitConfigs(c *Config) error {
for k, v := range c.Git {
if v.Organization == "" {
v.Organization = k
}
if v.Type != "github" && v.Type != "gitlab" {
return fmt.Errorf("Invalid Git type %q! Valid types are 'github' and 'gitlab'.", v.Type)
}
if v.Token == "" {
return fmt.Errorf("No token found for %s organization %s! All configured organizations need to have a valid token.", v.Type, k)
return fmt.Errorf("No token found for %s organization %s! All configured organizations need to have a valid token.", v.Type, v.Organization)
}
}
return nil
Expand Down Expand Up @@ -249,9 +255,9 @@ func parsePaths(c *Config, ep string) error {
return nil
}

func getEffectiveConfig(key, org string) interface{} {
func getEffectiveConfig(key, chefOrg string) interface{} {
if cfg.Chef.Type == "enterprise" {
if c, found := cfg.Customer[org]; found {
if c, found := cfg.Customer[chefOrg]; found {
conf := reflect.ValueOf(c).Elem()
v := conf.FieldByName(key)
if !v.IsNil() {
Expand Down
26 changes: 13 additions & 13 deletions cookbook.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import (

func processCookbook(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.Request) {
return func(w http.ResponseWriter, r *http.Request) {
if getEffectiveConfig("Mode", getOrgFromRequest(r)).(string) == "silent" && getEffectiveConfig("CommitChanges", getOrgFromRequest(r)).(bool) == false {
if getEffectiveConfig("Mode", getChefOrgFromRequest(r)).(string) == "silent" && getEffectiveConfig("CommitChanges", getChefOrgFromRequest(r)).(bool) == false {
p.ServeHTTP(w, r)
return
}
Expand All @@ -63,7 +63,7 @@ func processCookbook(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.R
errorHandler(w, fmt.Sprintf("Failed to unmarshal body %s: %s", string(body), err), http.StatusBadGateway)
return
}
if getEffectiveConfig("Mode", cg.Organization).(string) != "silent" {
if getEffectiveConfig("Mode", cg.ChefOrg).(string) != "silent" {
if errCode, err := cg.checkCookbookFrozen(); err != nil {
if strings.Contains(r.Header.Get("User-Agent"), "Ridley") {
errCode = http.StatusConflict
Expand Down Expand Up @@ -93,7 +93,7 @@ func processCookbook(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.R
}
}
}
if getEffectiveConfig("CommitChanges", cg.Organization).(bool) {
if getEffectiveConfig("CommitChanges", cg.ChefOrg).(bool) {
details := cg.getCookbookChangeDetails(r)
go cg.syncedGitUpdate(r.Method, details)
}
Expand All @@ -102,9 +102,9 @@ func processCookbook(p *httputil.ReverseProxy) func(http.ResponseWriter, *http.R
}

func (cg *ChefGuard) processCookbookFiles() error {
if cg.OrganizationID == nil {
if cg.ChefOrgID == nil {
if err := cg.getOrganizationID(); err != nil {
return fmt.Errorf("Failed to get organization ID for %s: %s", cg.Organization, err)
return fmt.Errorf("Failed to get organization ID for %s: %s", cg.ChefOrg, err)
}
}
buf := new(bytes.Buffer)
Expand All @@ -120,7 +120,7 @@ func (cg *ChefGuard) processCookbookFiles() error {
// Let's first find and save the .gitignore and chefignore files
for _, f := range cg.Cookbook.RootFiles {
if f.Name == ".gitignore" || f.Name == "chefignore" {
content, err := downloadCookbookFile(client, *cg.OrganizationID, f.Checksum)
content, err := downloadCookbookFile(client, *cg.ChefOrgID, f.Checksum)
if err != nil {
return fmt.Errorf("Failed to dowload %s from the %s cookbook: %s", f.Path, cg.Cookbook.Name, err)
}
Expand All @@ -144,7 +144,7 @@ func (cg *ChefGuard) processCookbookFiles() error {
continue
}

content, err := downloadCookbookFile(client, *cg.OrganizationID, f.Checksum)
content, err := downloadCookbookFile(client, *cg.ChefOrgID, f.Checksum)
if err != nil {
return fmt.Errorf("Failed to dowload %s from the %s cookbook: %s", f.Path, cg.Cookbook.Name, err)
}
Expand Down Expand Up @@ -230,7 +230,7 @@ func (cg *ChefGuard) getOrganizationID() error {
re := regexp.MustCompile(`^.*/organization-(.*)\/checksum-.*$`)
u := sb.Checksums["00000000000000000000000000000000"].URL
if res := re.FindStringSubmatch(u); res != nil {
cg.OrganizationID = &res[1]
cg.ChefOrgID = &res[1]
return nil
}
return fmt.Errorf("Could not find an organization ID in reply: %s", string(body))
Expand All @@ -255,17 +255,17 @@ func (cg *ChefGuard) tagAndPublishCookbook() (int, error) {
tag := fmt.Sprintf("v%s", cg.Cookbook.Version)

if !cg.SourceCookbook.tagged {
mail := fmt.Sprintf("%s@%s", cg.User, getEffectiveConfig("MailDomain", cg.Organization).(string))
err := tagCookbook(cg.SourceCookbook.gitOrg, cg.Cookbook.Name, tag, cg.User, mail)
mail := fmt.Sprintf("%s@%s", cg.User, getEffectiveConfig("MailDomain", cg.ChefOrg).(string))
err := tagCookbook(cg.SourceCookbook.gitConfig, cg.Cookbook.Name, tag, cg.User, mail)
if err != nil {
return http.StatusBadGateway, err
}
}
if getEffectiveConfig("PublishCookbook", cg.Organization).(bool) && cg.SourceCookbook.private {
if getEffectiveConfig("PublishCookbook", cg.ChefOrg).(bool) && cg.SourceCookbook.private {
if err := cg.publishCookbook(); err != nil {
errText := err.Error()
if !cg.SourceCookbook.tagged {
err := untagCookbook(cg.SourceCookbook.gitOrg, cg.Cookbook.Name, tag)
err := untagCookbook(cg.SourceCookbook.gitConfig, cg.Cookbook.Name, tag)
if err != nil {
errText = fmt.Sprintf("%s - NOTE: Failed to untag the repo during cleanup!", errText)
}
Expand All @@ -292,7 +292,7 @@ func (cg *ChefGuard) getCookbookChangeDetails(r *http.Request) []byte {

source := "N/A"
if cg.SourceCookbook != nil {
source = cg.SourceCookbook.DownloadURL.String()
source = strings.Split(cg.SourceCookbook.DownloadURL.String(), "&")[0]
}

details := fmt.Sprintf(
Expand Down

0 comments on commit 77c3374

Please sign in to comment.