Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

Compute Module에서 Ontology SDK 사용

OSDK를 사용하려면 생성한 SDK 패키지, 대상 데이터 권한과 앱 자격 증명 및 네트워크 연결을 함께 구성합니다. SDK를 이미지에 설치하는 빌드용 토큰과 실행 중 서비스 사용자 인증은 용도가 다릅니다.

예제의 api:ontologies-read 같은 범위 이름은 기존 API 보안 모델을 기준으로 합니다. 고급 API 보안을 사용하는 Developer Console 앱에서는 api:use-ontologies-read처럼 해당 API 네임스페이스에 맞는 작업 범위를 요청해야 합니다. 앱의 보안 모델과 SDK가 호출하는 API를 확인하여 애플리케이션 제한과 범위를 맞춥니다.

권한과 앱 자격 증명

  1. Developer Console의 OAuth & restrictions > Resource and operation restrictions에서 Troubleshoot access를 엽니다.
  2. 대상 자원의 Security에서 앱 client ID로 서비스 사용자를 찾아 필요한 접근을 부여합니다.
  3. 데이터셋 기반 객체라면 보안 구성에 따라 객체 집합뿐 아니라 기반 데이터셋의 접근도 필요할 수 있습니다.
  4. Foundry 호스트로 나가는 소스를 Compute Module에 연결합니다.
  5. Configure에서 Application permissions를 선택하고 Use other app credentials를 엽니다.
  6. Developer Console 앱의 client ID와 client secret을 입력하고 Apply한 뒤 구성을 저장합니다.

실행 중 자격 증명은 CLIENT_ID와 CLIENT_SECRET으로 제공됩니다. Python에서는 retrieve_third_party_id_and_creds()로, Java에서는 System.getenv 또는 SDK의 EnvVars로 읽을 수 있습니다. 결과에 적용되는 데이터 권한은 서비스 사용자의 권한입니다.

로컬 Docker의 Python OSDK

Developer Console에서 Python, Backend service와 Application permissions를 선택하여 SDK를 생성합니다. Console이 제시하는 패키지 이름, 버전과 저장소 주소를 사용합니다.

다음 src/app.py의 demo_python_sdk와 Employee는 가상 생성 패키지와 객체 유형입니다. 실제 생성 이름으로 바꿉니다. FOUNDRY_HOST에는 프로토콜을 제외한 호스트를 설정합니다.

import os
from compute_modules.annotations import function
from demo_python_sdk import FoundryClient, ConfidentialClientAuth

@function
def get_object(context, event) -> list[str]:
    host = os.environ["FOUNDRY_HOST"]
    auth = ConfidentialClientAuth(
        client_id=os.environ["CLIENT_ID"],
        client_secret=os.environ["CLIENT_SECRET"],
        hostname=host,
        should_refresh=True,
        scopes=["api:ontologies-read"],
    )
    target_rid = os.environ.get("FOUNDRY_ONTOLOGY_RID")
    options = {"rid": target_rid} if target_rid else {}
    client = FoundryClient(auth=auth, hostname=host, **options)
    return [str(employee) for employee in client.ontology.objects.Employee.take(1)]

이 함수는 조회한 최대 한 객체를 문자열 목록으로 반환합니다. 객체가 없으면 빈 목록이며 인증이나 조회 실패는 예외로 전달합니다. 원시 객체나 토큰을 로그에 남기지 않습니다.

requirements.txt:

foundry-compute-modules==0.34.0

생성 SDK의 정확한 패키지명==버전은 OSDK_PACKAGE_SPEC으로 제공하여 아래 Docker 빌드에서 함께 설치합니다. 비공개 SDK 저장소와 SDK 자산 저장소의 RID는 Developer Console이 표시한 실제 값을 사용합니다.

