<commit_before>// Copyright 2019 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 cache

import (
	"context"
	"fmt"

	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/lsp/telemetry"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
	"golang.org/x/tools/internal/telemetry/trace"
	errors "golang.org/x/xerrors"
)

func (view *view) loadParseTypecheck(ctx context.Context, f *goFile, fh source.FileHandle) error {
	ctx, done := trace.StartSpan(ctx, "cache.view.loadParseTypeCheck", telemetry.URI.Of(f.URI()))
	defer done()

	meta, err := view.load(ctx, f, fh)
	if err != nil {
		return err
	}
	for _, m := range meta {
		imp := &importer{
			view:              view,
			config:            view.Config(ctx),
			seen:              make(map[packageID]struct{}),
			topLevelPackageID: m.id,
		}
		cph, err := imp.checkPackageHandle(ctx, m)
		if err != nil {
			log.Error(ctx, "loadParseTypeCheck: failed to get CheckPackageHandle", err, telemetry.Package.Of(m.id))
			continue
		}
		if _, err := cph.check(ctx); err != nil {
			log.Error(ctx, "loadParseTypeCheck: failed to check package", err, telemetry.Package.Of(m.id))
			continue
		}
		// Cache this package on the file object, since all dependencies are cached in the Import function.
		if err := imp.cachePackage(ctx, cph); err != nil {
			log.Error(ctx, "loadParseTypeCheck: failed to cache package", err, telemetry.Package.Of(m.id))
			continue
		}
	}
	return nil
}

func (view *view) load(ctx context.Context, f *goFile, fh source.FileHandle) ([]*metadata, error) {
	ctx, done := trace.StartSpan(ctx, "cache.view.load", telemetry.URI.Of(f.URI()))
	defer done()

	view.mu.Lock()
	defer view.mu.Unlock()

	view.mcache.mu.Lock()
	defer view.mcache.mu.Unlock()

	var toDelete []packageID
	f.mu.Lock()
	for id, cph := range f.pkgs {
		if cph != nil {
			toDelete = append(toDelete, id)
		}
	}
	f.mu.Unlock()

	// If the AST for this file is trimmed, and we are explicitly type-checking it,
	// don't ignore function bodies.
	if f.wrongParseMode(ctx, fh, source.ParseFull) {
		// Remove the package and all of its reverse dependencies from the cache.
		for _, id := range toDelete {
			f.view.remove(ctx, id, map[packageID]struct{}{})
		}
	}

	// Get the metadata for the file.
	meta, err := view.checkMetadata(ctx, f, fh)
	if err != nil {
		return nil, err
	}
	if len(meta) == 0 {
		return nil, fmt.Errorf("no package metadata found for %s", f.URI())
	}
	return meta, nil
}

// checkMetadata determines if we should run go/packages.Load for this file.
// If yes, update the metadata for the file and its package.
func (v *view) checkMetadata(ctx context.Context, f *goFile, fh source.FileHandle) ([]*metadata, error) {
	// Check if we need to re-run go/packages before loading the package.
	f.mu.Lock()
	runGopackages := v.shouldRunGopackages(ctx, f, fh)
	metadata := f.metadata()
	f.mu.Unlock()

	// The package metadata is correct as-is, so just return it.
	if !runGopackages {
		return metadata, nil
	}

	// Check if the context has been canceled before calling packages.Load.
	if ctx.Err() != nil {
		return nil, ctx.Err()
	}

	ctx, done := trace.StartSpan(ctx, "packages.Load", telemetry.File.Of(f.filename()))
	defer done()
	pkgs, err := packages.Load(v.Config(ctx), fmt.Sprintf("file=%s", f.filename()))
	if len(pkgs) == 0 {
		if err == nil {
			err = errors.Errorf("go/packages.Load: no packages found for %s", f.filename())
		}
		// Return this error as a diagnostic to the user.
		return nil, err
	}
	// Track missing imports as we look at the package's errors.
	missingImports := make(map[packagePath]struct{})

	log.Print(ctx, "go/packages.Load", tag.Of("packages", len(pkgs)))
	for _, pkg := range pkgs {
		log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
		// Build the import graph for this package.
		if err := v.link(ctx, &importGraph{
			pkgPath:        packagePath(pkg.PkgPath),
			pkg:            pkg,
			parent:         nil,
			missingImports: make(map[packagePath]struct{}),
		}); err != nil {
			return nil, err
		}
	}
	m, err := validateMetadata(ctx, missingImports, f)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func validateMetadata(ctx context.Context, missingImports map[packagePath]struct{}, f *goFile) ([]*metadata, error) {
	f.mu.Lock()
	defer f.mu.Unlock()

	// If `go list` failed to get data for the file in question (this should never happen).
	if len(f.meta) == 0 {
		return nil, errors.Errorf("loadParseTypecheck: no metadata found for %v", f.filename())
	}

	// If we have already seen these missing imports before, and we have type information,
	// there is no need to continue.
	if sameSet(missingImports, f.missingImports) && len(f.pkgs) != 0 {
		return nil, nil
	}

	// Otherwise, update the missing imports map.
	f.missingImports = missingImports

	return f.metadata(), nil
}

func sameSet(x, y map[packagePath]struct{}) bool {
	if len(x) != len(y) {
		return false
	}
	for k := range x {
		if _, ok := y[k]; !ok {
			return false
		}
	}
	return true
}

// shouldRunGopackages reparses a file's package and import declarations to
// determine if they have changed.
// It assumes that the caller holds the lock on the f.mu lock.
func (v *view) shouldRunGopackages(ctx context.Context, f *goFile, fh source.FileHandle) (result bool) {
	defer func() {
		// Clear metadata if we are intending to re-run go/packages.
		if result {
			// Reset the file's metadata and type information if we are re-running `go list`.
			for k := range f.meta {
				delete(f.meta, k)
			}
			for k := range f.pkgs {
				delete(f.pkgs, k)
			}
		}
	}()

	if len(f.meta) == 0 || len(f.missingImports) > 0 {
		return true
	}
	// Get file content in case we don't already have it.
	parsed, err := v.session.cache.ParseGoHandle(fh, source.ParseHeader).Parse(ctx)
	if err == context.Canceled {
		log.Error(ctx, "parsing file header", err, tag.Of("file", f.URI()))
		return false
	}
	if parsed == nil {
		return true
	}
	// Check if the package's name has changed, by checking if this is a filename
	// we already know about, and if so, check if its package name has changed.
	for _, m := range f.meta {
		for _, uri := range m.files {
			if span.CompareURI(uri, f.URI()) == 0 {
				if m.name != parsed.Name.Name {
					return true
				}
			}
		}
	}
	// If the package's imports have changed, re-run `go list`.
	if len(f.imports) != len(parsed.Imports) {
		return true
	}
	for i, importSpec := range f.imports {
		if importSpec.Path.Value != parsed.Imports[i].Path.Value {
			return true
		}
	}
	return false
}

type importGraph struct {
	pkgPath        packagePath
	pkg            *packages.Package
	parent         *metadata
	missingImports map[packagePath]struct{}
}

func (v *view) link(ctx context.Context, g *importGraph) error {
	// Recreate the metadata rather than reusing it to avoid locking.
	m := &metadata{
		id:         packageID(g.pkg.ID),
		pkgPath:    g.pkgPath,
		name:       g.pkg.Name,
		typesSizes: g.pkg.TypesSizes,
		errors:     g.pkg.Errors,
	}
	for _, filename := range g.pkg.CompiledGoFiles {
		m.files = append(m.files, span.FileURI(filename))

		// Call the unlocked version of getFile since we are holding the view's mutex.
		f, err := v.getFile(ctx, span.FileURI(filename))
		if err != nil {
			log.Error(ctx, "no file", err, telemetry.File.Of(filename))
			continue
		}
		gof, ok := f.(*goFile)
		if !ok {
			log.Error(ctx, "not a Go file", nil, telemetry.File.Of(filename))
			continue
		}
		// Cache the metadata for this file.
		gof.mu.Lock()
		if gof.meta == nil {
			gof.meta = make(map[packageID]*metadata)
		}
		gof.meta[m.id] = m
		gof.mu.Unlock()
	}

	// Preserve the import graph.
	if original, ok := v.mcache.packages[m.id]; ok {
		m.children = original.children
		m.parents = original.parents
	}
	if m.children == nil {
		m.children = make(map[packageID]*metadata)
	}
	if m.parents == nil {
		m.parents = make(map[packageID]bool)
	}

	// Add the metadata to the cache.
	v.mcache.packages[m.id] = m
	v.mcache.ids[g.pkgPath] = m.id

	// Connect the import graph.
	if g.parent != nil {
		m.parents[g.parent.id] = true
		g.parent.children[m.id] = m
	}
	for importPath, importPkg := range g.pkg.Imports {
		importPkgPath := packagePath(importPath)
		if importPkgPath == g.pkgPath {
			return fmt.Errorf("cycle detected in %s", importPath)
		}
		// Don't remember any imports with significant errors.
		if importPkgPath != "unsafe" && len(importPkg.CompiledGoFiles) == 0 {
			g.missingImports[importPkgPath] = struct{}{}
			continue
		}
		if _, ok := m.children[packageID(importPkg.ID)]; !ok {
			if err := v.link(ctx, &importGraph{
				pkgPath:        importPkgPath,
				pkg:            importPkg,
				parent:         m,
				missingImports: g.missingImports,
			}); err != nil {
				log.Error(ctx, "error in dependecny", err)
			}
		}
	}
	// Clear out any imports that have been removed since the package was last loaded.
	for importID := range m.children {
		child, ok := v.mcache.packages[importID]
		if !ok {
			continue
		}
		importPath := string(child.pkgPath)
		if _, ok := g.pkg.Imports[importPath]; ok {
			continue
		}
		delete(m.children, importID)
		delete(child.parents, m.id)
	}
	return nil
}

func identicalFileHandles(old, new []source.ParseGoHandle) bool {
	if len(old) != len(new) {
		return false
	}
	oldByIdentity := make(map[string]struct{}, len(old))
	for _, ph := range old {
		oldByIdentity[hashParseKey(ph)] = struct{}{}
	}
	for _, ph := range new {
		if _, found := oldByIdentity[hashParseKey(ph)]; !found {
			return false
		}
		delete(oldByIdentity, hashParseKey(ph))
	}
	return len(oldByIdentity) == 0
}
<commit_msg>internal/lsp: avoid invalid state due to context cancelation<commit_after>// Copyright 2019 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 cache

import (
	"context"
	"fmt"

	"golang.org/x/tools/go/packages"
	"golang.org/x/tools/internal/lsp/source"
	"golang.org/x/tools/internal/lsp/telemetry"
	"golang.org/x/tools/internal/span"
	"golang.org/x/tools/internal/telemetry/log"
	"golang.org/x/tools/internal/telemetry/tag"
	"golang.org/x/tools/internal/telemetry/trace"
	errors "golang.org/x/xerrors"
)

func (view *view) loadParseTypecheck(ctx context.Context, f *goFile, fh source.FileHandle) error {
	ctx, done := trace.StartSpan(ctx, "cache.view.loadParseTypeCheck", telemetry.URI.Of(f.URI()))
	defer done()

	meta, err := view.load(ctx, f, fh)
	if err != nil {
		return err
	}
	for _, m := range meta {
		imp := &importer{
			view:              view,
			config:            view.Config(ctx),
			seen:              make(map[packageID]struct{}),
			topLevelPackageID: m.id,
		}
		cph, err := imp.checkPackageHandle(ctx, m)
		if err != nil {
			log.Error(ctx, "loadParseTypeCheck: failed to get CheckPackageHandle", err, telemetry.Package.Of(m.id))
			continue
		}
		if _, err := cph.check(ctx); err != nil {
			log.Error(ctx, "loadParseTypeCheck: failed to check package", err, telemetry.Package.Of(m.id))
			continue
		}
		// Cache this package on the file object, since all dependencies are cached in the Import function.
		if err := imp.cachePackage(ctx, cph); err != nil {
			log.Error(ctx, "loadParseTypeCheck: failed to cache package", err, telemetry.Package.Of(m.id))
			continue
		}
	}
	return nil
}

func (view *view) load(ctx context.Context, f *goFile, fh source.FileHandle) ([]*metadata, error) {
	ctx, done := trace.StartSpan(ctx, "cache.view.load", telemetry.URI.Of(f.URI()))
	defer done()

	view.mu.Lock()
	defer view.mu.Unlock()

	view.mcache.mu.Lock()
	defer view.mcache.mu.Unlock()

	var toDelete []packageID
	f.mu.Lock()
	for id, cph := range f.pkgs {
		if cph != nil {
			toDelete = append(toDelete, id)
		}
	}
	f.mu.Unlock()

	// If the AST for this file is trimmed, and we are explicitly type-checking it,
	// don't ignore function bodies.
	if f.wrongParseMode(ctx, fh, source.ParseFull) {
		// Remove the package and all of its reverse dependencies from the cache.
		for _, id := range toDelete {
			f.view.remove(ctx, id, map[packageID]struct{}{})
		}
	}

	// Get the metadata for the file.
	meta, err := view.checkMetadata(ctx, f, fh)
	if err != nil {
		return nil, err
	}
	if len(meta) == 0 {
		return nil, fmt.Errorf("no package metadata found for %s", f.URI())
	}
	return meta, nil
}

// checkMetadata determines if we should run go/packages.Load for this file.
// If yes, update the metadata for the file and its package.
func (v *view) checkMetadata(ctx context.Context, f *goFile, fh source.FileHandle) ([]*metadata, error) {
	// Check if we need to re-run go/packages before loading the package.
	f.mu.Lock()
	runGopackages := v.shouldRunGopackages(ctx, f, fh)
	metadata := f.metadata()
	f.mu.Unlock()

	// The package metadata is correct as-is, so just return it.
	if !runGopackages {
		return metadata, nil
	}

	// Check if the context has been canceled before calling packages.Load.
	if ctx.Err() != nil {
		return nil, ctx.Err()
	}

	ctx, done := trace.StartSpan(ctx, "packages.Load", telemetry.File.Of(f.filename()))
	defer done()
	pkgs, err := packages.Load(v.Config(ctx), fmt.Sprintf("file=%s", f.filename()))
	if len(pkgs) == 0 {
		if err == nil {
			err = errors.Errorf("go/packages.Load: no packages found for %s", f.filename())
		}
		// Return this error as a diagnostic to the user.
		return nil, err
	}
	// Track missing imports as we look at the package's errors.
	missingImports := make(map[packagePath]struct{})

	// Clear metadata since we are re-running go/packages.
	// Reset the file's metadata and type information if we are re-running `go list`.
	f.mu.Lock()
	for k := range f.meta {
		delete(f.meta, k)
	}
	for k := range f.pkgs {
		delete(f.pkgs, k)
	}
	f.mu.Unlock()

	log.Print(ctx, "go/packages.Load", tag.Of("packages", len(pkgs)))
	for _, pkg := range pkgs {
		log.Print(ctx, "go/packages.Load", tag.Of("package", pkg.PkgPath), tag.Of("files", pkg.CompiledGoFiles))
		// Build the import graph for this package.
		if err := v.link(ctx, &importGraph{
			pkgPath:        packagePath(pkg.PkgPath),
			pkg:            pkg,
			parent:         nil,
			missingImports: make(map[packagePath]struct{}),
		}); err != nil {
			return nil, err
		}
	}
	m, err := validateMetadata(ctx, missingImports, f)
	if err != nil {
		return nil, err
	}
	return m, nil
}

func validateMetadata(ctx context.Context, missingImports map[packagePath]struct{}, f *goFile) ([]*metadata, error) {
	f.mu.Lock()
	defer f.mu.Unlock()

	// If `go list` failed to get data for the file in question (this should never happen).
	if len(f.meta) == 0 {
		return nil, errors.Errorf("loadParseTypecheck: no metadata found for %v", f.filename())
	}

	// If we have already seen these missing imports before, and we have type information,
	// there is no need to continue.
	if sameSet(missingImports, f.missingImports) && len(f.pkgs) != 0 {
		return nil, nil
	}

	// Otherwise, update the missing imports map.
	f.missingImports = missingImports

	return f.metadata(), nil
}

func sameSet(x, y map[packagePath]struct{}) bool {
	if len(x) != len(y) {
		return false
	}
	for k := range x {
		if _, ok := y[k]; !ok {
			return false
		}
	}
	return true
}

// shouldRunGopackages reparses a file's package and import declarations to
// determine if they have changed.
// It assumes that the caller holds the lock on the f.mu lock.
func (v *view) shouldRunGopackages(ctx context.Context, f *goFile, fh source.FileHandle) (result bool) {
	if len(f.meta) == 0 || len(f.missingImports) > 0 {
		return true
	}
	// Get file content in case we don't already have it.
	parsed, err := v.session.cache.ParseGoHandle(fh, source.ParseHeader).Parse(ctx)
	if err == context.Canceled {
		log.Error(ctx, "parsing file header", err, tag.Of("file", f.URI()))
		return false
	}
	if parsed == nil {
		return true
	}
	// Check if the package's name has changed, by checking if this is a filename
	// we already know about, and if so, check if its package name has changed.
	for _, m := range f.meta {
		for _, uri := range m.files {
			if span.CompareURI(uri, f.URI()) == 0 {
				if m.name != parsed.Name.Name {
					return true
				}
			}
		}
	}
	// If the package's imports have changed, re-run `go list`.
	if len(f.imports) != len(parsed.Imports) {
		return true
	}
	for i, importSpec := range f.imports {
		if importSpec.Path.Value != parsed.Imports[i].Path.Value {
			return true
		}
	}
	return false
}

type importGraph struct {
	pkgPath        packagePath
	pkg            *packages.Package
	parent         *metadata
	missingImports map[packagePath]struct{}
}

func (v *view) link(ctx context.Context, g *importGraph) error {
	// Recreate the metadata rather than reusing it to avoid locking.
	m := &metadata{
		id:         packageID(g.pkg.ID),
		pkgPath:    g.pkgPath,
		name:       g.pkg.Name,
		typesSizes: g.pkg.TypesSizes,
		errors:     g.pkg.Errors,
	}
	for _, filename := range g.pkg.CompiledGoFiles {
		m.files = append(m.files, span.FileURI(filename))

		// Call the unlocked version of getFile since we are holding the view's mutex.
		f, err := v.getFile(ctx, span.FileURI(filename))
		if err != nil {
			log.Error(ctx, "no file", err, telemetry.File.Of(filename))
			continue
		}
		gof, ok := f.(*goFile)
		if !ok {
			log.Error(ctx, "not a Go file", nil, telemetry.File.Of(filename))
			continue
		}
		// Cache the metadata for this file.
		gof.mu.Lock()
		if gof.meta == nil {
			gof.meta = make(map[packageID]*metadata)
		}
		gof.meta[m.id] = m
		gof.mu.Unlock()
	}

	// Preserve the import graph.
	if original, ok := v.mcache.packages[m.id]; ok {
		m.children = original.children
		m.parents = original.parents
	}
	if m.children == nil {
		m.children = make(map[packageID]*metadata)
	}
	if m.parents == nil {
		m.parents = make(map[packageID]bool)
	}

	// Add the metadata to the cache.
	v.mcache.packages[m.id] = m
	v.mcache.ids[g.pkgPath] = m.id

	// Connect the import graph.
	if g.parent != nil {
		m.parents[g.parent.id] = true
		g.parent.children[m.id] = m
	}
	for importPath, importPkg := range g.pkg.Imports {
		importPkgPath := packagePath(importPath)
		if importPkgPath == g.pkgPath {
			return fmt.Errorf("cycle detected in %s", importPath)
		}
		// Don't remember any imports with significant errors.
		if importPkgPath != "unsafe" && len(importPkg.CompiledGoFiles) == 0 {
			g.missingImports[importPkgPath] = struct{}{}
			continue
		}
		if _, ok := m.children[packageID(importPkg.ID)]; !ok {
			if err := v.link(ctx, &importGraph{
				pkgPath:        importPkgPath,
				pkg:            importPkg,
				parent:         m,
				missingImports: g.missingImports,
			}); err != nil {
				log.Error(ctx, "error in dependecny", err)
			}
		}
	}
	// Clear out any imports that have been removed since the package was last loaded.
	for importID := range m.children {
		child, ok := v.mcache.packages[importID]
		if !ok {
			continue
		}
		importPath := string(child.pkgPath)
		if _, ok := g.pkg.Imports[importPath]; ok {
			continue
		}
		delete(m.children, importID)
		delete(child.parents, m.id)
	}
	return nil
}

func identicalFileHandles(old, new []source.ParseGoHandle) bool {
	if len(old) != len(new) {
		return false
	}
	oldByIdentity := make(map[string]struct{}, len(old))
	for _, ph := range old {
		oldByIdentity[hashParseKey(ph)] = struct{}{}
	}
	for _, ph := range new {
		if _, found := oldByIdentity[hashParseKey(ph)]; !found {
			return false
		}
		delete(oldByIdentity, hashParseKey(ph))
	}
	return len(oldByIdentity) == 0
}
<|endoftext|>


<commit_before>// Copyright 2020-2021 Buf Technologies, Inc.
//
// 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 git

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"os/exec"
	"strconv"
	"strings"

	"github.com/bufbuild/buf/internal/pkg/app"
	"github.com/bufbuild/buf/internal/pkg/storage"
	"github.com/bufbuild/buf/internal/pkg/storage/storageos"
	"github.com/bufbuild/buf/internal/pkg/tmp"
	"go.opencensus.io/trace"
	"go.uber.org/multierr"
	"go.uber.org/zap"
)

