Implementation¶
Every cloud provider is made up of one or more resources. Each resource implementation will manage the lifecycle of a resource in the cloud: create, read, update, and delete.
A resource is any entity in a cloud provider that has state. For example, aws::load-balancer
or
aws::instance
are resources with state whereas a service like AWS Rekognition has no persistent state so
it would not need to be implemented as a resource in Gyro.
Note
With the exception of refresh()
the methods documented below provide a GyroUI
and State
objects.
The GyroUI
object can be used to output additional information to the user’s console.
The State
object can be used to periodically save state between operations within one of the CRUD methods. For
example, if creation of an object requires multiple API calls then state should be saved (i.e. state.save()
) between
each API call to ensure state has a view consistent with the cloud provider’s state.
Implementing refresh¶
The refresh()
method is called to refresh the state of a resource. Gyro will call this method on every
resource loaded from state. Any properties saved in state will set on the resource prior to calling this method.
Implementations should reload the resource properties using cloud provider APIs. This ensures that Gyro can detect changes to a resource that were made outside of Gyro, such as the providers web console.
If a resource cannot be found this method should return false, otherwise return true to indicate the resource was refreshed.
Note
Lists and sets in a resource should be cleared (i.e. myset.clear()
) prior to updating them to ensure
the any values that may have been removed is reflected in the updated resource.
getVolumes().clear();
getVolumes().add(volume);
The following is an example implementation of refresh()
for an EBS volume in AWS:
@Override
protected boolean refresh() {
Ec2Client client = createClient(Ec2Client.class);
Volume volume = getVolume(client);
if (volume == null) {
return false;
}
setId(volume.volumeId());
setAvailabilityZone(volume.availabilityZone());
setCreateTime(Date.from(volume.createTime()));
setEncrypted(volume.encrypted());
setIops(volume.iops());
setKms(!ObjectUtils.isBlank(volume.kmsKeyId()) ? findById(KmsKeyResource.class, volume.kmsKeyId()) : null);
setSize(volume.size());
setSnapshot(!ObjectUtils.isBlank(volume.snapshotId()) ? findById(EbsSnapshotResource.class, volume.snapshotId()) : null);
setState(volume.stateAsString());
setVolumeType(volume.volumeTypeAsString());
DescribeVolumeAttributeResponse responseAutoEnableIo = client.describeVolumeAttribute(
r -> r.volumeId(getId()).attribute(VolumeAttributeName.AUTO_ENABLE_IO)
);
setAutoEnableIo(responseAutoEnableIo.autoEnableIO().value());
return true;
}
Implementing create¶
The create(GyroUI ui, State state)
method is called to create a resource. Gyro will call this method for every resource
it determines needs to be created.
Implementations should create the resource in the cloud provider and update output properties after creation. At a minimum the id that uniquely identifies the resource in the cloud provider should be set.
Note
After create(...)
returns Gyro will call state.save()
to persist information the newly
created resource. When creating a resource requires multiple API calls then save.state()
should
be called after each API call.
The following example implementation creates an EBS volume in AWS:
@Override
protected void create(GyroUI ui, State state) {
Ec2Client client = createClient(Ec2Client.class);
CreateVolumeResponse response = client.createVolume(
r -> r.availabilityZone(getAvailabilityZone())
.encrypted(getEncrypted())
.iops(getVolumeType().equals("io1") ? getIops() : null)
.kmsKeyId(getKms() != null ? getKms().getId() : null)
.size(getSize())
.snapshotId(getSnapshot() != null ? getSnapshot().getId() : null)
.volumeType(getVolumeType())
);
setId(response.volumeId());
setCreateTime(Date.from(response.createTime()));
setState(response.stateAsString());
}
Implementing update¶
The update(GyroUI ui, State state, Resource config, Set<String> changedProperties)
method is called by Gyro when
it determines that one or more resource properties should be updated. This method will only be called if the properties
that changed are marked with the @Updatable
annotation. In cases where both updatable and non-updatable properties are
changed this method will not be called, instead if a workflow exists for this the resource type it will be executed,
otherwise all changes will be skipped.
The changedProperties
set contains the names of fields that changed. This allows implementations to minimum the
of API calls necessary to effect an update.
The following example implementation updates an EBS volume in AWS:
@Override
protected void update(GyroUI ui, State state, AwsResource config, Set<String> changedProperties) {
Ec2Client client = createClient(Ec2Client.class);
if (changedProperties.contains("iops") || changedProperties.contains("size") || changedProperties.contains("volume-type")) {
client.modifyVolume(
r -> r.volumeId(getId())
.iops(getVolumeType().equals("io1") ? getIops() : null)
.size(getSize())
.volumeType(getVolumeType())
);
}
if (changedProperties.contains("auto-enable-io")) {
client.modifyVolumeAttribute(
r -> r.volumeId(getId())
.autoEnableIO(a -> a.value(getAutoEnableIo()))
);
}
}
Implementing delete¶
The delete(GyroUI ui, State state)
method is called by Gyro when it determines that a resource should be deleted
from the cloud provider. The resource implementation should delete the resource from the cloud provider.