func (b *etcdBackend) SetServiceMeta(service string, meta *discoverd.ServiceMeta) error { serviceKey := b.serviceKey(service) _, err := b.etcd.Get(serviceKey, false, false) if isEtcdNotFound(err) { return NotFoundError{Service: service} } if err != nil { return err } var res *etcd.Response key := path.Join(serviceKey, "meta") if meta.Index == 0 { res, err = b.etcd.Create(key, string(meta.Data), 0) if isEtcdExists(err) { err = hh.ObjectExistsErr(fmt.Sprintf("Service metadata for %q already exists, use index=n to set", service)) } } else { res, err = b.etcd.CompareAndSwap(key, string(meta.Data), 0, "", meta.Index) if isEtcdNotFound(err) { err = hh.PreconditionFailedErr(fmt.Sprintf("Service metadata for %q does not exist, use index=0 to set", service)) } else if isEtcdCompareFailed(err) { err = hh.PreconditionFailedErr(fmt.Sprintf("Service metadata for %q exists, but wrong index provided", service)) } } if err != nil { return err } meta.Index = res.Node.ModifiedIndex return nil }
func (r *AppRepo) Add(data interface{}) error { app := data.(*ct.App) tx, err := r.db.Begin() if err != nil { return err } if app.Name == "" { var nameID uint32 if err := tx.QueryRow("SELECT nextval('name_ids')").Scan(&nameID); err != nil { tx.Rollback() return err } app.Name = name.Get(nameID) } if len(app.Name) > 100 || !utils.AppNamePattern.MatchString(app.Name) { return ct.ValidationError{Field: "name", Message: "is invalid"} } if app.ID == "" { app.ID = random.UUID() } if app.Strategy == "" { app.Strategy = "all-at-once" } meta, err := json.Marshal(app.Meta) if err != nil { return err } if err := tx.QueryRow("INSERT INTO apps (app_id, name, meta, strategy) VALUES ($1, $2, $3, $4) RETURNING created_at, updated_at", app.ID, app.Name, meta, app.Strategy).Scan(&app.CreatedAt, &app.UpdatedAt); err != nil { tx.Rollback() if postgres.IsUniquenessError(err, "apps_name_idx") { return httphelper.ObjectExistsErr(fmt.Sprintf("application %q already exists", app.Name)) } return err } if err := createEvent(tx.Exec, &ct.Event{ AppID: app.ID, ObjectID: app.ID, ObjectType: ct.EventTypeApp, }, app); err != nil { tx.Rollback() return err } if err := tx.Commit(); err != nil { return err } if !app.System() && r.defaultDomain != "" { route := (&router.HTTPRoute{ Domain: fmt.Sprintf("%s.%s", app.Name, r.defaultDomain), Service: app.Name + "-web", }).ToRoute() if err := createRoute(r.db, r.router, app.ID, route); err != nil { log.Printf("Error creating default route for %s: %s", app.Name, err) } } return nil }
func (s *Store) applySetServiceMetaCommand(cmd []byte, index uint64) error { var c setServiceMetaCommand if err := json.Unmarshal(cmd, &c); err != nil { return err } // Verify that the service exists. service := s.data.Services[c.Service] if service == nil { return NotFoundError{Service: c.Service} } // If no index is provided then the meta should not be set. curr := s.data.Metas[c.Service] if c.Meta.Index == 0 { if curr != nil { return hh.ObjectExistsErr(fmt.Sprintf("Service metadata for %q already exists, use index=n to set", c.Service)) } } else { if curr == nil { return hh.PreconditionFailedErr(fmt.Sprintf("Service metadata for %q does not exist, use index=0 to set", c.Service)) } else if curr.Index != c.Meta.Index { return hh.PreconditionFailedErr(fmt.Sprintf("Service metadata for %q exists, but wrong index provided", c.Service)) } } leaderID := c.Meta.LeaderID c.Meta.LeaderID = "" // Update the meta and set the index. c.Meta.Index = index s.data.Metas[c.Service] = c.Meta if leaderID != "" { // If a new leader was included in the meta update, apply it s.data.Leaders[c.Service] = leaderID } // Broadcast EventKindServiceMeta event. s.broadcast(&discoverd.Event{ Service: c.Service, Kind: discoverd.EventKindServiceMeta, ServiceMeta: c.Meta, }) if leaderID != "" { // Broadcast leader update, if the new instance exists if inst := s.data.Instances[c.Service][leaderID]; inst != nil { s.broadcast(&discoverd.Event{ Service: c.Service, Kind: discoverd.EventKindLeader, Instance: inst, }) } } return nil }
func (r *AppRepo) Add(data interface{}) error { app := data.(*ct.App) tx, err := r.db.Begin() if err != nil { return err } if app.Name == "" { var nameID int64 if err := tx.QueryRow("app_next_name_id").Scan(&nameID); err != nil { tx.Rollback() return err } // Safe cast because name_ids is limited to 32 bit size in schema app.Name = name.Get(uint32(nameID)) } if len(app.Name) > 100 || !utils.AppNamePattern.MatchString(app.Name) { return ct.ValidationError{Field: "name", Message: "is invalid"} } if app.ID == "" { app.ID = random.UUID() } if app.Strategy == "" { app.Strategy = "all-at-once" } if app.DeployTimeout == 0 { app.DeployTimeout = ct.DefaultDeployTimeout } if err := tx.QueryRow("app_insert", app.ID, app.Name, app.Meta, app.Strategy, app.DeployTimeout).Scan(&app.CreatedAt, &app.UpdatedAt); err != nil { tx.Rollback() if postgres.IsUniquenessError(err, "apps_name_idx") { return httphelper.ObjectExistsErr(fmt.Sprintf("application %q already exists", app.Name)) } return err } if err := createEvent(tx.Exec, &ct.Event{ AppID: app.ID, ObjectID: app.ID, ObjectType: ct.EventTypeApp, }, app); err != nil { tx.Rollback() return err } if err := tx.Commit(); err != nil { return err } if !app.System() && r.defaultDomain != "" { route := (&router.HTTPRoute{ Domain: fmt.Sprintf("%s.%s", app.Name, r.defaultDomain), Service: app.Name + "-web", }).ToRoute() if err := createRoute(r.db, r.router, app.ID, route); err != nil { log.Printf("Error creating default route for %s: %s", app.Name, err) } } return nil }
func (r *AppRepo) Add(data interface{}) error { app := data.(*ct.App) if app.Name == "" { var nameID uint32 if err := r.db.QueryRow("SELECT nextval('name_ids')").Scan(&nameID); err != nil { return err } app.Name = name.Get(nameID) } if len(app.Name) > 100 || !appNamePattern.MatchString(app.Name) { return ct.ValidationError{Field: "name", Message: "is invalid"} } if app.ID == "" { app.ID = random.UUID() } if app.Strategy == "" { app.Strategy = "all-at-once" } meta := metaToHstore(app.Meta) if err := r.db.QueryRow("INSERT INTO apps (app_id, name, meta, strategy) VALUES ($1, $2, $3, $4) RETURNING created_at, updated_at", app.ID, app.Name, meta, app.Strategy).Scan(&app.CreatedAt, &app.UpdatedAt); err != nil { if postgres.IsUniquenessError(err, "apps_name_idx") { return httphelper.ObjectExistsErr(fmt.Sprintf("application %q already exists", app.Name)) } return err } app.ID = postgres.CleanUUID(app.ID) if !app.System() && r.defaultDomain != "" { route := (&router.HTTPRoute{ Domain: fmt.Sprintf("%s.%s", app.Name, r.defaultDomain), Service: app.Name + "-web", }).ToRoute() route.ParentRef = routeParentRef(app.ID) if err := r.router.CreateRoute(route); err != nil { log.Printf("Error creating default route for %s: %s", app.Name, err) } } return nil }