func (c *client) NextDevice(
	ctx types.Context,
	opts types.Store) (string, error) {

	if c.isController() {
		return "", utils.NewUnsupportedForClientTypeError(
			c.clientType, "NextDevice")
	}

	if supported, _ := c.Supported(ctx, opts); !supported {
		return "", errExecutorNotSupported
	}

	ctx = context.RequireTX(ctx.Join(c.ctx))

	serviceName, ok := context.ServiceName(ctx)
	if !ok {
		return "", goof.New("missing service name")
	}

	si, err := c.getServiceInfo(serviceName)
	if err != nil {
		return "", err
	}
	driverName := si.Driver.Name

	out, err := c.runExecutor(ctx, driverName, types.LSXCmdNextDevice)
	if err != nil {
		return "", err
	}

	ctx.Debug("xli nextdevice success")
	return gotil.Trim(string(out)), nil
}
Example #2
0
func (c *client) requireCtx(ctx types.Context) types.Context {
	if ctx == nil {
		ctx = c.ctx
	} else {
		ctx = ctx.Join(c.ctx)
	}
	return context.RequireTX(ctx)
}
func (c *client) Supported(
	ctx types.Context,
	opts types.Store) (bool, error) {

	if c.isController() {
		return false, utils.NewUnsupportedForClientTypeError(
			c.clientType, "Supported")
	}

	ctx = context.RequireTX(ctx.Join(c.ctx))

	serviceName, ok := context.ServiceName(ctx)
	if !ok {
		return false, goof.New("missing service name")
	}

	si, err := c.getServiceInfo(serviceName)
	if err != nil {
		return false, err
	}
	driverName := strings.ToLower(si.Driver.Name)

	// check to see if the driver's executor is supported on this host
	if ok := c.supportedCache.IsSet(driverName); ok {
		return c.supportedCache.GetBool(driverName), nil
	}

	out, err := c.runExecutor(ctx, driverName, types.LSXCmdSupported)
	if err != nil {
		if err == types.ErrNotImplemented {
			ctx.WithField("serviceDriver", driverName).Warn(
				"supported cmd not implemented")
			c.supportedCache.Set(driverName, true)
			ctx.WithField("supported", true).Debug("cached supported flag")
			return true, nil
		}
		return false, err
	}

	if len(out) == 0 {
		return false, nil
	}

	out = bytes.TrimSpace(out)
	b, err := strconv.ParseBool(string(out))
	if err != nil {
		return false, err
	}

	c.supportedCache.Set(driverName, b)
	ctx.WithField("supported", b).Debug("cached supported flag")
	return b, nil
}
func (c *client) WaitForDevice(
	ctx types.Context,
	opts *types.WaitForDeviceOpts) (bool, *types.LocalDevices, error) {

	if c.isController() {
		return false, nil, utils.NewUnsupportedForClientTypeError(
			c.clientType, "WaitForDevice")
	}

	if supported, _ := c.Supported(ctx, opts.Opts); !supported {
		return false, nil, errExecutorNotSupported
	}

	ctx = context.RequireTX(ctx.Join(c.ctx))

	serviceName, ok := context.ServiceName(ctx)
	if !ok {
		return false, nil, goof.New("missing service name")
	}

	si, err := c.getServiceInfo(serviceName)
	if err != nil {
		return false, nil, err
	}
	driverName := si.Driver.Name

	out, err := c.runExecutor(
		ctx, driverName, types.LSXCmdWaitForDevice,
		opts.ScanType.String(), opts.Token, opts.Timeout.String())

	if err != types.ErrTimedOut {
		return false, nil, err
	}

	matched := err == nil

	ld, err := unmarshalLocalDevices(ctx, out)
	if err != nil {
		return false, nil, err
	}

	ctx.Debug("xli waitfordevice success")
	return matched, ld, nil
}
func (c *client) LocalDevices(
	ctx types.Context,
	opts *types.LocalDevicesOpts) (*types.LocalDevices, error) {

	if c.isController() {
		return nil, utils.NewUnsupportedForClientTypeError(
			c.clientType, "LocalDevices")
	}

	if supported, _ := c.Supported(ctx, opts.Opts); !supported {
		return nil, errExecutorNotSupported
	}

	ctx = context.RequireTX(ctx.Join(c.ctx))

	serviceName, ok := context.ServiceName(ctx)
	if !ok {
		return nil, goof.New("missing service name")
	}

	si, err := c.getServiceInfo(serviceName)
	if err != nil {
		return nil, err
	}
	driverName := si.Driver.Name

	out, err := c.runExecutor(
		ctx, driverName, types.LSXCmdLocalDevices, opts.ScanType.String())
	if err != nil {
		return nil, err
	}

	ld, err := unmarshalLocalDevices(ctx, out)
	if err != nil {
		return nil, err
	}

	ctx.Debug("xli localdevices success")
	return ld, nil
}
Example #6
0
func (c *client) httpDo(
	ctx types.Context,
	method, path string,
	payload, reply interface{}) (*http.Response, error) {

	reqBody, err := encPayload(payload)
	if err != nil {
		return nil, err
	}

	url := fmt.Sprintf("http://%s%s", c.host, path)
	req, err := http.NewRequest(method, url, reqBody)
	if err != nil {
		return nil, err
	}

	ctx = context.RequireTX(ctx)
	tx := context.MustTransaction(ctx)
	ctx = ctx.WithValue(transactionHeaderKey, tx)

	if iid, ok := context.InstanceID(ctx); ok {
		ctx = ctx.WithValue(instanceIDHeaderKey, iid)
	} else if iidMap, ok := ctx.Value(
		context.AllInstanceIDsKey).(types.InstanceIDMap); ok {
		if len(iidMap) > 0 {
			var iids []fmt.Stringer
			for _, iid := range iidMap {
				iids = append(iids, iid)
			}
			ctx = ctx.WithValue(instanceIDHeaderKey, iids)
		}
	}

	if lds, ok := context.LocalDevices(ctx); ok {
		ctx = ctx.WithValue(localDevicesHeaderKey, lds)
	} else if ldsMap, ok := ctx.Value(
		context.AllLocalDevicesKey).(types.LocalDevicesMap); ok {
		if len(ldsMap) > 0 {
			var ldsess []fmt.Stringer
			for _, lds := range ldsMap {
				ldsess = append(ldsess, lds)
			}
			ctx = ctx.WithValue(localDevicesHeaderKey, ldsess)
		}
	}

	for key := range context.CustomHeaderKeys() {

		var headerName string

		switch tk := key.(type) {
		case string:
			headerName = tk
		case fmt.Stringer:
			headerName = tk.String()
		default:
			headerName = fmt.Sprintf("%v", key)
		}

		if headerName == "" {
			continue
		}

		val := ctx.Value(key)
		switch tv := val.(type) {
		case string:
			req.Header.Add(headerName, tv)
		case fmt.Stringer:
			req.Header.Add(headerName, tv.String())
		case []string:
			for _, sv := range tv {
				req.Header.Add(headerName, sv)
			}
		case []fmt.Stringer:
			for _, sv := range tv {
				req.Header.Add(headerName, sv.String())
			}
		default:
			if val != nil {
				req.Header.Add(headerName, fmt.Sprintf("%v", val))
			}
		}
	}

	c.logRequest(req)

	res, err := ctxhttp.Do(ctx, &c.Client, req)
	if err != nil {
		return nil, err
	}
	defer c.setServerName(res)

	c.logResponse(res)

	if res.StatusCode > 299 {
		httpErr, err := goof.DecodeHTTPError(res.Body)
		if err != nil {
			return res, goof.WithField("status", res.StatusCode, "http error")
		}
		return res, httpErr
	}

	if req.Method != http.MethodHead && reply != nil {
		if err := decRes(res.Body, reply); err != nil {
			return nil, err
		}
	}

	return res, nil
}
func (c *client) InstanceID(
	ctx types.Context,
	opts types.Store) (*types.InstanceID, error) {

	if c.isController() {
		return nil, utils.NewUnsupportedForClientTypeError(
			c.clientType, "InstanceID")
	}

	if supported, _ := c.Supported(ctx, opts); !supported {
		return nil, errExecutorNotSupported
	}

	ctx = context.RequireTX(ctx.Join(c.ctx))

	serviceName, ok := context.ServiceName(ctx)
	if !ok {
		return nil, goof.New("missing service name")
	}

	si, err := c.getServiceInfo(serviceName)
	if err != nil {
		return nil, err
	}
	driverName := strings.ToLower(si.Driver.Name)

	// check to see if the driver's instance ID is cached
	if iid := c.instanceIDCache.GetInstanceID(driverName); iid != nil {
		return iid, nil
	}

	out, err := c.runExecutor(ctx, driverName, types.LSXCmdInstanceID)
	if err != nil {
		return nil, err
	}

	iid := &types.InstanceID{}
	if err := iid.UnmarshalText(out); err != nil {
		return nil, err
	}

	ctx = ctx.WithValue(context.InstanceIDKey, iid)

	if iid.HasMetadata() {
		ctx.Debug("sending instanceID in API.InstanceInspect call")
		instance, err := c.InstanceInspect(ctx, serviceName)
		if err != nil {
			return nil, err
		}
		ctx.Debug("received instanceID from API.InstanceInspect call")
		iid.ID = instance.InstanceID.ID
		iid.Fields = instance.InstanceID.Fields
		iid.DeleteMetadata()
	}

	c.instanceIDCache.Set(driverName, iid)
	ctx.Debug("cached instanceID")

	ctx.Debug("xli instanceID success")
	return iid, nil
}