|
16 | 16 | "print(f\"✅ Found Expected Feast version: {actual_version} in workbench\")" |
17 | 17 | ] |
18 | 18 | }, |
| 19 | + { |
| 20 | + "cell_type": "code", |
| 21 | + "execution_count": null, |
| 22 | + "metadata": {}, |
| 23 | + "outputs": [], |
| 24 | + "source": [ |
| 25 | + "# --- Configuration Variables ---\n", |
| 26 | + "import os \n", |
| 27 | + "\n", |
| 28 | + "# Fetch token and server directly from oc CLI\n", |
| 29 | + "import subprocess\n", |
| 30 | + "\n", |
| 31 | + "def oc(cmd):\n", |
| 32 | + " return subprocess.check_output(cmd, shell=True).decode(\"utf-8\").strip()\n", |
| 33 | + "\n", |
| 34 | + "token = oc(\"oc whoami -t\")\n", |
| 35 | + "server = oc(\"oc whoami --show-server\")\n", |
| 36 | + "namespace = os.environ.get(\"NAMESPACE\")\n" |
| 37 | + ] |
| 38 | + }, |
| 39 | + { |
| 40 | + "cell_type": "code", |
| 41 | + "execution_count": null, |
| 42 | + "metadata": {}, |
| 43 | + "outputs": [], |
| 44 | + "source": [ |
| 45 | + "!oc login --token=$token --server=$server" |
| 46 | + ] |
| 47 | + }, |
| 48 | + { |
| 49 | + "cell_type": "code", |
| 50 | + "execution_count": null, |
| 51 | + "metadata": {}, |
| 52 | + "outputs": [], |
| 53 | + "source": [ |
| 54 | + "# Add user permission to namespace\n", |
| 55 | + "!oc adm policy add-role-to-user admin $(oc whoami) -n $namespace" |
| 56 | + ] |
| 57 | + }, |
19 | 58 | { |
20 | 59 | "cell_type": "code", |
21 | 60 | "execution_count": null, |
|
34 | 73 | ").read()\n", |
35 | 74 | "\n", |
36 | 75 | "# Save the configmap data into an environment variable (if needed)\n", |
37 | | - "os.environ[\"CONFIGMAP_DATA\"] = yaml_content\n" |
| 76 | + "os.environ[\"CONFIGMAP_DATA\"] = yaml_content" |
38 | 77 | ] |
39 | 78 | }, |
40 | 79 | { |
|
43 | 82 | "metadata": {}, |
44 | 83 | "outputs": [], |
45 | 84 | "source": [ |
46 | | - "#!/usr/bin/env python3\n", |
47 | | - "import os\n", |
48 | | - "import json\n", |
49 | | - "import yaml\n", |
50 | | - "from pathlib import Path\n", |
51 | | - "from typing import Dict, List, Any, Optional\n", |
52 | 85 | "from feast import FeatureStore\n", |
53 | | - "from feast.repo_config import RepoConfig\n", |
54 | | - "\n", |
55 | | - "def create_feature_store_yaml(config_content: str, config_name: str) -> str:\n", |
56 | | - " \"\"\"\n", |
57 | | - " Create a feature_store.yaml file from config content.\n", |
58 | | - " \n", |
59 | | - " Args:\n", |
60 | | - " config_content: YAML content as string\n", |
61 | | - " config_name: Name identifier for the config (used for filename)\n", |
62 | | - " \n", |
63 | | - " Returns:\n", |
64 | | - " Path to the created YAML file\n", |
65 | | - " \"\"\"\n", |
66 | | - " # Parse the YAML content to validate it\n", |
67 | | - " try:\n", |
68 | | - " config_dict = yaml.safe_load(config_content)\n", |
69 | | - " except yaml.YAMLError as e:\n", |
70 | | - " raise ValueError(f\"Failed to parse YAML content for {config_name}: {e}\")\n", |
71 | | - " \n", |
72 | | - " # Ensure required fields are present\n", |
73 | | - " required_fields = ['project', 'registry', 'provider']\n", |
74 | | - " for field in required_fields:\n", |
75 | | - " if field not in config_dict:\n", |
76 | | - " raise ValueError(f\"Failed to create config {config_name}: missing required field '{field}'\")\n", |
77 | | - " \n", |
78 | | - " # Create filename\n", |
79 | | - " filename = f\"feature_store_{config_name}.yaml\"\n", |
80 | | - " filepath = Path(filename)\n", |
81 | | - " \n", |
82 | | - " # Write the YAML file\n", |
83 | | - " with open(filepath, 'w') as f:\n", |
84 | | - " yaml.dump(config_dict, f, default_flow_style=False, sort_keys=False)\n", |
85 | | - " \n", |
86 | | - " return str(filepath)\n", |
87 | | - "\n", |
88 | | - "\n", |
89 | | - "def create_feature_store_object(yaml_file_path: str) -> FeatureStore:\n", |
90 | | - " \"\"\"\n", |
91 | | - " Create a FeatureStore object from a YAML file.\n", |
92 | | - " \n", |
93 | | - " Args:\n", |
94 | | - " yaml_file_path: Path to the feature_store.yaml file\n", |
95 | | - " \n", |
96 | | - " Returns:\n", |
97 | | - " FeatureStore object\n", |
98 | | - " \"\"\"\n", |
99 | | - " try:\n", |
100 | | - " # Create FeatureStore from the YAML file\n", |
101 | | - " fs = FeatureStore(fs_yaml_file=Path(yaml_file_path))\n", |
102 | | - " return fs\n", |
103 | | - " except Exception as e:\n", |
104 | | - " raise RuntimeError(f\"Failed to create FeatureStore object from {yaml_file_path}: {e}\")\n", |
105 | | - "\n", |
106 | | - "\n", |
107 | | - "def process_client_configs(client_configs: Dict[str, str]) -> Dict[str, Dict[str, Any]]:\n", |
108 | | - " \"\"\"\n", |
109 | | - " Process multiple client config YAML contents and create feature stores.\n", |
110 | | - " \n", |
111 | | - " Args:\n", |
112 | | - " client_configs: Dictionary mapping config names to YAML content strings\n", |
113 | | - " \n", |
114 | | - " Returns:\n", |
115 | | - " Dictionary with results for each config\n", |
116 | | - " \"\"\"\n", |
117 | | - " results = {}\n", |
118 | | - " created_yamls = []\n", |
119 | | - " feature_stores = {}\n", |
120 | | - " \n", |
121 | | - " print(\"Creating feature store YAMLs and objects...\")\n", |
122 | | - " print(\"=\" * 50)\n", |
123 | | - " \n", |
124 | | - " for config_name, config_content in client_configs.items():\n", |
125 | | - " try:\n", |
126 | | - " print(f\"\\nProcessing config: {config_name}\")\n", |
127 | | - "\n", |
128 | | - " # Create YAML file\n", |
129 | | - " yaml_path = create_feature_store_yaml(config_content, config_name)\n", |
130 | | - " created_yamls.append(yaml_path)\n", |
131 | | - " print(f\"✓ Created YAML file: {yaml_path}\")\n", |
132 | | - " \n", |
133 | | - " # Create FeatureStore object\n", |
134 | | - " fs = create_feature_store_object(yaml_path)\n", |
135 | | - " fs_var_name = f\"fs_{fs.project}\"\n", |
136 | | - " globals()[fs_var_name] = fs\n", |
137 | | - " feature_stores[config_name] = fs_var_name\n", |
138 | | - " print(f\"✓ Created FeatureStore object: {fs_var_name}\")\n", |
139 | | - "\n", |
140 | | - " results[config_name] = {\n", |
141 | | - " 'yaml_path': yaml_path,\n", |
142 | | - " 'feature_store': fs_var_name,\n", |
143 | | - " 'project_name': fs.project,\n", |
144 | | - " 'success': True,\n", |
145 | | - " 'error': None\n", |
146 | | - " }\n", |
147 | | - " \n", |
148 | | - " except Exception as e:\n", |
149 | | - " print(f\"✗ Failed to process config {config_name}: {e}\")\n", |
150 | | - " results[config_name] = {\n", |
151 | | - " 'yaml_path': None,\n", |
152 | | - " 'feature_store': None,\n", |
153 | | - " 'project_name': None,\n", |
154 | | - " 'success': False,\n", |
155 | | - " 'error': str(e)\n", |
156 | | - " }\n", |
157 | | - " \n", |
158 | | - " return results\n", |
159 | | - "\n", |
160 | | - "\n", |
161 | | - "def print_summary(results: Dict[str, Dict[str, Any]]) -> None:\n", |
162 | | - " \"\"\"\n", |
163 | | - " Print summary of all operations.\n", |
164 | | - " \n", |
165 | | - " Args:\n", |
166 | | - " results: Results dictionary from process_client_configs\n", |
167 | | - " \"\"\"\n", |
168 | | - " print(\"\\n\" + \"=\" * 50)\n", |
169 | | - " print(\"SUMMARY\")\n", |
170 | | - " print(\"=\" * 50)\n", |
171 | | - "\n", |
172 | | - " successful_configs = [name for name, result in results.items() if result['success']]\n", |
173 | | - " failed_configs = [name for name, result in results.items() if not result['success']]\n", |
174 | | - " print(f\"\\n\\n✓✓Feature Store YAML files have been created in: {os.getcwd()}\")\n", |
175 | | - " print(f\"\\n✓ Successfully processed {len(successful_configs)} config(s):\")\n", |
176 | | - " for config_name in successful_configs:\n", |
177 | | - " result = results[config_name]\n", |
178 | | - " print(f\" - {config_name}: {result['yaml_path']} (Project: {result['project_name']})\")\n", |
179 | | - "\n", |
180 | | - " if failed_configs:\n", |
181 | | - " print(f\"\\n✗ Failed to process {len(failed_configs)} config(s):\")\n", |
182 | | - " for config_name in failed_configs:\n", |
183 | | - " result = results[config_name]\n", |
184 | | - " print(f\" - {config_name}: {result['error']}\")\n", |
185 | | - "\n", |
186 | | - " print(f\"\\n\\n✓✓ Feature Store Object(s) details:\")\n", |
187 | | - " for config_name in successful_configs:\n", |
188 | | - " result = results[config_name]\n", |
189 | | - " print(f\"> Object Name - {result['feature_store']} ; project name - {result['project_name']} ; yaml path - {result['yaml_path']}\")\n", |
190 | | - "\n", |
191 | | - " print(\"\\n\")\n", |
192 | | - " print(\"=\" * 25, \"Usage:\", \"=\" * 25)\n", |
193 | | - " print(\"You can now use feature store object(s) to access the feature store resources and functions!\")\n", |
194 | | - " print(\"\\n// Note: Replace object_name with the actual object name from the list above.\")\n", |
195 | | - " print(\"object_name.list_features()\\nobject_name.get_historical_features()\")\n", |
196 | | - " print(\"=\" * 58)\n", |
197 | | - "\n", |
198 | | - "\n", |
199 | | - "def main():\n", |
200 | | - " \"\"\"\n", |
201 | | - " Main function to demonstrate usage with example configs.\n", |
202 | | - " \"\"\"\n", |
203 | | - " yaml_content = os.getenv(\"CONFIGMAP_DATA\")\n", |
204 | | - "\n", |
205 | | - " if not yaml_content:\n", |
206 | | - " raise ValueError(\"CONFIGMAP_DATA environment variable is not set.\")\n", |
207 | | - "\n", |
208 | | - " # Use environment YAML as config\n", |
209 | | - " client_configs = {\n", |
210 | | - " \"feast_credit_scoring_client\": yaml_content\n", |
211 | | - " }\n", |
212 | | - "\n", |
213 | | - " print(\"=\" * 50)\n", |
214 | | - " print(\"This script will create feature store YAMLs and objects from client configs.\")\n", |
215 | | - " print(f\"Processing {len(client_configs)} selected configurations...\")\n", |
216 | | - " \n", |
217 | | - " # Process the configs\n", |
218 | | - " results = process_client_configs(client_configs)\n", |
219 | | - " \n", |
220 | | - " # Print summary\n", |
221 | | - " print_summary(results)\n", |
222 | | - "\n", |
223 | | - "\n", |
224 | | - "if __name__ == \"__main__\":\n", |
225 | | - " main()" |
| 86 | + "fs_credit_scoring_local = FeatureStore(fs_yaml_file='/opt/app-root/src/feast-config/credit_scoring_local')" |
226 | 87 | ] |
227 | 88 | }, |
228 | 89 | { |
|
0 commit comments