העברה של קבצים או אובייקטים ספציפיים באמצעות קובץ מניפסט

אפשר להשתמש ב-Storage Transfer Service כדי להעביר קבצים או אובייקטים ספציפיים, שמצוינים באמצעות מניפסט. מניפסט הוא קובץ CSV שמועלה ל-Cloud Storage ומכיל רשימה של קבצים או אובייקטים ש-Storage Transfer Service יפעל לגביהם.

אפשר להשתמש במניפסט להעברות הבאות:

  • מ-AWS S3, מאחסון תואם ל-S3, מ-Azure Blobstore או מ-Cloud Storage לקטגוריה של Cloud Storage.

  • ממערכת קבצים לקטגוריה של Cloud Storage.

  • מקטגוריה של Cloud Storage למערכת קבצים.

  • בין שתי מערכות קבצים.

  • ממקור HTTP/HTTPS שנגיש באופן ציבורי לקטגוריה של Cloud Storage. פועלים לפי ההוראות במאמר יצירת רשימת כתובות URL, כי הפורמט של המניפסט ייחודי לרשימות של כתובות URL.

יצירת מניפסט

אלה הדרישות לגבי קובצי מניפסט:

  • המניפסטים חייבים להיות בפורמט CSV.
  • הם יכולים להכיל כל תו בקידוד UTF-8.
  • העמודה הראשונה חייבת להיות שם קובץ או שם אובייקט. השם הוא יחסי לנתיב הבסיס או לקטגוריה ולתיקייה שצוינו במשימת ההעברה. פרטים נוספים זמינים במאמרים העברות של מערכת קבצים והעברות של מאגר אובייקטים.
  • קובצי מניפסט לא תומכים בתווים כלליים לחיפוש. אי אפשר להשתמש בשמות של תיקיות בלי שם של קובץ או אובייקט.
  • אם שם הקובץ או האובייקט מכיל פסיק, צריך להקיף את השם במירכאות כפולות. לדוגמה, "doe,john.txt".
  • אין הגבלה על הגודל של קובץ המניפסט.

מומלץ לבדוק את ההעברה עם קבוצת משנה קטנה של קבצים או אובייקטים, כדי למנוע קריאות מיותרות ל-API בגלל שגיאות בהגדרות.

אפשר לעקוב אחרי הסטטוס של העברות הקבצים בדף Transfer Jobs. קבצים או אובייקטים שההעברה שלהם נכשלה מופיעים ביומני ההעברה.

העברות של מערכת קבצים

כדי ליצור מניפסט של קבצים במערכת קבצים, יוצרים קובץ CSV עם עמודה אחת שמכילה את נתיבי הקבצים ביחס לתיקיית השורש שצוינה ביצירת משימת ההעברה.

לדוגמה, כדי להעביר את הקבצים הבאים של מערכת הקבצים:

נתיב קובץ
rootdir/dir1/subdir1/file1.txt
rootdir/file2.txt
rootdir/dir2/subdir1/file3.txt

המניפסט אמור להיראות כמו בדוגמה הבאה:

dir1/subdir1/file1.txt
file2.txt
dir2/subdir1/file3.txt

שומרים את קובץ המניפסט עם שם קובץ כלשהו וסיומת .csv.

העברות של מאגרי אובייקטים

כדי ליצור מניפסט של אובייקטים, יוצרים קובץ CSV שבעמודה הראשונה שלו מופיעים שמות האובייקטים ביחס לשם הקטגוריה ולנתיב שצוינו ביצירת משימת ההעברה. כל האובייקטים צריכים להיות באותה קטגוריה.

אפשר גם לציין עמודה שנייה אופציונלית עם מספר הגנרציה של הגרסה הספציפית להעברה ב-Cloud Storage.

לדוגמה, יכול להיות שתרצו להעביר את האובייקטים הבאים:

נתיב האובייקט מספר הדור ב-Cloud Storage
SOURCE_PATH/object1.pdf 1664826685911832
SOURCE_PATH/object2.pdf
SOURCE_PATH/object3.pdf 1664826610699837