// bufCloneOrigin is the name for the remote. It helps distinguish the origin of
// the repo we're cloning from the "origin" of our clone (which is the repo
// being cloned).
const bufCloneOrigin = "bufCloneOrigin"

type cloner struct {
	logger            *zap.Logger
	storageosProvider storageos.Provider
	options           ClonerOptions
}

func newCloner(
	logger *zap.Logger,
	storageosProvider storageos.Provider,
	options ClonerOptions,
) *cloner {
	return &cloner{
		logger:            logger,
		storageosProvider: storageosProvider,
		options:           options,
	}
}

func (c *cloner) CloneToBucket(
	ctx context.Context,
	envContainer app.EnvContainer,
	url string,
	depth uint32,
	writeBucket storage.WriteBucket,
	options CloneToBucketOptions,
) (retErr error) {
	ctx, span := trace.StartSpan(ctx, "git_clone_to_bucket")
	defer span.End()

	var err error
	switch {
	case strings.HasPrefix(url, "http://"),
		strings.HasPrefix(url, "https://"),
		strings.HasPrefix(url, "ssh://"),
		strings.HasPrefix(url, "git://"),
		strings.HasPrefix(url, "file://"):
	default:
		return fmt.Errorf("invalid git url: %q", url)
	}

	if depth == 0 {
		return errors.New("depth must be > 0")
	}

	depthArg := strconv.Itoa(int(depth))

	tmpDir, err := tmp.NewDir()
	if err != nil {
		return err
	}
	defer func() {
		retErr = multierr.Append(retErr, tmpDir.Close())
	}()

	buffer := bytes.NewBuffer(nil)
	cmd := exec.CommandContext(ctx, "git", "init")
	cmd.Dir = tmpDir.AbsPath()
	cmd.Env = app.Environ(envContainer)
	cmd.Stderr = buffer
	if err := cmd.Run(); err != nil {
		return newGitCommandError(err, buffer, tmpDir)
	}

	buffer.Reset()
	cmd = exec.CommandContext(ctx, "git", "remote", "add", bufCloneOrigin, url)
	cmd.Dir = tmpDir.AbsPath()
	cmd.Env = app.Environ(envContainer)
	cmd.Stderr = buffer
	if err := cmd.Run(); err != nil {
		return newGitCommandError(err, buffer, tmpDir)
	}

	var args []string
	if strings.HasPrefix(url, "https://") {
		// These extraArgs MUST be first, as the -c flag potentially produced
		// is only a flag on the parent git command, not on git fetch.
		extraArgs, err := c.getArgsForHTTPSCommand(envContainer)
		if err != nil {
			return err
		}
		args = append(args, extraArgs...)
	}
	fetchRef, checkoutRefs := getRefspecsForName(options.Name)
	args = append(
		args,
		"fetch",
		"--depth", depthArg,
		bufCloneOrigin,
		fetchRef,
	)

	if strings.HasPrefix(url, "ssh://") {
		envContainer, err = c.getEnvContainerWithGitSSHCommand(envContainer)
		if err != nil {
			return err
		}
	}

	buffer.Reset()
	cmd = exec.CommandContext(ctx, "git", args...)
	cmd.Dir = tmpDir.AbsPath()
	cmd.Env = app.Environ(envContainer)
	cmd.Stderr = buffer
	if err := cmd.Run(); err != nil {
		return newGitCommandError(err, buffer, tmpDir)
	}

	for _, checkoutRef := range checkoutRefs {
		buffer.Reset()
		cmd = exec.CommandContext(ctx, "git", "checkout", checkoutRef)
		cmd.Dir = tmpDir.AbsPath()
		cmd.Env = app.Environ(envContainer)
		cmd.Stderr = buffer
		if err := cmd.Run(); err != nil {
			return newGitCommandError(err, buffer, tmpDir)
		}
	}

	if options.RecurseSubmodules {
		args = []string{
			"submodule",
			"update",
			"--init",
			"--recursive",
			"--depth",
			depthArg,
		}
		buffer.Reset()
		cmd = exec.CommandContext(ctx, "git", args...)
		cmd.Env = app.Environ(envContainer)
		cmd.Dir = tmpDir.AbsPath()
		cmd.Stderr = buffer
		if err := cmd.Run(); err != nil {
			// Suppress printing of temp path
			return fmt.Errorf("%v\n%v", err, strings.Replace(buffer.String(), tmpDir.AbsPath(), "", -1))
		}
	}

	// we do NOT want to read in symlinks
	tmpReadWriteBucket, err := c.storageosProvider.NewReadWriteBucket(tmpDir.AbsPath())
	if err != nil {
		return err
	}
	var readBucket storage.ReadBucket = tmpReadWriteBucket
	if options.Mapper != nil {
		readBucket = storage.MapReadBucket(readBucket, options.Mapper)
	}
	ctx, span2 := trace.StartSpan(ctx, "git_clone_to_bucket_copy")
	defer span2.End()
	// do NOT copy external paths
	_, err = storage.Copy(ctx, readBucket, writeBucket)
	return err
}

