func TestRPC(t *testing.T) { namespace := "space-of-names" serviceID := flux.ServiceID(namespace + "/service") serviceList := []flux.ServiceID{serviceID} services := flux.ServiceIDSet{} services.Add(serviceList) regrades := []platform.RegradeSpec{ platform.RegradeSpec{ ServiceID: serviceID, NewDefinition: []byte("imagine a definition here"), }, } serviceAnswer := []platform.Service{ platform.Service{ ID: flux.ServiceID("foobar/hello"), IP: "10.32.1.45", Metadata: map[string]string{}, Status: "ok", Containers: platform.ContainersOrExcuse{ Containers: []platform.Container{ platform.Container{ Name: "frobnicator", Image: "quay.io/example.com/frob:v0.4.5", }, }, }, }, platform.Service{}, } mock := &platform.MockPlatform{ AllServicesArgTest: func(ns string, ss flux.ServiceIDSet) error { if !(ns == namespace && ss.Contains(serviceID)) { return fmt.Errorf("did not get expected args, got %q, %+v", ns, ss) } return nil }, AllServicesAnswer: serviceAnswer, SomeServicesArgTest: func(ss []flux.ServiceID) error { if !reflect.DeepEqual(ss, serviceList) { return fmt.Errorf("did not get expected args, got %+v", ss) } return nil }, SomeServicesAnswer: serviceAnswer, RegradeArgTest: func(specs []platform.RegradeSpec) error { if !reflect.DeepEqual(regrades, specs) { return fmt.Errorf("did not get expected args, got %+v", specs) } return nil }, RegradeError: nil, } clientConn, serverConn := pipes() server, err := NewServer(mock) if err != nil { t.Fatal(err) } go server.ServeConn(serverConn) client := NewClient(clientConn) if err := client.Ping(); err != nil { t.Fatal(err) } ss, err := client.AllServices(namespace, services) if err != nil { t.Error(err) } if !reflect.DeepEqual(ss, mock.AllServicesAnswer) { t.Error(fmt.Errorf("expected %d result(s), got %+v", len(mock.AllServicesAnswer), ss)) } mock.AllServicesError = fmt.Errorf("all services query failure") ss, err = client.AllServices(namespace, services) if err == nil { t.Error("expected error, got nil") } ss, err = client.SomeServices(serviceList) if err != nil { t.Error(err) } if !reflect.DeepEqual(ss, mock.SomeServicesAnswer) { t.Error(fmt.Errorf("expected %d result(s), got %+v", len(mock.SomeServicesAnswer), ss)) } mock.SomeServicesError = fmt.Errorf("fail for some reason") ss, err = client.SomeServices(serviceList) if err == nil { t.Error("expected error, got nil") } err = client.Regrade(regrades) if err != nil { t.Error(err) } regradeErrors := platform.RegradeError{ serviceID: fmt.Errorf("it just failed"), } mock.RegradeError = regradeErrors err = client.Regrade(regrades) if !reflect.DeepEqual(err, regradeErrors) { t.Errorf("expected RegradeError, got %#v", err) } }
func (r *Releaser) Handle(job *jobs.Job, updater jobs.JobUpdater) (err error) { spec := job.Params.(jobs.ReleaseJobParams) releaseType := "unknown" defer func(begin time.Time) { r.metrics.ReleaseDuration.With( "release_type", releaseType, "release_kind", fmt.Sprint(spec.Kind), "success", fmt.Sprint(err == nil), ).Observe(time.Since(begin).Seconds()) }(time.Now()) inst, err := r.instancer.Get(job.Instance) if err != nil { return err } inst.Logger = log.NewContext(inst.Logger).With("job", job.ID) updateJob := func(format string, args ...interface{}) { status := fmt.Sprintf(format, args...) job.Status = status job.Log = append(job.Log, status) updater.UpdateJob(*job) } exclude := flux.ServiceIDSet{} exclude.Add(spec.Excludes) locked, err := lockedServices(inst) if err != nil { return err } exclude.Add(locked) updateJob("Calculating release actions.") switch { case spec.ServiceSpec == flux.ServiceSpecAll && spec.ImageSpec == flux.ImageSpecLatest: releaseType = "release_all_to_latest" return r.releaseImages(releaseType, "Release latest images to all services", inst, spec.Kind, allServicesExcept(exclude), allLatestImages, updateJob) case spec.ServiceSpec == flux.ServiceSpecAll && spec.ImageSpec == flux.ImageSpecNone: releaseType = "release_all_without_update" return r.releaseWithoutUpdate(releaseType, "Apply latest config to all services", inst, spec.Kind, allServicesExcept(exclude), updateJob) case spec.ServiceSpec == flux.ServiceSpecAll: releaseType = "release_all_for_image" imageID := flux.ParseImageID(string(spec.ImageSpec)) return r.releaseImages(releaseType, fmt.Sprintf("Release %s to all services", imageID), inst, spec.Kind, allServicesExcept(exclude), exactlyTheseImages([]flux.ImageID{imageID}), updateJob) case spec.ImageSpec == flux.ImageSpecLatest: releaseType = "release_one_to_latest" serviceID, err := flux.ParseServiceID(string(spec.ServiceSpec)) if err != nil { return errors.Wrapf(err, "parsing service ID from spec %s", spec.ServiceSpec) } services := flux.ServiceIDs([]flux.ServiceID{serviceID}).Without(exclude) return r.releaseImages(releaseType, fmt.Sprintf("Release latest images to %s", serviceID), inst, spec.Kind, exactlyTheseServices(services), allLatestImages, updateJob) case spec.ImageSpec == flux.ImageSpecNone: releaseType = "release_one_without_update" serviceID, err := flux.ParseServiceID(string(spec.ServiceSpec)) if err != nil { return errors.Wrapf(err, "parsing service ID from spec %s", spec.ServiceSpec) } services := flux.ServiceIDs([]flux.ServiceID{serviceID}).Without(exclude) return r.releaseWithoutUpdate(releaseType, fmt.Sprintf("Apply latest config to %s", serviceID), inst, spec.Kind, exactlyTheseServices(services), updateJob) default: releaseType = "release_one" serviceID, err := flux.ParseServiceID(string(spec.ServiceSpec)) if err != nil { return errors.Wrapf(err, "parsing service ID from spec %s", spec.ServiceSpec) } services := flux.ServiceIDs([]flux.ServiceID{serviceID}).Without(exclude) imageID := flux.ParseImageID(string(spec.ImageSpec)) return r.releaseImages(releaseType, fmt.Sprintf("Release %s to %s", imageID, serviceID), inst, spec.Kind, exactlyTheseServices(services), exactlyTheseImages([]flux.ImageID{imageID}), updateJob) } }