המניפסט אמור להיראות כמו בדוגמה הבאה:

object1.pdf,1664826685911832
object2.pdf
object3.pdf,1664826610699837

שומרים את קובץ המניפסט עם שם קובץ כלשהו וסיומת .csv.

העברות HTTP/HTTPS

כדי להעביר קבצים ספציפיים ממקור HTTP או HTTPS, עיינו בהוראות במאמר יצירת רשימת כתובות URL.

פרסום המניפסט

אחרי שיוצרים את המניפסט, צריך להפוך אותו לזמין ל-Storage Transfer Service. ל-Storage Transfer Service יש גישה לקובץ בקטגוריה של Cloud Storage או במערכת הקבצים.

העלאת המניפסט ל-Cloud Storage

אפשר לאחסן את קובץ המניפסט בכל קטגוריה של Cloud Storage.

לסוכן השירות שמפעיל את ההעברה צריכה להיות הרשאת storage.objects.get בקטגוריה שמכילה את המניפסט. בקטע מתן ההרשאות הנדרשות מוסבר איך למצוא את מזהה סוכן השירות ואיך לתת לסוכן השירות הרשאות בקטגוריה.

הוראות להעלאת המניפסט לקטגוריה מפורטות במאמר העלאת אובייקטים במסמכי התיעוד של Cloud Storage.

לדוגמה, כדי להעלות קובץ ל-Cloud Storage באמצעות ה-CLI של gcloud, משתמשים בפקודה gcloud storage cp:

gcloud storage cp MANIFEST.CSV gs://DESTINATION_BUCKET_NAME/

מחליפים את מה שכתוב בשדות הבאים:

  • ‫MANIFEST.CSV הוא הנתיב המקומי לקובץ המניפסט. לדוגמה, Desktop/manifest01.csv.

  • ‫DESTINATION_BUCKET_NAME הוא שם הקטגוריה שאליה מעלים את האובייקט. לדוגמה, my-bucket.

אם הפעולה בוצעה ללא שגיאות, התשובה תיראה כמו בדוגמה הבאה:

Completed files 1/1 | 164.3kiB/164.3kiB

אתם יכולים להצפין מניפסט או את הקטגוריה שמכילה אותו באמצעות מפתחות הצפנה של Cloud KMS בניהול הלקוח. במקרה כזה, צריך לתת את התפקיד Cloud KMS CryptoKey Encrypter/Decrypter (roles/cloudkms.cryptoKeyEncrypterDecrypter) במפתח Cloud KMS שמשמש להצפנת המניפסט לשני סוכני השירות הבאים:

  • סוכן השירות של Storage Transfer Service,‏ project-PROJECT_NUMBER@storage-transfer-service.iam.gserviceaccount.com.
  • סוכן השירות של Cloud Storage בפרויקט שמכיל את הקטגוריה של המניפסט, service-PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com.

במאמר הקצאת מפתח Cloud KMS לסוכן שירות מוסבר איך מקצים את התפקיד הזה. אין תמיכה במפתחות הצפנה באספקת הלקוח (CSEK).

אחסון המניפסט במערכת קבצים

אתם יכולים לאחסן את קובץ המניפסט במערכת הקבצים של המקור או היעד.

לסוכני ההעברה צריכה להיות גישה למיקום של הקובץ. אם אתם מגבילים את הגישה לספרייה של הסוכנים, ודאו שקובץ המניפסט נמצא בספרייה שנטענה.

התחלת העברה

אל תשנו את קובץ המניפסט עד שפעולת ההעברה תסתיים. מומלץ לנעול את קובץ המניפסט בזמן ההעברה.

מסוף Cloud

כדי להתחיל העברה עם מניפסט ממסוף Cloud:

  1. פועלים לפי ההוראות במאמר יצירת העברות כדי לבחור את המקור, היעד והאפשרויות.

  2. בשלב האחרון, Choose settings, מסמנים את התיבה Provide list of files to transfer via קובץ מניפסט.

  3. מזינים את המיקום של קובץ המניפסט.

gcloud

כדי להעביר את הקבצים או האובייקטים שרשומים במניפסט, צריך לכלול את הדגל --manifest-file=MANIFEST_FILE בפקודה gcloud transfer jobs create.

gcloud transfer jobs create SOURCE DESTINATION \
  --manifest-file=MANIFEST_FILE

הערך MANIFEST_FILE יכול להיות כל אחד מהערכים הבאים:

  • הנתיב לקובץ ה-CSV בקטגוריה של Cloud Storage:

    --manifest-file=gs://my_bucket/sample_manifest.csv
    

    אם הקטגוריה או הקובץ לא ציבוריים, אפשר לקרוא פרטים על ההרשאות הנדרשות במאמר העלאת המניפסט ל-Cloud Storage.

  • הנתיב היחסי ממערכת הקבצים SOURCE, כולל כל נתיב שצוין:

    --manifest-file=source://relative_path/sample_manifest.csv
    
  • הנתיב היחסי ממערכת הקבצים DESTINATION, כולל כל נתיב שצוין:

    --manifest-file=destination://relative_path/sample_manifest.csv
    

‫REST וספריות לקוח

REST

כדי להעביר את הקבצים או האובייקטים שרשומים במניפסט, מבצעים קריאה ל-API של createTransferJob שמציינת transferSpec עם השדה transferManifest שנוסף. לדוגמה:

POST https://storagetransfer.googleapis.com/v1/transferJobs

...
  "transferSpec": {
      "posixDataSource": {
          "rootDirectory": "/home/",
      },
      "gcsDataSink": {
          "bucketName": "GCS_NEARLINE_SINK_NAME",
          "path": "GCS_SINK_PATH",
      },
      "transferManifest": {
          "location": "gs://my_bucket/sample_manifest.csv"
      }
  }

אפשר לאחסן את קובץ המניפסט בקטגוריה של Cloud Storage, או במערכת הקבצים של המקור או היעד. קטגוריות של Cloud Storage צריכות להשתמש בקידומת gs:// ולכלול את הנתיב המלא, כולל שם הקטגוריה. מיקומים במערכת הקבצים חייבים להשתמש בקידומת source:// או destination://, והם יחסיים למקור או ליעד של מערכת הקבצים, ולתיקיית השורש האופציונלית.

המשך


import (
	"context"
	"fmt"
	"io"

	storagetransfer "cloud.google.com/go/storagetransfer/apiv1"
	"cloud.google.com/go/storagetransfer/apiv1/storagetransferpb"
)

func transferUsingManifest(w io.Writer, projectID string, sourceAgentPoolName string, rootDirectory string, gcsSinkBucket string, manifestBucket string, manifestObjectName string) (*storagetransferpb.TransferJob, error) {
	// Your project id
	// projectId := "myproject-id"

	// The agent pool associated with the POSIX data source. If not provided, defaults to the default agent
	// sourceAgentPoolName := "projects/my-project/agentPools/transfer_service_default"

	// The root directory path on the source filesystem
	// rootDirectory := "/directory/to/transfer/source"

	// The ID of the GCS bucket to transfer data to
	// gcsSinkBucket := "my-sink-bucket"

	// The ID of the GCS bucket that contains the manifest file
	// manifestBucket := "my-manifest-bucket"

	// The name of the manifest file in manifestBucket that specifies which objects to transfer
	// manifestObjectName := "path/to/manifest.csv"

	ctx := context.Background()
	client, err := storagetransfer.NewClient(ctx)
	if err != nil {
		return nil, fmt.Errorf("storagetransfer.NewClient: %w", err)
	}
	defer client.Close()

	manifestLocation := "gs://" + manifestBucket + "/" + manifestObjectName
	req := &storagetransferpb.CreateTransferJobRequest{
		TransferJob: &storagetransferpb.TransferJob{
			ProjectId: projectID,
			TransferSpec: &storagetransferpb.TransferSpec{
				SourceAgentPoolName: sourceAgentPoolName,
				DataSource: &storagetransferpb.TransferSpec_PosixDataSource{
					PosixDataSource: &storagetransferpb.PosixFilesystem{RootDirectory: rootDirectory},
				},
				DataSink: &storagetransferpb.TransferSpec_GcsDataSink{
					GcsDataSink: &storagetransferpb.GcsData{BucketName: gcsSinkBucket},
				},
				TransferManifest: &storagetransferpb.TransferManifest{Location: manifestLocation},
			},
			Status: storagetransferpb.TransferJob_ENABLED,
		},
	}

	resp, err := client.CreateTransferJob(ctx, req)
	if err != nil {
		return nil, fmt.Errorf("failed to create transfer job: %w", err)
	}
	if _, err = client.RunTransferJob(ctx, &storagetransferpb.RunTransferJobRequest{
		ProjectId: projectID,
		JobName:   resp.Name,
	}); err != nil {
		return nil, fmt.Errorf("failed to run transfer job: %w", err)
	}
	fmt.Fprintf(w, "Created and ran transfer job from %v to %v using manifest file %v with name %v", rootDirectory, gcsSinkBucket, manifestLocation, resp.Name)
	return resp, nil
}

