Unverified Commit e60f622b authored by Iceber Gu's avatar Iceber Gu Committed by GitHub
Browse files

Merge pull request #160 from cleverhu/support-raw-sql-query

support raw sql query
parents 85761c75 3f85f643
Showing with 74 additions and 5 deletions
+74 -5
package internalstorage
import (
"k8s.io/apimachinery/pkg/util/runtime"
utilfeature "k8s.io/apiserver/pkg/util/feature"
"k8s.io/component-base/featuregate"
)
const (
// AllowRawSQLQuery is a feature gate for the apiserver to allow querying by the raw sql.
//
// owner: @cleverhu
// alpha: v0.3.0
AllowRawSQLQuery featuregate.Feature = "AllowRawSQLQuery"
)
func init() {
runtime.Must(utilfeature.DefaultMutableFeatureGate.Add(defaultInternalStorageFeatureGates))
}
// defaultInternalStorageFeatureGates consists of all known custom internalstorage feature keys.
// To add a new feature, define a key for it above and add it here.
var defaultInternalStorageFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
AllowRawSQLQuery: {Default: false, PreRelease: featuregate.Alpha},
}
......@@ -14,10 +14,15 @@ import (
"k8s.io/apimachinery/pkg/selection"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/validation/field"
utilfeature "k8s.io/apiserver/pkg/util/feature"
internal "github.com/clusterpedia-io/api/clusterpedia"
)
const (
URLQueryWhereSQL = "whereSQL"
)
var (
supportedOrderByFields = sets.NewString("cluster", "namespace", "name", "created_at", "resource_version")
)
......@@ -55,6 +60,15 @@ func applyListOptionsToQuery(query *gorm.DB, opts *internal.ListOptions, applyFn
query = query.Where("created_at < ?", opts.Before.Time.UTC())
}
if utilfeature.DefaultMutableFeatureGate.Enabled(AllowRawSQLQuery) {
if len(opts.URLQuery[URLQueryWhereSQL]) > 0 {
// TODO: prevent SQL injection.
// If a string of numbers is passed in from SQL, the query will be taken as ID by default.
// If the SQL contains English letter, it will be passed in as column.
query = query.Where(opts.URLQuery[URLQueryWhereSQL][0])
}
}
if opts.LabelSelector != nil {
if requirements, selectable := opts.LabelSelector.Requirements(); selectable {
for _, requirement := range requirements {
......@@ -137,7 +151,7 @@ func applyListOptionsToQuery(query *gorm.DB, opts *internal.ListOptions, applyFn
for _, orderby := range opts.OrderBy {
field := orderby.Field
if supportedOrderByFields.Has(field) {
if field == "resource_version"{
if field == "resource_version" {
field = "CAST(resource_version as decimal)"
}
column := clause.OrderByColumn{
......
......@@ -68,7 +68,7 @@ type ListOptions struct {
ExtraLabelSelector labels.Selector
// +k8s:conversion-fn:drop
ExtraQuery url.Values
URLQuery url.Values
// RelatedResources []schema.GroupVersionKind
}
......
......@@ -183,6 +183,10 @@ func Convert_v1beta1_ListOptions_To_clusterpedia_ListOptions(in *ListOptions, ou
if out.Before.Before(out.Since) {
return fmt.Errorf("Invalid Query, Since is after Before")
}
if len(in.urlQuery) > 0 {
// Out URLQuery will not be modified, so deepcopy is not used here.
out.URLQuery = in.urlQuery
}
return nil
}
......@@ -229,6 +233,8 @@ func Convert_url_Values_To_v1beta1_ListOptions(in *url.Values, out *ListOptions,
if err := metav1.Convert_url_Values_To_v1_ListOptions(in, &out.ListOptions, s); err != nil {
return err
}
// Save the native query parameters for use by listoptions.
out.urlQuery = *in
return autoConvert_url_Values_To_v1beta1_ListOptions(in, out, s)
}
......
package v1beta1
import (
"net/url"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
)
......@@ -46,6 +48,8 @@ type ListOptions struct {
// +optional
WithRemainingCount *bool `json:"withRemainingCount,omitempty"`
urlQuery url.Values
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
......
......@@ -201,6 +201,7 @@ func autoConvert_v1beta1_ListOptions_To_clusterpedia_ListOptions(in *ListOptions
out.OwnerSeniority = in.OwnerSeniority
out.WithContinue = (*bool)(unsafe.Pointer(in.WithContinue))
out.WithRemainingCount = (*bool)(unsafe.Pointer(in.WithRemainingCount))
// WARNING: in.urlQuery requires manual conversion: does not exist in peer-type
return nil
}
......@@ -227,7 +228,7 @@ func autoConvert_clusterpedia_ListOptions_To_v1beta1_ListOptions(in *clusterpedi
out.WithRemainingCount = (*bool)(unsafe.Pointer(in.WithRemainingCount))
// WARNING: in.EnhancedFieldSelector requires manual conversion: does not exist in peer-type
// WARNING: in.ExtraLabelSelector requires manual conversion: does not exist in peer-type
// WARNING: in.ExtraQuery requires manual conversion: does not exist in peer-type
// WARNING: in.URLQuery requires manual conversion: does not exist in peer-type
return nil
}
......@@ -318,5 +319,7 @@ func autoConvert_url_Values_To_v1beta1_ListOptions(in *url.Values, out *ListOpti
} else {
out.WithRemainingCount = nil
}
// WARNING: Field urlQuery does not have json tag, skipping.
return nil
}
......@@ -6,6 +6,8 @@
package v1beta1
import (
url "net/url"
runtime "k8s.io/apimachinery/pkg/runtime"
)
......@@ -110,6 +112,21 @@ func (in *ListOptions) DeepCopyInto(out *ListOptions) {
*out = new(bool)
**out = **in
}
if in.urlQuery != nil {
in, out := &in.urlQuery, &out.urlQuery
*out = make(url.Values, len(*in))
for key, val := range *in {
var outVal []string
if val == nil {
(*out)[key] = nil
} else {
in, out := &val, &outVal
*out = make([]string, len(*in))
copy(*out, *in)
}
(*out)[key] = outVal
}
}
return
}
......
......@@ -149,8 +149,8 @@ func (in *ListOptions) DeepCopyInto(out *ListOptions) {
if in.ExtraLabelSelector != nil {
out.ExtraLabelSelector = in.ExtraLabelSelector.DeepCopySelector()
}
if in.ExtraQuery != nil {
in, out := &in.ExtraQuery, &out.ExtraQuery
if in.URLQuery != nil {
in, out := &in.URLQuery, &out.URLQuery
*out = make(url.Values, len(*in))
for key, val := range *in {
var outVal []string
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment