-
Notifications
You must be signed in to change notification settings - Fork 1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Python-centric feast deploy CLI (#1362)
* Python-centric feast deploy CLI Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * sqlite provider Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * add a proper test for local Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * gcp test Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * add missing files and mark integration test Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * reconcile configs Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * add missing file Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * add missing dep Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * add missing dep Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * fix deps again Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * use datastore not firestore Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * fix tests Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com> * comments Signed-off-by: Oleg Avdeev <oleg.v.avdeev@gmail.com>
- Loading branch information
Showing
14 changed files
with
480 additions
and
58 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
# from .provider import Provider |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
from datetime import datetime | ||
from typing import List, Optional | ||
|
||
from feast import FeatureTable | ||
from feast.infra.provider import Provider | ||
from feast.repo_config import DatastoreOnlineStoreConfig | ||
|
||
|
||
def _delete_all_values(client, key) -> None: | ||
""" | ||
Delete all data under the key path in datastore. | ||
""" | ||
while True: | ||
query = client.query(kind="Value", ancestor=key) | ||
entities = list(query.fetch(limit=1000)) | ||
if not entities: | ||
return | ||
|
||
for entity in entities: | ||
print("Deleting: {}".format(entity)) | ||
client.delete(entity.key) | ||
|
||
|
||
class Gcp(Provider): | ||
_project_id: Optional[str] | ||
|
||
def __init__(self, config: Optional[DatastoreOnlineStoreConfig]): | ||
if config: | ||
self._project_id = config.project_id | ||
else: | ||
self._project_id = None | ||
|
||
def _initialize_client(self): | ||
from google.cloud import datastore | ||
|
||
if self._project_id is not None: | ||
return datastore.Client(self.project_id) | ||
else: | ||
return datastore.Client() | ||
|
||
def update_infra( | ||
self, | ||
project: str, | ||
tables_to_delete: List[FeatureTable], | ||
tables_to_keep: List[FeatureTable], | ||
): | ||
from google.cloud import datastore | ||
|
||
client = self._initialize_client() | ||
|
||
for table in tables_to_keep: | ||
key = client.key("FeastProject", project, "FeatureTable", table.name) | ||
entity = datastore.Entity(key=key) | ||
entity.update({"created_at": datetime.utcnow()}) | ||
client.put(entity) | ||
|
||
for table in tables_to_delete: | ||
_delete_all_values( | ||
client, client.key("FeastProject", project, "FeatureTable", table.name) | ||
) | ||
|
||
# Delete the table metadata datastore entity | ||
key = client.key("FeastProject", project, "FeatureTable", table.name) | ||
client.delete(key) | ||
|
||
def teardown_infra(self, project: str, tables: List[FeatureTable]) -> None: | ||
client = self._initialize_client() | ||
|
||
for table in tables: | ||
_delete_all_values( | ||
client, client.key("FeastProject", project, "FeatureTable", table.name) | ||
) | ||
|
||
# Delete the table metadata datastore entity | ||
key = client.key("FeastProject", project, "FeatureTable", table.name) | ||
client.delete(key) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import os | ||
import sqlite3 | ||
from typing import List | ||
|
||
from feast import FeatureTable | ||
from feast.infra.provider import Provider | ||
from feast.repo_config import LocalOnlineStoreConfig | ||
|
||
|
||
def _table_id(project: str, table: FeatureTable) -> str: | ||
return f"{project}_{table.name}" | ||
|
||
|
||
class LocalSqlite(Provider): | ||
_db_path: str | ||
|
||
def __init__(self, config: LocalOnlineStoreConfig): | ||
self._db_path = config.path | ||
|
||
def update_infra( | ||
self, | ||
project: str, | ||
tables_to_delete: List[FeatureTable], | ||
tables_to_keep: List[FeatureTable], | ||
): | ||
conn = sqlite3.connect(self._db_path) | ||
for table in tables_to_keep: | ||
conn.execute( | ||
f"CREATE TABLE IF NOT EXISTS {_table_id(project, table)} (key BLOB, value BLOB)" | ||
) | ||
|
||
for table in tables_to_delete: | ||
conn.execute(f"DROP TABLE IF EXISTS {_table_id(project, table)}") | ||
|
||
def teardown_infra(self, project: str, tables: List[FeatureTable]) -> None: | ||
os.unlink(self._db_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import abc | ||
from typing import List | ||
|
||
from feast import FeatureTable | ||
from feast.repo_config import RepoConfig | ||
|
||
|
||
class Provider(abc.ABC): | ||
@abc.abstractmethod | ||
def update_infra( | ||
self, | ||
project: str, | ||
tables_to_delete: List[FeatureTable], | ||
tables_to_keep: List[FeatureTable], | ||
): | ||
""" | ||
Reconcile cloud resources with the objects declared in the feature repo. | ||
Args: | ||
tables_to_delete: Tables that were deleted from the feature repo, so provider needs to | ||
clean up the corresponding cloud resources. | ||
tables_to_keep: Tables that are still in the feature repo. Depending on implementation, | ||
provider may or may not need to update the corresponding resources. | ||
""" | ||
... | ||
|
||
@abc.abstractmethod | ||
def teardown_infra(self, project: str, tables: List[FeatureTable]): | ||
""" | ||
Tear down all cloud resources for a repo. | ||
Args: | ||
tables: Tables that are declared in the feature repo. | ||
""" | ||
... | ||
|
||
|
||
def get_provider(config: RepoConfig) -> Provider: | ||
if config.provider == "gcp": | ||
from feast.infra.gcp import Gcp | ||
|
||
return Gcp(config.online_store.datastore) | ||
elif config.provider == "local": | ||
from feast.infra.local_sqlite import LocalSqlite | ||
|
||
assert config.online_store.local is not None | ||
return LocalSqlite(config.online_store.local) | ||
else: | ||
raise ValueError(config) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
from pathlib import Path | ||
from typing import NamedTuple, Optional | ||
|
||
import yaml | ||
from bindr import bind | ||
|
||
|
||
class LocalOnlineStoreConfig(NamedTuple): | ||
path: str | ||
|
||
|
||
class DatastoreOnlineStoreConfig(NamedTuple): | ||
project_id: str | ||
|
||
|
||
class OnlineStoreConfig(NamedTuple): | ||
datastore: Optional[DatastoreOnlineStoreConfig] = None | ||
local: Optional[LocalOnlineStoreConfig] = None | ||
|
||
|
||
class RepoConfig(NamedTuple): | ||
metadata_store: str | ||
project: str | ||
provider: str | ||
online_store: OnlineStoreConfig | ||
|
||
|
||
def load_repo_config(repo_path: Path) -> RepoConfig: | ||
with open(repo_path / "feature_store.yaml") as f: | ||
raw_config = yaml.safe_load(f) | ||
return bind(RepoConfig, raw_config) |
Oops, something went wrong.