Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ require (
kmodules.xyz/go-containerregistry v0.0.15
kmodules.xyz/monitoring-agent-api v0.34.3
kmodules.xyz/offshoot-api v0.34.0
kmodules.xyz/resource-metadata v0.47.1-0.20260626202730-925518073731
kmodules.xyz/resource-metadata v0.47.1-0.20260627061026-da58ac8b5beb
kmodules.xyz/resource-metrics v0.34.4-0.20260626131047-afdc9726717d
kmodules.xyz/resource-metrics/utils v0.34.1-0.20260622121456-42ed2b0a80a4
kmodules.xyz/sets v0.29.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -1187,8 +1187,8 @@ kmodules.xyz/monitoring-agent-api v0.34.3 h1:8dCTSatkKbi9CTAQ3+u7OmoyUghLvKTqqcl
kmodules.xyz/monitoring-agent-api v0.34.3/go.mod h1:0WtVdliczkCmjA/QyB2ZriVwABSA8Fhzt01yMEukFLY=
kmodules.xyz/offshoot-api v0.34.0 h1:HnOOp8FrCjTWjtNApRDo6Ahe79tOlLrJmyye4xxO4Kk=
kmodules.xyz/offshoot-api v0.34.0/go.mod h1:F+B59yYw4CZJ4uD4xu6C+mMLzIXUtuH7E+SbDICl9jE=
kmodules.xyz/resource-metadata v0.47.1-0.20260626202730-925518073731 h1:10DfU8wlQMZuf3zNrm2OifWN9vbUOudkjqjGyWwXJsc=
kmodules.xyz/resource-metadata v0.47.1-0.20260626202730-925518073731/go.mod h1:ejz7IVjhqmj6VH8CVfprocJK/IM++OeunrfUp51ZrIw=
kmodules.xyz/resource-metadata v0.47.1-0.20260627061026-da58ac8b5beb h1:Ngy++XrNh7unP5h1wqyDtqoBguo8b4HoibvIRedHy0Q=
kmodules.xyz/resource-metadata v0.47.1-0.20260627061026-da58ac8b5beb/go.mod h1:ejz7IVjhqmj6VH8CVfprocJK/IM++OeunrfUp51ZrIw=
kmodules.xyz/resource-metrics v0.34.4-0.20260626131047-afdc9726717d h1:vgDVnRBzVuhbhlHYi8VWL/mJ8LHNk+z5ipVjIpTA2N4=
kmodules.xyz/resource-metrics v0.34.4-0.20260626131047-afdc9726717d/go.mod h1:R34IKtp5+NqcQz7AQJheBJK6Iem0LqrCbm/55Mn+ECQ=
kmodules.xyz/resource-metrics/utils v0.34.1-0.20260622121456-42ed2b0a80a4 h1:AhuMryuO4hKbnqH7QyVciCar8mQ2WYPqP0f1WVqzALQ=
Expand Down
4 changes: 2 additions & 2 deletions pkg/apiserver/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ import (
resourcesservicestorage "kubeops.dev/ui-server/pkg/registry/core/resourceservice"
resourcesummarystorage "kubeops.dev/ui-server/pkg/registry/core/resourcesummary"
coststorage "kubeops.dev/ui-server/pkg/registry/cost/reports"
editortemplatestorage "kubeops.dev/ui-server/pkg/registry/editor/editortemplate"
editormodelstorage "kubeops.dev/ui-server/pkg/registry/editor/editormodel"
audittokenreqstorage "kubeops.dev/ui-server/pkg/registry/identity/audittokenrequest"
clusteridstorage "kubeops.dev/ui-server/pkg/registry/identity/clusteridentity"
inboxtokenreqstorage "kubeops.dev/ui-server/pkg/registry/identity/inboxtokenrequest"
Expand Down Expand Up @@ -439,7 +439,7 @@ func (c completedConfig) New(ctx context.Context) (*UIServer, error) {
apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(editorapi.SchemeGroupVersion.Group, Scheme, metav1.ParameterCodec, Codecs)

v1alpha1storage := map[string]rest.Storage{}
v1alpha1storage[editorapi.ResourceEditorTemplates] = editortemplatestorage.NewStorage(ctrlClient)
v1alpha1storage[editorapi.ResourceEditorModels] = editormodelstorage.NewStorage(cfg, Scheme, mgr.GetRESTMapper())
apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1storage

if err := s.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

package editortemplate
package editormodel

import (
"context"
Expand All @@ -23,18 +23,23 @@ import (
"strings"

apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/meta"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
apirequest "k8s.io/apiserver/pkg/endpoints/request"
"k8s.io/apiserver/pkg/registry/rest"
restclient "k8s.io/client-go/rest"
editorapi "kmodules.xyz/resource-metadata/apis/editor/v1alpha1"
"kubepack.dev/lib-app/pkg/editor"
"sigs.k8s.io/controller-runtime/pkg/client"
driversapi "x-helm.dev/apimachinery/apis/drivers/v1alpha1"
)

type Storage struct {
kc client.Client
cfg *restclient.Config
scheme *runtime.Scheme
mapper meta.RESTMapper
}

var (
Expand All @@ -45,35 +50,54 @@ var (
_ rest.SingularNameProvider = &Storage{}
)

func NewStorage(kc client.Client) *Storage {
return &Storage{kc: kc}
func NewStorage(cfg *restclient.Config, scheme *runtime.Scheme, mapper meta.RESTMapper) *Storage {
return &Storage{cfg: cfg, scheme: scheme, mapper: mapper}
}

func (r *Storage) GroupVersionKind(_ schema.GroupVersion) schema.GroupVersionKind {
return editorapi.SchemeGroupVersion.WithKind(editorapi.ResourceKindEditorTemplate)
return editorapi.SchemeGroupVersion.WithKind(editorapi.ResourceKindEditorModel)
}

func (r *Storage) NamespaceScoped() bool {
return false
}

func (r *Storage) GetSingularName() string {
return strings.ToLower(editorapi.ResourceKindEditorTemplate)
return strings.ToLower(editorapi.ResourceKindEditorModel)
}

func (r *Storage) New() runtime.Object {
return &editorapi.EditorTemplate{}
return &editorapi.EditorModel{}
}

func (r *Storage) Destroy() {}

// Create reconstructs the editor template for an existing installation from the
// callerClient returns a controller-runtime client that impersonates the API
// caller, so the in-cluster reads done while reconstructing the editor model are
// authorized against the caller's own RBAC.
func (r *Storage) callerClient(ctx context.Context) (client.Client, error) {
user, ok := apirequest.UserFrom(ctx)
if !ok {
return nil, apierrors.NewBadRequest("missing user info in request context")
}
cfg := restclient.CopyConfig(r.cfg)
cfg.Impersonate = restclient.ImpersonationConfig{
UserName: user.GetName(),
UID: user.GetUID(),
Groups: user.GetGroups(),
Extra: user.GetExtra(),
}
return client.New(cfg, client.Options{Scheme: r.scheme, Mapper: r.mapper})
}

// Create reconstructs the editor model for an existing installation from the
// chart values supplied in the request. The caller (b3) is responsible for the
// slow parts -- pulling the chart (getChart) and creating the AppRelease if
// missing -- so this method only performs fast in-cluster reads and stays within
// the aggregated apiserver request budget.
// the aggregated apiserver request budget. Those reads run as the caller via
// impersonation, so they are authorized against the caller's own RBAC.
func (r *Storage) Create(ctx context.Context, obj runtime.Object, _ rest.ValidateObjectFunc, _ *metav1.CreateOptions) (runtime.Object, error) {
in, ok := obj.(*editorapi.EditorTemplate)
in, ok := obj.(*editorapi.EditorModel)
if !ok {
return nil, fmt.Errorf("invalid object type: %T", obj)
}
Expand All @@ -89,17 +113,22 @@ func (r *Storage) Create(ctx context.Context, obj runtime.Object, _ rest.Validat
}
}

kc, err := r.callerClient(ctx)
if err != nil {
return nil, err
}

var app driversapi.AppRelease
if err := r.kc.Get(ctx, client.ObjectKey{Namespace: md.Release.Namespace, Name: md.Release.Name}, &app); err != nil {
if err := kc.Get(ctx, client.ObjectKey{Namespace: md.Release.Namespace, Name: md.Release.Name}, &app); err != nil {
return nil, err
}

tpl, err := editor.EditorChartValueManifest(r.kc, &app, md, values)
tpl, err := editor.EditorChartValueManifest(kc, &app, md, values)
if err != nil {
return nil, err
}

resp := &editorapi.EditorTemplateResponse{
resp := &editorapi.EditorModelResponse{
Manifest: string(tpl.Manifest),
}
if tpl.Values != nil {
Expand All @@ -110,7 +139,7 @@ func (r *Storage) Create(ctx context.Context, obj runtime.Object, _ rest.Validat
resp.Values = &runtime.RawExtension{Raw: raw}
}
for _, res := range tpl.Resources {
item := editorapi.EditorTemplateResource{
item := editorapi.EditorModelResource{
Filename: res.Filename,
Key: res.Key,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import (
)

const (
ResourceKindEditorTemplate = "EditorTemplate"
ResourceEditorTemplate = "editortemplate"
ResourceEditorTemplates = "editortemplates"
ResourceKindEditorModel = "EditorModel"
ResourceEditorModel = "editormodel"
ResourceEditorModels = "editormodels"
)

// EditorTemplate loads the editor model, manifest and resources for an existing
// EditorModel loads the editor model, manifest and resources for an existing
// installation identified by its metadata. It is the aggregated-API equivalent
// of kubepack.dev/lib-app/pkg/editor.LoadResourceEditorModel (see
// chart_template.go loadEditorModel2).
Expand All @@ -40,17 +40,17 @@ const (
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:object:root=true
// +kubebuilder:resource:scope=Cluster
type EditorTemplate struct {
type EditorModel struct {
metav1.TypeMeta `json:",inline"`
// Request identifies the installation to load.
// +optional
Request *EditorTemplateRequest `json:"request,omitempty"`
Request *EditorModelRequest `json:"request,omitempty"`
// Response holds the loaded editor template.
// +optional
Response *EditorTemplateResponse `json:"response,omitempty"`
Response *EditorModelResponse `json:"response,omitempty"`
}

type EditorTemplateRequest struct {
type EditorModelRequest struct {
releasesapi.ModelMetadata `json:",inline"`
// Values is the editor chart's values, fetched by the caller. The chart is
// pulled (getChart) by the caller because it can take longer than the
Expand All @@ -60,7 +60,7 @@ type EditorTemplateRequest struct {
Values *runtime.RawExtension `json:"values,omitempty"`
}

type EditorTemplateResponse struct {
type EditorModelResponse struct {
// Manifest is the rendered manifest of the existing installation.
// +optional
Manifest string `json:"manifest,omitempty"`
Expand All @@ -69,10 +69,10 @@ type EditorTemplateResponse struct {
Values *runtime.RawExtension `json:"values,omitempty"`
// Resources holds the individual resources of the existing installation.
// +optional
Resources []EditorTemplateResource `json:"resources,omitempty"`
Resources []EditorModelResource `json:"resources,omitempty"`
}

type EditorTemplateResource struct {
type EditorModelResource struct {
// +optional
Filename string `json:"filename,omitempty"`
// +optional
Expand Down
Loading
Loading