func (c *cloner) getArgsForHTTPSCommand(envContainer app.EnvContainer) ([]string, error) {
	if c.options.HTTPSUsernameEnvKey == "" || c.options.HTTPSPasswordEnvKey == "" {
		return nil, nil
	}
	httpsUsernameSet := envContainer.Env(c.options.HTTPSUsernameEnvKey) != ""
	httpsPasswordSet := envContainer.Env(c.options.HTTPSPasswordEnvKey) != ""
	if !httpsUsernameSet {
		if httpsPasswordSet {
			return nil, fmt.Errorf("%s set but %s not set", c.options.HTTPSPasswordEnvKey, c.options.HTTPSUsernameEnvKey)
		}
		return nil, nil
	}
	c.logger.Debug("git_credential_helper_override")
	return []string{
		"-c",
		fmt.Sprintf(
			// TODO: is this OK for windows/other platforms?
			// we might need an alternate flow where the binary has a sub-command to do this, and calls itself
			//
			// putting the variable name in this script, NOT the actual variable value
			// we do not want to store the variable on disk, ever
			// this is especially important if the program dies
			// note that this means i.e. HTTPS_PASSWORD=foo invoke_program does not work as
			// this variable needs to be in the actual global environment
			// TODO this is a mess
			"credential.helper=!f(){ echo username=${%s}; echo password=${%s}; };f",
			c.options.HTTPSUsernameEnvKey,
			c.options.HTTPSPasswordEnvKey,
		),
	}, nil
}

func (c *cloner) getEnvContainerWithGitSSHCommand(envContainer app.EnvContainer) (app.EnvContainer, error) {
	gitSSHCommand, err := c.getGitSSHCommand(envContainer)
	if err != nil {
		return nil, err
	}
	if gitSSHCommand != "" {
		c.logger.Debug("git_ssh_command_override")
		return app.NewEnvContainerWithOverrides(
			envContainer,
			map[string]string{
				"GIT_SSH_COMMAND": gitSSHCommand,
			},
		), nil
	}
	return envContainer, nil
}

func (c *cloner) getGitSSHCommand(envContainer app.EnvContainer) (string, error) {
	sshKeyFilePath := envContainer.Env(c.options.SSHKeyFileEnvKey)
	sshKnownHostsFiles := envContainer.Env(c.options.SSHKnownHostsFilesEnvKey)
	if sshKeyFilePath == "" {
		if sshKnownHostsFiles != "" {
			return "", fmt.Errorf("%s set but %s not set", c.options.SSHKnownHostsFilesEnvKey, c.options.SSHKeyFileEnvKey)
		}
		return "", nil
	}
	if sshKnownHostsFilePaths := getSSHKnownHostsFilePaths(sshKnownHostsFiles); len(sshKnownHostsFilePaths) > 0 {
		return fmt.Sprintf(
			`ssh -q -i "%s" -o "IdentitiesOnly=yes" -o "UserKnownHostsFile=%s"`,
			sshKeyFilePath,
			strings.Join(sshKnownHostsFilePaths, " "),
		), nil
	}
	// we want to set StrictHostKeyChecking=no because the SSH key file variable was set, so
	// there is an ask to override the default ssh settings here
	return fmt.Sprintf(
		`ssh -q -i "%s" -o "IdentitiesOnly=yes" -o "UserKnownHostsFile=%s" -o "StrictHostKeyChecking=no"`,
		sshKeyFilePath,
		app.DevNullFilePath,
	), nil
}

func getSSHKnownHostsFilePaths(sshKnownHostsFiles string) []string {
	if sshKnownHostsFiles == "" {
		return nil
	}
	var filePaths []string
	for _, filePath := range strings.Split(sshKnownHostsFiles, ":") {
		filePath = strings.TrimSpace(filePath)
		if filePath != "" {
			filePaths = append(filePaths, filePath)
		}
	}
	return filePaths
}

func getRefspecsForName(gitName Name) (string, []string) {
	if gitName == nil {
		return "HEAD", []string{"FETCH_HEAD"}
	}
	if gitName.cloneBranch() != "" && gitName.checkout() != "" {
		// When doing branch/tag clones, make sure we use a
		// refspec that creates a local referece in `refs/` even if the ref
		// is remote tracking, so that the checkoutRefs may reference it,
		// for example:
		//   branch=origin/main,ref=origin/main~1
		fetchRefSpec := gitName.cloneBranch() + ":" + gitName.cloneBranch()
		return fetchRefSpec, []string{"FETCH_HEAD", gitName.checkout()}
	} else if gitName.cloneBranch() != "" {
		return gitName.cloneBranch(), []string{"FETCH_HEAD"}
	} else if gitName.checkout() != "" {
		// After fetch we won't have checked out any refs. This
		// will cause `refs=` containing "HEAD" to fail, as HEAD
		// is a special case that is not fetched into a ref but
		// instead refers to the current commit checked out. By
		// checking out "FETCH_HEAD" before checking out the
		// user supplied ref, we behave similarly to git clone.
		return "HEAD", []string{"FETCH_HEAD", gitName.checkout()}
	} else {
		return "HEAD", []string{"FETCH_HEAD"}
	}
}

func newGitCommandError(
	err error,
	buffer *bytes.Buffer,
	tmpDir tmp.Dir,
) error {
	// Suppress printing of temp path
	return fmt.Errorf("%v\n%v", err, strings.TrimSpace(strings.Replace(buffer.String(), tmpDir.AbsPath(), "", -1)))
}
<commit_msg>Add git args for http auth to checkout/submodule (#394)<commit_after>// Copyright 2020-2021 Buf Technologies, Inc.
//
// 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 git

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"os/exec"
	"strconv"
	"strings"

	"github.com/bufbuild/buf/internal/pkg/app"
	"github.com/bufbuild/buf/internal/pkg/storage"
	"github.com/bufbuild/buf/internal/pkg/storage/storageos"
	"github.com/bufbuild/buf/internal/pkg/tmp"
	"go.opencensus.io/trace"
	"go.uber.org/multierr"
	"go.uber.org/zap"
)

// bufCloneOrigin is the name for the remote. It helps distinguish the origin of
// the repo we're cloning from the "origin" of our clone (which is the repo
// being cloned).
const bufCloneOrigin = "bufCloneOrigin"

type cloner struct {
	logger            *zap.Logger
	storageosProvider storageos.Provider
	options           ClonerOptions
}

func newCloner(
	logger *zap.Logger,
	storageosProvider storageos.Provider,
	options ClonerOptions,
) *cloner {
	return &cloner{
		logger:            logger,
		storageosProvider: storageosProvider,
		options:           options,
	}
}

func (c *cloner) CloneToBucket(
	ctx context.Context,
	envContainer app.EnvContainer,
	url string,
	depth uint32,
	writeBucket storage.WriteBucket,
	options CloneToBucketOptions,
) (retErr error) {
	ctx, span := trace.StartSpan(ctx, "git_clone_to_bucket")
	defer span.End()

	var err error
	switch {
	case strings.HasPrefix(url, "http://"),
		strings.HasPrefix(url, "https://"),
		strings.HasPrefix(url, "ssh://"),
		strings.HasPrefix(url, "git://"),
		strings.HasPrefix(url, "file://"):
	default:
		return fmt.Errorf("invalid git url: %q", url)
	}

	if depth == 0 {
		return errors.New("depth must be > 0")
	}

	depthArg := strconv.Itoa(int(depth))

	tmpDir, err := tmp.NewDir()
	if err != nil {
		return err
	}
	defer func() {
		retErr = multierr.Append(retErr, tmpDir.Close())
	}()

	buffer := bytes.NewBuffer(nil)
	cmd := exec.CommandContext(ctx, "git", "init")
	cmd.Dir = tmpDir.AbsPath()
	cmd.Env = app.Environ(envContainer)
	cmd.Stderr = buffer
	if err := cmd.Run(); err != nil {
		return newGitCommandError(err, buffer, tmpDir)
	}

	buffer.Reset()
	cmd = exec.CommandContext(ctx, "git", "remote", "add", bufCloneOrigin, url)
	cmd.Dir = tmpDir.AbsPath()
	cmd.Env = app.Environ(envContainer)
	cmd.Stderr = buffer
	if err := cmd.Run(); err != nil {
		return newGitCommandError(err, buffer, tmpDir)
	}

	var gitConfigAuthArgs []string
	if strings.HasPrefix(url, "https://") {
		// These extraArgs MUST be first, as the -c flag potentially produced
		// is only a flag on the parent git command, not on git fetch.
		extraArgs, err := c.getArgsForHTTPSCommand(envContainer)
		if err != nil {
			return err
		}
		gitConfigAuthArgs = append(gitConfigAuthArgs, extraArgs...)
	}
	fetchRef, checkoutRefs := getRefspecsForName(options.Name)
	fetchArgs := append(
		gitConfigAuthArgs,
		"fetch",
		"--depth", depthArg,
		bufCloneOrigin,
		fetchRef,
	)

	if strings.HasPrefix(url, "ssh://") {
		envContainer, err = c.getEnvContainerWithGitSSHCommand(envContainer)
		if err != nil {
			return err
		}
	}

	buffer.Reset()
	cmd = exec.CommandContext(ctx, "git", fetchArgs...)
	cmd.Dir = tmpDir.AbsPath()
	cmd.Env = app.Environ(envContainer)
	cmd.Stderr = buffer
	if err := cmd.Run(); err != nil {
		return newGitCommandError(err, buffer, tmpDir)
	}

	for _, checkoutRef := range checkoutRefs {
		buffer.Reset()
		args := append(
			gitConfigAuthArgs,
			"checkout",
			checkoutRef,
		)
		cmd = exec.CommandContext(ctx, "git", args...)
		cmd.Dir = tmpDir.AbsPath()
		cmd.Env = app.Environ(envContainer)
		cmd.Stderr = buffer
		if err := cmd.Run(); err != nil {
			return newGitCommandError(err, buffer, tmpDir)
		}
	}

	if options.RecurseSubmodules {
		submoduleArgs := append(
			gitConfigAuthArgs,
			"submodule",
			"update",
			"--init",
			"--recursive",
			"--depth",
			depthArg,
		)
		buffer.Reset()
		cmd = exec.CommandContext(ctx, "git", submoduleArgs...)
		cmd.Env = app.Environ(envContainer)
		cmd.Dir = tmpDir.AbsPath()
		cmd.Stderr = buffer
		if err := cmd.Run(); err != nil {
			// Suppress printing of temp path
			return fmt.Errorf("%v\n%v", err, strings.Replace(buffer.String(), tmpDir.AbsPath(), "", -1))
		}
	}

	// we do NOT want to read in symlinks
	tmpReadWriteBucket, err := c.storageosProvider.NewReadWriteBucket(tmpDir.AbsPath())
	if err != nil {
		return err
	}
	var readBucket storage.ReadBucket = tmpReadWriteBucket
	if options.Mapper != nil {
		readBucket = storage.MapReadBucket(readBucket, options.Mapper)
	}
	ctx, span2 := trace.StartSpan(ctx, "git_clone_to_bucket_copy")
	defer span2.End()
	// do NOT copy external paths
	_, err = storage.Copy(ctx, readBucket, writeBucket)
	return err
}

