Skip to content

Commit

Permalink
feat: Onboard Cloud Storage Geo Index Dataset (#219)
Browse files Browse the repository at this point in the history
  • Loading branch information
vasuc-google committed Nov 24, 2021
1 parent 977b687 commit 27a2c8e
Show file tree
Hide file tree
Showing 13 changed files with 827 additions and 0 deletions.
@@ -0,0 +1,37 @@
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# The base image for this build
FROM python:3.8

# Allow statements and log messages to appear in Cloud logs
ENV PYTHONUNBUFFERED True

# Copy the requirements file into the image
COPY requirements.txt ./

# Install the packages specified in the requirements file
RUN python3 -m pip install --no-cache-dir -r requirements.txt

# The WORKDIR instruction sets the working directory for any RUN, CMD,
# ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile.
# If the WORKDIR doesn’t exist, it will be created even if it’s not used in
# any subsequent Dockerfile instruction
WORKDIR /custom

# Copy the specific data processing script/s in the image under /custom/*
COPY ./csv_transform.py .

# Command to run the data processing script when the container is run
CMD ["python3", "csv_transform.py"]
@@ -0,0 +1,137 @@
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import json
import logging
import os
import pathlib
import subprocess
import typing

import pandas as pd
import requests
from google.cloud import storage


def main(
source_url: str,
source_file: pathlib.Path,
target_file: pathlib.Path,
chunksize: str,
target_gcs_bucket: str,
target_gcs_path: str,
headers: typing.List[str],
rename_mappings: dict,
pipeline_name: str,
) -> None:

logging.info("Creating 'files' folder")
pathlib.Path("./files").mkdir(parents=True, exist_ok=True)

logging.info(f"Downloading file {source_url}")
download_file(source_url, source_file)
chunksz = int(chunksize)

logging.info(f"Reading csv file {source_url}")
with pd.read_csv(
source_file,
engine="python",
encoding="utf-8",
quotechar='"',
compression="gzip",
chunksize=chunksz,
) as reader:
for chunk_number, chunk in enumerate(reader):
logging.info(f"Processing batch {chunk_number}")
target_file_batch = str(target_file).replace(
".csv", "-" + str(chunk_number) + ".csv"
)
df = pd.DataFrame()
df = pd.concat([df, chunk])

logging.info(" Renaming headers...")
rename_headers(df, rename_mappings)
logging.info("Transform: Reordering headers..")
df = df[headers]
if pipeline_name == "sentinel_2_index":
df["total_size"] = df["total_size"].astype("Int64")

process_chunk(df, target_file_batch)

logging.info(f"Appending batch {chunk_number} to {target_file}")
if chunk_number == 0:
subprocess.run(["cp", target_file_batch, target_file])
else:
subprocess.check_call([f"sed -i '1d' {target_file_batch}"], shell=True)
subprocess.check_call(
[f"cat {target_file_batch} >> {target_file}"], shell=True
)
subprocess.run(["rm", target_file_batch])

logging.info(
f"Uploading output file to.. gs://{target_gcs_bucket}/{target_gcs_path}"
)
upload_file_to_gcs(target_file, target_gcs_bucket, target_gcs_path)


def process_chunk(df: pd.DataFrame, target_file_batch: str) -> None:

logging.info(f"Saving to output file.. {target_file_batch}")
try:
save_to_new_file(df, file_path=str(target_file_batch))
except Exception as e:
logging.error(f"Error saving output file: {e}.")
logging.info("..Done!")


def rename_headers(df: pd.DataFrame, rename_mappings: dict) -> None:
df = df.rename(columns=rename_mappings, inplace=True)


def save_to_new_file(df: pd.DataFrame, file_path) -> None:
df.to_csv(file_path, index=False)


def download_file(source_url: str, source_file: pathlib.Path) -> None:
logging.info(f"Downloading {source_url} into {source_file}")
r = requests.get(source_url, stream=True)
if r.status_code == 200:
with open(source_file, "wb") as f:
for chunk in r:
f.write(chunk)
else:
logging.error(f"Couldn't download {source_url}: {r.text}")


def upload_file_to_gcs(file_path: pathlib.Path, gcs_bucket: str, gcs_path: str) -> None:
storage_client = storage.Client()
bucket = storage_client.bucket(gcs_bucket)
blob = bucket.blob(gcs_path)
blob.upload_from_filename(file_path)


if __name__ == "__main__":
logging.getLogger().setLevel(logging.INFO)

main(
source_url=os.environ["SOURCE_URL"],
source_file=pathlib.Path(os.environ["SOURCE_FILE"]).expanduser(),
target_file=pathlib.Path(os.environ["TARGET_FILE"]).expanduser(),
chunksize=os.environ["CHUNKSIZE"],
target_gcs_bucket=os.environ["TARGET_GCS_BUCKET"],
target_gcs_path=os.environ["TARGET_GCS_PATH"],
headers=json.loads(os.environ["CSV_HEADERS"]),
rename_mappings=json.loads(os.environ["RENAME_MAPPINGS"]),
pipeline_name=os.environ["PIPELINE_NAME"],
)
@@ -0,0 +1,3 @@
requests
pandas
google-cloud-storage
@@ -0,0 +1,26 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


resource "google_bigquery_dataset" "cloud_storage_geo_index" {
dataset_id = "cloud_storage_geo_index"
project = var.project_id
description = "cloud_storage_geo_index data"
}

output "bigquery_dataset-cloud_storage_geo_index-dataset_id" {
value = google_bigquery_dataset.cloud_storage_geo_index.dataset_id
}
@@ -0,0 +1,39 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


resource "google_bigquery_table" "landsat_index" {
project = var.project_id
dataset_id = "cloud_storage_geo_index"
table_id = "landsat_index"

description = "landsat_index dataset"




depends_on = [
google_bigquery_dataset.cloud_storage_geo_index
]
}

output "bigquery_table-landsat_index-table_id" {
value = google_bigquery_table.landsat_index.table_id
}

output "bigquery_table-landsat_index-id" {
value = google_bigquery_table.landsat_index.id
}
28 changes: 28 additions & 0 deletions datasets/cloud_storage_geo_index/_terraform/provider.tf
@@ -0,0 +1,28 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


provider "google" {
project = var.project_id
impersonate_service_account = var.impersonating_acct
region = var.region
}

data "google_client_openid_userinfo" "me" {}

output "impersonating-account" {
value = data.google_client_openid_userinfo.me.email
}
@@ -0,0 +1,39 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


resource "google_bigquery_table" "sentinel_2_index" {
project = var.project_id
dataset_id = "cloud_storage_geo_index"
table_id = "sentinel_2_index"

description = "sentinel_2_index dataset"




depends_on = [
google_bigquery_dataset.cloud_storage_geo_index
]
}

output "bigquery_table-sentinel_2_index-table_id" {
value = google_bigquery_table.sentinel_2_index.table_id
}

output "bigquery_table-sentinel_2_index-id" {
value = google_bigquery_table.sentinel_2_index.id
}
23 changes: 23 additions & 0 deletions datasets/cloud_storage_geo_index/_terraform/variables.tf
@@ -0,0 +1,23 @@
/**
* Copyright 2021 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/


variable "project_id" {}
variable "bucket_name_prefix" {}
variable "impersonating_acct" {}
variable "region" {}
variable "env" {}

25 changes: 25 additions & 0 deletions datasets/cloud_storage_geo_index/dataset.yaml
@@ -0,0 +1,25 @@
# Copyright 2021 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

dataset:
name: cloud_storage_geo_index
friendly_name: Cloud_Storage_Geo_Index
description: landsat_index datasets
dataset_sources: ~
terms_of_use: ~

resources:
- type: bigquery_dataset
dataset_id: cloud_storage_geo_index
description: Cloud_Storage_Geo_Index Data

0 comments on commit 27a2c8e

Please sign in to comment.