Пример #1
0
func (c *client) downloadExecutor(ctx types.Context) error {

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

	ctx.Debug("downloading executor")

	f, err := os.OpenFile(
		types.LSX.String(),
		os.O_CREATE|os.O_RDWR|os.O_TRUNC,
		0755)
	if err != nil {
		return err
	}

	defer f.Close()

	rdr, err := c.APIClient.ExecutorGet(ctx, types.LSX.Name())
	n, err := io.Copy(f, rdr)
	if err != nil {
		return err
	}

	if err := f.Sync(); err != nil {
		return err
	}

	ctx.WithField("bytes", n).Debug("downloaded executor")
	return nil
}
Пример #2
0
func (c *client) getExecutorChecksum(ctx types.Context) (string, error) {

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

	ctx.Debug("getting executor checksum")

	f, err := os.Open(types.LSX.String())
	if err != nil {
		return "", err
	}
	defer f.Close()

	h := md5.New()
	buf := make([]byte, 1024)
	for {
		n, err := f.Read(buf)
		if err == io.EOF {
			break
		}
		if err != nil {
			return "", err
		}
		if _, err := h.Write(buf[:n]); err != nil {
			return "", err
		}
	}

	sum := fmt.Sprintf("%x", h.Sum(nil))
	ctx.WithField("localChecksum", sum).Debug("got local executor checksum")
	return sum, nil
}
Пример #3
0
func (d *driver) VolumeAttach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeAttachOpts) (*types.Volume, string, error) {

	if d.isController() {
		return nil, "", utils.NewUnsupportedForClientTypeError(
			d.clientType, "VolumeAttach")
	}

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

	nextDevice, err := d.NextDevice(ctx, utils.NewStore())
	if err != nil {
		return nil, "", err
	}

	var nextDevicePtr *string
	if nextDevice != "" {
		nextDevicePtr = &nextDevice
	}

	req := &types.VolumeAttachRequest{
		NextDeviceName: nextDevicePtr,
		Force:          opts.Force,
		Opts:           opts.Opts.Map(),
	}

	return d.client.VolumeAttach(ctx, serviceName, volumeID, req)
}
Пример #4
0
func (c *client) lsxMutexSignal() error {
	if c.isController() {
		return utils.NewUnsupportedForClientTypeError(
			c.clientType, "lsxMutexSignal")
	}
	return os.RemoveAll(lsxMutex)
}
Пример #5
0
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
}
Пример #6
0
func (c *client) Instances(
	ctx types.Context) (map[string]*types.Instance, error) {

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

	ctx = c.withAllInstanceIDs(c.requireCtx(ctx))
	return c.APIClient.Instances(ctx)
}
Пример #7
0
func (c *client) ExecutorGet(
	ctx types.Context, name string) (io.ReadCloser, error) {

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

	ctx = c.requireCtx(ctx)
	return c.APIClient.ExecutorGet(ctx, name)
}
Пример #8
0
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
}
Пример #9
0
func (c *client) runExecutor(
	ctx types.Context, args ...string) ([]byte, error) {

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

	ctx.Debug("waiting on executor lock")
	if err := c.lsxMutexWait(); err != nil {
		return nil, err
	}

	defer func() {
		ctx.Debug("signalling executor lock")
		if err := c.lsxMutexSignal(); err != nil {
			panic(err)
		}
	}()

	lsxBin := types.LSX.String()
	cmd := exec.Command(lsxBin, args...)
	cmd.Env = os.Environ()

	configEnvVars := c.config.EnvVars()
	for _, cev := range configEnvVars {
		// ctx.WithField("value", cev).Debug("set executor env var")
		cmd.Env = append(cmd.Env, cev)
	}

	out, err := cmd.Output()

	if exitError, ok := err.(*exec.ExitError); ok {
		exitCode := exitError.Sys().(syscall.WaitStatus).ExitStatus()
		switch exitCode {
		case types.LSXExitCodeNotImplemented:
			return nil, types.ErrNotImplemented
		case types.LSXExitCodeTimedOut:
			return nil, types.ErrTimedOut
		}
		return nil, goof.WithFieldsE(
			map[string]interface{}{
				"lsx":  lsxBin,
				"args": args,
			},
			"error executing xcli",
			err)
	}

	return out, err
}
Пример #10
0
func (c *client) InstanceInspect(
	ctx types.Context, service string) (*types.Instance, error) {

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

	ctx = c.withInstanceID(c.requireCtx(ctx), service)
	i, err := c.APIClient.InstanceInspect(ctx, service)
	if err != nil {
		return nil, err
	}
	return i, nil
}
Пример #11
0
func (c *client) lsxMutexWait() error {

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

	for {
		f, err := os.OpenFile(lsxMutex, os.O_CREATE|os.O_EXCL, 0644)
		if err != nil {
			time.Sleep(time.Millisecond * 500)
			continue
		}
		return f.Close()
	}
}
Пример #12
0
func (d *driver) InstanceInspect(
	ctx types.Context,
	opts types.Store) (*types.Instance, error) {

	if d.isController() {
		return nil, utils.NewUnsupportedForClientTypeError(
			d.clientType, "InstanceInspect")
	}

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

	return d.client.InstanceInspect(ctx, serviceName)
}
Пример #13
0
func (c *client) updateExecutor(ctx types.Context) error {

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

	ctx.Debug("updating executor")

	lsxi := c.lsxCache.GetExecutorInfo(types.LSX.Name())
	if lsxi == nil {
		return goof.WithField("lsx", types.LSX, "unknown executor")
	}

	ctx.Debug("waiting on executor lock")
	if err := c.lsxMutexWait(); err != nil {
		return err
	}
	defer func() {
		ctx.Debug("signalling executor lock")
		if err := c.lsxMutexSignal(); err != nil {
			panic(err)
		}
	}()

	if !types.LSX.Exists() {
		ctx.Debug("executor does not exist, download executor")
		return c.downloadExecutor(ctx)
	}

	ctx.Debug("executor exists, getting local checksum")

	checksum, err := c.getExecutorChecksum(ctx)
	if err != nil {
		return err
	}

	if lsxi.MD5Checksum != checksum {
		ctx.WithFields(log.Fields{
			"remoteChecksum": lsxi.MD5Checksum,
			"localChecksum":  checksum,
		}).Debug("executor checksums do not match, download executor")
		return c.downloadExecutor(ctx)
	}

	return nil
}
Пример #14
0
func (c *client) VolumeDetachAll(
	ctx types.Context,
	request *types.VolumeDetachRequest) (types.ServiceVolumeMap, error) {

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

	ctx = c.withAllInstanceIDs(c.requireCtx(ctx))
	ctxA, err := c.withAllLocalDevices(ctx)
	if err != nil {
		return nil, err
	}
	ctx = ctxA

	return c.APIClient.VolumeDetachAll(ctx, request)
}
Пример #15
0
func (c *client) Executors(
	ctx types.Context) (map[string]*types.ExecutorInfo, error) {

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

	ctx = c.requireCtx(ctx)
	lsxInfo, err := c.APIClient.Executors(ctx)
	if err != nil {
		return nil, err
	}
	for k, v := range lsxInfo {
		c.lsxCache.Set(k, v)
	}
	return lsxInfo, nil
}
Пример #16
0
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
}
Пример #17
0
func (c *client) VolumeDetach(
	ctx types.Context,
	service string,
	volumeID string,
	request *types.VolumeDetachRequest) (*types.Volume, error) {

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

	ctx = c.withInstanceID(c.requireCtx(ctx), service)
	ctxA, err := c.withAllLocalDevices(ctx)
	if err != nil {
		return nil, err
	}
	ctx = ctxA

	return c.APIClient.VolumeDetach(ctx, service, volumeID, request)
}
Пример #18
0
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
}
Пример #19
0
func (d *driver) VolumeDetach(
	ctx types.Context,
	volumeID string,
	opts *types.VolumeDetachOpts) (*types.Volume, error) {

	if d.isController() {
		return nil, utils.NewUnsupportedForClientTypeError(
			d.clientType, "VolumeDetach")
	}

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

	req := &types.VolumeDetachRequest{
		Force: opts.Force,
		Opts:  opts.Opts.Map(),
	}

	return d.client.VolumeDetach(ctx, serviceName, volumeID, req)
}
Пример #20
0
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
}