func (c *cloner) getArgsForHTTPSCommand(envContainer app.EnvContainer) ([]string, error) {
	if c.options.HTTPSUsernameEnvKey == "" || c.options.HTTPSPasswordEnvKey == "" {
		return nil, nil
	}
	httpsUsernameSet := envContainer.Env(c.options.HTTPSUsernameEnvKey) != ""
	httpsPasswordSet := envContainer.Env(c.options.HTTPSPasswordEnvKey) != ""
	if !httpsUsernameSet {
		if httpsPasswordSet {
			return nil, fmt.Errorf("%s set but %s not set", c.options.HTTPSPasswordEnvKey, c.options.HTTPSUsernameEnvKey)
		}
		return nil, nil
	}
	c.logger.Debug("git_credential_helper_override")
	return []string{
		"-c",
		fmt.Sprintf(
			// TODO: is this OK for windows/other platforms?
			// we might need an alternate flow where the binary has a sub-command to do this, and calls itself
			//
			// putting the variable name in this script, NOT the actual variable value
			// we do not want to store the variable on disk, ever
			// this is especially important if the program dies
			// note that this means i.e. HTTPS_PASSWORD=foo invoke_program does not work as
			// this variable needs to be in the actual global environment
			// TODO this is a mess
			"credential.helper=!f(){ echo username=${%s}; echo password=${%s}; };f",
			c.options.HTTPSUsernameEnvKey,
			c.options.HTTPSPasswordEnvKey,
		),
	}, nil
}

func (c *cloner) getEnvContainerWithGitSSHCommand(envContainer app.EnvContainer) (app.EnvContainer, error) {
	gitSSHCommand, err := c.getGitSSHCommand(envContainer)
	if err != nil {
		return nil, err
	}
	if gitSSHCommand != "" {
		c.logger.Debug("git_ssh_command_override")
		return app.NewEnvContainerWithOverrides(
			envContainer,
			map[string]string{
				"GIT_SSH_COMMAND": gitSSHCommand,
			},
		), nil
	}
	return envContainer, nil
}

func (c *cloner) getGitSSHCommand(envContainer app.EnvContainer) (string, error) {
	sshKeyFilePath := envContainer.Env(c.options.SSHKeyFileEnvKey)
	sshKnownHostsFiles := envContainer.Env(c.options.SSHKnownHostsFilesEnvKey)
	if sshKeyFilePath == "" {
		if sshKnownHostsFiles != "" {
			return "", fmt.Errorf("%s set but %s not set", c.options.SSHKnownHostsFilesEnvKey, c.options.SSHKeyFileEnvKey)
		}
		return "", nil
	}
	if sshKnownHostsFilePaths := getSSHKnownHostsFilePaths(sshKnownHostsFiles); len(sshKnownHostsFilePaths) > 0 {
		return fmt.Sprintf(
			`ssh -q -i "%s" -o "IdentitiesOnly=yes" -o "UserKnownHostsFile=%s"`,
			sshKeyFilePath,
			strings.Join(sshKnownHostsFilePaths, " "),
		), nil
	}
	// we want to set StrictHostKeyChecking=no because the SSH key file variable was set, so
	// there is an ask to override the default ssh settings here
	return fmt.Sprintf(
		`ssh -q -i "%s" -o "IdentitiesOnly=yes" -o "UserKnownHostsFile=%s" -o "StrictHostKeyChecking=no"`,
		sshKeyFilePath,
		app.DevNullFilePath,
	), nil
}

func getSSHKnownHostsFilePaths(sshKnownHostsFiles string) []string {
	if sshKnownHostsFiles == "" {
		return nil
	}
	var filePaths []string
	for _, filePath := range strings.Split(sshKnownHostsFiles, ":") {
		filePath = strings.TrimSpace(filePath)
		if filePath != "" {
			filePaths = append(filePaths, filePath)
		}
	}
	return filePaths
}

func getRefspecsForName(gitName Name) (string, []string) {
	if gitName == nil {
		return "HEAD", []string{"FETCH_HEAD"}
	}
	if gitName.cloneBranch() != "" && gitName.checkout() != "" {
		// When doing branch/tag clones, make sure we use a
		// refspec that creates a local referece in `refs/` even if the ref
		// is remote tracking, so that the checkoutRefs may reference it,
		// for example:
		//   branch=origin/main,ref=origin/main~1
		fetchRefSpec := gitName.cloneBranch() + ":" + gitName.cloneBranch()
		return fetchRefSpec, []string{"FETCH_HEAD", gitName.checkout()}
	} else if gitName.cloneBranch() != "" {
		return gitName.cloneBranch(), []string{"FETCH_HEAD"}
	} else if gitName.checkout() != "" {
		// After fetch we won't have checked out any refs. This
		// will cause `refs=` containing "HEAD" to fail, as HEAD
		// is a special case that is not fetched into a ref but
		// instead refers to the current commit checked out. By
		// checking out "FETCH_HEAD" before checking out the
		// user supplied ref, we behave similarly to git clone.
		return "HEAD", []string{"FETCH_HEAD", gitName.checkout()}
	} else {
		return "HEAD", []string{"FETCH_HEAD"}
	}
}

func newGitCommandError(
	err error,
	buffer *bytes.Buffer,
	tmpDir tmp.Dir,
) error {
	// Suppress printing of temp path
	return fmt.Errorf("%v\n%v", err, strings.TrimSpace(strings.Replace(buffer.String(), tmpDir.AbsPath(), "", -1)))
}
<|endoftext|>


<commit_before>package template