# syntax=docker/dockerfile:1
FROM python:3.12
WORKDIR /app
COPY requirements.txt ./
ARG FOUNDRY_HOST
ARG OSDK_REPOSITORY_RID
ARG SDK_ASSET_REPOSITORY_RID
ARG OSDK_PACKAGE_SPEC
RUN --mount=type=secret,id=FOUNDRY_TOKEN,env=FOUNDRY_TOKEN,required=true \
    test -n "$FOUNDRY_HOST" && \
    test -n "$OSDK_REPOSITORY_RID" && \
    test -n "$SDK_ASSET_REPOSITORY_RID" && \
    test -n "$OSDK_PACKAGE_SPEC" && \
    python -m pip install --no-cache-dir --upgrade \
      -r requirements.txt "$OSDK_PACKAGE_SPEC" \
      --extra-index-url "https://user:$FOUNDRY_TOKEN@$FOUNDRY_HOST/artifacts/api/repositories/$OSDK_REPOSITORY_RID/contents/release/pypi/simple" \
      --extra-index-url "https://user:$FOUNDRY_TOKEN@$FOUNDRY_HOST/artifacts/api/repositories/$SDK_ASSET_REPOSITORY_RID/contents/release/pypi/simple"
COPY src/app.py ./app.py
USER 5000
ENTRYPOINT ["python", "app.py"]

FOUNDRY_TOKEN은 빌드용 private 저장소 접근 토큰이며 BuildKit secret으로 전달합니다. Dockerfile의 ENV, 일반 build argument 또는 커밋한 설정에 비밀 값을 넣지 않습니다.

: "${FOUNDRY_HOST:?FOUNDRY_HOST is required}"
: "${FOUNDRY_TOKEN:?FOUNDRY_TOKEN is required}"
: "${OSDK_REPOSITORY_RID:?OSDK_REPOSITORY_RID is required}"
: "${SDK_ASSET_REPOSITORY_RID:?SDK_ASSET_REPOSITORY_RID is required}"
: "${OSDK_PACKAGE_SPEC:?OSDK_PACKAGE_SPEC is required}"
docker buildx build --platform=linux/amd64 --load \
  --secret id=FOUNDRY_TOKEN,env=FOUNDRY_TOKEN \
  --build-arg "FOUNDRY_HOST=$FOUNDRY_HOST" \
  --build-arg "OSDK_REPOSITORY_RID=$OSDK_REPOSITORY_RID" \
  --build-arg "SDK_ASSET_REPOSITORY_RID=$SDK_ASSET_REPOSITORY_RID" \
  --build-arg "OSDK_PACKAGE_SPEC=$OSDK_PACKAGE_SPEC" \
  -t osdk-compute-module:0.0.1 .

빌드한 이미지는 Artifacts의 Docker 게시 경로로 올리고 모듈의 컨테이너에 연결합니다. 빌드용 FOUNDRY_HOST argument는 실행 환경 변수로 자동 유지되지 않으므로 Compute Module에도 FOUNDRY_HOST를 설정합니다.

Code Repositories의 Python

Developer Console에서 Python, Backend service와 Application permissions를 선택하면 Conda SDK를 생성할 수 있습니다.

Python 저장소의 Libraries에서 생성한 SDK를 검색해 추가합니다.

이 경로에서도 위 get_object 구현을 사용할 수 있으며 패키지 import를 해당 Conda SDK의 생성 이름에 맞춥니다. 객체를 읽는 예에는 api:ontologies-read를 사용합니다. 객체 편집 또는 미디어 집합 읽기/쓰기까지 수행한다면 그 작업에 맞는 api:ontologies-write, api:mediasets-read, api:mediasets-write 범위와 실제 자원 권한을 추가합니다.

