-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Added feast Go operator db stores support #4771
base: master
Are you sure you want to change the base?
Conversation
|
||
if services.OfflineStore.Persistence != nil && | ||
services.OfflineStore.Persistence.FilePersistence != nil && | ||
len(services.OfflineStore.Persistence.FilePersistence.Type) > 0 { | ||
persistenceType = services.OfflineStore.Persistence.FilePersistence.Type | ||
} else if services.OfflineStore.Persistence != nil && | ||
services.OfflineStore.Persistence.DBPersistence != nil { | ||
if len(services.OfflineStore.Persistence.DBPersistence.Type) > 0 { | ||
var err error | ||
persistenceType = services.OfflineStore.Persistence.DBPersistence.Type | ||
secretKeyName := services.OfflineStore.Persistence.DBPersistence.SecretKeyName | ||
if len(secretKeyName) == 0 { | ||
secretKeyName = persistenceType | ||
} | ||
parametersMap, err = secretExtractionFunc(services.OfflineStore.Persistence.DBPersistence.SecretRef.Name, secretKeyName) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for these setRepoConfig functions, maybe we can clean it up a bit by consolidating?
if services.OfflineStore.Persistence != nil && | |
services.OfflineStore.Persistence.FilePersistence != nil && | |
len(services.OfflineStore.Persistence.FilePersistence.Type) > 0 { | |
persistenceType = services.OfflineStore.Persistence.FilePersistence.Type | |
} else if services.OfflineStore.Persistence != nil && | |
services.OfflineStore.Persistence.DBPersistence != nil { | |
if len(services.OfflineStore.Persistence.DBPersistence.Type) > 0 { | |
var err error | |
persistenceType = services.OfflineStore.Persistence.DBPersistence.Type | |
secretKeyName := services.OfflineStore.Persistence.DBPersistence.SecretKeyName | |
if len(secretKeyName) == 0 { | |
secretKeyName = persistenceType | |
} | |
parametersMap, err = secretExtractionFunc(services.OfflineStore.Persistence.DBPersistence.SecretRef.Name, secretKeyName) | |
if err != nil { | |
return err | |
} | |
} | |
} | |
offlinePersistence := services.OfflineStore.Persistence | |
if offlinePersistence != nil && | |
offlinePersistence.FilePersistence != nil && | |
len(offlinePersistence.FilePersistence.Type) > 0 { | |
persistenceType = offlinePersistence.FilePersistence.Type | |
} else if offlinePersistence != nil && | |
offlinePersistence.DBPersistence != nil { | |
if len(offlinePersistence.DBPersistence.Type) > 0 { | |
var err error | |
persistenceType = offlinePersistence.DBPersistence.Type | |
secretKeyName := offlinePersistence.DBPersistence.SecretKeyName | |
if len(secretKeyName) == 0 { | |
secretKeyName = persistenceType | |
} | |
parametersMap, err = secretExtractionFunc(offlinePersistence.DBPersistence.SecretRef.Name, secretKeyName) | |
if err != nil { | |
return err | |
} | |
} | |
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
var err error | ||
filePath = "" | ||
persistenceType = services.Registry.Local.Persistence.DBPersistence.Type | ||
secretKeyName := services.Registry.Local.Persistence.DBPersistence.SecretKeyName | ||
if len(secretKeyName) == 0 { | ||
secretKeyName = persistenceType | ||
} | ||
parametersMap, err = secretExtractionFunc(services.Registry.Local.Persistence.DBPersistence.SecretRef.Name, secretKeyName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need to declare an error var... instead use a short assignment statement as we do elsewhere in the code.
var err error | |
filePath = "" | |
persistenceType = services.Registry.Local.Persistence.DBPersistence.Type | |
secretKeyName := services.Registry.Local.Persistence.DBPersistence.SecretKeyName | |
if len(secretKeyName) == 0 { | |
secretKeyName = persistenceType | |
} | |
parametersMap, err = secretExtractionFunc(services.Registry.Local.Persistence.DBPersistence.SecretRef.Name, secretKeyName) | |
filePath = "" | |
persistenceType = services.Registry.Local.Persistence.DBPersistence.Type | |
secretKeyName := services.Registry.Local.Persistence.DBPersistence.SecretKeyName | |
if len(secretKeyName) == 0 { | |
secretKeyName = persistenceType | |
} | |
parametersMap, err := secretExtractionFunc(services.Registry.Local.Persistence.DBPersistence.SecretRef.Name, secretKeyName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't since parametersMap is defined outside the if and is used outside the if and if I use :=
it shadows that value
repoConfig.Registry = RegistryConfig{
RegistryType: RegistryConfigType(persistenceType),
Path: filePath,
S3AdditionalKwargs: s3AdditionalKwargs,
DBParameters: parametersMap,
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if I use := it shadows that value
what does this mean?
fwiw, go will detect that parametersMap
has already been declared and reassign it accordingly.
e.g. this will print 3 4 5 6
package main
import "fmt"
func main() {
var i, j int = 1, 2
k := 3
i, j, k, l := 3, 4, 5, 6
fmt.Println(i, j, k, l)
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I change that to :=
I am getting an error unused variable parametersMap
see https://go.dev/play/p/WDtgq1kGlFc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok... because its not being used until after the if statement... i see now.
} else if services.OnlineStore.Persistence != nil && | ||
services.OnlineStore.Persistence.DBPersistence != nil { | ||
if len(services.OnlineStore.Persistence.DBPersistence.Type) > 0 { | ||
var err error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my pervious comment
} else if services.OfflineStore.Persistence != nil && | ||
services.OfflineStore.Persistence.DBPersistence != nil { | ||
if len(services.OfflineStore.Persistence.DBPersistence.Type) > 0 { | ||
var err error |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See my pervious comment
objectKey := client.ObjectKeyFromObject(secret) | ||
if err := feast.Client.Get(feast.Context, objectKey, secret); err != nil { | ||
if apierrors.IsNotFound(err) || err != nil { | ||
return nil, fmt.Errorf("invalid secret %s for offline store", secretRef) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe just return the error here but log an Error prior to the return
return nil, fmt.Errorf("invalid secret %s for offline store", secretRef) | |
logger := log.FromContext(feast.Context) | |
logger.Error("invalid secret %s for offline store", secretRef) | |
return nil, err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@tmihalac the issue you are referring to is already closed. @tchughesiv should we create a new one or reopen it? |
In the description, the registry:
local:
persistence:
store:
type: postgres |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you also add a sample Secret (with postgres properties) to the same file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, an example of the sql
registry type could be helpful, since it has some specific management of the db type in the path
property:
registry:
registry_type: sql
path: postgresql://postgres:[email protected]:55001/feast
cache_ttl_seconds: 60
sqlalchemy_config_kwargs:
echo: false
pool_pre_ping: true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did you commit the change? II can't see it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet still working on it, trying to find a fix for db parameters the same as the config object parameters
|
||
Expect(err.Error()).To(Equal("invalid secret invalid_secret for offline store")) | ||
|
||
By("Referring to a secret that doesn't exist") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe change of of the two By("Referring to a secret that doesn't exist")
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add simple tests for invalid store type for each of the feast service?
@tmihalac @dmartinol we should be opening new issues for operator PRs |
repoConfig.Registry = RegistryConfig{ | ||
RegistryType: RegistryConfigType(persistenceType), | ||
Path: filePath, | ||
S3AdditionalKwargs: s3AdditionalKwargs, | ||
DBParameters: parametersMap, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have you tested what happens if a user specificies a conflicting registry_type
in their secret? we need to be sure the operator has final say on setting that field in the feature_store.yaml
. Same goes for type
in online/offlineStores. If you find it can be overwritten by the parametersMap
, maybe we set RegistryType
last? As a secondary line of code after this RegistryConfig declaration?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe the same needs to be done for filePath
and s3AdditionalKwargs
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and some unit tests around this phenomenon? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i'm realizing this is more important at the time of yaml marshaling... and i'm expecting that the defined fields should take precedence when that happens. it's possible all we really need here are good unit tests around the marshaled yaml to ensure this is the case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe test how setting a different registry_type
in DBParameters
map will effect the resulting yaml
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tmihalac please rebase on master
branch
59a08d7
to
8a4fd21
Compare
Signed-off-by: Theodor Mihalache <[email protected]>
8a4fd21
to
ee0a943
Compare
@tmihalac please open a new gh issue for this PR |
S3AdditionalKwargs *map[string]string `json:"s3_additional_kwargs,omitempty"` | ||
Path string `yaml:"path,omitempty"` | ||
RegistryType RegistryConfigType `yaml:"registry_type,omitempty"` | ||
S3AdditionalKwargs *map[string]string `json:"s3_additional_kwargs,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you fix this? its not related to your change but needs to be fixed.
S3AdditionalKwargs *map[string]string `json:"s3_additional_kwargs,omitempty"` | |
S3AdditionalKwargs *map[string]string `yaml:"s3_additional_kwargs,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
//val := reflect.ValueOf(s).Field(i) | ||
|
||
//// Check that the object is a pointer so we can modify it | ||
//if val.Kind() != reflect.Ptr || val.IsNil() { | ||
// return false, fmt.Errorf("expected a pointer to struct, got %v", val.Kind()) | ||
//} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this be cleaned up?
//val := reflect.ValueOf(s).Field(i) | |
//// Check that the object is a pointer so we can modify it | |
//if val.Kind() != reflect.Ptr || val.IsNil() { | |
// return false, fmt.Errorf("expected a pointer to struct, got %v", val.Kind()) | |
//} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// Check if the value is a pointer and dereference it if necessary | ||
//if t.Kind() == reflect.Ptr { | ||
// t = t.Elem() | ||
//} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@tmihalac should your descrip example be fixed? i'd imagine it will look like this? with the kind: FeatureStore
metadata:
name: sample-s3-registry
spec:
feastProject: my_project
services:
onlineStore:
persistence:
store:
type: postgres
secretRef:
name: _SECRET_NAME_ # Secret keys should be placed as-is under the `type` (e.g postgres) key or under the secretKeyName if specified
secretKeyName: my-postgres # The secret key the db parameters are in (optional parameter) |
You are right fixing it now |
Done |
Type string `json:"type,omitempty"` | ||
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should these be required fields?
Type string `json:"type,omitempty"` | |
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` | |
Type string `json:"type"` | |
SecretRef *corev1.LocalObjectReference `json:"secretRef"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dmartinol @lokeshrangineni @redhatHameed
I am not sure, what do you think ? anyone ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dmartinol gave a thumbs up. @tmihalac from a code & usability standpoint... aren't these 2 fields required if the user decides to configure a db store? (i believe they are) if so, we need to make them required in the CRD.
Type string `json:"type,omitempty"` | ||
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` | ||
SecretKeyName string `json:"secretKeyName,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
Type string `json:"type,omitempty"` | ||
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` | ||
SecretKeyName string `json:"secretKeyName,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same?
// +kubebuilder:validation:Enum=snowflake.offline;bigquery;redshift;spark;postgres;feast_trino.trino.TrinoOfflineStore;redis | ||
Type string `json:"type,omitempty"` | ||
SecretRef *corev1.LocalObjectReference `json:"secretRef,omitempty"` | ||
SecretKeyName string `json:"secretKeyName,omitempty"` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe add a comment to SecretKeyName
explaining what the default will be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tchughesiv
What do you mean by default ? there is no default , do you mean when that field is not specified in the CR ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you mean when that field is not specified in the CR ?
yes ... isn't the default here the db store type? i'm saying just add a comment above the field (which will add documentation to the CRD) so the user understands this
Signed-off-by: Theodor Mihalache <[email protected]>
Signed-off-by: Theodor Mihalache <[email protected]>
Signed-off-by: Theodor Mihalache <[email protected]>
What this PR does / why we need it:
This PR adds db stores persistence configuration options to the FeatureStore CRD.
DB store para
Which issue(s) this PR fixes:
Relates to #4783