var (
	ProtoFNC = `syntax = "proto3";

package {{.FQDN}};

service {{title .Alias}} {
	rpc Call(Request) returns (Response) {}
}

message Message {
	string say = 1;
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}
`

	ProtoSRV = `syntax = "proto3";

package {{.FQDN}};

service {{title .Alias}} {
	rpc Call(Request) returns (Response) {}
	rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
	rpc PingPong(stream Ping) returns (stream Pong) {}
}

message Message {
	string say = 1;
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}

message StreamingRequest {
	int64 count = 1;
}

message StreamingResponse {
	int64 count = 1;
}

message Ping {
	int64 stroke = 1;
}

message Pong {
	int64 stroke = 1;
}
`

	ProtoAPI = `syntax = "proto3";

package {{.FQDN}};

import "github.com/micro/go-micro/v2/api/proto/api.proto";

service {{title .Alias}} {
	rpc Call(go.api.Request) returns (go.api.Response) {}
}
`
)
<commit_msg>updated proto template (#534)<commit_after>package template

var (
	ProtoFNC = `syntax = "proto3";

package {{.FQDN}};

option go_package = "{{.Dir}}/proto/{{.Alias}}";

service {{title .Alias}} {
	rpc Call(Request) returns (Response) {}
}

message Message {
	string say = 1;
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}
`

	ProtoSRV = `syntax = "proto3";

package {{.FQDN}};

service {{title .Alias}} {
	rpc Call(Request) returns (Response) {}
	rpc Stream(StreamingRequest) returns (stream StreamingResponse) {}
	rpc PingPong(stream Ping) returns (stream Pong) {}
}

message Message {
	string say = 1;
}

message Request {
	string name = 1;
}

message Response {
	string msg = 1;
}

message StreamingRequest {
	int64 count = 1;
}

message StreamingResponse {
	int64 count = 1;
}

message Ping {
	int64 stroke = 1;
}

message Pong {
	int64 stroke = 1;
}
`

	ProtoAPI = `syntax = "proto3";

package {{.FQDN}};

import "github.com/micro/go-micro/v2/api/proto/api.proto";

service {{title .Alias}} {
	rpc Call(go.api.Request) returns (go.api.Response) {}
}
`
)
<|endoftext|>


<commit_before>/*
Copyright 2019 The Ceph-CSI 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 util

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"strings"
)

const (
	// defaultCsiSubvolumeGroup defines the default name for the CephFS CSI subvolumegroup.
	// This was hardcoded once and defaults to the old value to keep backward compatibility.
	defaultCsiSubvolumeGroup = "csi"

	// CsiConfigFile is the location of the CSI config file
	CsiConfigFile = "/etc/ceph-csi-config/config.json"
)

// ClusterInfo strongly typed JSON spec for the below JSON structure.
type ClusterInfo struct {
	// ClusterID is used for unique identification
	ClusterID string `json:"clusterID"`
	// RadosNamespace is a rados namespace in the pool
	RadosNamespace string `json:"radosNamespace"`
	// Monitors is monitor list for corresponding cluster ID
	Monitors []string `json:"monitors"`
	// CephFS contains CephFS specific options
	CephFS struct {
		// SubvolumeGroup contains the name of the SubvolumeGroup for CSI volumes
		SubvolumeGroup string `json:"subvolumeGroup"`
	} `json:"cephFS"`
}

// Expected JSON structure in the passed in config file is,
// [
// 	{
// 		"clusterID": "<cluster-id>",
//		"radosNamespace": "<rados-namespace>",
// 		"monitors":
// 			[
// 				"<monitor-value>",
// 				"<monitor-value>",
// 				...
// 			],
//         "cephFS": {
//           "subvolumeGroup": "<subvolumegroup for cephfs volumes>"
//         }
// 	},
// 	...
// ].
func readClusterInfo(pathToConfig, clusterID string) (*ClusterInfo, error) {
	var config []ClusterInfo

	// #nosec
	content, err := ioutil.ReadFile(pathToConfig)
	if err != nil {
		err = fmt.Errorf("error fetching configuration for cluster ID (%s). (%s)", clusterID, err)
		return nil, err
	}

	err = json.Unmarshal(content, &config)
	if err != nil {
		return nil, fmt.Errorf("unmarshal failed: %v. raw buffer response: %s",
			err, string(content))
	}

	for _, cluster := range config {
		if cluster.ClusterID == clusterID {
			return &cluster, nil
		}
	}

	return nil, fmt.Errorf("missing configuration for cluster ID (%s)", clusterID)
}

// Mons returns a comma separated MON list from the csi config for the given clusterID.
func Mons(pathToConfig, clusterID string) (string, error) {
	cluster, err := readClusterInfo(pathToConfig, clusterID)
	if err != nil {
		return "", err
	}

	if len(cluster.Monitors) == 0 {
		return "", fmt.Errorf("empty monitor list for cluster ID (%s) in config", clusterID)
	}
	return strings.Join(cluster.Monitors, ","), nil
}

// RadosNamespace returns the namespace for the given clusterID.
func RadosNamespace(pathToConfig, clusterID string) (string, error) {
	cluster, err := readClusterInfo(pathToConfig, clusterID)
	if err != nil {
		return "", err
	}
	return cluster.RadosNamespace, nil
}

// CephFSSubvolumeGroup returns the subvolumeGroup for CephFS volumes. If not set, it returns the default value "csi".
func CephFSSubvolumeGroup(pathToConfig, clusterID string) (string, error) {
	cluster, err := readClusterInfo(pathToConfig, clusterID)
	if err != nil {
		return "", err
	}

	if cluster.CephFS.SubvolumeGroup == "" {
		return defaultCsiSubvolumeGroup, nil
	}
	return cluster.CephFS.SubvolumeGroup, nil
}

// GetMonsAndClusterID returns monitors and clusterID information read from
// configfile.
func GetMonsAndClusterID(options map[string]string) (string, string, error) {
	clusterID, ok := options["clusterID"]
	if !ok {
		return "", "", errors.New("clusterID must be set")
	}

	monitors, err := Mons(CsiConfigFile, clusterID)
	if err != nil {
		return "", "", fmt.Errorf("failed to fetch monitor list using clusterID (%s): %w", clusterID, err)
	}

	return monitors, clusterID, nil
}
<commit_msg>cleanup: standardize error format in util.readClusterInfo()<commit_after>/*
Copyright 2019 The Ceph-CSI 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 util

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"strings"
)

const (
	// defaultCsiSubvolumeGroup defines the default name for the CephFS CSI subvolumegroup.
	// This was hardcoded once and defaults to the old value to keep backward compatibility.
	defaultCsiSubvolumeGroup = "csi"

	// CsiConfigFile is the location of the CSI config file
	CsiConfigFile = "/etc/ceph-csi-config/config.json"
)

// ClusterInfo strongly typed JSON spec for the below JSON structure.
type ClusterInfo struct {
	// ClusterID is used for unique identification
	ClusterID string `json:"clusterID"`
	// RadosNamespace is a rados namespace in the pool
	RadosNamespace string `json:"radosNamespace"`
	// Monitors is monitor list for corresponding cluster ID
	Monitors []string `json:"monitors"`
	// CephFS contains CephFS specific options
	CephFS struct {
		// SubvolumeGroup contains the name of the SubvolumeGroup for CSI volumes
		SubvolumeGroup string `json:"subvolumeGroup"`
	} `json:"cephFS"`
}

// Expected JSON structure in the passed in config file is,
// [
// 	{
// 		"clusterID": "<cluster-id>",
//		"radosNamespace": "<rados-namespace>",
// 		"monitors":
// 			[
// 				"<monitor-value>",
// 				"<monitor-value>",
// 				...
// 			],
//         "cephFS": {
//           "subvolumeGroup": "<subvolumegroup for cephfs volumes>"
//         }
// 	},
// 	...
// ].
func readClusterInfo(pathToConfig, clusterID string) (*ClusterInfo, error) {
	var config []ClusterInfo

	// #nosec
	content, err := ioutil.ReadFile(pathToConfig)
	if err != nil {
		err = fmt.Errorf("error fetching configuration for cluster ID %q: %w", clusterID, err)
		return nil, err
	}

	err = json.Unmarshal(content, &config)
	if err != nil {
		return nil, fmt.Errorf("unmarshal failed (%w), raw buffer response: %s",
			err, string(content))
	}

	for _, cluster := range config {
		if cluster.ClusterID == clusterID {
			return &cluster, nil
		}
	}

	return nil, fmt.Errorf("missing configuration for cluster ID %q", clusterID)
}

// Mons returns a comma separated MON list from the csi config for the given clusterID.
func Mons(pathToConfig, clusterID string) (string, error) {
	cluster, err := readClusterInfo(pathToConfig, clusterID)
	if err != nil {
		return "", err
	}

	if len(cluster.Monitors) == 0 {
		return "", fmt.Errorf("empty monitor list for cluster ID (%s) in config", clusterID)
	}
	return strings.Join(cluster.Monitors, ","), nil
}

// RadosNamespace returns the namespace for the given clusterID.
func RadosNamespace(pathToConfig, clusterID string) (string, error) {
	cluster, err := readClusterInfo(pathToConfig, clusterID)
	if err != nil {
		return "", err
	}
	return cluster.RadosNamespace, nil
}

// CephFSSubvolumeGroup returns the subvolumeGroup for CephFS volumes. If not set, it returns the default value "csi".
func CephFSSubvolumeGroup(pathToConfig, clusterID string) (string, error) {
	cluster, err := readClusterInfo(pathToConfig, clusterID)
	if err != nil {
		return "", err
	}

	if cluster.CephFS.SubvolumeGroup == "" {
		return defaultCsiSubvolumeGroup, nil
	}
	return cluster.CephFS.SubvolumeGroup, nil
}

// GetMonsAndClusterID returns monitors and clusterID information read from
// configfile.
func GetMonsAndClusterID(options map[string]string) (string, string, error) {
	clusterID, ok := options["clusterID"]
	if !ok {
		return "", "", errors.New("clusterID must be set")
	}

	monitors, err := Mons(CsiConfigFile, clusterID)
	if err != nil {
		return "", "", fmt.Errorf("failed to fetch monitor list using clusterID (%s): %w", clusterID, err)
	}

	return monitors, clusterID, nil
}
<|endoftext|>


<commit_before>// Copyright 2010 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.

/*

Goinstall is an experiment in automatic package installation.
It installs packages, possibly downloading them from the internet.
It maintains a list of public Go packages at http://godashboard.appspot.com/package.

Usage:
	goinstall [flags] importpath...

Flags and default settings:
	-dashboard=true   tally public packages on godashboard.appspot.com
	-update=false     update already-downloaded packages
	-v=false          verbose operation

Goinstall installs each of the packages identified on the command line.
It installs a package's prerequisites before trying to install the package itself.

The source code for a package with import path foo/bar is expected
to be in the directory $GOROOT/src/pkg/foo/bar/.  If the import
path refers to a code hosting site, goinstall will download the code
if necessary.  The recognized code hosting sites are:

	BitBucket (Mercurial)

		import "bitbucket.org/user/project"
		import "bitbucket.org/user/project/sub/directory"

	GitHub (Git)

		import "github.com/user/project.git"
		import "github.com/user/project.git/sub/directory"

	Google Code Project Hosting (Mercurial, Subversion)

		import "project.googlecode.com/hg"
		import "project.googlecode.com/hg/sub/directory"

		import "project.googlecode.com/svn/trunk"
		import "project.googlecode.com/svn/trunk/sub/directory"

	Launchpad

		import "launchpad.net/project
		import "launchpad.net/project/series
		import "launchpad.net/project/series/sub/directory

		import "launchpad.net/~user/project/branch
		import "launchpad.net/~user/project/branch/sub/directory

If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
already exists and contains an appropriate checkout, goinstall will not
attempt to fetch updates.  The -update flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.

When downloading or updating, goinstall first looks for a tag or branch
named "release".  If there is one, it uses that version of the code.
Otherwise it uses the default version selected by the version control
system, typically HEAD for git, tip for Mercurial.

After a successful download and installation of a publicly accessible
remote package, goinstall reports the installation to godashboard.appspot.com,
which increments a count associated with the package and the time
of its most recent installation.  This mechanism powers the package list
at http://godashboard.appspot.com/package, allowing Go programmers
to learn about popular packages that might be worth looking at.
The -dashboard=false flag disables this reporting.

By default, goinstall prints output only when it encounters an error.
The -v flag causes goinstall to print information about packages
being considered and installed.

Goinstall does not attempt to be a replacement for make.
Instead, it invokes "make install" after locating the package sources.
For local packages without a Makefile and all remote packages,
goinstall creates and uses a temporary Makefile constructed from
the import path and the list of Go files in the package.
*/
package documentation
<commit_msg>goinstall docs: fixed typos (Added mising closing quotes.)<commit_after>// Copyright 2010 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.

/*

Goinstall is an experiment in automatic package installation.
It installs packages, possibly downloading them from the internet.
It maintains a list of public Go packages at http://godashboard.appspot.com/package.

Usage:
	goinstall [flags] importpath...

Flags and default settings:
	-dashboard=true   tally public packages on godashboard.appspot.com
	-update=false     update already-downloaded packages
	-v=false          verbose operation

Goinstall installs each of the packages identified on the command line.
It installs a package's prerequisites before trying to install the package itself.

The source code for a package with import path foo/bar is expected
to be in the directory $GOROOT/src/pkg/foo/bar/.  If the import
path refers to a code hosting site, goinstall will download the code
if necessary.  The recognized code hosting sites are:

	BitBucket (Mercurial)

		import "bitbucket.org/user/project"
		import "bitbucket.org/user/project/sub/directory"

	GitHub (Git)

		import "github.com/user/project.git"
		import "github.com/user/project.git/sub/directory"

	Google Code Project Hosting (Mercurial, Subversion)

		import "project.googlecode.com/hg"
		import "project.googlecode.com/hg/sub/directory"

		import "project.googlecode.com/svn/trunk"
		import "project.googlecode.com/svn/trunk/sub/directory"

	Launchpad

		import "launchpad.net/project"
		import "launchpad.net/project/series"
		import "launchpad.net/project/series/sub/directory"

		import "launchpad.net/~user/project/branch"
		import "launchpad.net/~user/project/branch/sub/directory"

If the destination directory (e.g., $GOROOT/src/pkg/bitbucket.org/user/project)
already exists and contains an appropriate checkout, goinstall will not
attempt to fetch updates.  The -update flag changes this behavior,
causing goinstall to update all remote packages encountered during
the installation.

When downloading or updating, goinstall first looks for a tag or branch
named "release".  If there is one, it uses that version of the code.
Otherwise it uses the default version selected by the version control
system, typically HEAD for git, tip for Mercurial.

After a successful download and installation of a publicly accessible
remote package, goinstall reports the installation to godashboard.appspot.com,
which increments a count associated with the package and the time
of its most recent installation.  This mechanism powers the package list
at http://godashboard.appspot.com/package, allowing Go programmers
to learn about popular packages that might be worth looking at.
The -dashboard=false flag disables this reporting.

By default, goinstall prints output only when it encounters an error.
The -v flag causes goinstall to print information about packages
being considered and installed.

Goinstall does not attempt to be a replacement for make.
Instead, it invokes "make install" after locating the package sources.
For local packages without a Makefile and all remote packages,
goinstall creates and uses a temporary Makefile constructed from
the import path and the list of Go files in the package.
*/
package documentation
<|endoftext|>


<commit_before>// Copyright 2010 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.

// This file contains the test for canonical struct tags.

package main

import (
	"errors"
	"go/ast"
	"reflect"
	"strconv"
)

func init() {
	register("structtags",
		"check that struct field tags have canonical format and apply to exported fields as needed",
		checkCanonicalFieldTag,
		field)
}

// checkCanonicalFieldTag checks a struct field tag.
func checkCanonicalFieldTag(f *File, node ast.Node) {
	field := node.(*ast.Field)
	if field.Tag == nil {
		return
	}

	tag, err := strconv.Unquote(field.Tag.Value)
	if err != nil {
		f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
		return
	}

	if err := validateStructTag(tag); err != nil {
		f.Badf(field.Pos(), "struct field tag %s not compatible with reflect.StructTag.Get: %s", field.Tag.Value, err)
	}

	// Check for use of json or xml tags with unexported fields.

	// Embedded struct. Nothing to do for now, but that
	// may change, depending on what happens with issue 7363.
	if len(field.Names) == 0 {
		return
	}

	if field.Names[0].IsExported() {
		return
	}

	st := reflect.StructTag(tag)
	for _, enc := range [...]string{"json", "xml"} {
		if st.Get(enc) != "" {
			f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc)
			return
		}
	}
}

var (
	errTagSyntax      = errors.New("bad syntax for struct tag pair")
	errTagKeySyntax   = errors.New("bad syntax for struct tag key")
	errTagValueSyntax = errors.New("bad syntax for struct tag value")
)

// validateStructTag parses the struct tag and returns an error if it is not
// in the canonical format, which is a space-separated list of key:"value"
// settings. The value may contain spaces.
func validateStructTag(tag string) error {
	// This code is based on the StructTag.Get code in package reflect.

	for tag != "" {
		// Skip leading space.
		i := 0
		for i < len(tag) && tag[i] == ' ' {
			i++
		}
		tag = tag[i:]
		if tag == "" {
			break
		}

		// Scan to colon. A space, a quote or a control character is a syntax error.
		// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
		// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
		// as it is simpler to inspect the tag's bytes than the tag's runes.
		i = 0
		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
			i++
		}
		if i == 0 {
			return errTagKeySyntax
		}
		if i+1 >= len(tag) || tag[i] != ':' {
			return errTagSyntax
		}
		if tag[i+1] != '"' {
			return errTagValueSyntax
		}
		tag = tag[i+1:]

		// Scan quoted string to find value.
		i = 1
		for i < len(tag) && tag[i] != '"' {
			if tag[i] == '\\' {
				i++
			}
			i++
		}
		if i >= len(tag) {
			return errTagValueSyntax
		}
		qvalue := tag[:i+1]
		tag = tag[i+1:]

		if _, err := strconv.Unquote(qvalue); err != nil {
			return errTagValueSyntax
		}
	}
	return nil
}
<commit_msg>cmd/vet: re-quote struct tags when printing errors<commit_after>// Copyright 2010 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.

