curl --request PUT \
--url https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"rules": [
{
"priority": 1,
"selection": {
"count_number": 10,
"tag_prefixes": [
"prod-"
],
"tag_patterns": [
"release-*"
],
"count_unit": "days"
},
"action": "expire",
"description": "Keep the last 10 prod builds"
}
]
}
'import requests
url = "https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy"
payload = { "rules": [
{
"priority": 1,
"selection": {
"count_number": 10,
"tag_prefixes": ["prod-"],
"tag_patterns": ["release-*"],
"count_unit": "days"
},
"action": "expire",
"description": "Keep the last 10 prod builds"
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
rules: [
{
priority: 1,
selection: {
count_number: 10,
tag_prefixes: ['prod-'],
tag_patterns: ['release-*'],
count_unit: 'days'
},
action: 'expire',
description: 'Keep the last 10 prod builds'
}
]
})
};
fetch('https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'rules' => [
[
'priority' => 1,
'selection' => [
'count_number' => 10,
'tag_prefixes' => [
'prod-'
],
'tag_patterns' => [
'release-*'
],
'count_unit' => 'days'
],
'action' => 'expire',
'description' => 'Keep the last 10 prod builds'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy"
payload := strings.NewReader("{\n \"rules\": [\n {\n \"priority\": 1,\n \"selection\": {\n \"count_number\": 10,\n \"tag_prefixes\": [\n \"prod-\"\n ],\n \"tag_patterns\": [\n \"release-*\"\n ],\n \"count_unit\": \"days\"\n },\n \"action\": \"expire\",\n \"description\": \"Keep the last 10 prod builds\"\n }\n ]\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"rules\": [\n {\n \"priority\": 1,\n \"selection\": {\n \"count_number\": 10,\n \"tag_prefixes\": [\n \"prod-\"\n ],\n \"tag_patterns\": [\n \"release-*\"\n ],\n \"count_unit\": \"days\"\n },\n \"action\": \"expire\",\n \"description\": \"Keep the last 10 prod builds\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"rules\": [\n {\n \"priority\": 1,\n \"selection\": {\n \"count_number\": 10,\n \"tag_prefixes\": [\n \"prod-\"\n ],\n \"tag_patterns\": [\n \"release-*\"\n ],\n \"count_unit\": \"days\"\n },\n \"action\": \"expire\",\n \"description\": \"Keep the last 10 prod builds\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"policy": {
"rules": [
{
"priority": 1,
"selection": {
"tag_status": "tagged",
"count_type": "image_count_more_than",
"count_number": 10,
"tag_prefixes": [
"prod-"
],
"tag_patterns": [
"release-*"
],
"count_unit": "days"
},
"action": "expire",
"description": "Keep the last 10 prod builds"
}
],
"updated_at": "2023-11-07T05:31:56Z",
"last_evaluated_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}Set the lifecycle policy
Rules are applied in priority order and an image is claimed by
the FIRST rule that matches it. That is what makes “keep the last
10 prod-* images (priority 1), expire everything older than 90
days (priority 100)” mean what it reads as, rather than having the
second rule also delete the images the first one kept.
Three constraints exist to stop a policy from quietly meaning something other than it appears to:
- At most one rule may select
tag_status: any, and it must carry the highest priority number. A catch-all at priority 1 would claim every image before any specific rule ran, leaving the careful rules below it silently dead. - A
taggedrule must list a prefix or a pattern. Without one it isanyin disguise, and would escape the constraint above. - A tag pattern of exactly
*is refused for the same reason.
Installing a policy resets last_evaluated_at: rules that have
just been rewritten have never run in their current form.
curl --request PUT \
--url https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"rules": [
{
"priority": 1,
"selection": {
"count_number": 10,
"tag_prefixes": [
"prod-"
],
"tag_patterns": [
"release-*"
],
"count_unit": "days"
},
"action": "expire",
"description": "Keep the last 10 prod builds"
}
]
}
'import requests
url = "https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy"
payload = { "rules": [
{
"priority": 1,
"selection": {
"count_number": 10,
"tag_prefixes": ["prod-"],
"tag_patterns": ["release-*"],
"count_unit": "days"
},
"action": "expire",
"description": "Keep the last 10 prod builds"
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.put(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'PUT',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
rules: [
{
priority: 1,
selection: {
count_number: 10,
tag_prefixes: ['prod-'],
tag_patterns: ['release-*'],
count_unit: 'days'
},
action: 'expire',
description: 'Keep the last 10 prod builds'
}
]
})
};
fetch('https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_POSTFIELDS => json_encode([
'rules' => [
[
'priority' => 1,
'selection' => [
'count_number' => 10,
'tag_prefixes' => [
'prod-'
],
'tag_patterns' => [
'release-*'
],
'count_unit' => 'days'
],
'action' => 'expire',
'description' => 'Keep the last 10 prod builds'
]
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy"
payload := strings.NewReader("{\n \"rules\": [\n {\n \"priority\": 1,\n \"selection\": {\n \"count_number\": 10,\n \"tag_prefixes\": [\n \"prod-\"\n ],\n \"tag_patterns\": [\n \"release-*\"\n ],\n \"count_unit\": \"days\"\n },\n \"action\": \"expire\",\n \"description\": \"Keep the last 10 prod builds\"\n }\n ]\n}")
req, _ := http.NewRequest("PUT", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.put("https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"rules\": [\n {\n \"priority\": 1,\n \"selection\": {\n \"count_number\": 10,\n \"tag_prefixes\": [\n \"prod-\"\n ],\n \"tag_patterns\": [\n \"release-*\"\n ],\n \"count_unit\": \"days\"\n },\n \"action\": \"expire\",\n \"description\": \"Keep the last 10 prod builds\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://registry.{region}.basaltic.sh/v1/repositories/{repository_id}/lifecycle-policy")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Put.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"rules\": [\n {\n \"priority\": 1,\n \"selection\": {\n \"count_number\": 10,\n \"tag_prefixes\": [\n \"prod-\"\n ],\n \"tag_patterns\": [\n \"release-*\"\n ],\n \"count_unit\": \"days\"\n },\n \"action\": \"expire\",\n \"description\": \"Keep the last 10 prod builds\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"policy": {
"rules": [
{
"priority": 1,
"selection": {
"tag_status": "tagged",
"count_type": "image_count_more_than",
"count_number": 10,
"tag_prefixes": [
"prod-"
],
"tag_patterns": [
"release-*"
],
"count_unit": "days"
},
"action": "expire",
"description": "Keep the last 10 prod builds"
}
],
"updated_at": "2023-11-07T05:31:56Z",
"last_evaluated_at": "2023-11-07T05:31:56Z"
}
}{
"error": {
"code": "INVALID_INPUT",
"message": "Invalid request parameters",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "UNAUTHORIZED",
"message": "Authentication required",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "ACCESS_DENIED",
"message": "You don't have permission to perform this action",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"request_id": "550e8400-e29b-41d4-a716-446655440000"
}
}registry:PutLifecyclePolicy. See REGISTRY permissions for the full list, what each one covers, and an example policy.Authorizations
An OAuth 2.0 bearer token, sent as Authorization: Bearer <token>.
This is the recommended way to authenticate.
Get one by exchanging a service account's access key pair at
POST /v1/oauth/token with grant_type=client_credentials. It is the
standard client-credentials grant, so any OAuth-aware library will
obtain and refresh it for you.
curl -s -u "$KEY_ID:$SECRET" -d grant_type=client_credentials \
https://iam.basaltic.sh/v1/oauth/token
Tokens last an hour by default. The same access key pair is separately your AWS SigV4 credential for the S3-compatible object endpoint, which speaks nothing else.
Path Parameters
"a1b2c3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
Body
25Show child attributes
Show child attributes
Response
Policy stored.
Show child attributes
Show child attributes

