예제 #1
0
파일: update.go 프로젝트: pulcy/gluon
func UpdateAllMachines(flags *UpdateFlags, log *logging.Logger) error {
	// Get all members
	members, err := flags.GetClusterMembers(log)
	if err != nil {
		return maskAny(err)
	}

	// Pull image on all machines
	log.Infof("Pulling gluon image on %d machines", len(members))
	var pullGroup errgroup.Group
	for _, m := range members {
		m := m
		pullGroup.Go(func() error {
			return maskAny(pullImage(m, *flags, log))
		})
	}
	if err := pullGroup.Wait(); err != nil {
		return maskAny(err)
	}

	// Update all machines, one at a time
	for index, m := range members {
		if index > 0 {
			log.Infof("Waiting %s...", flags.MachineDelay)
			time.Sleep(flags.MachineDelay)
		}
		if err := updateMachine(m, *flags, log); err != nil {
			return maskAny(err)
		}
	}

	return nil
}
예제 #2
0
func TestZeroGroup(t *testing.T) {
	err1 := errors.New("errgroup_test: 1")
	err2 := errors.New("errgroup_test: 2")

	cases := []struct {
		errs []error
	}{
		{errs: []error{}},
		{errs: []error{nil}},
		{errs: []error{err1}},
		{errs: []error{err1, nil}},
		{errs: []error{err1, nil, err2}},
	}

	for _, tc := range cases {
		var g errgroup.Group

		var firstErr error
		for i, err := range tc.errs {
			err := err
			g.Go(func() error { return err })

			if firstErr == nil && err != nil {
				firstErr = err
			}

			if gErr := g.Wait(); gErr != firstErr {
				t.Errorf("after %T.Go(func() error { return err }) for err in %v\n"+
					"g.Wait() = %v; want %v",
					g, tc.errs[:i+1], err, firstErr)
			}
		}
	}
}
예제 #3
0
func TestConfigProcessContent(t *testing.T) {
	Convey("Testing ProcessContent()", t, func() {
		newCfg := func() *Config {
			return NewConfig(
				API("/bin/cli-shell-api"),
				Arch(runtime.GOARCH),
				Bash("/bin/bash"),
				Cores(runtime.NumCPU()),
				Dir("/:~/"),
				DNSsvc("service dnsmasq restart"),
				Ext("blacklist.conf"),
				FileNameFmt("%v/%v.%v.%v"),
				InCLI("inSession"),
				Level("service dns forwarding"),
				Method("GET"),
				Nodes([]string{domains, hosts}),
				Prefix("address="),
				LTypes([]string{files, PreDomns, PreHosts, urls}),
				Timeout(30*time.Second),
				WCard(Wildcard{Node: "*s", Name: "*"}),
			)
		}

		tests := []struct {
			c      *Config
			cfg    string
			ct     IFace
			err    error
			expErr bool
			name   string
		}{
			{
				c:      newCfg(),
				cfg:    testCfg,
				ct:     FileObj,
				err:    fmt.Errorf("open /:~/=../testdata/blist.hosts.src: no such file or directory\nopen /:~//hosts.tasty.blacklist.conf: no such file or directory"),
				expErr: true,
				name:   "File",
			},
		}
		for _, tt := range tests {
			So(tt.c.ReadCfg(&CFGstatic{Cfg: tt.cfg}), ShouldBeNil)
			var g errgroup.Group
			obj, err := tt.c.NewContent(tt.ct)
			So(err, ShouldBeNil)
			g.Go(func() error { return tt.c.ProcessContent(obj) })
			err = g.Wait()
			if (err != nil) == tt.expErr {
				So(err.Error(), ShouldEqual, tt.err.Error())
			}
		}

		Convey("Testing ProcessContent() if no arguments ", func() {
			var g errgroup.Group
			g.Go(func() error { return newCfg().ProcessContent() })
			err := g.Wait()
			So(err, ShouldNotBeNil)
		})
	})
}
예제 #4
0
func TestMarshalRace(t *testing.T) {
	// unregistered extension
	desc := &proto.ExtensionDesc{
		ExtendedType:  (*pb.MyMessage)(nil),
		ExtensionType: (*bool)(nil),
		Field:         101010100,
		Name:          "emptyextension",
		Tag:           "varint,0,opt",
	}

	m := &pb.MyMessage{Count: proto.Int32(4)}
	if err := proto.SetExtension(m, desc, proto.Bool(true)); err != nil {
		t.Errorf("proto.SetExtension(m, desc, true): got error %q, want nil", err)
	}

	var g errgroup.Group
	for n := 3; n > 0; n-- {
		g.Go(func() error {
			_, err := proto.Marshal(m)
			return err
		})
	}
	if err := g.Wait(); err != nil {
		t.Fatal(err)
	}
}
예제 #5
0
func fetchParallelizableUsageItems(group *models.Group, username string) (*Usage, error) {
	var g errgroup.Group

	var cus *stripe.Customer
	var subscription *stripe.Sub

	g.Go(func() (err error) {
		cus, err = EnsureCustomerForGroup(username, group.Slug, nil)
		if err != nil {
			return err
		}

		subscription, err = EnsureSubscriptionForGroup(group.Slug, nil)
		return err
	})

	// Active users count.
	var activeCount int
	g.Go(func() (err error) {
		activeCount, err = (&socialapimodels.PresenceDaily{}).CountDistinctByGroupName(group.Slug)
		return err
	})

	// Trialing user count is set if only sub is trialing.
	var trialCount int
	g.Go(func() (err error) {
		if group.Payment.Subscription.Status != "trialing" {
			return nil
		}

		trialCount, err = (&socialapimodels.PresenceDaily{}).CountDistinctProcessedByGroupName(group.Slug)
		return err
	})

	if err := g.Wait(); err != nil {
		return nil, err
	}

	usage := &Usage{
		User: &UserInfo{
			Total: activeCount,
		},
		ExpectedPlan:    nil,
		Due:             0,
		NextBillingDate: time.Unix(subscription.PeriodEnd, 0),
		Subscription:    subscription,
		Customer:        cus,
		Trial: &TrialInfo{
			User: &UserInfo{
				Total: trialCount,
			},
		},
	}

	return usage, nil
}
예제 #6
0
func TestClients(t *testing.T) {
	var (
		builder = testutil.NewBuilder(nil)

		idA = machine.ID("servA")
		idB = machine.ID("servB")

		servA = &testutil.Server{}
		servB = &testutil.Server{}
	)

	cs, err := clients.New(testOptions(builder))
	if err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}
	defer cs.Close()

	var g errgroup.Group
	create := map[machine.ID]client.DynamicAddrFunc{
		idA: servA.AddrFunc(),
		idB: servB.AddrFunc(),
		idA: servA.AddrFunc(), // duplicate.
		idA: servA.AddrFunc(), // duplicate.
	}

	for id, dynAddr := range create {
		id, dynAddr := id, dynAddr // Local copy for concurrency.
		g.Go(func() error {
			return cs.Create(id, dynAddr)
		})
	}
	if err := g.Wait(); err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}

	if regs := cs.Registered(); len(regs) != 2 {
		t.Fatalf("want clients count = 2; got %d", len(regs))
	}

	if _, err := cs.Client(idA); err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}

	if err := cs.Drop(idA); err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}

	if _, err := cs.Client(idA); err != machine.ErrMachineNotFound {
		t.Fatalf("want machine not found; got %v", err)
	}

	if regs := cs.Registered(); len(regs) != 1 {
		t.Fatalf("want clients count = 1; got %d", len(regs))
	}
}
func (c Client) Get(
	location *os.File,
	contentURL string,
	progressWriter io.Writer,
) error {
	req, err := http.NewRequest("HEAD", contentURL, nil)
	if err != nil {
		return fmt.Errorf("failed to construct HEAD request: %s", err)
	}

	resp, err := c.httpClient.Do(req)
	if err != nil {
		return fmt.Errorf("failed to make HEAD request: %s", err)
	}

	contentURL = resp.Request.URL.String()

	ranges, err := c.ranger.BuildRange(resp.ContentLength)
	if err != nil {
		return fmt.Errorf("failed to construct range: %s", err)
	}

	c.bar.SetOutput(progressWriter)
	c.bar.SetTotal(resp.ContentLength)
	c.bar.Kickoff()

	defer c.bar.Finish()

	var g errgroup.Group
	for _, r := range ranges {
		byteRange := r
		g.Go(func() error {
			respBytes, err := c.retryableRequest(contentURL, byteRange.HTTPHeader)
			if err != nil {
				return fmt.Errorf("failed during retryable request: %s", err)
			}

			bytesWritten, err := location.WriteAt(respBytes, byteRange.Lower)
			if err != nil {
				return fmt.Errorf("failed to write file: %s", err)
			}

			c.bar.Add(bytesWritten)

			return nil
		})
	}

	if err := g.Wait(); err != nil {
		return err
	}

	return nil
}
예제 #8
0
func TestDynamicClientContext(t *testing.T) {
	var (
		serv    = &testutil.Server{}
		builder = testutil.NewBuilder(nil)
	)

	dc, err := client.NewDynamic(testutil.DynamicOpts(serv, builder))
	if err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}
	defer dc.Close()

	ctx := dc.Client().Context()
	serv.TurnOn()
	if err := testutil.WaitForContextClose(ctx, time.Second); err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}

	const ContextWorkers = 10

	var g errgroup.Group
	for i := 0; i < ContextWorkers; i++ {
		g.Go(func() error {
			select {
			case <-dc.Client().Context().Done():
				return errors.New("context closed unexpectedly")
			case <-time.After(50 * time.Millisecond):
				return nil
			}
		})
	}
	// Machine is on so dynamic client should not close its context.
	if err := g.Wait(); err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}

	ctx = dc.Client().Context()
	serv.TurnOff()
	for i := 0; i < ContextWorkers; i++ {
		g.Go(func() error {
			select {
			case <-ctx.Done():
				return nil
			case <-time.After(time.Second):
				return errors.New("timed out")
			}
		})
	}
	// Machine is off so its context channel should be closed by dynamic client.
	if err := g.Wait(); err != nil {
		t.Fatalf("want err = nil; got %v", err)
	}
}
예제 #9
0
// JustErrors illustrates the use of a Group in place of a sync.WaitGroup to
// simplify goroutine counting and error handling. This example is derived from
// the sync.WaitGroup example at https://golang.org/pkg/sync/#example_WaitGroup.
func ExampleGroup_justErrors() {
	var g errgroup.Group
	var urls = []string{
		"http://www.golang.org/",
		"http://www.google.com/",
		"http://www.somestupidname.com/",
	}
	for _, url := range urls {
		// Launch a goroutine to fetch the URL.
		url := url // https://golang.org/doc/faq#closures_and_goroutines
		g.Go(func() error {
			// Fetch the URL.
			resp, err := http.Get(url)
			if err == nil {
				resp.Body.Close()
			}
			return err
		})
	}
	// Wait for all HTTP fetches to complete.
	if err := g.Wait(); err == nil {
		fmt.Println("Successfully fetched all URLs.")
	}
}
예제 #10
0
// EnsureInfoForGroup ensures data validity of the group, if customer does not
// exist, creates if, if sub does not exist, creates it
func EnsureInfoForGroup(group *models.Group, username string) (*Usage, error) {
	usage, err := fetchParallelizableUsageItems(group, username)
	if err != nil {
		return nil, err
	}

	var g errgroup.Group
	g.Go(func() error {
		expectedPlan, err := getPlan(usage.Subscription, usage.User.Total)
		if err != nil {
			return err
		}
		usage.ExpectedPlan = expectedPlan
		usage.Due = uint64(usage.User.Total) * expectedPlan.Amount
		return nil
	})

	g.Go(func() error {
		if usage.Trial.User.Total == 0 {
			return nil
		}
		trialPlan, err := getPlan(usage.Subscription, usage.Trial.User.Total)
		if err != nil {
			return err
		}
		usage.Trial.ExpectedPlan = trialPlan
		usage.Trial.Due = uint64(usage.Trial.User.Total) * trialPlan.Amount
		return nil
	})

	if err := g.Wait(); err != nil {
		return nil, err
	}

	return usage, nil
}
예제 #11
0
// Main takes a list of urls and request parameters, then fetches the URLs and
// outputs the headers to stdout
func Main(cookie, etag string, gzip, ignoreBody bool, urls ...string) error {
	for nurl, url := range urls {
		// Separate subsequent lookups with newline
		if nurl > 0 {
			fmt.Println()
		}

		req, err := http.NewRequest("GET", url, nil)
		if err != nil {
			return err
		}

		if gzip {
			req.Header.Add("Accept-Encoding", "gzip, deflate")
		}

		if etag != "" {
			req.Header.Add("If-None-Match", etag)
		}

		if cookie != "" {
			req.Header.Add("Cookie", cookie)
		}

		start := time.Now()
		resp, err := client.Do(req)
		duration := time.Since(start)

		var (
			n  int64
			eg errgroup.Group
		)
		// Ignore the error if it's just our errRedirect
		switch urlErr, ok := err.(*netURL.Error); {
		case err == nil:
			if ignoreBody {
				break
			}

			eg.Go(func() error {
				// Copying to /dev/null just to make sure this is real
				n, err = io.Copy(ioutil.Discard, resp.Body)
				duration = time.Since(start)
				if err != nil {
					return err
				}
				return nil
			})
		case ok && urlErr.Err == errRedirect:
		default:
			return err
		}

		fmt.Println("GET", url)
		fmt.Println(resp.Proto, resp.Status)
		fmt.Println()
		fmt.Println(prettyprint.ResponseHeader(resp.Header))

		if err := eg.Wait(); err != nil {
			return err
		}

		if err := resp.Body.Close(); err != nil {
			return err
		}

		tw := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
		fmt.Fprintf(tw, "Time\t%s\n", prettyprint.Duration(duration))
		if n != 0 {
			fmt.Fprintf(tw, "Content length\t%s\n", prettyprint.Size(n))
			bps := prettyprint.Size(float64(n) / duration.Seconds())
			fmt.Fprintf(tw, "Speed\t%s/s\n", bps)
		}
		if err := tw.Flush(); err != nil {
			return err
		}
	}

	return nil
}
예제 #12
0
func TestProcessContent(t *testing.T) {
	Convey("Testing ProcessContent(), setting up temporary directory in /tmp", t, func() {
		dir, err := ioutil.TempDir("/tmp", "testBlacklist")
		So(err, ShouldBeNil)
		defer os.RemoveAll(dir)

		Convey("Testing ProcessContent()", func() {
			c := NewConfig(
				Dir(dir),
				Ext("blacklist.conf"),
				FileNameFmt("%v/%v.%v.%v"),
				Method("GET"),
				Nodes([]string{domains, hosts}),
				Prefix("address="),
				LTypes([]string{PreDomns, PreHosts, files, urls}),
			)

			tests := []struct {
				err       error
				exp       string
				expDexMap list
				expExcMap list
				f         string
				fdata     string
				name      string
				obj       IFace
			}{
				{
					name:      "ExRtObj",
					err:       nil,
					exp:       "[\nDesc:\t \"root-excludes exclusions\"\nDisabled: false\nFile:\t \"\"\nIP:\t \"0.0.0.0\"\nLtype:\t \"root-excludes\"\nName:\t \"root-excludes\"\nnType:\t \"excRoot\"\nPrefix:\t \"\"\nType:\t \"root-excludes\"\nURL:\t \"\"\n]",
					expDexMap: list{entry: entry{"ytimg.com": 0}},
					expExcMap: list{entry: entry{"ytimg.com": 0}},
					obj:       ExRtObj,
				},
				{
					name:      "ExDmObj",
					err:       nil,
					exp:       "[\nDesc:\t \"domn-excludes exclusions\"\nDisabled: false\nFile:\t \"\"\nIP:\t \"0.0.0.0\"\nLtype:\t \"domn-excludes\"\nName:\t \"domn-excludes\"\nnType:\t \"excDomn\"\nPrefix:\t \"\"\nType:\t \"domn-excludes\"\nURL:\t \"\"\n]",
					expDexMap: list{RWMutex: &sync.RWMutex{}, entry: make(entry)},
					expExcMap: list{RWMutex: &sync.RWMutex{}, entry: make(entry)},
					obj:       ExDmObj,
				},
				{
					name:      "ExHtObj",
					err:       nil,
					exp:       "[\nDesc:\t \"host-excludes exclusions\"\nDisabled: false\nFile:\t \"\"\nIP:\t \"192.168.168.1\"\nLtype:\t \"host-excludes\"\nName:\t \"host-excludes\"\nnType:\t \"excHost\"\nPrefix:\t \"\"\nType:\t \"host-excludes\"\nURL:\t \"\"\n]",
					expDexMap: list{RWMutex: &sync.RWMutex{}, entry: make(entry)},
					expExcMap: list{RWMutex: &sync.RWMutex{}, entry: make(entry)},
					obj:       ExHtObj,
				},
				{
					name: "PreDObj",
					err:  nil,
					exp:  "[\nDesc:\t \"pre-configured-domain blacklist content\"\nDisabled: false\nFile:\t \"\"\nIP:\t \"0.0.0.0\"\nLtype:\t \"pre-configured-domain\"\nName:\t \"includes.[8]\"\nnType:\t \"preDomn\"\nPrefix:\t \"\"\nType:\t \"pre-configured-domain\"\nURL:\t \"\"\n]",
					expDexMap: list{
						entry: entry{
							"adsrvr.org":         0,
							"adtechus.net":       0,
							"advertising.com":    0,
							"centade.com":        0,
							"doubleclick.net":    0,
							"free-counter.co.uk": 0,
							"intellitxt.com":     0,
							"kiosked.com":        0,
						},
					},
					expExcMap: list{entry: entry{"ytimg.com": 0}},
					f:         dir + "/pre-configured-domain.includes.[8].blacklist.conf",
					fdata:     "address=/adsrvr.org/0.0.0.0\naddress=/adtechus.net/0.0.0.0\naddress=/advertising.com/0.0.0.0\naddress=/centade.com/0.0.0.0\naddress=/doubleclick.net/0.0.0.0\naddress=/free-counter.co.uk/0.0.0.0\naddress=/intellitxt.com/0.0.0.0\naddress=/kiosked.com/0.0.0.0\n",
					obj:       PreDObj,
				},
				{
					name:      "PreHObj",
					err:       nil,
					exp:       "[\nDesc:\t \"pre-configured-host blacklist content\"\nDisabled: false\nFile:\t \"\"\nIP:\t \"192.168.168.1\"\nLtype:\t \"pre-configured-host\"\nName:\t \"includes.[1]\"\nnType:\t \"preHost\"\nPrefix:\t \"\"\nType:\t \"pre-configured-host\"\nURL:\t \"\"\n]",
					expDexMap: list{entry: entry{"ytimg.com": 0}},
					expExcMap: list{entry: entry{"ytimg.com": 0}},
					f:         dir + "/pre-configured-host.includes.[1].blacklist.conf",
					fdata:     "address=/beap.gemini.yahoo.com/192.168.168.1\n",
					obj:       PreHObj,
				},
				{
					name: "FileObj",
					err:  fmt.Errorf("open %v/hosts./tasty.blacklist.conf: no such file or directory", dir),
					exp:  filesMin,
					expDexMap: list{
						entry: entry{
							"cw.bad.ultraadverts.site.eu": 1,
							"really.bad.phishing.site.ru": 1,
						},
					},
					expExcMap: list{entry: entry{"ytimg.com": 0}},
					f:         dir + "/hosts.tasty.blacklist.conf",
					fdata:     "address=/cw.bad.ultraadverts.site.eu/10.10.10.10\naddress=/really.bad.phishing.site.ru/10.10.10.10\n",
					obj:       FileObj,
				},
			}

			So(c.ReadCfg(&CFGstatic{Cfg: CfgMimimal}), ShouldBeNil)

			for _, tt := range tests {
				Convey("Testing "+tt.name+" ProcessContent()", func() {
					obj, err := c.NewContent(tt.obj)
					So(err, ShouldBeNil)

					if tt.f != "" {
						So(fmt.Sprint(obj), ShouldEqual, tt.exp)
					}

					var g errgroup.Group
					g.Go(func() error { return c.ProcessContent(obj) })
					err = g.Wait()

					if err != nil {
						Convey("Testing "+tt.name+" ProcessContent().Error():", func() {
							Convey("Error should match expected", func() {
								So(err, ShouldResemble, tt.err)
							})
						})
					}

					switch tt.f {
					default:
						reader, err := getFile(tt.f)
						So(err, ShouldBeNil)

						act, err := ioutil.ReadAll(reader)
						So(err, ShouldBeNil)

						Convey("Testing "+tt.name+" ProcessContent(): file data should match expected", func() {
							So(string(act), ShouldEqual, tt.fdata)
						})

					case "":
						Convey("Testing "+tt.name+" ProcessContent(): Dex map should match expected", func() {
							So(c.Dex.entry, ShouldResemble, tt.expDexMap.entry)
						})

						Convey("Testing "+tt.name+" ProcessContent(): Exc map should match expected", func() {
							So(c.Exc.entry, ShouldResemble, tt.expExcMap.entry)
						})

						Convey("Testing "+tt.name+" ProcessContent(): Obj should match expected", func() {
							So(obj.String(), ShouldEqual, tt.exp)
						})
					}
				})
			}
		})
	})
}