// This file contains the test for canonical struct tags.

package main

import (
	"errors"
	"go/ast"
	"reflect"
	"strconv"
)

func init() {
	register("structtags",
		"check that struct field tags have canonical format and apply to exported fields as needed",
		checkCanonicalFieldTag,
		field)
}

// checkCanonicalFieldTag checks a struct field tag.
func checkCanonicalFieldTag(f *File, node ast.Node) {
	field := node.(*ast.Field)
	if field.Tag == nil {
		return
	}

	tag, err := strconv.Unquote(field.Tag.Value)
	if err != nil {
		f.Badf(field.Pos(), "unable to read struct tag %s", field.Tag.Value)
		return
	}

	if err := validateStructTag(tag); err != nil {
		raw, _ := strconv.Unquote(field.Tag.Value) // field.Tag.Value is known to be a quoted string
		f.Badf(field.Pos(), "struct field tag %q not compatible with reflect.StructTag.Get: %s", raw, err)
	}

	// Check for use of json or xml tags with unexported fields.

	// Embedded struct. Nothing to do for now, but that
	// may change, depending on what happens with issue 7363.
	if len(field.Names) == 0 {
		return
	}

	if field.Names[0].IsExported() {
		return
	}

	st := reflect.StructTag(tag)
	for _, enc := range [...]string{"json", "xml"} {
		if st.Get(enc) != "" {
			f.Badf(field.Pos(), "struct field %s has %s tag but is not exported", field.Names[0].Name, enc)
			return
		}
	}
}

var (
	errTagSyntax      = errors.New("bad syntax for struct tag pair")
	errTagKeySyntax   = errors.New("bad syntax for struct tag key")
	errTagValueSyntax = errors.New("bad syntax for struct tag value")
)

// validateStructTag parses the struct tag and returns an error if it is not
// in the canonical format, which is a space-separated list of key:"value"
// settings. The value may contain spaces.
func validateStructTag(tag string) error {
	// This code is based on the StructTag.Get code in package reflect.

	for tag != "" {
		// Skip leading space.
		i := 0
		for i < len(tag) && tag[i] == ' ' {
			i++
		}
		tag = tag[i:]
		if tag == "" {
			break
		}

		// Scan to colon. A space, a quote or a control character is a syntax error.
		// Strictly speaking, control chars include the range [0x7f, 0x9f], not just
		// [0x00, 0x1f], but in practice, we ignore the multi-byte control characters
		// as it is simpler to inspect the tag's bytes than the tag's runes.
		i = 0
		for i < len(tag) && tag[i] > ' ' && tag[i] != ':' && tag[i] != '"' && tag[i] != 0x7f {
			i++
		}
		if i == 0 {
			return errTagKeySyntax
		}
		if i+1 >= len(tag) || tag[i] != ':' {
			return errTagSyntax
		}
		if tag[i+1] != '"' {
			return errTagValueSyntax
		}
		tag = tag[i+1:]

		// Scan quoted string to find value.
		i = 1
		for i < len(tag) && tag[i] != '"' {
			if tag[i] == '\\' {
				i++
			}
			i++
		}
		if i >= len(tag) {
			return errTagValueSyntax
		}
		qvalue := tag[:i+1]
		tag = tag[i+1:]

		if _, err := strconv.Unquote(qvalue); err != nil {
			return errTagValueSyntax
		}
	}
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"time"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// NotificationUser defines how to model a NotificationUser
type NotificationUser struct {
	ID          bson.ObjectId   `bson:"_id,omitempty"`
	UserId      bson.ObjectId   `json:"userid"`
	Token       string          `json:"token"`
	Os          string          `json:"os"`
}

// NotificationUser defines how to model a NotificationUser
type Notification struct {
	ID          bson.ObjectId   `bson:"_id,omitempty"`
	Sender      bson.ObjectId   `json:"sender"`
	Receiver    bson.ObjectId   `json:"receiver"`
	Content			bson.ObjectId		`json:"content"`
	Comment			Comment					`json:"comment,omitempty" bson:",omitempty"`
	Message			string					`json:"message"`
	Seen				bool						`json:"seen"`
	Date				time.Time				`json:"date"`
	Type				string					`json:"type"`
}

type Notifications []Notification

func CreateOrUpdateNotificationUser(user NotificationUser){
  session, _ := mgo.Dial("127.0.0.1")
  defer session.Close()
  session.SetMode(mgo.Monotonic, true)
  db := session.DB("insapp").C("notification_user")
  res, _ := db.Find(bson.M{"userid": user.UserId}).Count()
  if res > 0 {
  	db.Update(bson.M{"userid": user.UserId}, bson.M{"$set": bson.M{ "token": user.Token, "os": user.Os }})
  }else{
    db.Insert(user)
  }
}

func AddNotification(notification Notification) {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	notification.ID = bson.NewObjectId()
	notification.Date = time.Now()
	notification.Seen = false
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	res := db.Insert(notification)
	fmt.Println(res)
}

func GetNotificationsForUser(userID bson.ObjectId) Notifications {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	var result Notifications
	db.Find(bson.M{"receiver" : userID}).Sort("-date").Limit(30).All(&result)
	return result
}

func ReadNotificationForUser(userID bson.ObjectId, notifID bson.ObjectId) Notifications{
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.Update(bson.M{"_id": notifID}, bson.M{"$set": bson.M{"seen": true}})
	return GetNotificationsForUser(userID)
}

func DeleteNotificationsForUser(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.Remove(bson.M{"receiver": id})
}

func DeleteNotificationsForComment(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.Remove(bson.M{"comment._id": id})
}

func DeleteNotificationsForPost(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.Remove(bson.M{"content": id})
}

func DeleteNotificationsForEvent(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.Remove(bson.M{"content": id})
}

func DeleteNotificationTokenForUser(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification_user")
	db.Remove(bson.M{"userid": id})
}
<commit_msg>Cascade removal for notification<commit_after>package main

import (
	"time"
	"fmt"
	"gopkg.in/mgo.v2"
	"gopkg.in/mgo.v2/bson"
)

// NotificationUser defines how to model a NotificationUser
type NotificationUser struct {
	ID          bson.ObjectId   `bson:"_id,omitempty"`
	UserId      bson.ObjectId   `json:"userid"`
	Token       string          `json:"token"`
	Os          string          `json:"os"`
}

// NotificationUser defines how to model a NotificationUser
type Notification struct {
	ID          bson.ObjectId   `bson:"_id,omitempty"`
	Sender      bson.ObjectId   `json:"sender"`
	Receiver    bson.ObjectId   `json:"receiver"`
	Content			bson.ObjectId		`json:"content"`
	Comment			Comment					`json:"comment,omitempty" bson:",omitempty"`
	Message			string					`json:"message"`
	Seen				bool						`json:"seen"`
	Date				time.Time				`json:"date"`
	Type				string					`json:"type"`
}

type Notifications []Notification

func CreateOrUpdateNotificationUser(user NotificationUser){
  session, _ := mgo.Dial("127.0.0.1")
  defer session.Close()
  session.SetMode(mgo.Monotonic, true)
  db := session.DB("insapp").C("notification_user")
  res, _ := db.Find(bson.M{"userid": user.UserId}).Count()
  if res > 0 {
  	db.Update(bson.M{"userid": user.UserId}, bson.M{"$set": bson.M{ "token": user.Token, "os": user.Os }})
  }else{
    db.Insert(user)
  }
}

func AddNotification(notification Notification) {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	notification.ID = bson.NewObjectId()
	notification.Date = time.Now()
	notification.Seen = false
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	res := db.Insert(notification)
	fmt.Println(res)
}

func GetNotificationsForUser(userID bson.ObjectId) Notifications {
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	var result Notifications
	db.Find(bson.M{"receiver" : userID}).Sort("-date").Limit(30).All(&result)
	return result
}

func ReadNotificationForUser(userID bson.ObjectId, notifID bson.ObjectId) Notifications{
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.Update(bson.M{"_id": notifID}, bson.M{"$set": bson.M{"seen": true}})
	return GetNotificationsForUser(userID)
}

func DeleteNotificationsForUser(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.RemoveAll(bson.M{"receiver": id})
}

func DeleteNotificationsForComment(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.RemoveAll(bson.M{"comment._id": id})
}

func DeleteNotificationsForPost(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.RemoveAll(bson.M{"content": id})
}

func DeleteNotificationsForEvent(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification")
	db.RemoveAll(bson.M{"content": id})
}

func DeleteNotificationTokenForUser(id bson.ObjectId){
	session, _ := mgo.Dial("127.0.0.1")
	defer session.Close()
	session.SetMode(mgo.Monotonic, true)
	db := session.DB("insapp").C("notification_user")
	db.RemoveAll(bson.M{"userid": id})
}
<|endoftext|>


<commit_before>package cephfs

import (
	"fmt"
	"os"
	"syscall"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	CephMountTest string = "/tmp/ceph/mds/mnt/"
)

func TestCreateMount(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	assert.NotNil(t, mount)
}

func TestMountRoot(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)
}

func TestSyncFs(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)
}

func TestChangeDir(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	require.NoError(t, err)

	dir1 := mount.CurrentDir()
	assert.NotNil(t, dir1)

	err = mount.MakeDir("/asdf", 0755)
	assert.NoError(t, err)

	err = mount.ChangeDir("/asdf")
	assert.NoError(t, err)

	dir2 := mount.CurrentDir()
	assert.NotNil(t, dir2)

	assert.NotEqual(t, dir1, dir2)
	assert.Equal(t, dir1, "/")
	assert.Equal(t, dir2, "/asdf")
}

func TestRemoveDir(t *testing.T) {
	dirname := "one"
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.MakeDir(dirname, 0755)
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)

	// os.Stat the actual mounted location to verify Makedir/RemoveDir
	_, err = os.Stat(CephMountTest + dirname)
	assert.NoError(t, err)

	err = mount.RemoveDir(dirname)
	assert.NoError(t, err)

	_, err = os.Stat(CephMountTest + dirname)
	assert.EqualError(t, err,
		fmt.Sprintf("stat %s: no such file or directory", CephMountTest+dirname))
}

func TestUnmountMount(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)
	fmt.Printf("%#v\n", mount.IsMounted())

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)
	assert.True(t, mount.IsMounted())

	err = mount.Unmount()
	assert.NoError(t, err)
	assert.False(t, mount.IsMounted())
}

func TestReleaseMount(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.Release()
	assert.NoError(t, err)
}

func TestChmodDir(t *testing.T) {
	dirname := "two"
	var stats_before uint32 = 0755
	var stats_after uint32 = 0700
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.MakeDir(dirname, stats_before)
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)

	// os.Stat the actual mounted location to verify Makedir/RemoveDir
	stats, err := os.Stat(CephMountTest + dirname)
	require.NoError(t, err)

	assert.Equal(t, uint32(stats.Mode().Perm()), stats_before)

	err = mount.Chmod(dirname, stats_after)
	assert.NoError(t, err)

	stats, err = os.Stat(CephMountTest + dirname)
	assert.Equal(t, uint32(stats.Mode().Perm()), stats_after)
}

// Not cross-platform, go's os does not specifiy Sys return type
func TestChown(t *testing.T) {
	dirname := "three"
	// dockerfile creates bob user account
	var bob uint32 = 1010
	var root uint32 = 0

	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.MakeDir(dirname, 0755)
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)

	// os.Stat the actual mounted location to verify Makedir/RemoveDir
	stats, err := os.Stat(CephMountTest + dirname)
	require.NoError(t, err)

	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), root)
	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), root)

	err = mount.Chown(dirname, bob, bob)
	assert.NoError(t, err)

	stats, err = os.Stat(CephMountTest + dirname)
	assert.NoError(t, err)
	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), bob)
	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), bob)

}

func TestCephFSError(t *testing.T) {
	err := getError(0)
	assert.NoError(t, err)

	err = getError(-5) // IO error
	assert.Error(t, err)
	assert.Equal(t, err.Error(), "cephfs: ret=5, Input/output error")

	err = getError(345) // no such errno
	assert.Error(t, err)
	assert.Equal(t, err.Error(), "cephfs: ret=345")
}
<commit_msg>cephfs: fix linting errors found in cephfs_test.go<commit_after>package cephfs