Code Repositories의 Java

  1. Developer Console에서 Java, Backend service와 Application permissions를 선택하여 Maven SDK를 생성합니다. 예시 Maven locator는 com.palantir.foundry:osdk-compute-module-demo-sdk이며 실제 생성 좌표와 버전을 사용합니다.

  1. Java 저장소의 Libraries에서 해당 Maven SDK를 찾아 추가합니다.

  1. 숨김 파일을 표시하고 배포 애플리케이션 정의 디렉터리의 build.gradle을 엽니다.

  1. Libraries에서 선택한 전체 Maven 좌표를 dependencies의 implementation에 추가합니다.

다음은 가상 패키지 osdk_compute_module_demo_sdk의 Employee를 조회하는 모듈입니다. 실제 생성 패키지 및 객체 API 이름을 사용합니다.

import com.palantir.computemodules.ComputeModule;
import com.palantir.computemodules.functions.Context;
import com.palantir.foundry.osdk_compute_module_demo_sdk.FoundryClient;
import com.palantir.foundry.osdk_compute_module_demo_sdk.objects.Employee;
import com.palantir.osdk.api.auth.ConfidentialClientAuth;
import com.palantir.osdk.internal.api.FoundryConnectionConfig;
import java.util.stream.Stream;

public final class EmployeeModule {
    public record Request() {}

    private static final FoundryClient CLIENT = FoundryClient.builder()
            .auth(ConfidentialClientAuth.builder()
                    .clientId(System.getenv("CLIENT_ID"))
                    .clientSecret(System.getenv("CLIENT_SECRET"))
                    .build())
            .connectionConfig(FoundryConnectionConfig.builder()
                    .foundryUri("https://" + System.getenv("FOUNDRY_HOST"))
                    .build())
            .build();

    public static void main(String[] args) {
        ComputeModule.builder()
                .add(EmployeeModule::getObject, Request.class, String.class, "get_object")
                .build()
                .start();
    }

    static String getObject(Context context, Request request) {
        try (Stream<Employee> employees = CLIENT.ontology().objects().Employee().fetchStream()) {
            return employees.findFirst()
                    .map(Employee::toString)
                    .orElseThrow(() -> new IllegalStateException("No Employee object is accessible"));
        }
    }
}

클라이언트는 재사용하고 첫 객체만 읽습니다. 접근 가능한 객체가 없으면 명시적인 예외가 발생합니다. 이 예제는 Java 21로 구성하며 생성 OSDK의 지원 범위는 Java OSDK 참조를 따릅니다.

Marketplace 설치 대상 온톨로지

Marketplace로 설치한 모듈에는 설치 프로젝트의 온톨로지 RID를 FOUNDRY_ONTOLOGY_RID로 제공합니다. 위 Python 예제는 값이 있으면 FoundryClient의 rid로 전달하고, 없으면 생성 SDK의 기본 온톨로지를 사용합니다.

TypeScript에서는 다음처럼 대상 RID와 client credentials를 함께 구성할 수 있습니다. SOURCE_ONTOLOGY_RID는 Marketplace 밖에서 사용할 원본 온톨로지의 실제 RID입니다.

import { createClient } from "@osdk/client";
import { createConfidentialOauthClient } from "@osdk/oauth";

function requiredEnv(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

const foundryUrl = `https://${requiredEnv("FOUNDRY_HOST")}`;
const ontologyRid = process.env.FOUNDRY_ONTOLOGY_RID
  ?? requiredEnv("SOURCE_ONTOLOGY_RID");
const auth = createConfidentialOauthClient(
  requiredEnv("CLIENT_ID"),
  requiredEnv("CLIENT_SECRET"),
  foundryUrl,
  ["api:ontologies-read"],
);
export const client = createClient(`${foundryUrl}/api`, ontologyRid, auth);

원본과 대상 온톨로지의 모든 엔터티 API 이름이 일치해야 OSDK가 대상을 해석할 수 있습니다. RID만 바꿔도 객체, 속성, 액션 등의 API 이름 차이까지 자동으로 해결되지는 않습니다. 패키징 시 이름과 자원 매핑은 Developer Console의 Marketplace 설치에서도 확인합니다.