Beispiel #1
0
func (k *Klient) send(queryString, method string, req, resp interface{}) (string, error) {
	queryString, err := utils.QueryString(queryString)
	if err != nil {
		return "", err
	}

	k.Log.Debug("calling %q method on %q with %+v", method, queryString, req)

	kref, err := klient.ConnectTimeout(k.Kite, queryString, k.dialTimeout())
	if err != nil {
		k.Log.Debug("connecting to %q klient failed: %s", queryString, err)

		return "", err
	}
	defer kref.Close()

	r, err := kref.Client.TellWithTimeout(method, k.timeout(), req)
	if err != nil {
		k.Log.Debug("sending request to %q klient failed: %s", queryString, err)

		return "", err
	}

	if err := r.Unmarshal(resp); err != nil {
		return "", errors.New("reading response from klient failed: " + err.Error())
	}

	k.Log.Debug("received %+v response from %q (%q)", resp, method, queryString)

	return kref.URL(), nil
}
Beispiel #2
0
func (k *Klient) cmd(queryString, method, boxPath string) error {
	queryString, err := utils.QueryString(queryString)
	if err != nil {
		return err
	}

	k.Log.Debug("calling %q command on %q with %q", method, queryString, boxPath)

	kref, err := klient.ConnectTimeout(k.Kite, queryString, k.dialTimeout())
	if err != nil {
		k.Log.Debug("connecting to %q klient failed: %s", queryString, err)

		return err
	}

	done := make(chan error, 1)

	success := dnode.Callback(func(*dnode.Partial) {
		done <- nil
	})

	failure := dnode.Callback(func(r *dnode.Partial) {
		msg, err := r.One().String()
		if err != nil {
			err = errors.New("unknown failure")
		} else {
			err = errors.New(msg)
		}
		done <- err
	})

	lost := make(chan struct{})
	beat := make(chan struct{})
	stop := make(chan struct{})
	defer close(stop)

	go func() {
		// Heartbeat timer is initially stopped since at this
		// point we do not know whether klient supports heartbeats.
		// On first heartbeat we activate the timer and set the ch.
		var (
			t  *time.Timer
			ch <-chan time.Time
		)

		for {
			select {
			case <-stop:
				return
			case <-ch:
				lost <- struct{}{}
			case <-beat:
				if t == nil {
					t = time.NewTimer(defaultDialTimeout)
					ch = t.C
					defer t.Stop()
				}

				t.Reset(defaultDialTimeout)
			}
		}
	}()

	heartbeat := dnode.Callback(func(r *dnode.Partial) {
		beat <- struct{}{}
	})

	req := &Command{
		FilePath:  boxPath,
		Success:   success,
		Failure:   failure,
		Heartbeat: heartbeat,
	}

	if k.Debug {
		log := k.Log.New(method)
		req.Output = dnode.Callback(func(r *dnode.Partial) {
			log.Debug("%s", r.One().MustString())
		})
	}

	if _, err = kref.Client.TellWithTimeout(method, k.timeout(), req); err != nil {
		return errors.New("sending request to klient failed: " + err.Error())
	}

	select {
	case err := <-done:
		return err
	case <-time.After(k.timeout()):
		return fmt.Errorf("timed out calling %q on %q", method, queryString)
	case <-lost:
		return errors.New("connection to your KD Daemon was lost due to inactivity")
	}
}
Beispiel #3
0
// RemoveUsersFromMachine removes the collaboraters from the host machine
func (c *Controller) RemoveUsersFromMachine(ping *models.Ping, toBeRemovedUsers []bson.ObjectId) error {
	// if channel id is nil, there is nothing to do
	if ping.ChannelId == 0 {
		return nil
	}

	ws, err := modelhelper.GetWorkspaceByChannelId(strconv.FormatInt(ping.ChannelId, 10))
	if err != nil {
		return filterErr(err)
	}

	m, err := modelhelper.GetMachineByUid(ws.MachineUID)
	if err != nil {
		return filterErr(err)
	}

	// Get the klient.
	klientRef, err := klient.ConnectTimeout(c.kite, m.QueryString, time.Second*10)
	if err != nil {
		if err == klient.ErrDialingFailed || err == kite.ErrNoKitesAvailable {
			c.log.Error(
				"[%s] Klient is not registered to Kontrol. Err: %s",
				m.QueryString,
				err,
			)

			return nil // if the machine is not open, we cant do anything
		}

		return err
	}
	defer klientRef.Close()

	type args struct {
		Username string

		// we are not gonna use this propery here, just for reference
		// Permanent bool
	}

	var iterErr error

	for _, toBeDeletedUser := range toBeRemovedUsers {

		// fetch user for its username
		u, err := modelhelper.GetUserById(toBeDeletedUser.Hex())
		if err != nil {
			c.log.Error("couldnt get user", err.Error())

			// if we cant find the regarding user, do not do anything
			if err == mgo.ErrNotFound {
				continue
			}

			iterErr = err

			continue // do not stop iterating, unshare from others
		}

		param := args{
			Username: u.Name,
		}

		_, err = klientRef.Client.Tell("klient.unshare", param)
		if err != nil {
			c.log.Error("couldnt unshare %+v", err.Error())

			// those are so error prone, force klient side not to change the API
			// or make them exported to some other package?
			if strings.Contains(err.Error(), "user is permanent") {
				continue
			}

			if strings.Contains(err.Error(), "user is not in the shared list") {
				continue
			}

			if strings.Contains(err.Error(), "User not found") {
				continue
			}

			iterErr = err

			continue // do not stop iterating, unshare from others
		}
	}

	res, err := klientRef.Client.Tell("klient.shared", nil)
	if err == nil {
		c.log.Info("other users in the machine: %+v", res.MustString())
	}

	// iterErr will be nil if we dont encounter to any error in iter
	return iterErr

}