diff --git a/pkg/apimachinery/apis/common/v0alpha1/types.go b/pkg/apimachinery/apis/common/v0alpha1/types.go index 8ccc08c62a0..34b21adaa3e 100644 --- a/pkg/apimachinery/apis/common/v0alpha1/types.go +++ b/pkg/apimachinery/apis/common/v0alpha1/types.go @@ -1,23 +1,46 @@ package v0alpha1 import ( + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" ) // Similar to // https://dev-k8sref-io.web.app/docs/common-definitions/objectreference-/ // ObjectReference contains enough information to let you inspect or modify the referred object. type ObjectReference struct { - Resource string `json:"resource,omitempty"` - Namespace string `json:"namespace,omitempty"` - Name string `json:"name,omitempty"` - // APIGroup is the name of the API group that contains the referred object. // The empty string represents the core API group. APIGroup string `json:"apiGroup,omitempty"` // APIVersion is the version of the API group that contains the referred object. APIVersion string `json:"apiVersion,omitempty"` + + // See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds + Kind string `json:"kind,omitempty"` + + // Tenant isolation + Namespace string `json:"namespace,omitempty"` + + // Explicit resource identifier + Name string `json:"name,omitempty"` + + // May contain a valid JSON/Go field access statement + FieldPath string `json:"fieldPath,omitempty"` + + // Sepcific deployment of an object + UID types.UID `json:"uid,omitempty"` +} + +func (r ObjectReference) ToOwnerReference() metav1.OwnerReference { + return metav1.OwnerReference{ + APIVersion: fmt.Sprintf("%s/%s", r.APIGroup, r.APIVersion), + Kind: r.Kind, + Name: r.Name, + UID: r.UID, + } } // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apimachinery/apis/common/v0alpha1/unstructured.go b/pkg/apimachinery/apis/common/v0alpha1/unstructured.go index 17417fd85fa..db4c2e73302 100644 --- a/pkg/apimachinery/apis/common/v0alpha1/unstructured.go +++ b/pkg/apimachinery/apis/common/v0alpha1/unstructured.go @@ -13,9 +13,9 @@ import ( // Unstructured allows objects that do not have Golang structs registered to be manipulated // generically. type Unstructured struct { - // Object is a JSON compatible map with string, float, int, bool, []interface{}, - // or map[string]interface{} children. - Object map[string]interface{} + // Object is a JSON compatible map with string, float, int, bool, []any, + // or map[string]any children. + Object map[string]any } // Produce an API definition that represents map[string]any @@ -27,7 +27,7 @@ func (u Unstructured) OpenAPIDefinition() openapi.OpenAPIDefinition { AdditionalProperties: &spec.SchemaOrBool{Allows: true}, }, VendorExtensible: spec.VendorExtensible{ - Extensions: map[string]interface{}{ + Extensions: map[string]any{ "x-kubernetes-preserve-unknown-fields": true, }, }, @@ -35,14 +35,18 @@ func (u Unstructured) OpenAPIDefinition() openapi.OpenAPIDefinition { } } -func (u *Unstructured) UnstructuredContent() map[string]interface{} { +func (u *Unstructured) IsZero() bool { + return len(u.Object) == 0 +} + +func (u *Unstructured) UnstructuredContent() map[string]any { if u.Object == nil { - return make(map[string]interface{}) + return make(map[string]any) } return u.Object } -func (u *Unstructured) SetUnstructuredContent(content map[string]interface{}) { +func (u *Unstructured) SetUnstructuredContent(content map[string]any) { u.Object = content } @@ -64,7 +68,7 @@ func (u *Unstructured) DeepCopy() *Unstructured { } out := new(Unstructured) *out = *u - out.Object = deepCopyJSONValue(u.Object).(map[string]interface{}) + out.Object = deepCopyJSONValue(u.Object).(map[string]any) return out } @@ -78,24 +82,24 @@ func (u *Unstructured) DeepCopyInto(out *Unstructured) { // runtime.DeepCopyJSON(u.Object) // // BUT this avoids panic on int -func deepCopyJSONValue(x interface{}) interface{} { +func deepCopyJSONValue(x any) any { switch x := x.(type) { - case map[string]interface{}: + case map[string]any: if x == nil { - // Typed nil - an interface{} that contains a type map[string]interface{} with a value of nil + // Typed nil - an any that contains a type map[string]any with a value of nil return x } - clone := make(map[string]interface{}, len(x)) + clone := make(map[string]any, len(x)) for k, v := range x { clone[k] = deepCopyJSONValue(v) } return clone - case []interface{}: + case []any: if x == nil { - // Typed nil - an interface{} that contains a type []interface{} with a value of nil + // Typed nil - an any that contains a type []any with a value of nil return x } - clone := make([]interface{}, len(x)) + clone := make([]any, len(x)) for i, v := range x { clone[i] = deepCopyJSONValue(v) } @@ -124,23 +128,23 @@ func deepCopyJSONValue(x interface{}) interface{} { } } -func (u *Unstructured) Set(field string, value interface{}) { +func (u *Unstructured) Set(field string, value any) { if u.Object == nil { - u.Object = make(map[string]interface{}) + u.Object = make(map[string]any) } _ = unstructured.SetNestedField(u.Object, value, field) } func (u *Unstructured) Remove(fields ...string) { if u.Object == nil { - u.Object = make(map[string]interface{}) + u.Object = make(map[string]any) } unstructured.RemoveNestedField(u.Object, fields...) } -func (u *Unstructured) SetNestedField(value interface{}, fields ...string) { +func (u *Unstructured) SetNestedField(value any, fields ...string) { if u.Object == nil { - u.Object = make(map[string]interface{}) + u.Object = make(map[string]any) } _ = unstructured.SetNestedField(u.Object, value, fields...) } diff --git a/pkg/apimachinery/apis/common/v0alpha1/unstructured_test.go b/pkg/apimachinery/apis/common/v0alpha1/unstructured_test.go index 1698bd081c0..296212398bd 100644 --- a/pkg/apimachinery/apis/common/v0alpha1/unstructured_test.go +++ b/pkg/apimachinery/apis/common/v0alpha1/unstructured_test.go @@ -10,13 +10,13 @@ import ( func TestDeepCopyJSON(t *testing.T) { obj := &Unstructured{ - Object: map[string]interface{}{ + Object: map[string]any{ "int": int(2), "int16": int16(2), "int32": int32(2), "uint64": uint64(2), "ref": &ObjectReference{ - Resource: "x", + Kind: "x", }, "array": []any{ int(1), int64(2), "hello", @@ -25,7 +25,7 @@ func TestDeepCopyJSON(t *testing.T) { "bool": true, "map": map[string]any{ "x": &ObjectReference{ - Resource: "x", + Kind: "x", }, }, "object": &v1.APIGroup{ diff --git a/pkg/apimachinery/apis/common/v0alpha1/zz_generated.openapi.go b/pkg/apimachinery/apis/common/v0alpha1/zz_generated.openapi.go index 2064fa5fac8..f4465722266 100644 --- a/pkg/apimachinery/apis/common/v0alpha1/zz_generated.openapi.go +++ b/pkg/apimachinery/apis/common/v0alpha1/zz_generated.openapi.go @@ -83,34 +83,51 @@ func schema_apimachinery_apis_common_v0alpha1_ObjectReference(ref common.Referen Description: "Similar to https://dev-k8sref-io.web.app/docs/common-definitions/objectreference-/ ObjectReference contains enough information to let you inspect or modify the referred object.", Type: []string{"object"}, Properties: map[string]spec.Schema{ - "resource": { + "apiGroup": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "APIGroup is the name of the API group that contains the referred object. The empty string represents the core API group.", + Type: []string{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + Description: "APIVersion is the version of the API group that contains the referred object.", + Type: []string{"string"}, + Format: "", + }, + }, + "kind": { + SchemaProps: spec.SchemaProps{ + Description: "See https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#types-kinds", + Type: []string{"string"}, + Format: "", }, }, "namespace": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "Tenant isolation", + Type: []string{"string"}, + Format: "", }, }, "name": { SchemaProps: spec.SchemaProps{ - Type: []string{"string"}, - Format: "", + Description: "Explicit resource identifier", + Type: []string{"string"}, + Format: "", }, }, - "apiGroup": { + "fieldPath": { SchemaProps: spec.SchemaProps{ - Description: "APIGroup is the name of the API group that contains the referred object. The empty string represents the core API group.", + Description: "May contain a valid JSON/Go field access statement", Type: []string{"string"}, Format: "", }, }, - "apiVersion": { + "uid": { SchemaProps: spec.SchemaProps{ - Description: "APIVersion is the version of the API group that contains the referred object.", + Description: "Sepcific deployment of an object", Type: []string{"string"}, Format: "", }, diff --git a/pkg/apimachinery/utils/blob.go b/pkg/apimachinery/utils/blob.go new file mode 100644 index 00000000000..ca023560cc9 --- /dev/null +++ b/pkg/apimachinery/utils/blob.go @@ -0,0 +1,88 @@ +package utils + +import ( + "bytes" + "fmt" + "mime" + "strconv" + "strings" +) + +type BlobInfo struct { + UID string `json:"uid"` + Size int64 `json:"size,omitempty"` + Hash string `json:"hash,omitempty"` + MimeType string `json:"mime,omitempty"` + Charset string `json:"charset,omitempty"` // content type = mime+charset +} + +// Content type is mime + charset +func (b *BlobInfo) SetContentType(v string) { + var params map[string]string + var err error + + b.Charset = "" + b.MimeType, params, err = mime.ParseMediaType(v) + if err != nil { + return + } + b.Charset = params["charset"] +} + +// Content type is mime + charset +func (b *BlobInfo) ContentType() string { + sb := bytes.NewBufferString(b.MimeType) + if b.Charset != "" { + sb.WriteString("; charset=") + sb.WriteString(b.Charset) + } + return sb.String() +} + +func (b *BlobInfo) String() string { + sb := bytes.NewBufferString(b.UID) + if b.Size > 0 { + fmt.Fprintf(sb, "; size=%d", b.Size) + } + if b.Hash != "" { + sb.WriteString("; hash=") + sb.WriteString(b.Hash) + } + if b.MimeType != "" { + sb.WriteString("; mime=") + sb.WriteString(b.MimeType) + } + if b.Charset != "" { + sb.WriteString("; charset=") + sb.WriteString(b.Charset) + } + return sb.String() +} + +func ParseBlobInfo(v string) *BlobInfo { + if v == "" { + return nil + } + info := &BlobInfo{} + for i, part := range strings.Split(v, ";") { + if i == 0 { + info.UID = part + continue + } + kv := strings.Split(strings.TrimSpace(part), "=") + if len(kv) == 2 { + val := kv[1] + switch kv[0] { + case "size": + info.Size, _ = strconv.ParseInt(val, 10, 64) + case "hash": + info.Hash = val + case "mime": + info.MimeType = val + case "charset": + info.Charset = val + } + } + } + return info +} diff --git a/pkg/apimachinery/utils/meta.go b/pkg/apimachinery/utils/meta.go index 2907897851b..0d19536138d 100644 --- a/pkg/apimachinery/utils/meta.go +++ b/pkg/apimachinery/utils/meta.go @@ -1,12 +1,9 @@ package utils import ( - "bytes" "fmt" - "mime" "reflect" "strconv" - "strings" "time" "k8s.io/apimachinery/pkg/api/meta" @@ -824,82 +821,3 @@ func (m *grafanaMetaAccessor) SetSourceProperties(v SourceProperties) { m.obj.SetAnnotations(annot) } - -type BlobInfo struct { - UID string `json:"uid"` - Size int64 `json:"size,omitempty"` - Hash string `json:"hash,omitempty"` - MimeType string `json:"mime,omitempty"` - Charset string `json:"charset,omitempty"` // content type = mime+charset -} - -// Content type is mime + charset -func (b *BlobInfo) SetContentType(v string) { - var params map[string]string - var err error - - b.Charset = "" - b.MimeType, params, err = mime.ParseMediaType(v) - if err != nil { - return - } - b.Charset = params["charset"] -} - -// Content type is mime + charset -func (b *BlobInfo) ContentType() string { - sb := bytes.NewBufferString(b.MimeType) - if b.Charset != "" { - sb.WriteString("; charset=") - sb.WriteString(b.Charset) - } - return sb.String() -} - -func (b *BlobInfo) String() string { - sb := bytes.NewBufferString(b.UID) - if b.Size > 0 { - fmt.Fprintf(sb, "; size=%d", b.Size) - } - if b.Hash != "" { - sb.WriteString("; hash=") - sb.WriteString(b.Hash) - } - if b.MimeType != "" { - sb.WriteString("; mime=") - sb.WriteString(b.MimeType) - } - if b.Charset != "" { - sb.WriteString("; charset=") - sb.WriteString(b.Charset) - } - return sb.String() -} - -func ParseBlobInfo(v string) *BlobInfo { - if v == "" { - return nil - } - info := &BlobInfo{} - for i, part := range strings.Split(v, ";") { - if i == 0 { - info.UID = part - continue - } - kv := strings.Split(strings.TrimSpace(part), "=") - if len(kv) == 2 { - val := kv[1] - switch kv[0] { - case "size": - info.Size, _ = strconv.ParseInt(val, 10, 64) - case "hash": - info.Hash = val - case "mime": - info.MimeType = val - case "charset": - info.Charset = val - } - } - } - return info -} diff --git a/public/api-merged.json b/public/api-merged.json index 0778d9d6d3d..2f2eed4fca5 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -22070,7 +22070,7 @@ "type": "object", "properties": { "Object": { - "description": "Object is a JSON compatible map with string, float, int, bool, []interface{},\nor map[string]interface{} children.", + "description": "Object is a JSON compatible map with string, float, int, bool, []any,\nor map[string]any children.", "type": "object", "additionalProperties": {} } diff --git a/public/openapi3.json b/public/openapi3.json index f6a8589a689..3a1e1c93c5b 100644 --- a/public/openapi3.json +++ b/public/openapi3.json @@ -12117,7 +12117,7 @@ "properties": { "Object": { "additionalProperties": {}, - "description": "Object is a JSON compatible map with string, float, int, bool, []interface{},\nor map[string]interface{} children.", + "description": "Object is a JSON compatible map with string, float, int, bool, []any,\nor map[string]any children.", "type": "object" } },