Java


import com.google.storagetransfer.v1.proto.StorageTransferServiceClient;
import com.google.storagetransfer.v1.proto.TransferProto;
import com.google.storagetransfer.v1.proto.TransferTypes.GcsData;
import com.google.storagetransfer.v1.proto.TransferTypes.PosixFilesystem;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferJob;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferManifest;
import com.google.storagetransfer.v1.proto.TransferTypes.TransferSpec;
import java.io.IOException;

public class TransferUsingManifest {

  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.

    // Your project id
    String projectId = "my-project-id";

    // The agent pool associated with the POSIX data source. If not provided, defaults to the
    // default agent
    String sourceAgentPoolName = "projects/my-project-id/agentPools/transfer_service_default";

    // The root directory path on the source filesystem
    String rootDirectory = "/directory/to/transfer/source";

    // The ID of the GCS bucket to transfer data to
    String gcsSinkBucket = "my-sink-bucket";

    // The ID of the GCS bucket which has your manifest file
    String manifestBucket = "my-bucket";

    // The ID of the object in manifestBucket that specifies which files to transfer
    String manifestObjectName = "path/to/manifest.csv";

    transferUsingManifest(
        projectId,
        sourceAgentPoolName,
        rootDirectory,
        gcsSinkBucket,
        manifestBucket,
        manifestObjectName);
  }

  public static void transferUsingManifest(
      String projectId,
      String sourceAgentPoolName,
      String rootDirectory,
      String gcsSinkBucket,
      String manifestBucket,
      String manifestObjectName)
      throws IOException {
    String manifestLocation = "gs://" + manifestBucket + "/" + manifestObjectName;
    TransferJob transferJob =
        TransferJob.newBuilder()
            .setProjectId(projectId)
            .setTransferSpec(
                TransferSpec.newBuilder()
                    .setSourceAgentPoolName(sourceAgentPoolName)
                    .setPosixDataSource(
                        PosixFilesystem.newBuilder().setRootDirectory(rootDirectory).build())
                    .setGcsDataSink((GcsData.newBuilder().setBucketName(gcsSinkBucket)).build())
                    .setTransferManifest(
                        TransferManifest.newBuilder().setLocation(manifestLocation).build()))
            .setStatus(TransferJob.Status.ENABLED)
            .build();

    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the "close" method on the client to safely clean up any remaining background resources,
    // or use "try-with-close" statement to do this automatically.
    try (StorageTransferServiceClient storageTransfer = StorageTransferServiceClient.create()) {

      // Create the transfer job
      TransferJob response =
          storageTransfer.createTransferJob(
              TransferProto.CreateTransferJobRequest.newBuilder()
                  .setTransferJob(transferJob)
                  .build());

      System.out.println(
          "Created and ran a transfer job from "
              + rootDirectory
              + " to "
              + gcsSinkBucket
              + " using "
              + "manifest file "
              + manifestLocation
              + " with name "
              + response.getName());
    }
  }
}

