Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
## Release (2026-MM-DD)

- `automation`: [v0.1.0](services/automation/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Automation service

## Release (2026-08-25)

- `alb`: [v0.6.0](services/alb/CHANGELOG.md#v060)
Expand Down
6 changes: 6 additions & 0 deletions examples/automation/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
dependencies {
implementation project (':services:automation')
implementation 'com.squareup.okhttp3:okhttp:4.12.0'
}

ext.mainClassName = 'cloud.stackit.sdk.automation.examples.AutomationExample'
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
package cloud.stackit.sdk.automation.examples;

import cloud.stackit.sdk.automation.v1betaapi.api.AutomationApi;
import cloud.stackit.sdk.automation.v1betaapi.model.*;
import cloud.stackit.sdk.automation.v1betaapi.model.SnapshotRetentionPolicyCount.KindEnum;
import cloud.stackit.sdk.automation.v1betaapi.model.VolumeExecutionResponse.StatusEnum;
import cloud.stackit.sdk.core.exception.ApiException;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.TimeUnit;

final class AutomationExample {

private AutomationExample() {}

@SuppressWarnings({
"PMD.CyclomaticComplexity",
"PMD.CognitiveComplexity",
"PMD.NPathComplexity",
"PMD.NcssCount",
"PMD.SystemPrintln",
"PMD.AvoidDuplicateLiterals",
"PMD.AvoidThrowingRawExceptionTypes"
})
public static void main(String[] args) throws IOException {
// Credentials are read from the credentialsFile in
// `~/.stackit/credentials.json` or the env
// STACKIT_SERVICE_ACCOUNT_KEY_PATH / STACKIT_SERVICE_ACCOUNT_KEY
AutomationApi automationApi = new AutomationApi();

// the id of your STACKIT project, read from env var for this example
String projectId = System.getenv("STACKIT_PROJECT_ID");
if (projectId == null || projectId.isEmpty()) {
System.err.println("Environment variable 'STACKIT_PROJECT_ID' not found.");
return;
}

// the region which should be used to interact with the automation service
String region = "eu01";

try {
/*
* ///////////////////////////////////////////////////////
* // V O L U M E T E M P L A T E S //
* ///////////////////////////////////////////////////////
*/
/* list all available volume templates */
ListTemplatesResponse listTemplates =
automationApi.listVolumeTemplates(projectId, region, null, null);
System.out.println("Listing volume templates:");
Objects.requireNonNull(listTemplates.getItems());
for (Template template : listTemplates.getItems()) {
System.out.println("* Template ID: " + template.getId());
}
/* if there is a nextPageToken, fetch next page of results */
while (listTemplates.getNextPageToken() != null
&& !"".equals(listTemplates.getNextPageToken())) {
listTemplates =
automationApi.listVolumeTemplates(
projectId, region, null, listTemplates.getNextPageToken());
System.out.println("Listing next page of volume templates:");
Objects.requireNonNull(listTemplates.getItems());
for (Template template : listTemplates.getItems()) {
System.out.println("* Template ID: " + template.getId());
}
}

/* get one specific volume template */
GetVolumeTemplateResponse template =
automationApi.getVolumeTemplate(
projectId, region, listTemplates.getItems().get(0).getId());
System.out.println("\n\nFetched volume template:");
System.out.println("* Template ID: " + template.getId());
System.out.println("* Template name: " + template.getName());
System.out.println("* Template description: " + template.getDescription());

/*
* ///////////////////////////////////////////////////////
* // V O L U M E A U T O M A T I O N //
* ///////////////////////////////////////////////////////
*/
/* create a volume automation with a schedule trigger (daily at 02:00) */
VolumeAutomation volumeAutomation =
automationApi.createVolumeAutomation(
projectId,
region,
new CreateVolumeAutomationPayload()
.description(
"Creates daily recovery points for all volumes with specified label")
.name("My Daily Volume Recovery Point Creation Automation")
.templateId(UUID.fromString(template.getId()))
.input(
new VolumeAutomationInput(
new VolumeRecoveryPointManagementInput()
.inheritVolumeLabels(true)
.kind("VolumeRecoveryPointManagement")
.recoveryPointLabels(
Collections.singletonMap(
"exampleLabelKey1",
"exampleLabelValue1"))
.snapshotRetentionPolicy(
new SnapshotRetentionPolicy(
new SnapshotRetentionPolicyCount()
.kind(
KindEnum
.COUNT)
.value(2)))
.volumeLabelSelector(
"myLabelkey1=myLabelValue,myLabelKey2=myOtherLabelValue")))
.triggers(
new AutomationTriggers()
.schedule(
new AutomationScheduleTrigger()
.rrule(
"DTSTART;TZID=Europe/Sofia:20200803T023000\nRRULE:FREQ=DAILY;INTERVAL=1"))));
System.out.println("\n\nCreated volume automation:");
System.out.println("* Automation ID: " + volumeAutomation.getId());
System.out.println("* Automation name: " + volumeAutomation.getName());
System.out.println("* Automation description: " + volumeAutomation.getDescription());

/* list all volume automations */
ListAutomationsResponse listAutomations =
automationApi.listVolumeAutomations(projectId, region, null, null);
System.out.println("\n\nListing volume automations:");
Objects.requireNonNull(listAutomations.getItems());
for (ListAutomationsItem automation : listAutomations.getItems()) {
System.out.println("* Automation ID: " + automation.getId());
}
/* if there is a nextPageToken, fetch next page of results */
while (listAutomations.getNextPageToken() != null
&& !"".equals(listAutomations.getNextPageToken())) {
listAutomations =
automationApi.listVolumeAutomations(
projectId, region, null, listAutomations.getNextPageToken());
System.out.println("\nListing next page of volume automations:");
Objects.requireNonNull(listAutomations.getItems());
for (ListAutomationsItem automation : listAutomations.getItems()) {
System.out.println("* Automation ID: " + automation.getId());
}
}

/* update an automation */
VolumeAutomation updatedAutomation =
automationApi.partialUpdateVolumeAutomation(
projectId,
region,
volumeAutomation.getId().toString(),
null,
new PartialUpdateVolumeAutomationPayload()
.description("Updated daily recovery points automation")
.name(
"Updated Daily Volume Recovery Point Creation Automation"));
System.out.println("\n\nUpdated volume automation:");
System.out.println("* Automation ID: " + updatedAutomation.getId());
System.out.println("* Automation name: " + updatedAutomation.getName());
System.out.println("* Automation description: " + updatedAutomation.getDescription());

/* get one specific volume automation */
VolumeAutomation fetchedAutomation =
automationApi.getVolumeAutomation(
projectId, region, volumeAutomation.getId().toString());
System.out.println("\n\nFetched updated volume template:");
System.out.println("* Automation ID: " + fetchedAutomation.getId());
System.out.println("* Automation name: " + fetchedAutomation.getName());
System.out.println("* Automation description: " + fetchedAutomation.getDescription());

/*
* ///////////////////////////////////////////////////////
* // E X E C U T I O N S //
* ///////////////////////////////////////////////////////
*/

/* trigger an automation execution */
VolumeExecutionResponse createdExecution =
automationApi.createVolumeExecution(
projectId, region, volumeAutomation.getId().toString());
System.out.println("\n\nTriggered volume automation execution:");
System.out.println("* Execution ID: " + createdExecution.getId());
System.out.println("* Execution status: " + createdExecution.getStatus());

/* wait for the automation executing to complete */
while (createdExecution.getStatus() == StatusEnum.PENDING
|| createdExecution.getStatus() == StatusEnum.RUNNING) {
System.out.println("* Waiting for automation execution to complete ...");
TimeUnit.SECONDS.sleep(2);
createdExecution =
automationApi.getVolumeExecution(
projectId,
region,
volumeAutomation.getId().toString(),
createdExecution.getId().toString());
}
System.out.println("* Automation execution completed");

/* list all executions of a specifc volume automation */
ListExecutionsResponse listExecutions =
automationApi.listVolumeExecutions(
projectId, region, volumeAutomation.getId().toString(), null, null);
System.out.println("\n\nListing executions of the volume automation:");
Objects.requireNonNull(listExecutions.getItems());
for (ListExecutionsItem execution : listExecutions.getItems()) {
System.out.println("* Execution ID: " + execution.getId());
}

/*
* ///////////////////////////////////////////////////////
* // D E L E T I O N //
* ///////////////////////////////////////////////////////
*/
/* trigger deletion of the created application load balancer instance */
System.out.println("\n\nDeleting created volume automation");
automationApi.deleteVolumeAutomation(
projectId, region, volumeAutomation.getId().toString());
System.out.printf(
"* Successfully deleted automation with ID \"%s\"",
volumeAutomation.getId().toString());
} catch (ApiException | InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,22 @@
import java.util.Map;
import java.util.Objects;

/** Use this option to limit the IP ranges that can use the Application Load Balancer. */
/**
* Use this option to limit the IP ranges that can use the Application Load Balancer. Only one of
* `allowed_source_ranges` or `ip_block_list_name` may be set at the same time.
*/
@javax.annotation.Generated(value = "JavaGenerator", comments = "Generator version: 7.19.0")
public class LoadbalancerOptionAccessControl {
public static final String SERIALIZED_NAME_ALLOWED_SOURCE_RANGES = "allowedSourceRanges";

@SerializedName(SERIALIZED_NAME_ALLOWED_SOURCE_RANGES)
@javax.annotation.Nullable private List<String> allowedSourceRanges = new ArrayList<>();

public static final String SERIALIZED_NAME_IP_BLOCK_LIST_NAME = "ipBlockListName";

@SerializedName(SERIALIZED_NAME_IP_BLOCK_LIST_NAME)
@javax.annotation.Nullable private String ipBlockListName;

public LoadbalancerOptionAccessControl() {}

public LoadbalancerOptionAccessControl allowedSourceRanges(
Expand All @@ -57,7 +65,8 @@ public LoadbalancerOptionAccessControl addAllowedSourceRangesItem(
}

/**
* Application Load Balancer is accessible only from an IP address in this range
* Application Load Balancer is accessible only from an IP address in this range. Mutually
* exclusive with &#x60;ipBlockListName&#x60;.
*
* @return allowedSourceRanges
*/
Expand All @@ -70,6 +79,27 @@ public void setAllowedSourceRanges(
this.allowedSourceRanges = allowedSourceRanges;
}

public LoadbalancerOptionAccessControl ipBlockListName(
@javax.annotation.Nullable String ipBlockListName) {
this.ipBlockListName = ipBlockListName;
return this;
}

/**
* Reference to an IP block list by name. Traffic originating from any IP in the referenced list
* is denied access to the Application Load Balancer. See \&quot;IP Lists API\&quot; for how to
* manage IP block lists. Mutually exclusive with &#x60;allowedSourceRanges&#x60;.
*
* @return ipBlockListName
*/
@javax.annotation.Nullable public String getIpBlockListName() {
return ipBlockListName;
}

public void setIpBlockListName(@javax.annotation.Nullable String ipBlockListName) {
this.ipBlockListName = ipBlockListName;
}

/**
* A container for additional, undeclared properties. This is a holder for any undeclared
* properties as specified with the 'additionalProperties' keyword in the OAS document.
Expand Down Expand Up @@ -127,14 +157,16 @@ public boolean equals(Object o) {
return Objects.equals(
this.allowedSourceRanges,
loadbalancerOptionAccessControl.allowedSourceRanges)
&& Objects.equals(
this.ipBlockListName, loadbalancerOptionAccessControl.ipBlockListName)
&& Objects.equals(
this.additionalProperties,
loadbalancerOptionAccessControl.additionalProperties);
}

@Override
public int hashCode() {
return Objects.hash(allowedSourceRanges, additionalProperties);
return Objects.hash(allowedSourceRanges, ipBlockListName, additionalProperties);
}

@Override
Expand All @@ -144,6 +176,7 @@ public String toString() {
sb.append(" allowedSourceRanges: ")
.append(toIndentedString(allowedSourceRanges))
.append("\n");
sb.append(" ipBlockListName: ").append(toIndentedString(ipBlockListName)).append("\n");
sb.append(" additionalProperties: ")
.append(toIndentedString(additionalProperties))
.append("\n");
Expand All @@ -167,7 +200,8 @@ private String toIndentedString(Object o) {

static {
// a set of all properties/fields (JSON key names)
openapiFields = new HashSet<String>(Arrays.asList("allowedSourceRanges"));
openapiFields =
new HashSet<String>(Arrays.asList("allowedSourceRanges", "ipBlockListName"));

// a set of required properties/fields (JSON key names)
openapiRequiredFields = new HashSet<String>(0);
Expand Down Expand Up @@ -202,6 +236,14 @@ public static void validateJsonElement(JsonElement jsonElement) throws IOExcepti
"Expected the field `allowedSourceRanges` to be an array in the JSON string but got `%s`",
jsonObj.get("allowedSourceRanges").toString()));
}
if ((jsonObj.get("ipBlockListName") != null && !jsonObj.get("ipBlockListName").isJsonNull())
&& !jsonObj.get("ipBlockListName").isJsonPrimitive()) {
throw new IllegalArgumentException(
String.format(
java.util.Locale.ROOT,
"Expected the field `ipBlockListName` to be a primitive type in the JSON string but got `%s`",
jsonObj.get("ipBlockListName").toString()));
}
}

public static class CustomTypeAdapterFactory implements TypeAdapterFactory {
Expand Down
2 changes: 2 additions & 0 deletions services/automation/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## v0.1.0
- Initial onboarding of STACKIT Java SDK for Automation service
Loading
Loading