import (
	"fmt"
	"os"
	"syscall"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

var (
	CephMountTest = "/tmp/ceph/mds/mnt/"
)

func TestCreateMount(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	assert.NotNil(t, mount)
}

func TestMountRoot(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)
}

func TestSyncFs(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)
}

func TestChangeDir(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	require.NoError(t, err)

	dir1 := mount.CurrentDir()
	assert.NotNil(t, dir1)

	err = mount.MakeDir("/asdf", 0755)
	assert.NoError(t, err)

	err = mount.ChangeDir("/asdf")
	assert.NoError(t, err)

	dir2 := mount.CurrentDir()
	assert.NotNil(t, dir2)

	assert.NotEqual(t, dir1, dir2)
	assert.Equal(t, dir1, "/")
	assert.Equal(t, dir2, "/asdf")
}

func TestRemoveDir(t *testing.T) {
	dirname := "one"
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.MakeDir(dirname, 0755)
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)

	// os.Stat the actual mounted location to verify Makedir/RemoveDir
	_, err = os.Stat(CephMountTest + dirname)
	assert.NoError(t, err)

	err = mount.RemoveDir(dirname)
	assert.NoError(t, err)

	_, err = os.Stat(CephMountTest + dirname)
	assert.EqualError(t, err,
		fmt.Sprintf("stat %s: no such file or directory", CephMountTest+dirname))
}

func TestUnmountMount(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)
	fmt.Printf("%#v\n", mount.IsMounted())

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)
	assert.True(t, mount.IsMounted())

	err = mount.Unmount()
	assert.NoError(t, err)
	assert.False(t, mount.IsMounted())
}

func TestReleaseMount(t *testing.T) {
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.Release()
	assert.NoError(t, err)
}

func TestChmodDir(t *testing.T) {
	dirname := "two"
	var stats_before uint32 = 0755
	var stats_after uint32 = 0700
	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.MakeDir(dirname, stats_before)
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)

	// os.Stat the actual mounted location to verify Makedir/RemoveDir
	stats, err := os.Stat(CephMountTest + dirname)
	require.NoError(t, err)

	assert.Equal(t, uint32(stats.Mode().Perm()), stats_before)

	err = mount.Chmod(dirname, stats_after)
	assert.NoError(t, err)

	stats, err = os.Stat(CephMountTest + dirname)
	assert.Equal(t, uint32(stats.Mode().Perm()), stats_after)
}

// Not cross-platform, go's os does not specifiy Sys return type
func TestChown(t *testing.T) {
	dirname := "three"
	// dockerfile creates bob user account
	var bob uint32 = 1010
	var root uint32

	mount, err := CreateMount()
	assert.NoError(t, err)
	require.NotNil(t, mount)

	err = mount.ReadDefaultConfigFile()
	assert.NoError(t, err)

	err = mount.Mount()
	assert.NoError(t, err)

	err = mount.MakeDir(dirname, 0755)
	assert.NoError(t, err)

	err = mount.SyncFs()
	assert.NoError(t, err)

	// os.Stat the actual mounted location to verify Makedir/RemoveDir
	stats, err := os.Stat(CephMountTest + dirname)
	require.NoError(t, err)

	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), root)
	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), root)

	err = mount.Chown(dirname, bob, bob)
	assert.NoError(t, err)

	stats, err = os.Stat(CephMountTest + dirname)
	assert.NoError(t, err)
	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Uid), bob)
	assert.Equal(t, uint32(stats.Sys().(*syscall.Stat_t).Gid), bob)

}

func TestCephFSError(t *testing.T) {
	err := getError(0)
	assert.NoError(t, err)

	err = getError(-5) // IO error
	assert.Error(t, err)
	assert.Equal(t, err.Error(), "cephfs: ret=5, Input/output error")

	err = getError(345) // no such errno
	assert.Error(t, err)
	assert.Equal(t, err.Error(), "cephfs: ret=345")
}
<|endoftext|>


<commit_before>package stack

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

	"github.com/appcelerator/amp/api/rpc/account"
	. "github.com/appcelerator/amp/api/rpc/stack"
	"github.com/appcelerator/amp/tests"
	"github.com/docker/docker/pkg/stringid"
	"github.com/stretchr/testify/assert"
)

var (
	h *helpers.Helper
)

func setup() (err error) {
	h, err = helpers.New()
	if err != nil {
		return err
	}
	return nil
}

func tearDown() {
}

func TestMain(m *testing.M) {
	if err := setup(); err != nil {
		log.Fatal(err)
	}
	code := m.Run()
	tearDown()
	os.Exit(code)
}

func TestStackDeploy(t *testing.T) {
	testUser := h.RandomUser()

	// Create user
	userCtx := h.CreateUser(t, &testUser)

	// Create stack
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	drq := &DeployRequest{
		Name:    "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16],
		Compose: compose,
	}
	drp, err := h.Stacks().Deploy(userCtx, drq)
	assert.NoError(t, err)
	assert.NotEmpty(t, drp.FullName)
	assert.NotEmpty(t, drp.Answer)

	rrq := &RemoveRequest{
		Stack: drp.FullName,
	}
	_, err = h.Stacks().Remove(userCtx, rrq)
	assert.NoError(t, err)
}