Node.js


// Imports the Google Cloud client library
const {
  StorageTransferServiceClient,
} = require('@google-cloud/storage-transfer');

/**
 * TODO(developer): Uncomment the following lines before running the sample.
 */
// Your project id
// const projectId = 'my-project'

// The agent pool associated with the POSIX data source. Defaults to the default agent
// const sourceAgentPoolName = 'projects/my-project/agentPools/transfer_service_default'

// The root directory path on the source filesystem
// const rootDirectory = '/directory/to/transfer/source'

// The ID of the GCS bucket to transfer data to
// const gcsSinkBucket = 'my-sink-bucket'

// Transfer manifest location. Must be a `gs:` URL
// const manifestLocation = 'gs://my-bucket/sample_manifest.csv'

// Creates a client
const client = new StorageTransferServiceClient();

/**
 * Creates a request to transfer from the local file system to the sink bucket
 */
async function transferViaManifest() {
  const createRequest = {
    transferJob: {
      projectId,
      transferSpec: {
        sourceAgentPoolName,
        posixDataSource: {
          rootDirectory,
        },
        gcsDataSink: {bucketName: gcsSinkBucket},
        transferManifest: {
          location: manifestLocation,
        },
      },
      status: 'ENABLED',
    },
  };

  // Runs the request and creates the job
  const [transferJob] = await client.createTransferJob(createRequest);

  const runRequest = {
    jobName: transferJob.name,
    projectId: projectId,
  };

  await client.runTransferJob(runRequest);

  console.log(
    `Created and ran a transfer job from '${rootDirectory}' to '${gcsSinkBucket}' using manifest \`${manifestLocation}\` with name ${transferJob.name}`
  );
}

transferViaManifest();

Python

from google.cloud import storage_transfer


def create_transfer_with_manifest(
    project_id: str,
    description: str,
    source_agent_pool_name: str,
    root_directory: str,
    sink_bucket: str,
    manifest_location: str,
):
    """Create a transfer from a POSIX file system to a GCS bucket using
    a manifest file."""

    client = storage_transfer.StorageTransferServiceClient()

    # The ID of the Google Cloud Platform Project that owns the job
    # project_id = 'my-project-id'

    # A useful description for your transfer job
    # description = 'My transfer job'

    # The agent pool associated with the POSIX data source.
    # Defaults to 'projects/{project_id}/agentPools/transfer_service_default'
    # source_agent_pool_name = 'projects/my-project/agentPools/my-agent'

    # The root directory path on the source filesystem
    # root_directory = '/directory/to/transfer/source'

    # Google Cloud Storage destination bucket name
    # sink_bucket = 'my-gcs-destination-bucket'

    # Transfer manifest location. Must be a `gs:` URL
    # manifest_location = 'gs://my-bucket/sample_manifest.csv'

    transfer_job_request = storage_transfer.CreateTransferJobRequest(
        {
            "transfer_job": {
                "project_id": project_id,
                "description": description,
                "status": storage_transfer.TransferJob.Status.ENABLED,
                "transfer_spec": {
                    "source_agent_pool_name": source_agent_pool_name,
                    "posix_data_source": {
                        "root_directory": root_directory,
                    },
                    "gcs_data_sink": {
                        "bucket_name": sink_bucket,
                    },
                    "transfer_manifest": {"location": manifest_location},
                },
            }
        }
    )

    result = client.create_transfer_job(transfer_job_request)
    print(f"Created transferJob: {result.name}")

האובייקטים או הקבצים במניפסט לא בהכרח מועברים לפי הסדר שבו הם מופיעים.

אם המניפסט כולל קבצים שכבר קיימים ביעד, המערכת מדלגת על הקבצים האלה, אלא אם צוינה האפשרות overwrite objects already existing in sink.

אם המניפסט כולל אובייקטים שקיימים בגרסה אחרת ביעד, האובייקט ביעד יוחלף בגרסת המקור של האובייקט. אם היעד הוא קטגוריה עם גרסאות, נוצרת גרסה חדשה של האובייקט.

המאמרים הבאים