Skip to content
Merged
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
14 changes: 10 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,11 +357,17 @@ instance = j1.create_integration_instance(

```python
# Start sync job for an integration instance
sync_job = j1.start_sync_job(instance_id='<id-of-integration-instance>')
print(f"Started sync job: {sync_job['job']['_id']}")
sync_job = j1.start_sync_job(
instance_id=instance_id,
sync_mode="PATCH",
source="integration-external"
)

sync_job_id = sync_job['job'].get('id')
print(f"Started sync job: {sync_job_id}")

# The returned job ID is used for subsequent operations
job_id = sync_job['job']['_id']
job_id = sync_job_id
```

##### Upload Batch of Entities
Expand Down Expand Up @@ -514,7 +520,7 @@ print(f"Uploaded {len(combined_payload['entities'])} entities and {len(combined_
```python
# Finalize the sync job
result = j1.finalize_sync_job(instance_job_id='<id-of-integration-sync-job>')
print(f"Finalized sync job: {result['job']['_id']}")
print(f"Finalized sync job: {result['job'].get('id')}")

# Check job status
if result['job']['status'] == 'COMPLETED':
Expand Down
2 changes: 1 addition & 1 deletion examples/04_integration_management.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ def sync_job_examples(j1, instance_id):
try:
sync_job = j1.start_sync_job(
instance_id=instance_id,
sync_mode="CREATE_OR_UPDATE",
sync_mode="PATCH",
source="api"
)
job_id = sync_job['job']['_id']
Expand Down
69 changes: 69 additions & 0 deletions examples/bulk_upload.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from jupiterone.client import JupiterOneClient
import os

account = os.environ.get("JUPITERONE_ACCOUNT")
token = os.environ.get("JUPITERONE_TOKEN")
url = "https://graphql.us.jupiterone.io"

j1 = JupiterOneClient(account=account, token=token, url=url)

instance_id = "e7113c37-1ea8-4d00-9b82-c24952e70916"

sync_job = j1.start_sync_job(
instance_id=instance_id,
sync_mode="PATCH",
source="integration-external"
)

print(sync_job)
sync_job_id = sync_job['job'].get('id')

# Prepare entities payload
entities_payload = [
{
"_key": "server-001",
"_type": "aws_ec2_instance",
"_class": "Host",
"displayName": "web-server-001",
"instanceId": "i-1234567890abcdef0",
"instanceType": "t3.micro",
"state": "running",
"tag.Environment": "production",
"tag.Team": "engineering"
},
{
"_key": "server-002",
"_type": "aws_ec2_instance",
"_class": "Host",
"displayName": "web-server-002",
"instanceId": "i-0987654321fedcba0",
"instanceType": "t3.small",
"state": "running",
"tag.Environment": "staging",
"tag.Team": "engineering"
},
{
"_key": "database-001",
"_type": "aws_rds_instance",
"_class": "Database",
"displayName": "prod-database",
"dbInstanceIdentifier": "prod-db",
"engine": "postgres",
"dbInstanceClass": "db.t3.micro",
"tag.Environment": "production",
"tag.Team": "data"
}
]

# Upload entities batch
result = j1.upload_entities_batch_json(
instance_job_id=sync_job_id,
entities_list=entities_payload
)
print(f"Uploaded {len(entities_payload)} entities")
print(result)

# Finalize the sync job
result = j1.finalize_sync_job(instance_job_id=sync_job_id)
print(f"Finalized sync job: {result['job']['id']}")

4 changes: 2 additions & 2 deletions examples/examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,9 @@
integration_instance_id = "<GUID>"

# start_sync_job
# sync_mode can be "DIFF", "CREATE_OR_UPDATE", or "PATCH"
# sync_mode can be "DIFF" or "PATCH"
start_sync_job_r = j1.start_sync_job(instance_id=integration_instance_id,
sync_mode='CREATE_OR_UPDATE',
sync_mode='PATCH',
source='integration-external')
print("start_sync_job()")
print(start_sync_job_r)
Expand Down
141 changes: 141 additions & 0 deletions examples/sync_job_workflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#!/usr/bin/env python3
"""
JupiterOne Sync Job Workflow Example

This example demonstrates the core synchronization job workflow:
1. Start a sync job
2. Upload entities batch
3. Finalize the sync job

This is a standalone script that can be run independently to test
the sync job functionality.

Note: This example uses PATCH sync mode, which is suitable for entity-only
uploads. If you need to upload relationships, use DIFF sync mode instead.
See: https://docs.jupiterone.io/reference/pipeline-upgrade#patch-sync-jobs-cannot-target-relationships
"""

import os
import sys
from jupiterone.client import JupiterOneClient

def main():
"""Main function to demonstrate sync job workflow."""

# Initialize JupiterOne client
# You can set these as environment variables or replace with your values
api_token = os.getenv('JUPITERONE_API_TOKEN')
account_id = os.getenv('JUPITERONE_ACCOUNT_ID')

if not api_token or not account_id:
print("Error: Please set JUPITERONE_API_TOKEN and JUPITERONE_ACCOUNT_ID environment variables")
print("Example:")
print(" export JUPITERONE_API_TOKEN='your-api-token'")
print(" export JUPITERONE_ACCOUNT_ID='your-account-id'")
sys.exit(1)

# Create JupiterOne client
j1 = JupiterOneClient(token=api_token, account=account_id)

print("=== JupiterOne Sync Job Workflow Example ===\n")

# You'll need to replace this with an actual integration instance ID
instance_id = os.getenv('JUPITERONE_INSTANCE_ID')
if not instance_id:
print("Error: Please set JUPITERONE_INSTANCE_ID environment variable")
print("Example:")
print(" export JUPITERONE_INSTANCE_ID='your-integration-instance-id'")
sys.exit(1)

try:
# Step 1: Start sync job
print("1. Starting synchronization job...")
print(" Note: Using PATCH mode (entities only). Use DIFF mode if uploading relationships.")
sync_job = j1.start_sync_job(
instance_id=instance_id,
sync_mode="PATCH",
source="integration-external"
)

sync_job_id = sync_job['job'].get('id')
print(f"✓ Started sync job: {sync_job_id}")
print(f" Status: {sync_job['job']['status']}")
print()

# Step 2: Upload entities batch
print("2. Uploading entities batch...")

# Sample entities payload
entities_payload = [
{
"_key": "example-server-001",
"_type": "example_server",
"_class": "Host",
"displayName": "Example Server 001",
"hostname": "server-001.example.com",
"ipAddress": "192.168.1.100",
"operatingSystem": "Linux",
"tag.Environment": "development",
"tag.Team": "engineering",
"tag.Purpose": "web_server"
},
{
"_key": "example-server-002",
"_type": "example_server",
"_class": "Host",
"displayName": "Example Server 002",
"hostname": "server-002.example.com",
"ipAddress": "192.168.1.101",
"operatingSystem": "Linux",
"tag.Environment": "staging",
"tag.Team": "engineering",
"tag.Purpose": "database_server"
},
{
"_key": "example-database-001",
"_type": "example_database",
"_class": "Database",
"displayName": "Example Database 001",
"databaseName": "app_db",
"engine": "postgresql",
"version": "13.4",
"tag.Environment": "development",
"tag.Team": "data"
}
]

# Upload entities
upload_result = j1.upload_entities_batch_json(
instance_job_id=sync_job_id,
entities_list=entities_payload
)
print(f"✓ Uploaded {len(entities_payload)} entities successfully")
print(f" Upload result: {upload_result}")
print()

# Step 3: Finalize sync job
print("3. Finalizing synchronization job...")
finalize_result = j1.finalize_sync_job(instance_job_id=sync_job_id)

finalize_job_id = finalize_result['job'].get('id')
print(f"✓ Finalized sync job: {finalize_job_id}")
print(f" Status: {finalize_result['job']['status']}")

# Check final status
if finalize_result['job']['status'] == 'COMPLETED':
print("✓ Sync job completed successfully!")
elif finalize_result['job']['status'] == 'FAILED':
error_msg = finalize_result['job'].get('error', 'Unknown error')
print(f"✗ Sync job failed: {error_msg}")
else:
print(f"ℹ Sync job status: {finalize_result['job']['status']}")

print("\n=== Sync Job Workflow Complete ===")

except Exception as e:
print(f"✗ Error during sync job workflow: {e}")
sys.exit(1)

if __name__ == "__main__":
main()

9 changes: 8 additions & 1 deletion jupiterone/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -662,8 +662,15 @@ def start_sync_job(

args:
instance_id (str): The "integrationInstanceId" request param for synchronization job
sync_mode (str): The "syncMode" request body property for synchronization job. "DIFF", "CREATE_OR_UPDATE", or "PATCH"
sync_mode (str): The "syncMode" request body property for synchronization job. "DIFF" or "PATCH"
source (str): The "source" request body property for synchronization job. "api" or "integration-external"

Note:
IMPORTANT: PATCH sync jobs cannot target relationships. If your sync job involves creating
or updating relationships, you must use "DIFF" sync_mode instead of "PATCH". This is due
to the JupiterOne data pipeline upgrade.

For more information, see: https://docs.jupiterone.io/reference/pipeline-upgrade#patch-sync-jobs-cannot-target-relationships
"""
endpoint = "/persister/synchronization/jobs"

Expand Down
Loading