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

‫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, כי פורמט המניפסט שונה מרשימות אחרות.

יצירת קובץ מניפסט

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

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

כדי להימנע מקריאות מיותרות ל-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.

לדוגמה, כדי להשתמש ב-gcloud CLI כדי להעלות קובץ ל-Cloud Storage, משתמשים בפקודה 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

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

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

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

  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

כדי להעביר את הקבצים או האובייקטים שמפורטים במניפסט, צריך לבצע קריאה ל-createTransferJob API שבה מצוין 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:// והם יחסיים למקור או ליעד של מערכת הקבצים, ולספריית הבסיס האופציונלית.

Go


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.

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

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