func TestStackDeployBetweenOrganizations(t *testing.T) {
	// Create organization with a user
	testUser := h.RandomUser()
	testOrg := h.RandomOrg()
	ownerCtx := h.CreateOrganization(t, &testOrg, &testUser)
	orgCtx := h.Switch(ownerCtx, t, testOrg.Name)

	// Create another organization with a user
	anotherUser := h.RandomUser()
	anotherOrg := h.RandomOrg()
	anotherOwnerCtx := h.CreateOrganization(t, &anotherOrg, &anotherUser)
	anotherOrgCtx := h.Switch(anotherOwnerCtx, t, anotherOrg.Name)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as org
	orgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	r, err := h.Stacks().Deploy(orgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Deploy another stack as another org
	anotherOrgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq = &DeployRequest{
		Name:    anotherOrgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(anotherOrgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Update another stack as org should fail
	rq = &DeployRequest{
		Name:    anotherOrgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(orgCtx, rq)
	assert.Error(t, err)

	// Update stack as another org should fail
	rq = &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(anotherOrgCtx, rq)
	assert.Error(t, err)

	// Remove stacks
	_, err = h.Stacks().Remove(orgCtx, &RemoveRequest{Stack: orgStack})
	assert.NoError(t, err)
	_, err = h.Stacks().Remove(anotherOrgCtx, &RemoveRequest{Stack: anotherOrgStack})
	assert.NoError(t, err)
}

func TestStackListBetweenOrganizations(t *testing.T) {
	// Create organization with a user
	testUser := h.RandomUser()
	testOrg := h.RandomOrg()
	ownerCtx := h.CreateOrganization(t, &testOrg, &testUser)
	orgCtx := h.Switch(ownerCtx, t, testOrg.Name)

	// Create another organization with a user
	anotherUser := h.RandomUser()
	anotherOrg := h.RandomOrg()
	anotherOwnerCtx := h.CreateOrganization(t, &anotherOrg, &anotherUser)
	anotherOrgCtx := h.Switch(anotherOwnerCtx, t, anotherOrg.Name)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as org
	orgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	r, err := h.Stacks().Deploy(orgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Deploy another stack as another org
	anotherOrgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq = &DeployRequest{
		Name:    anotherOrgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(anotherOrgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Listing stacks as org
	stacks, err := h.Stacks().List(orgCtx, &ListRequest{})
	assert.NoError(t, err)
	assert.Len(t, stacks.Entries, 1)
	for _, stack := range stacks.Entries {
		assert.NotEqual(t, stack.Stack.Name, anotherOrgStack)
	}

	// Listing stacks as another org
	stacks, err = h.Stacks().List(anotherOrgCtx, &ListRequest{})
	assert.NoError(t, err)
	assert.Len(t, stacks.Entries, 1)
	for _, stack := range stacks.Entries {
		assert.NotEqual(t, stack.Stack.Name, orgStack)
	}

	// Remove stacks
	_, err = h.Stacks().Remove(orgCtx, &RemoveRequest{Stack: orgStack})
	assert.NoError(t, err)
	_, err = h.Stacks().Remove(anotherOrgCtx, &RemoveRequest{Stack: anotherOrgStack})
	assert.NoError(t, err)
}

func TestDeleteAnOrganizationOwningStacksShouldFail(t *testing.T) {
	// Create organization with a user
	testUser := h.RandomUser()
	testOrg := h.RandomOrg()
	ownerCtx := h.CreateOrganization(t, &testOrg, &testUser)
	orgCtx := h.Switch(ownerCtx, t, testOrg.Name)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as org
	orgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	_, err = h.Stacks().Deploy(orgCtx, rq)
	assert.NoError(t, err)

	// Deleting the organization should fail
	_, err = h.Accounts().DeleteOrganization(orgCtx, &account.DeleteOrganizationRequest{Name: testOrg.Name})
	assert.Error(t, err)

	// Remove stack
	_, err = h.Stacks().Remove(orgCtx, &RemoveRequest{Stack: orgStack})
	assert.NoError(t, err)

	// Deleting the organization should succeed
	_, err = h.Accounts().DeleteOrganization(orgCtx, &account.DeleteOrganizationRequest{Name: testOrg.Name})
	assert.NoError(t, err)
}
<commit_msg>Adding integration test<commit_after>package stack

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

	"github.com/appcelerator/amp/api/rpc/account"
	. "github.com/appcelerator/amp/api/rpc/stack"
	"github.com/appcelerator/amp/tests"
	"github.com/docker/docker/pkg/stringid"
	"github.com/stretchr/testify/assert"
)

var (
	h *helpers.Helper
)

func setup() (err error) {
	h, err = helpers.New()
	if err != nil {
		return err
	}
	return nil
}

func tearDown() {
}

func TestMain(m *testing.M) {
	if err := setup(); err != nil {
		log.Fatal(err)
	}
	code := m.Run()
	tearDown()
	os.Exit(code)
}

func TestStackDeploy(t *testing.T) {
	testUser := h.RandomUser()

	// Create user
	userCtx := h.CreateUser(t, &testUser)

	// Create stack
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	drq := &DeployRequest{
		Name:    "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16],
		Compose: compose,
	}
	drp, err := h.Stacks().Deploy(userCtx, drq)
	assert.NoError(t, err)
	assert.NotEmpty(t, drp.FullName)
	assert.NotEmpty(t, drp.Answer)

	rrq := &RemoveRequest{
		Stack: drp.FullName,
	}
	_, err = h.Stacks().Remove(userCtx, rrq)
	assert.NoError(t, err)
}

func TestStackDeployBetweenOrganizations(t *testing.T) {
	// Create organization with a user
	testUser := h.RandomUser()
	testOrg := h.RandomOrg()
	ownerCtx := h.CreateOrganization(t, &testOrg, &testUser)
	orgCtx := h.Switch(ownerCtx, t, testOrg.Name)

	// Create another organization with a user
	anotherUser := h.RandomUser()
	anotherOrg := h.RandomOrg()
	anotherOwnerCtx := h.CreateOrganization(t, &anotherOrg, &anotherUser)
	anotherOrgCtx := h.Switch(anotherOwnerCtx, t, anotherOrg.Name)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as org
	orgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	r, err := h.Stacks().Deploy(orgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Deploy another stack as another org
	anotherOrgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq = &DeployRequest{
		Name:    anotherOrgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(anotherOrgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Update another stack as org should fail
	rq = &DeployRequest{
		Name:    anotherOrgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(orgCtx, rq)
	assert.Error(t, err)

	// Update stack as another org should fail
	rq = &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(anotherOrgCtx, rq)
	assert.Error(t, err)

	// Remove stacks
	_, err = h.Stacks().Remove(orgCtx, &RemoveRequest{Stack: orgStack})
	assert.NoError(t, err)
	_, err = h.Stacks().Remove(anotherOrgCtx, &RemoveRequest{Stack: anotherOrgStack})
	assert.NoError(t, err)
}

func TestStackListBetweenOrganizations(t *testing.T) {
	// Create organization with a user
	testUser := h.RandomUser()
	testOrg := h.RandomOrg()
	ownerCtx := h.CreateOrganization(t, &testOrg, &testUser)
	orgCtx := h.Switch(ownerCtx, t, testOrg.Name)

	// Create another organization with a user
	anotherUser := h.RandomUser()
	anotherOrg := h.RandomOrg()
	anotherOwnerCtx := h.CreateOrganization(t, &anotherOrg, &anotherUser)
	anotherOrgCtx := h.Switch(anotherOwnerCtx, t, anotherOrg.Name)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as org
	orgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	r, err := h.Stacks().Deploy(orgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Deploy another stack as another org
	anotherOrgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq = &DeployRequest{
		Name:    anotherOrgStack,
		Compose: compose,
	}
	r, err = h.Stacks().Deploy(anotherOrgCtx, rq)
	assert.NoError(t, err)
	assert.NotEmpty(t, r.FullName)
	assert.NotEmpty(t, r.Answer)

	// Listing stacks as org
	stacks, err := h.Stacks().List(orgCtx, &ListRequest{})
	assert.NoError(t, err)
	assert.Len(t, stacks.Entries, 1)
	for _, stack := range stacks.Entries {
		assert.NotEqual(t, stack.Stack.Name, anotherOrgStack)
	}

	// Listing stacks as another org
	stacks, err = h.Stacks().List(anotherOrgCtx, &ListRequest{})
	assert.NoError(t, err)
	assert.Len(t, stacks.Entries, 1)
	for _, stack := range stacks.Entries {
		assert.NotEqual(t, stack.Stack.Name, orgStack)
	}

	// Remove stacks
	_, err = h.Stacks().Remove(orgCtx, &RemoveRequest{Stack: orgStack})
	assert.NoError(t, err)
	_, err = h.Stacks().Remove(anotherOrgCtx, &RemoveRequest{Stack: anotherOrgStack})
	assert.NoError(t, err)
}

func TestDeleteAnOrganizationOwningStacksShouldFail(t *testing.T) {
	// Create organization with a user
	testUser := h.RandomUser()
	testOrg := h.RandomOrg()
	ownerCtx := h.CreateOrganization(t, &testOrg, &testUser)
	orgCtx := h.Switch(ownerCtx, t, testOrg.Name)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as org
	orgStack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    orgStack,
		Compose: compose,
	}
	_, err = h.Stacks().Deploy(orgCtx, rq)
	assert.NoError(t, err)

	// Deleting the organization should fail
	_, err = h.Accounts().DeleteOrganization(orgCtx, &account.DeleteOrganizationRequest{Name: testOrg.Name})
	assert.Error(t, err)

	// Remove stack
	_, err = h.Stacks().Remove(orgCtx, &RemoveRequest{Stack: orgStack})
	assert.NoError(t, err)

	// Deleting the organization should succeed
	_, err = h.Accounts().DeleteOrganization(orgCtx, &account.DeleteOrganizationRequest{Name: testOrg.Name})
	assert.NoError(t, err)
}

func TestDeleteUserOwningStacksShouldFail(t *testing.T) {
	// Create a user
	testUser := h.RandomUser()
	userCtx := h.CreateUser(t, &testUser)

	// Compose file
	compose, err := ioutil.ReadFile("pinger.yml")
	assert.NoError(t, err)

	// Deploy stack as user
	stack := "my-awesome-stack" + stringid.GenerateNonCryptoID()[:16]
	rq := &DeployRequest{
		Name:    stack,
		Compose: compose,
	}
	_, err = h.Stacks().Deploy(userCtx, rq)
	assert.NoError(t, err)

	// Deleting the user should fail
	_, err = h.Accounts().DeleteUser(userCtx, &account.DeleteUserRequest{Name: testUser.Name})
	assert.Error(t, err)

	// Remove stack
	_, err = h.Stacks().Remove(userCtx, &RemoveRequest{Stack: stack})
	assert.NoError(t, err)

	// Deleting the user should succeed
	_, err = h.Accounts().DeleteUser(userCtx, &account.DeleteUserRequest{Name: testUser.Name})
	assert.NoError(t, err)
}
<|endoftext|>


<commit_before>// Get the number of open files for a process and compare that against /proc/<pid>/limits and alert if
// over the given threshold.
//
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"flag"
	"fmt"
	"github.com/yieldbot/dhuran"
	"io/ioutil"
	// "github.com/shirou/gopsutil/process"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

// Get the pid for the supplied process
func get_pid(app string) string {
	pid_exp := regexp.MustCompile("[0-9]+")
	go_pid := os.Getpid()
	a_pid := ""
	fmt.Printf("golang binary pid: %v\n", go_pid)

	ps_aef := exec.Command("ps", "-aef")

	out, err := ps_aef.Output()
	if err != nil {
		dhuran.Check(err)
	}

	ps_aef.Start()

	lines := strings.Split(string(out), "\n")
	for i := range lines {
		if strings.Contains(lines[i], app) && !strings.Contains(lines[i], strconv.Itoa(go_pid)) {
			a_pid = pid_exp.FindString(lines[i])
      break
		}
	}
	return a_pid
}

// Calculate if the value is over a threshold
func determine_threshold(limit int, threshold int, num_fd int) bool {
  alarm := true
  t_limit := (float64(threshold) / float64(100)) * float64(limit)

  if float64(num_fd) > float64(t_limit) {
    alarm = true
  } else {
    alarm = false
  }
  return alarm
}

// Get the current number of open file handles for the process
func get_file_handles(pid string) (int, int, int) {
	var _s, _h string
	var s, h int
	limit_exp := regexp.MustCompile("[0-9]+")
	filename := `/proc/` + pid + `/limits`
  fd_loc := "/proc/" + pid + "/fd"
  num_fd := 0

	limits, err := ioutil.ReadFile(filename)
	if err != nil {
		dhuran.Check(err)
	}

	lines := strings.Split(string(limits), "\n")
	for i := range lines {
		if strings.Contains(lines[i], "open files") {
			limits := limit_exp.FindAllString(lines[i], 2)
			_s = limits[0]
			_h = limits[1]

			s, err = strconv.Atoi(_s)
			if err != nil {
				// YELLOW handle error
				fmt.Println(err)
				os.Exit(2)
			}
			h, err = strconv.Atoi(_h)
			if err != nil {
				// YELLOW handle error
				fmt.Println(err)
				os.Exit(2)
			}
		}
	}

  files, _ := ioutil.ReadDir(fd_loc)
    for _ = range files {
      num_fd = num_fd + 1
    }
	return s, h, num_fd
}

func main() {

	// set commandline flags
	AppPtr := flag.String("app", "sbin/init", "the process name")
	WarnPtr := flag.Int("warn", 75, "the alert warning threshold percentage")
	CritPtr := flag.Int("crit", 75, "the alert critical threshold percentage")

	flag.Parse()
	app := *AppPtr
	warn_threshold := *WarnPtr
	crit_threshold := *CritPtr

	var app_pid string
	var s_limit, h_limit, open_fd int

	if app != "" {
		// YELLOW check for a null or nil string
		// need to check for the process better, regex?
		app_pid = get_pid(app)
		s_limit, h_limit , open_fd = get_file_handles(app_pid)
    if determine_threshold(h_limit, crit_threshold, open_fd) {
      fmt.Printf("%v is over %v percent of the the open file handles hard limit of %v\n", app, crit_threshold, h_limit)
      os.Exit(2)
    } else if determine_threshold(s_limit, warn_threshold, open_fd) {
        fmt.Printf("%v is over %v percent of the open file handles soft limit of %v\n", app, warn_threshold, s_limit)
        os.Exit(1)
    } else {
      // YELLOW need to set some other conditions here in case this fails
      fmt.Printf("warning threshold: %v percent, critical threshold: %v percent\n", warn_threshold, crit_threshold)
      fmt.Printf("this is the number of open files at the specific point in time: %v\n", open_fd)
    	fmt.Printf("app pid is: %v\n", app_pid)
    	fmt.Printf("This is the soft limit: %v\n", s_limit)
    	fmt.Printf("This is the hard limit: %v\n", h_limit)
      os.Exit(0)
    }
	} else {
		fmt.Printf("Please enter a process name to check")
		os.Exit(100)
	}
}
<commit_msg>formated<commit_after>// Get the number of open files for a process and compare that against /proc/<pid>/limits and alert if
// over the given threshold.
//
//
// LICENSE:
//   Copyright 2015 Yieldbot. <devops@yieldbot.com>
//   Released under the MIT License; see LICENSE
//   for details.

package main

import (
	"flag"
	"fmt"
	"github.com/yieldbot/dhuran"
	"io/ioutil"
	// "github.com/shirou/gopsutil/process"
	"os"
	"os/exec"
	"regexp"
	"strconv"
	"strings"
)

// Get the pid for the supplied process
func get_pid(app string) string {
	pid_exp := regexp.MustCompile("[0-9]+")
	go_pid := os.Getpid()
	a_pid := ""
	fmt.Printf("golang binary pid: %v\n", go_pid)

	ps_aef := exec.Command("ps", "-aef")

	out, err := ps_aef.Output()
	if err != nil {
		dhuran.Check(err)
	}

	ps_aef.Start()

	lines := strings.Split(string(out), "\n")
	for i := range lines {
		if strings.Contains(lines[i], app) && !strings.Contains(lines[i], strconv.Itoa(go_pid)) {
			a_pid = pid_exp.FindString(lines[i])
			break
		}
	}
	return a_pid
}

// Calculate if the value is over a threshold
func determine_threshold(limit int, threshold int, num_fd int) bool {
	alarm := true
	t_limit := (float64(threshold) / float64(100)) * float64(limit)

	if float64(num_fd) > float64(t_limit) {
		alarm = true
	} else {
		alarm = false
	}
	return alarm
}

// Get the current number of open file handles for the process
func get_file_handles(pid string) (int, int, int) {
	var _s, _h string
	var s, h int
	limit_exp := regexp.MustCompile("[0-9]+")
	filename := `/proc/` + pid + `/limits`
	fd_loc := "/proc/" + pid + "/fd"
	num_fd := 0

	limits, err := ioutil.ReadFile(filename)
	if err != nil {
		dhuran.Check(err)
	}

	lines := strings.Split(string(limits), "\n")
	for i := range lines {
		if strings.Contains(lines[i], "open files") {
			limits := limit_exp.FindAllString(lines[i], 2)
			_s = limits[0]
			_h = limits[1]

			s, err = strconv.Atoi(_s)
			if err != nil {
				// YELLOW handle error
				fmt.Println(err)
				os.Exit(2)
			}
			h, err = strconv.Atoi(_h)
			if err != nil {
				// YELLOW handle error
				fmt.Println(err)
				os.Exit(2)
			}
		}
	}

	files, _ := ioutil.ReadDir(fd_loc)
	for _ = range files {
		num_fd = num_fd + 1
	}
	return s, h, num_fd
}

func main() {

	// set commandline flags
	AppPtr := flag.String("app", "sbin/init", "the process name")
	WarnPtr := flag.Int("warn", 75, "the alert warning threshold percentage")
	CritPtr := flag.Int("crit", 75, "the alert critical threshold percentage")

	flag.Parse()
	app := *AppPtr
	warn_threshold := *WarnPtr
	crit_threshold := *CritPtr

	var app_pid string
	var s_limit, h_limit, open_fd int

	if app != "" {
		// YELLOW check for a null or nil string
		// need to check for the process better, regex?
		app_pid = get_pid(app)
		s_limit, h_limit, open_fd = get_file_handles(app_pid)
		if determine_threshold(h_limit, crit_threshold, open_fd) {
			fmt.Printf("%v is over %v percent of the the open file handles hard limit of %v\n", app, crit_threshold, h_limit)
			os.Exit(2)
		} else if determine_threshold(s_limit, warn_threshold, open_fd) {
			fmt.Printf("%v is over %v percent of the open file handles soft limit of %v\n", app, warn_threshold, s_limit)
			os.Exit(1)
		} else {
			// YELLOW need to set some other conditions here in case this fails
			fmt.Printf("warning threshold: %v percent, critical threshold: %v percent\n", warn_threshold, crit_threshold)
			fmt.Printf("this is the number of open files at the specific point in time: %v\n", open_fd)
			fmt.Printf("app pid is: %v\n", app_pid)
			fmt.Printf("This is the soft limit: %v\n", s_limit)
			fmt.Printf("This is the hard limit: %v\n", h_limit)
			os.Exit(0)
		}
	} else {
		fmt.Printf("Please enter a process name to check")
		os.Exit(100)
	}
}
<|endoftext|>