Quickstart
This quickstart guide will help you build your first integration with the Vantage SDK. We'll walk through authentication, job submission, and monitoring.
Build your first Vantage SDK integration from scratch — authenticate, submit a job, and monitor the result.
Prerequisites
- Installed Vantage SDK for your preferred language
- Vantage account with API access
- At least one connected cluster
Get Your API Key
Log in to the Vantage Dashboard
Go to the Vantage Dashboard and sign in with your credentials.
Navigate to API Keys
Go to Settings → API Keys in the left sidebar.
Generate a new key
Click Generate New Key to create a new API key.
Copy and store the key
Copy the generated key and store it in a secure location, such as a password manager or environment variable.
Basic Setup
Python
import os
from vantage_sdk import VantageClient
# Initialize the client
client = VantageClient(
api_key=os.getenv("VANTAGE_API_KEY"),
organization="your-org-id"
)
# Test the connection
try:
health = client.health_check()
print(f"Connected to Vantage: {health}")
except Exception as e:
print(f"Connection failed: {e}")
JavaScript/TypeScript
import { VantageClient } from '@vantage/sdk';
// Initialize the client
const client = new VantageClient({
apiKey: process.env.VANTAGE_API_KEY,
organization: 'your-org-id'
});
// Test the connection
try {
const health = await client.healthCheck();
console.log(`Connected to Vantage: ${JSON.stringify(health)}`);
} catch (error) {
console.error(`Connection failed: ${error}`);
}
Go
package main
import (
"context"
"fmt"
"log"
"github.com/omnivector-solutions/vantage-sdk-go/vantage"
)
func main() {
// Initialize the client
client := vantage.NewClient(vantage.Config{
APIKey: os.Getenv("VANTAGE_API_KEY"),
Organization: "your-org-id",
})
// Test the connection
ctx := context.Background()
health, err := client.HealthCheck(ctx)
if err != nil {
log.Fatalf("Connection failed: %v", err)
}
fmt.Printf("Connected to Vantage: %+v\n", health)
}
Your First Job Submission
Let's submit a simple "Hello World" job to demonstrate the basic workflow.
Create a Job Template
First, let's explore available clusters and create a simple job template.
Python
# List available clusters
clusters = client.clusters.list()
print("Available clusters:")
for cluster in clusters:
print(f" - {cluster.name} ({cluster.status})")
# Create a simple job template
job_template = {
"name": "hello-world-python",
"description": "Simple hello world job",
"spec": {
"image": "ubuntu:22.04",
"command": ["echo", "Hello from Vantage Python SDK!"],
"resources": {
"cpu": "1",
"memory": "1Gi"
},
"timeout": "300s"
}
}
# Submit the job
job = client.jobs.submit(job_template)
print(f"Job submitted: {job.id}")
JavaScript/TypeScript
// List available clusters
const clusters = await client.clusters.list();
console.log('Available clusters:');
clusters.forEach(cluster => {
console.log(` - ${cluster.name} (${cluster.status})`);
});
// Create a simple job template
const jobTemplate = {
name: 'hello-world-js',
description: 'Simple hello world job',
spec: {
image: 'ubuntu:22.04',
command: ['echo', 'Hello from Vantage JavaScript SDK!'],
resources: {
cpu: '1',
memory: '1Gi'
},
timeout: '300s'
}
};
// Submit the job
const job = await client.jobs.submit(jobTemplate);
console.log(`Job submitted: ${job.id}`);
Go
// List available clusters
clusters, err := client.Clusters.List(ctx, nil)
if err != nil {
log.Fatalf("Failed to list clusters: %v", err)
}
fmt.Println("Available clusters:")
for _, cluster := range clusters {
fmt.Printf(" - %s (%s)\n", cluster.Name, cluster.Status)
}
// Create a simple job template
jobTemplate := &vantage.JobTemplate{
Name: "hello-world-go",
Description: "Simple hello world job",
Spec: vantage.JobSpec{
Image: "ubuntu:22.04",
Command: []string{"echo", "Hello from Vantage Go SDK!"},
Resources: vantage.Resources{
CPU: "1",
Memory: "1Gi",
},
Timeout: "300s",
},
}
// Submit the job
job, err := client.Jobs.Submit(ctx, jobTemplate)
if err != nil {
log.Fatalf("Failed to submit job: %v", err)
}
fmt.Printf("Job submitted: %s\n", job.ID)
Success looks like this: the SDK authenticates, the first API call returns data, and you are ready to build integrations.
Monitor Job Status
Now let's monitor the job until it completes.
Python
import time
def wait_for_job_completion(client, job_id, timeout=300):
"""Wait for job to complete with timeout"""
start_time = time.time()
while time.time() - start_time < timeout:
job = client.jobs.get(job_id)
print(f"Job {job_id} status: {job.status}")
if job.status in ['completed', 'failed', 'cancelled']:
return job
time.sleep(5) # Check every 5 seconds
raise TimeoutError(f"Job {job_id} did not complete within {timeout} seconds")
# Wait for completion
try:
completed_job = wait_for_job_completion(client, job.id)
print(f"Job completed with status: {completed_job.status}")
# Get job logs
logs = client.jobs.logs(job.id)
print(f"Job output:\n{logs}")
except TimeoutError as e:
print(f"Timeout: {e}")
JavaScript/TypeScript
async function waitForJobCompletion(
client: VantageClient,
jobId: string,
timeout: number = 300000
): Promise<Job> {
const startTime = Date.now();
while (Date.now() - startTime < timeout) {
const job = await client.jobs.get(jobId);
console.log(`Job ${jobId} status: ${job.status}`);
if (['completed', 'failed', 'cancelled'].includes(job.status)) {
return job;
}
await new Promise(resolve => setTimeout(resolve, 5000)); // Wait 5 seconds
}
throw new Error(`Job ${jobId} did not complete within ${timeout}ms`);
}
// Wait for completion
try {
const completedJob = await waitForJobCompletion(client, job.id);
console.log(`Job completed with status: ${completedJob.status}`);
// Get job logs
const logs = await client.jobs.logs(job.id);
console.log(`Job output:\n${logs}`);
} catch (error) {
console.error(`Error: ${error}`);
}
Go
func waitForJobCompletion(client *vantage.Client, jobID string, timeout time.Duration) (*vantage.Job, error) {
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
ticker := time.NewTicker(5 * time.Second)
defer ticker.Stop()
for {
select {
case <-ctx.Done():
return nil, fmt.Errorf("job %s did not complete within %v", jobID, timeout)
case <-ticker.C:
job, err := client.Jobs.Get(ctx, jobID)
if err != nil {
return nil, fmt.Errorf("failed to get job status: %v", err)
}
fmt.Printf("Job %s status: %s\n", jobID, job.Status)
switch job.Status {
case "completed", "failed", "cancelled":
return job, nil
}
}
}
}
// Wait for completion
completedJob, err := waitForJobCompletion(client, job.ID, 5*time.Minute)
if err != nil {
log.Fatalf("Job monitoring failed: %v", err)
}
fmt.Printf("Job completed with status: %s\n", completedJob.Status)
// Get job logs
logs, err := client.Jobs.Logs(ctx, job.ID)
if err != nil {
log.Printf("Failed to get logs: %v", err)
} else {
fmt.Printf("Job output:\n%s\n", logs)
}
Working with Data
Let's enhance our example to work with input and output data.
Upload Input Data
Python
# Upload input data
input_data = "Hello from uploaded file!"
input_file = client.storage.upload_string(
content=input_data,
path="/datasets/input.txt"
)
print(f"Uploaded input file: {input_file.path}")
JavaScript/TypeScript
// Upload input data
const inputData = 'Hello from uploaded file!';
const inputFile = await client.storage.uploadString(
inputData,
'/datasets/input.txt'
);
console.log(`Uploaded input file: ${inputFile.path}`);
Enhanced Job with Data Processing
Python
# Job that processes input data
data_processing_job = {
"name": "data-processing-python",
"description": "Job that processes input data",
"spec": {
"image": "ubuntu:22.04",
"command": [
"bash", "-c",
"cat /input/input.txt && echo ' - Processed by Vantage!' > /output/result.txt"
],
"resources": {
"cpu": "1",
"memory": "1Gi"
},
"volumes": [
{
"name": "input-data",
"source": "/datasets/input.txt",
"mount_path": "/input/input.txt"
},
{
"name": "output-data",
"mount_path": "/output",
"type": "output"
}
],
"timeout": "300s"
}
}
# Submit and monitor the job
data_job = client.jobs.submit(data_processing_job)
completed_data_job = wait_for_job_completion(client, data_job.id)
# Download output
if completed_data_job.status == 'completed':
output_files = client.jobs.outputs(data_job.id)
for output_file in output_files:
local_path = f"./downloads/{output_file.name}"
client.storage.download(output_file.path, local_path)
print(f"Downloaded: {local_path}")
Error Handling
Implement proper error handling for production use.
Python
from vantage_sdk.exceptions import (
VantageAPIError,
AuthenticationError,
ResourceNotFoundError,
RateLimitError
)
def robust_job_submission(client, job_template):
"""Submit job with comprehensive error handling"""
try:
job = client.jobs.submit(job_template)
print(f"Job submitted successfully: {job.id}")
return job
except AuthenticationError:
print("Authentication failed. Check your API key.")
return None
except RateLimitError as e:
print(f"Rate limit exceeded. Retry after {e.retry_after} seconds.")
return None
except ResourceNotFoundError as e:
print(f"Resource not found: {e.message}")
return None
except VantageAPIError as e:
print(f"API error {e.status_code}: {e.message}")
return None
except Exception as e:
print(f"Unexpected error: {e}")
return None
# Use the robust function
job = robust_job_submission(client, job_template)
if job:
print("Proceeding with job monitoring...")
JavaScript/TypeScript
import {
VantageAPIError,
AuthenticationError,
ResourceNotFoundError,
RateLimitError
} from '@vantage/sdk';
async function robustJobSubmission(
client: VantageClient,
jobTemplate: JobTemplate
): Promise<Job | null> {
try {
const job = await client.jobs.submit(jobTemplate);
console.log(`Job submitted successfully: ${job.id}`);
return job;
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed. Check your API key.');
} else if (error instanceof RateLimitError) {
console.error(`Rate limit exceeded. Retry after ${error.retryAfter} seconds.`);
} else if (error instanceof ResourceNotFoundError) {
console.error(`Resource not found: ${error.message}`);
} else if (error instanceof VantageAPIError) {
console.error(`API error ${error.statusCode}: ${error.message}`);
} else {
console.error(`Unexpected error: ${error}`);
}
return null;
}
}
// Use the robust function
const job = await robustJobSubmission(client, jobTemplate);
if (job) {
console.log('Proceeding with job monitoring...');
}
Batch Operations
Process multiple jobs efficiently.
Python
def submit_batch_jobs(client, job_templates):
"""Submit multiple jobs and track their progress"""
jobs = []
# Submit all jobs
for template in job_templates:
try:
job = client.jobs.submit(template)
jobs.append(job)
print(f"Submitted job: {job.id}")
except Exception as e:
print(f"Failed to submit job {template['name']}: {e}")
# Monitor all jobs
completed_jobs = []
pending_jobs = jobs[:]
while pending_jobs:
for job in pending_jobs[:]: # Copy list to safely modify during iteration
current_job = client.jobs.get(job.id)
if current_job.status in ['completed', 'failed', 'cancelled']:
completed_jobs.append(current_job)
pending_jobs.remove(job)
print(f"Job {job.id} finished with status: {current_job.status}")
if pending_jobs:
time.sleep(10) # Check every 10 seconds
return completed_jobs
# Create multiple job templates
job_templates = [
{
"name": f"batch-job-{i}",
"spec": {
"image": "ubuntu:22.04",
"command": ["echo", f"Batch job {i}"],
"resources": {"cpu": "1", "memory": "1Gi"}
}
}
for i in range(3)
]
# Submit and monitor batch jobs
completed_jobs = submit_batch_jobs(client, job_templates)
print(f"All {len(completed_jobs)} jobs completed!")
Next Steps
Common Patterns
Asynchronous Processing (Python)
import asyncio
from vantage_sdk import AsyncVantageClient
async def async_job_workflow():
async_client = AsyncVantageClient(api_key="your-key")
# Submit multiple jobs concurrently
job_templates = [create_job_template(i) for i in range(5)]
jobs = await asyncio.gather(*[
async_client.jobs.submit(template)
for template in job_templates
])
# Wait for all jobs to complete
completed_jobs = await asyncio.gather(*[
wait_for_job_completion_async(async_client, job.id)
for job in jobs
])
return completed_jobs
# Run async workflow
completed_jobs = asyncio.run(async_job_workflow())
Job Templates with Variables
# Template with variables
template_with_vars = {
"name": "parameterized-job",
"spec": {
"image": "python:3.11",
"command": ["python", "-c"],
"args": ["print(f'Processing {dataset} with {algorithm}')"],
"env": {
"DATASET": "{{dataset}}",
"ALGORITHM": "{{algorithm}}"
},
"resources": {
"cpu": "{{cpu_cores}}",
"memory": "{{memory_size}}"
}
}
}
# Submit with different parameters
for dataset in ['dataset1', 'dataset2']:
for algorithm in ['linear', 'neural']:
job_spec = substitute_variables(template_with_vars, {
'dataset': dataset,
'algorithm': algorithm,
'cpu_cores': '2',
'memory_size': '4Gi'
})
job = client.jobs.submit(job_spec)
print(f"Submitted {dataset}/{algorithm} job: {job.id}")
You're now ready to build powerful integrations with the Vantage platform!