Ejemplo n.º 1
0
// Upsert will insert a new Exception if nothing matching uniqueid exists
// Then, it will add to instances/traces of the Exception
func (exception *Exception) Upsert(trace *Trace, db *mgo.Database) (err error) {

	log.Printf("Upserting: %#v\n", exception)

	if err = db.C("exceptions").EnsureIndex(mgo.Index{Key: []string{"uniqueid"}, Unique: true}); err != nil {
		return
	}

	// First, we'll try to insert
	// Due to the unique constraint on UniqueID, this will fail if the record exists already
	err = db.C("exceptions").Insert(&exception)
	if err != nil && !mgo.IsDup(err) { // Swallow duplicate error
		return
	}

	// Now, we're going to push the instance to mark when this happened
	err = db.C("exceptions").Update(bson.M{"uniqueid": exception.UniqueId}, bson.M{
		"$push": bson.M{"instances": time.Now()},
	})

	if err != nil {
		return err
	}

	// Finally, we'll add the trace (for now, unlimited)
	err = db.C("exceptions").Update(bson.M{"uniqueid": exception.UniqueId}, bson.M{
		"$push": bson.M{"traces": &trace},
	})

	if err != nil {
		return err
	}

	return
}
Ejemplo n.º 2
0
func Test_newUser(t *testing.T) {
	c, session, err := connect(users)
	if err != nil {
		t.Fatal(err)
	}

	t.Logf("Test without email")
	foo, err := newUser(session, "Foo", "password", "")
	if err != nil {
		t.Error(err)
	}
	t.Logf("Test with email")
	nemo1, err := newUser(session, "Nemo", "password", "*****@*****.**")
	if err != nil {
		t.Error(err)
	}
	t.Logf("Test duplicate user")
	nemo2, err := newUser(session, "Nemo", "password", "*****@*****.**")
	if !mgo.IsDup(err) {
		t.Error(err)
	}

	if err = c.Remove(foo); err != nil {
		t.Error(err)
	}
	if err = c.Remove(nemo1); err != nil {
		t.Error(err)
	}
	if err = c.Remove(nemo2); err != mgo.ErrNotFound {
		t.Error(err)
	}
}
Ejemplo n.º 3
0
// PlatformAdd add a new platform to tsuru
func PlatformAdd(name string, args map[string]string, w io.Writer) error {
	var (
		provisioner provision.ExtensibleProvisioner
		ok          bool
	)
	if provisioner, ok = Provisioner.(provision.ExtensibleProvisioner); !ok {
		return errors.New("Provisioner is not extensible")
	}
	if name == "" {
		return errors.New("Platform name is required.")
	}
	p := Platform{Name: name}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	err = conn.Platforms().Insert(p)
	if err != nil {
		if mgo.IsDup(err) {
			return DuplicatePlatformError{}
		}
		return err
	}
	err = provisioner.PlatformAdd(name, args, w)
	if err != nil {
		db_err := conn.Platforms().RemoveId(p.Name)
		if db_err != nil {
			return fmt.Errorf("Caused by: %s and %s", err.Error(), db_err.Error())
		}
		return err
	}
	return nil
}
Ejemplo n.º 4
0
// New creates a representation of a git repository. It creates a Git
// repository using the "bare-dir" setting and saves repository's meta data in
// the database.
func New(name string, users []string, isPublic bool) (*Repository, error) {
	log.Debugf("Creating repository %q", name)
	r := &Repository{Name: name, Users: users, IsPublic: isPublic}
	if v, err := r.isValid(); !v {
		log.Errorf("repository.New: Invalid repository %q: %s", name, err)
		return r, err
	}
	if err := newBare(name); err != nil {
		log.Errorf("repository.New: Error creating bare repository for %q: %s", name, err)
		return r, err
	}
	barePath := barePath(name)
	if barePath != "" && isPublic {
		ioutil.WriteFile(barePath+"/git-daemon-export-ok", []byte(""), 0644)
		if f, err := fs.Filesystem().Create(barePath + "/git-daemon-export-ok"); err == nil {
			f.Close()
		}
	}
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	err = conn.Repository().Insert(&r)
	if mgo.IsDup(err) {
		log.Errorf("repository.New: Duplicate repository %q", name)
		return r, fmt.Errorf("A repository with this name already exists.")
	}
	return r, err
}
Ejemplo n.º 5
0
func (c *MongoCache) PutDistance(route Route, distance uint64) {
	s := c.session.Clone()
	defer s.Close()

	err := s.DB("").C("routes").Insert(NewCachedRoute(route, distance))
	if err != nil && !mgo.IsDup(err) {
		log.Println("MongoCache: PUT error -> ", err)
	}
}
Ejemplo n.º 6
0
func (c *MongoCache) PutTrip(username string, trip Trip) {
	s := c.session.Clone()
	defer s.Close()

	err := s.DB("").C("trips").Insert(NewCachedTrip(username, trip))
	if err != nil && !mgo.IsDup(err) {
		log.Println("MongoCache: PUT error -> ", err)
	}
}
Ejemplo n.º 7
0
// Add inserts new package and ignores if package exist already
func (p *Package) Add(pr *PackageRow) (*PackageRow, error) {
	pr.Created = time.Now()
	pr.Id = bson.NewObjectId()
	err := p.coll.Insert(pr)
	if err != nil && !mgo.IsDup(err) {
		return nil, err
	}
	return pr, nil
}
Ejemplo n.º 8
0
// insertUser inserts User to database.
// the user with that email exist. Note that indexes musted create fo MongoDB.
func (m *MgoUserManager) insertUser(u *auth.User) error {
	err := m.UserColl.Insert(u)
	if err != nil {
		if mgo.IsDup(err) {
			return auth.ErrDuplicateEmail
		}
		return err
	}

	return nil
}
Ejemplo n.º 9
0
func (rs *controller) Post(w http.ResponseWriter, request *http.Request, p httprouter.Params) {
	defer request.Body.Close()

	data, err := ioutil.ReadAll(request.Body)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	var rule Rule
	err = json.Unmarshal(data, &rule)
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	err = Save(&rule)
	if err != nil {
		if mgo.IsDup(err) {
			http.Error(w, err.Error(), http.StatusBadRequest)
		} else {
			http.Error(w, err.Error(), http.StatusInternalServerError)
		}
		return
	}
	axn, err := rule.GetAction()
	if err != nil {
		http.Error(w, err.Error(), http.StatusBadRequest)
		return
	}
	actions.Add(axn)
	req, err := http.NewRequest("POST", config.RuleEndpoint(), strings.NewReader(rule.EPL))
	if err != nil {
		mylog.Alert("rule controller POST", err)
	}
	resp, err := httpClient.Do(req)
	if err != nil {
		mylog.Alert("rule controller POST", err, resp)
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	if resp.StatusCode/100 != 2 {
		mylog.Alert("rule controller POST", resp.Status)
		http.Error(w, resp.Status, http.StatusInternalServerError)
		return
	}
	w.WriteHeader(http.StatusCreated)
	dataBack, err := json.Marshal(rule)
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}
	w.Write(dataBack)

}
Ejemplo n.º 10
0
// Register adds a new node to the scheduler, registering for use in
// the given team. The team parameter is optional, when set to "", the node
// will be used as a fallback node.
func (segregatedScheduler) Register(params map[string]string) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	node := node{ID: params["ID"], Address: params["address"], Teams: []string{params["team"]}}
	err = conn.Collection(schedulerCollection).Insert(node)
	if mgo.IsDup(err) {
		return errNodeAlreadyRegister
	}
	return err
}
Ejemplo n.º 11
0
// AddNodeToScheduler adds a new node to the scheduler, registering for use in
// the given team. The team parameter is optional, when set to "", the node
// will be used as a fallback node.
func addNodeToScheduler(n cluster.Node, team string) error {
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	node := node{ID: n.ID, Address: n.Address, Team: team}
	err = conn.Collection(schedulerCollection).Insert(node)
	if mgo.IsDup(err) {
		return errNodeAlreadyRegister
	}
	return err
}
Ejemplo n.º 12
0
func (ctx *MgoUserCtx) insertUser(u *Account, notif, app bool) error {
	err := ctx.userColl.Insert(u)
	if err != nil {
		if mgo.IsDup(err) {
			return membership.ErrDuplicateEmail
		}
		return err
	}

	if notif {
		return ctx.notifer.AccountAdded(u)
	}
	return nil
}
Ejemplo n.º 13
0
func (a *AuthMongoDBCtx) insertUser(u *User, notif, app bool) error {
	err := a.userColl.Insert(u)
	if err != nil {
		if mgo.IsDup(err) {
			return ErrDuplicateEmail
		}
		return err
	}

	if notif {
		return a.notifer.AccountAdded(u.Email, app)
	}
	return nil
}
Ejemplo n.º 14
0
// New creates a representation of a git repository. It creates a Git
// repository using the "bare-dir" setting and saves repository's meta data in
// the database.
func New(name string, users []string, isPublic bool) (*Repository, error) {
	r := &Repository{Name: name, Users: users, IsPublic: isPublic}
	if v, err := r.isValid(); !v {
		return r, err
	}
	if err := newBare(name); err != nil {
		return r, err
	}
	err := db.Session.Repository().Insert(&r)
	if mgo.IsDup(err) {
		return r, fmt.Errorf("A repository with this name already exists.")
	}
	return r, err
}
Ejemplo n.º 15
0
// PlatformAdd add a new platform to tsuru
func PlatformAdd(name string, file string) error {
	p := Platform{Name: name}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	err = conn.Platforms().Insert(p)
	if err != nil {
		if mgo.IsDup(err) {
			return DuplicatePlatformError{}
		}
		return err
	}
	err = Provisioner.PlatformAdd(name, file)
	return nil
}
Ejemplo n.º 16
0
func (m *MgoManager) insertUser(u *User) error {
	now := time.Now()
	u.LastActivity = &now
	if u.Profile == nil {
		u.Profile = &authmodel.Profile{}
	}
	u.Profile.JoinDay = u.LastActivity

	err := m.UserColl.Insert(u)
	if err != nil {
		if mgo.IsDup(err) {
			return authmodel.ErrDuplicateEmail
		}
		return err
	}

	return nil
}
Ejemplo n.º 17
0
func (ctx *MgoGroupCtx) AddGroupDetail(name string, info membership.GroupInfo,
	pri map[string]bool) (membership.Grouper, error) {
	g := &Group{}
	g.Id = bson.NewObjectId()
	g.Name = name
	g.Info = info
	g.Privilege = pri

	err := ctx.groupColl.Insert(g)
	if err != nil {
		if mgo.IsDup(err) {
			return nil, membership.ErrDuplicateName
		}
		return nil, err
	}

	return g, nil
}
Ejemplo n.º 18
0
// AddGroupDetail adds a group with full detail to database.
func (m *MgoGroupManager) AddGroupDetail(name string, info *auth.GroupInfo,
	pri []string) (*auth.Group, error) {
	group := &auth.Group{}
	group.Id = bson.NewObjectId()
	group.Name = name
	group.Info = *info
	group.Privilege = pri

	err := m.GroupColl.Insert(group)
	if err != nil {
		if mgo.IsDup(err) {
			return nil, auth.ErrDuplicateName
		}
		return nil, err
	}

	return group, nil
}
Ejemplo n.º 19
0
// Writes `key` in authorized_keys file (from current user)
// It does not writes in the database, there is no need for that since the key
// object is embedded on the user's document
func addKey(name, body, username string) error {
	key, err := newKey(name, username, body)
	if err != nil {
		return err
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	err = conn.Key().Insert(key)
	if err != nil {
		if mgo.IsDup(err) {
			return ErrDuplicateKey
		}
		return err
	}
	return writeKey(key)
}
Ejemplo n.º 20
0
// PlatformAdd add a new platform to tsuru
func PlatformAdd(name string, args map[string]string, w io.Writer) error {
	if name == "" {
		return errors.New("Platform name is required.")
	}
	p := Platform{Name: name}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	err = Provisioner.PlatformAdd(name, args, w)
	if err != nil {
		return err
	}
	err = conn.Platforms().Insert(p)
	if err != nil {
		if mgo.IsDup(err) {
			return DuplicatePlatformError{}
		}
		return err
	}
	return nil
}
Ejemplo n.º 21
0
// Creates a new user and write his/her keys into authorized_keys file.
//
// The authorized_keys file belongs to the user running the process.
func New(name string, keys map[string]string) (*User, error) {
	log.Debugf(`Creating user "%s"`, name)
	u := &User{Name: name}
	if v, err := u.isValid(); !v {
		log.Errorf("user.New: %s", err.Error())
		return u, err
	}
	conn, err := db.Conn()
	if err != nil {
		return nil, err
	}
	defer conn.Close()
	if err := conn.User().Insert(&u); err != nil {
		if mgo.IsDup(err) {
			log.Errorf("user.New: %q duplicate user", name)
			return u, errors.New("Could not create user: user already exists")
		}
		log.Errorf("user.New: %s", err)
		return u, err
	}
	return u, addKeys(keys, u.Name)
}
Ejemplo n.º 22
0
func (m *MgoManager) AddGroupDetail(name string, pri []string, info *authmodel.GroupInfo) (*authmodel.Group, error) {
	group := &Group{}
	group.Id = bson.NewObjectId()
	sid := group.Id.Hex()
	group.Group.Id = &sid
	group.Name = &name
	group.Privileges = pri
	group.Info = info
	if group.Name == nil {
		return nil, authmodel.ErrInvalidEmail
	}

	err := m.GroupColl.Insert(group)
	if err != nil {
		if mgo.IsDup(err) {
			return nil, authmodel.ErrDuplicateName
		}
		return nil, err
	}

	return &group.Group, nil
}
Ejemplo n.º 23
0
Archivo: team.go Proyecto: nemx/tsuru
func CreateTeam(name string, user ...*User) error {
	name = strings.TrimSpace(name)
	if !isTeamNameValid(name) {
		return ErrInvalidTeamName
	}
	team := Team{
		Name:  name,
		Users: make([]string, len(user)),
	}
	for i, u := range user {
		team.Users[i] = u.Email
	}
	conn, err := db.Conn()
	if err != nil {
		return err
	}
	defer conn.Close()
	err = conn.Teams().Insert(team)
	if mgo.IsDup(err) {
		return ErrTeamAlreadyExists
	}
	return err
}
Ejemplo n.º 24
0
func makeArticle(db *mgo.Database, p *wikiparse.Page) {
	a := article{}
	a.RevInfo.ID = p.Revisions[0].ID
	a.RevInfo.Timestamp = p.Revisions[0].Timestamp
	a.RevInfo.Contributor = p.Revisions[0].Contributor.Username
	a.RevInfo.ContributorID = p.Revisions[0].Contributor.ID
	a.RevInfo.Comment = p.Revisions[0].Comment

	a.Title = p.Title
	a.Text = p.Revisions[0].Text
	a.Links = wikiparse.FindLinks(a.Text)
	a.Files = wikiparse.FindFiles(a.Text)
	err := db.C(*collection).Insert(&a)
	if err != nil {
		if mgo.IsDup(err) {
			if *verbose == true {
				log.Printf("Duplicate Key Error inserting %s", a.Title)
			}
		} else {
			log.Printf("Error inserting %s: %s", a.Title, err)
		}
	}
	wg.Done()
}
Ejemplo n.º 25
0
// NewInstallationHandler ...
func NewInstallationHandler(w http.ResponseWriter, r *http.Request, c *Context) {
	machineId := r.PostFormValue("machine_id")
	xmppvoxVersion := r.PostFormValue("xmppvox_version")
	dosvoxInfoStr := r.PostFormValue("dosvox_info")
	machineInfoStr := r.PostFormValue("machine_info")
	if len(r.PostForm) != 4 || machineId == "" || xmppvoxVersion == "" || dosvoxInfoStr == "" || machineInfoStr == "" {
		http.Error(w, "Retry with POST parameters: machine_id, xmppvox_version, dosvox_info, machine_info",
			http.StatusBadRequest)
		return
	}
	var dosvoxInfo, machineInfo map[string]string
	err := json.Unmarshal([]byte(dosvoxInfoStr), &dosvoxInfo)
	if err != nil {
		http.Error(w, "Invalid JSON for dosvox_info", http.StatusBadRequest)
		return
	}
	err = json.Unmarshal([]byte(machineInfoStr), &machineInfo)
	if err != nil {
		http.Error(w, "Invalid JSON for machine_info", http.StatusBadRequest)
		return
	}
	i := NewInstallation(machineId, xmppvoxVersion, dosvoxInfo, machineInfo)
	err = c.Store.InsertInstallation(i)
	if mgo.IsDup(err) {
		http.Error(w, "Installation already registered", http.StatusBadRequest)
		return
	}
	switch err {
	case nil:
		fmt.Fprintln(w, machineId)
	default:
		http.Error(w, fmt.Sprintf("Failed to track install %s", machineId),
			http.StatusInternalServerError)
		log.Println(err)
	}
}
Ejemplo n.º 26
0
func (f *flusher) apply(t *transaction, pull map[bson.ObjectId]*transaction) error {
	f.debugf("Applying transaction %s", t)
	if t.State != tapplying {
		panic(fmt.Errorf("applying transaction in invalid state: %q", t.State))
	}
	if pull == nil {
		pull = map[bson.ObjectId]*transaction{t.Id: t}
	}

	// Compute the operation in which t's id may be pulled
	// out of txn-queue. That's on its last change, or the
	// first assertion.
	pullOp := make(map[docKey]int)
	for i := range t.Ops {
		op := &t.Ops[i]
		dkey := op.docKey()
		if _, ok := pullOp[dkey]; !ok || op.isChange() {
			pullOp[dkey] = i
		}
	}

	logRevnos := append([]int64(nil), t.Revnos...)
	logDoc := bson.D{{"_id", t.Id}}

	tt := tokenFor(t)
	for i := range t.Ops {
		op := &t.Ops[i]
		dkey := op.docKey()
		dqueue := f.queue[dkey]
		revno := t.Revnos[i]

		var opName string
		if debugEnabled {
			opName = op.name()
			f.debugf("Applying %s op %d (%s) on %v with txn-revno %d", t, i, opName, dkey, revno)
		}

		c := f.tc.Database.C(op.C)
		var revnoq, idq interface{}
		if revno == 0 || op.Insert != nil && revno == -1 {
			revnoq = bson.D{{"$exists", false}}
		} else {
			revnoq = revno
		}
		if op.Insert != nil {
			idq = dkey
		} else {
			idq = dkey.Id
		}
		qdoc := bson.D{{"_id", idq}, {"txn-revno", revnoq}, {"txn-queue", tt}}

		dontPull := tt
		isPullOp := pullOp[dkey] == i
		if isPullOp {
			dontPull = ""
		}
		pullAll := tokensToPull(dqueue, pull, dontPull)

		var d bson.D
		var outcome string
		var err error
		switch {
		case op.Update != nil:
			if revno < 0 {
				err = mgo.ErrNotFound
			} else {
				newRevno := revno + 1
				logRevnos[i] = newRevno
				if d, err = objToDoc(op.Update); err != nil {
					return err
				}
				if d, err = addToDoc(d, "$pullAll", bson.D{{"txn-queue", pullAll}}); err != nil {
					return err
				}
				if d, err = addToDoc(d, "$set", bson.D{{"txn-revno", newRevno}}); err != nil {
					return err
				}
				chaos("")
				err = c.Update(qdoc, d)
			}
		case op.Remove:
			if revno < 0 {
				err = mgo.ErrNotFound
			} else {
				newRevno := -revno - 1
				logRevnos[i] = newRevno
				nonce := newNonce()
				stash := txnInfo{}
				change := mgo.Change{
					Update:    bson.D{{"$push", bson.D{{"n", nonce}}}},
					Upsert:    true,
					ReturnNew: true,
				}
				if _, err = f.sc.FindId(dkey).Apply(change, &stash); err != nil {
					return err
				}
				change = mgo.Change{
					Update:    bson.D{{"$set", bson.D{{"txn-remove", t.Id}}}},
					ReturnNew: true,
				}
				var info txnInfo
				if _, err = c.Find(qdoc).Apply(change, &info); err == nil {
					// The document still exists so the stash previously
					// observed was either out of date or necessarily
					// contained the token being applied.
					f.debugf("Marked document %v to be removed on revno %d with queue: %v", dkey, info.Revno, info.Queue)
					updated := false
					if !hasToken(stash.Queue, tt) {
						var set, unset bson.D
						if revno == 0 {
							// Missing revno in stash means -1.
							set = bson.D{{"txn-queue", info.Queue}}
							unset = bson.D{{"n", 1}, {"txn-revno", 1}}
						} else {
							set = bson.D{{"txn-queue", info.Queue}, {"txn-revno", newRevno}}
							unset = bson.D{{"n", 1}}
						}
						qdoc := bson.D{{"_id", dkey}, {"n", nonce}}
						udoc := bson.D{{"$set", set}, {"$unset", unset}}
						if err = f.sc.Update(qdoc, udoc); err == nil {
							updated = true
						} else if err != mgo.ErrNotFound {
							return err
						}
					}
					if updated {
						f.debugf("Updated stash for document %v with revno %d and queue: %v", dkey, newRevno, info.Queue)
					} else {
						f.debugf("Stash for document %v was up-to-date", dkey)
					}
					err = c.Remove(qdoc)
				}
			}
		case op.Insert != nil:
			if revno >= 0 {
				err = mgo.ErrNotFound
			} else {
				newRevno := -revno + 1
				logRevnos[i] = newRevno
				if d, err = objToDoc(op.Insert); err != nil {
					return err
				}
				change := mgo.Change{
					Update:    bson.D{{"$set", bson.D{{"txn-insert", t.Id}}}},
					ReturnNew: true,
				}
				chaos("")
				var info txnInfo
				if _, err = f.sc.Find(qdoc).Apply(change, &info); err == nil {
					f.debugf("Stash for document %v has revno %d and queue: %v", dkey, info.Revno, info.Queue)
					d = setInDoc(d, bson.D{{"_id", op.Id}, {"txn-revno", newRevno}, {"txn-queue", info.Queue}})
					// Unlikely yet unfortunate race in here if this gets seriously
					// delayed. If someone inserts+removes meanwhile, this will
					// reinsert, and there's no way to avoid that while keeping the
					// collection clean or compromising sharding. applyOps can solve
					// the former, but it can't shard (SERVER-1439).
					chaos("insert")
					err = c.Insert(d)
					if err == nil || mgo.IsDup(err) {
						if err == nil {
							f.debugf("New document %v inserted with revno %d and queue: %v", dkey, info.Revno, info.Queue)
						} else {
							f.debugf("Document %v already existed", dkey)
						}
						chaos("")
						if err = f.sc.Remove(qdoc); err == nil {
							f.debugf("Stash for document %v removed", dkey)
						}
					}
					if pullOp[dkey] == i && len(pullAll) > 0 {
						_ = f.sc.UpdateId(dkey, bson.D{{"$pullAll", bson.D{{"txn-queue", pullAll}}}})
					}
				}
			}
		case op.Assert != nil:
			// TODO pullAll if pullOp[dkey] == i
		}
		if err == nil {
			outcome = "DONE"
		} else if err == mgo.ErrNotFound || mgo.IsDup(err) {
			outcome = "MISS"
			err = nil
		} else {
			outcome = err.Error()
		}
		if debugEnabled {
			f.debugf("Applying %s op %d (%s) on %v with txn-revno %d: %s", t, i, opName, dkey, revno, outcome)
		}
		if err != nil {
			return err
		}

		if f.lc != nil && op.isChange() {
			// Add change to the log document.
			var dr bson.D
			for li := range logDoc {
				elem := &logDoc[li]
				if elem.Name == op.C {
					dr = elem.Value.(bson.D)
					break
				}
			}
			if dr == nil {
				logDoc = append(logDoc, bson.DocElem{op.C, bson.D{{"d", []interface{}{}}, {"r", []int64{}}}})
				dr = logDoc[len(logDoc)-1].Value.(bson.D)
			}
			dr[0].Value = append(dr[0].Value.([]interface{}), op.Id)
			dr[1].Value = append(dr[1].Value.([]int64), logRevnos[i])
		}
	}
	t.State = tapplied

	if f.lc != nil {
		// Insert log document into the changelog collection.
		f.debugf("Inserting %s into change log", t)
		err := f.lc.Insert(logDoc)
		if err != nil && !mgo.IsDup(err) {
			return err
		}
	}

	// It's been applied, so errors are ignored here. It's fine for someone
	// else to win the race and mark it as applied, and it's also fine for
	// it to remain pending until a later point when someone will perceive
	// it has been applied and mark it at such.
	f.debugf("Marking %s as applied", t)
	chaos("set-applied")
	f.tc.Update(bson.D{{"_id", t.Id}, {"s", tapplying}}, bson.D{{"$set", bson.D{{"s", tapplied}}}})
	return nil
}
Ejemplo n.º 27
0
// Create creates a blob with the given name, reading
// the contents from the given reader. The sha256Hash
// parameter holds the sha256 hash of the blob's contents,
// encoded as ASCII hexadecimal.
//
// If a blob with the same content already exists in the store,
// that content will be reused, its reference count
// incremented, and alreadyExists will be true.
// No data will have been read from r in this case.
func (s *Storage) Create(sha256Hash string, r io.Reader) (alreadyExists bool, err error) {
	blobRef := hashName(sha256Hash)

	// First try to increment the file's reference count.
	err = s.incRefCount(blobRef)
	if err == nil {
		return true, nil
	}
	if err != mgo.ErrNotFound {
		return false, err
	}
	f, err := s.fs.Create(blobRef)
	if err != nil {
		return false, err
	}
	f.SetMeta(refCountMeta{RefCount: 1})
	f.SetName(blobRef)
	if err := copyAndCheckHash(f, r, sha256Hash); err != nil {
		// Remove any chunks that were written while we were checking the hash.
		f.Abort()
		if closeErr := f.Close(); closeErr != nil {
			// TODO add mgo.ErrAborted so that we can avoid a string error check.
			if closeErr.Error() != "write aborted" {
				log.Printf("cannot clean up after hash-mismatch file write: %v", closeErr)
			}
		}
		return false, err
	}

	err = f.Close()
	if err == nil {
		return false, nil
	}
	if !mgo.IsDup(err) {
		return false, err
	}
	// We cannot close the file because of a clashing index,
	// which means someone else has created the blob first,
	// so all we need to do is increment the ref count.
	err = s.incRefCount(blobRef)
	if err == nil {
		// Although technically, the content already exists,
		// we have already read the content from the reader,
		// so report alreadyExists=false.
		return false, nil
	}
	if err != mgo.ErrNotFound {
		return false, fmt.Errorf("cannot increment blob ref count: %v", err)
	}
	// Unfortunately the other party has deleted the blob
	// in between Close and incRefCount.
	// The chunks we have written have already been
	// deleted at this point, so there's nothing we
	// can do except return an error. This situation
	// should be vanishingly unlikely in practice as
	// it relies on
	// a) two simultaneous initial uploads of the same blob.
	// b) one upload being removed immediately after upload.
	// c) the removal happening in the exact window between
	// f.Close and s.incRefCount.
	return false, fmt.Errorf("duplicate blob removed at an inopportune moment")
}
Ejemplo n.º 28
0
			app = *ctx.Params[0].(*App)
		default:
			return nil, errors.New("First parameter must be App or *App.")
		}
		conn, err := db.Conn()
		if err != nil {
			return nil, err
		}
		defer conn.Close()
		app.Quota = quota.Unlimited
		if limit, err := config.GetInt("quota:units-per-app"); err == nil {
			app.Quota.Limit = limit
		}
		app.Units = append(app.Units, Unit{})
		err = conn.Apps().Insert(app)
		if mgo.IsDup(err) {
			return nil, ErrAppAlreadyExists
		}
		return &app, err
	},
	Backward: func(ctx action.BWContext) {
		app := ctx.FWResult.(*App)
		conn, err := db.Conn()
		if err != nil {
			log.Errorf("Could not connect to the database: %s", err)
			return
		}
		defer conn.Close()
		conn.Apps().Remove(bson.M{"name": app.Name})
	},
	MinParams: 1,