# DESIGN

# Provider interface

```golang
type InstanceGroup interface {
	Init(ctx context.Context, logger hclog.Logger, settings Settings) (ProviderInfo, error)

	// Update updates instance data from the instance group, passing a function
	// to perform instance reconciliation.
	Update(ctx context.Context, fn func(instance string, state State)) error

	// Increase requests more instances to be created. It returns how many
	// instances were successfully requested.
	Increase(ctx context.Context, n int) (succeeded int, err error)

	// Decrease removes the specified instances from the instance group. It
	// returns instance IDs of successful requests for removal.
	Decrease(ctx context.Context, instances []string) (succeeded []string, err error)

	// ConnectionInfo returns additional information about an instance,
	// useful for creating a connection.
	ConnectInfo(ctx context.Context, instance string) (ConnectInfo, error)
}
```

## Choices

### HashiCorp Go-Plugin

HashiCorp's Go Plugin system has been used extensively by HashiCorp in several
of their most popular projects.

Plugins are Go interface implementations. This is particularly useful because
the plugin interface is then not tied to any particular plugin system, Go
Plugin included.

Go Plugin is designed to work over a local reliable network. This is a good
sane expectation of a plugin system because it avoids so many potential
problems that can be caused by actual network activity, service discovery etc.

If a plugin needs to work over a network, this can be of course be implemented
within a custom plugin itself. However, if we wanted to support this for all
plugins in the future, the Go interface implementation and protocol would not
need to change.

### InstanceGroup vs. Instance

Most abstractions for creating compute instances work at the individual instance
level. Fleeting works with groups of instances, typically working with the cloud
provider's native Autoscaler/InstanceGroup functionality.

I believe there's certain benefits to this approach:
- It works well when you require a fleet of identical machines. The cloud
  provider may be able to optimize for this case and provide instances faster.
- Individual customization of each instance is usually a maintenance burden,
  requring that the library provides all possible configuration option. Instance
  Groups usually have an associated instance template that can be generated
  out-of-band.
- Individual instances require more API calls, with many APIs calls to
  individual endpoints to check the status of an instance. By working with
  groups of instances, Fleeting plugins can usually use `List()`-like calls to
  fetch the status of all instances under its control in a single call.

### Connectivity

Fleeting provides an abstract connector to connect to instances.

There's a large variation in how credentials are configured for each instance
group provider and customization is usually available on top of this.

Fleeting allows connection information to be provided to the instance group that
fills in the blanks or hints at certain credential setups that the provider can
otherwise not discover on its own.

This means for example, that if no `Password` is provided, the provider might
be able to provision credentials itself.

The connection information relayed back is the combination of user supplied,
discovered and generated values, allowing for a high degree of customization
whilst ensuring there's enough details for the abstractor connect to
successfully connect with.
