mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
[ui] Create/Delete volumes (#7029)
* [api/devstate] Add volumes to Devfile content * Add Volume related endpoints to API * Create/Delete volumes from the Volumes Tab * Update UI static files * API Devstate returns VolumeMounts * Display volume mounts in containers * [api] Add VolumeMounts to containers * [ui] Define container's volume mounts * [ui] e2e tests * Update UI static files * [ui] create volumes from container / exec command creation * Update UI static files * Update container display * Update UI static files * Regenerate UI static files
This commit is contained in:
3
pkg/apiserver-gen/.openapi-generator/FILES
generated
3
pkg/apiserver-gen/.openapi-generator/FILES
generated
@@ -20,6 +20,7 @@ go/model__devstate_exec_command_post_request.go
|
||||
go/model__devstate_image_post_request.go
|
||||
go/model__devstate_quantity_valid_post_request.go
|
||||
go/model__devstate_resource_post_request.go
|
||||
go/model__devstate_volume_post_request.go
|
||||
go/model__instance_get_200_response.go
|
||||
go/model_apply_command.go
|
||||
go/model_command.go
|
||||
@@ -38,3 +39,5 @@ go/model_metadata.go
|
||||
go/model_metadata_request.go
|
||||
go/model_resource.go
|
||||
go/model_telemetry_response.go
|
||||
go/model_volume.go
|
||||
go/model_volume_mount.go
|
||||
|
||||
4
pkg/apiserver-gen/go/api.go
generated
4
pkg/apiserver-gen/go/api.go
generated
@@ -51,6 +51,8 @@ type DevstateApiRouter interface {
|
||||
DevstateQuantityValidPost(http.ResponseWriter, *http.Request)
|
||||
DevstateResourcePost(http.ResponseWriter, *http.Request)
|
||||
DevstateResourceResourceNameDelete(http.ResponseWriter, *http.Request)
|
||||
DevstateVolumePost(http.ResponseWriter, *http.Request)
|
||||
DevstateVolumeVolumeNameDelete(http.ResponseWriter, *http.Request)
|
||||
}
|
||||
|
||||
// DefaultApiServicer defines the api actions for the DefaultApi service
|
||||
@@ -92,4 +94,6 @@ type DevstateApiServicer interface {
|
||||
DevstateQuantityValidPost(context.Context, DevstateQuantityValidPostRequest) (ImplResponse, error)
|
||||
DevstateResourcePost(context.Context, DevstateResourcePostRequest) (ImplResponse, error)
|
||||
DevstateResourceResourceNameDelete(context.Context, string) (ImplResponse, error)
|
||||
DevstateVolumePost(context.Context, DevstateVolumePostRequest) (ImplResponse, error)
|
||||
DevstateVolumeVolumeNameDelete(context.Context, string) (ImplResponse, error)
|
||||
}
|
||||
|
||||
51
pkg/apiserver-gen/go/api_devstate.go
generated
51
pkg/apiserver-gen/go/api_devstate.go
generated
@@ -170,6 +170,18 @@ func (c *DevstateApiController) Routes() Routes {
|
||||
"/api/v1/devstate/resource/{resourceName}",
|
||||
c.DevstateResourceResourceNameDelete,
|
||||
},
|
||||
{
|
||||
"DevstateVolumePost",
|
||||
strings.ToUpper("Post"),
|
||||
"/api/v1/devstate/volume",
|
||||
c.DevstateVolumePost,
|
||||
},
|
||||
{
|
||||
"DevstateVolumeVolumeNameDelete",
|
||||
strings.ToUpper("Delete"),
|
||||
"/api/v1/devstate/volume/{volumeName}",
|
||||
c.DevstateVolumeVolumeNameDelete,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -578,3 +590,42 @@ func (c *DevstateApiController) DevstateResourceResourceNameDelete(w http.Respon
|
||||
EncodeJSONResponse(result.Body, &result.Code, w)
|
||||
|
||||
}
|
||||
|
||||
// DevstateVolumePost -
|
||||
func (c *DevstateApiController) DevstateVolumePost(w http.ResponseWriter, r *http.Request) {
|
||||
devstateVolumePostRequestParam := DevstateVolumePostRequest{}
|
||||
d := json.NewDecoder(r.Body)
|
||||
d.DisallowUnknownFields()
|
||||
if err := d.Decode(&devstateVolumePostRequestParam); err != nil {
|
||||
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
|
||||
return
|
||||
}
|
||||
if err := AssertDevstateVolumePostRequestRequired(devstateVolumePostRequestParam); err != nil {
|
||||
c.errorHandler(w, r, err, nil)
|
||||
return
|
||||
}
|
||||
result, err := c.service.DevstateVolumePost(r.Context(), devstateVolumePostRequestParam)
|
||||
// If an error occurred, encode the error with the status code
|
||||
if err != nil {
|
||||
c.errorHandler(w, r, err, &result)
|
||||
return
|
||||
}
|
||||
// If no error, encode the body and the result code
|
||||
EncodeJSONResponse(result.Body, &result.Code, w)
|
||||
|
||||
}
|
||||
|
||||
// DevstateVolumeVolumeNameDelete -
|
||||
func (c *DevstateApiController) DevstateVolumeVolumeNameDelete(w http.ResponseWriter, r *http.Request) {
|
||||
params := mux.Vars(r)
|
||||
volumeNameParam := params["volumeName"]
|
||||
result, err := c.service.DevstateVolumeVolumeNameDelete(r.Context(), volumeNameParam)
|
||||
// If an error occurred, encode the error with the status code
|
||||
if err != nil {
|
||||
c.errorHandler(w, r, err, &result)
|
||||
return
|
||||
}
|
||||
// If no error, encode the body and the result code
|
||||
EncodeJSONResponse(result.Body, &result.Code, w)
|
||||
|
||||
}
|
||||
|
||||
@@ -34,10 +34,18 @@ type DevstateContainerPostRequest struct {
|
||||
|
||||
// CPU limit for the deployed container
|
||||
CpuLimit string `json:"cpuLimit,omitempty"`
|
||||
|
||||
// Volume to mount into the container filesystem
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
}
|
||||
|
||||
// AssertDevstateContainerPostRequestRequired checks if the required fields are not zero-ed
|
||||
func AssertDevstateContainerPostRequestRequired(obj DevstateContainerPostRequest) error {
|
||||
for _, el := range obj.VolumeMounts {
|
||||
if err := AssertVolumeMountRequired(el); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
39
pkg/apiserver-gen/go/model__devstate_volume_post_request.go
generated
Normal file
39
pkg/apiserver-gen/go/model__devstate_volume_post_request.go
generated
Normal file
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* odo dev
|
||||
*
|
||||
* API interface for 'odo dev'
|
||||
*
|
||||
* API version: 0.1
|
||||
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
|
||||
*/
|
||||
|
||||
package openapi
|
||||
|
||||
type DevstateVolumePostRequest struct {
|
||||
|
||||
// Name of the volume
|
||||
Name string `json:"name,omitempty"`
|
||||
|
||||
// Minimal size of the volume
|
||||
Size string `json:"size,omitempty"`
|
||||
|
||||
// True if the Volume is Ephemeral
|
||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||
}
|
||||
|
||||
// AssertDevstateVolumePostRequestRequired checks if the required fields are not zero-ed
|
||||
func AssertDevstateVolumePostRequestRequired(obj DevstateVolumePostRequest) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssertRecurseDevstateVolumePostRequestRequired recursively checks if required fields are not zero-ed in a nested slice.
|
||||
// Accepts only nested slice of DevstateVolumePostRequest (e.g. [][]DevstateVolumePostRequest), otherwise ErrTypeAssertionError is thrown.
|
||||
func AssertRecurseDevstateVolumePostRequestRequired(objSlice interface{}) error {
|
||||
return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error {
|
||||
aDevstateVolumePostRequest, ok := obj.(DevstateVolumePostRequest)
|
||||
if !ok {
|
||||
return ErrTypeAssertionError
|
||||
}
|
||||
return AssertDevstateVolumePostRequestRequired(aDevstateVolumePostRequest)
|
||||
})
|
||||
}
|
||||
8
pkg/apiserver-gen/go/model_container.go
generated
8
pkg/apiserver-gen/go/model_container.go
generated
@@ -25,6 +25,8 @@ type Container struct {
|
||||
CpuRequest string `json:"cpuRequest"`
|
||||
|
||||
CpuLimit string `json:"cpuLimit"`
|
||||
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts"`
|
||||
}
|
||||
|
||||
// AssertContainerRequired checks if the required fields are not zero-ed
|
||||
@@ -38,6 +40,7 @@ func AssertContainerRequired(obj Container) error {
|
||||
"memoryLimit": obj.MemoryLimit,
|
||||
"cpuRequest": obj.CpuRequest,
|
||||
"cpuLimit": obj.CpuLimit,
|
||||
"volumeMounts": obj.VolumeMounts,
|
||||
}
|
||||
for name, el := range elements {
|
||||
if isZero := IsZeroValue(el); isZero {
|
||||
@@ -45,6 +48,11 @@ func AssertContainerRequired(obj Container) error {
|
||||
}
|
||||
}
|
||||
|
||||
for _, el := range obj.VolumeMounts {
|
||||
if err := AssertVolumeMountRequired(el); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
8
pkg/apiserver-gen/go/model_devfile_content.go
generated
8
pkg/apiserver-gen/go/model_devfile_content.go
generated
@@ -20,6 +20,8 @@ type DevfileContent struct {
|
||||
|
||||
Resources []Resource `json:"resources"`
|
||||
|
||||
Volumes []Volume `json:"volumes"`
|
||||
|
||||
Events Events `json:"events"`
|
||||
|
||||
Metadata Metadata `json:"metadata"`
|
||||
@@ -33,6 +35,7 @@ func AssertDevfileContentRequired(obj DevfileContent) error {
|
||||
"containers": obj.Containers,
|
||||
"images": obj.Images,
|
||||
"resources": obj.Resources,
|
||||
"volumes": obj.Volumes,
|
||||
"events": obj.Events,
|
||||
"metadata": obj.Metadata,
|
||||
}
|
||||
@@ -62,6 +65,11 @@ func AssertDevfileContentRequired(obj DevfileContent) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, el := range obj.Volumes {
|
||||
if err := AssertVolumeRequired(el); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := AssertEventsRequired(obj.Events); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
44
pkg/apiserver-gen/go/model_volume.go
generated
Normal file
44
pkg/apiserver-gen/go/model_volume.go
generated
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* odo dev
|
||||
*
|
||||
* API interface for 'odo dev'
|
||||
*
|
||||
* API version: 0.1
|
||||
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
|
||||
*/
|
||||
|
||||
package openapi
|
||||
|
||||
type Volume struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
Ephemeral bool `json:"ephemeral,omitempty"`
|
||||
|
||||
Size string `json:"size,omitempty"`
|
||||
}
|
||||
|
||||
// AssertVolumeRequired checks if the required fields are not zero-ed
|
||||
func AssertVolumeRequired(obj Volume) error {
|
||||
elements := map[string]interface{}{
|
||||
"name": obj.Name,
|
||||
}
|
||||
for name, el := range elements {
|
||||
if isZero := IsZeroValue(el); isZero {
|
||||
return &RequiredError{Field: name}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssertRecurseVolumeRequired recursively checks if required fields are not zero-ed in a nested slice.
|
||||
// Accepts only nested slice of Volume (e.g. [][]Volume), otherwise ErrTypeAssertionError is thrown.
|
||||
func AssertRecurseVolumeRequired(objSlice interface{}) error {
|
||||
return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error {
|
||||
aVolume, ok := obj.(Volume)
|
||||
if !ok {
|
||||
return ErrTypeAssertionError
|
||||
}
|
||||
return AssertVolumeRequired(aVolume)
|
||||
})
|
||||
}
|
||||
43
pkg/apiserver-gen/go/model_volume_mount.go
generated
Normal file
43
pkg/apiserver-gen/go/model_volume_mount.go
generated
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* odo dev
|
||||
*
|
||||
* API interface for 'odo dev'
|
||||
*
|
||||
* API version: 0.1
|
||||
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
|
||||
*/
|
||||
|
||||
package openapi
|
||||
|
||||
type VolumeMount struct {
|
||||
Name string `json:"name"`
|
||||
|
||||
Path string `json:"path"`
|
||||
}
|
||||
|
||||
// AssertVolumeMountRequired checks if the required fields are not zero-ed
|
||||
func AssertVolumeMountRequired(obj VolumeMount) error {
|
||||
elements := map[string]interface{}{
|
||||
"name": obj.Name,
|
||||
"path": obj.Path,
|
||||
}
|
||||
for name, el := range elements {
|
||||
if isZero := IsZeroValue(el); isZero {
|
||||
return &RequiredError{Field: name}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssertRecurseVolumeMountRequired recursively checks if required fields are not zero-ed in a nested slice.
|
||||
// Accepts only nested slice of VolumeMount (e.g. [][]VolumeMount), otherwise ErrTypeAssertionError is thrown.
|
||||
func AssertRecurseVolumeMountRequired(objSlice interface{}) error {
|
||||
return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error {
|
||||
aVolumeMount, ok := obj.(VolumeMount)
|
||||
if !ok {
|
||||
return ErrTypeAssertionError
|
||||
}
|
||||
return AssertVolumeMountRequired(aVolumeMount)
|
||||
})
|
||||
}
|
||||
@@ -19,6 +19,7 @@ func (s *DevstateApiService) DevstateContainerPost(ctx context.Context, containe
|
||||
container.MemLimit,
|
||||
container.CpuReq,
|
||||
container.CpuLimit,
|
||||
container.VolumeMounts,
|
||||
)
|
||||
if err != nil {
|
||||
return openapi.Response(http.StatusInternalServerError, openapi.GeneralError{
|
||||
@@ -90,6 +91,30 @@ func (s *DevstateApiService) DevstateResourceResourceNameDelete(ctx context.Cont
|
||||
return openapi.Response(http.StatusOK, newContent), nil
|
||||
}
|
||||
|
||||
func (s *DevstateApiService) DevstateVolumePost(ctx context.Context, volume openapi.DevstateVolumePostRequest) (openapi.ImplResponse, error) {
|
||||
newContent, err := s.devfileState.AddVolume(
|
||||
volume.Name,
|
||||
volume.Ephemeral,
|
||||
volume.Size,
|
||||
)
|
||||
if err != nil {
|
||||
return openapi.Response(http.StatusInternalServerError, openapi.GeneralError{
|
||||
Message: fmt.Sprintf("Error adding the volume: %s", err),
|
||||
}), nil
|
||||
}
|
||||
return openapi.Response(http.StatusOK, newContent), nil
|
||||
}
|
||||
|
||||
func (s *DevstateApiService) DevstateVolumeVolumeNameDelete(ctx context.Context, volumeName string) (openapi.ImplResponse, error) {
|
||||
newContent, err := s.devfileState.DeleteVolume(volumeName)
|
||||
if err != nil {
|
||||
return openapi.Response(http.StatusInternalServerError, openapi.GeneralError{
|
||||
Message: fmt.Sprintf("Error deleting the volume: %s", err),
|
||||
}), nil
|
||||
}
|
||||
return openapi.Response(http.StatusOK, newContent), nil
|
||||
}
|
||||
|
||||
func (s *DevstateApiService) DevstateApplyCommandPost(ctx context.Context, command openapi.DevstateApplyCommandPostRequest) (openapi.ImplResponse, error) {
|
||||
newContent, err := s.devfileState.AddApplyCommand(
|
||||
command.Name,
|
||||
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
. "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
|
||||
openapi "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
|
||||
)
|
||||
|
||||
func TestDevfileState_AddExecCommand(t *testing.T) {
|
||||
@@ -36,6 +37,7 @@ func TestDevfileState_AddExecCommand(t *testing.T) {
|
||||
"2Gi",
|
||||
"100m",
|
||||
"200m",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -96,10 +98,12 @@ schemaVersion: 2.2.0
|
||||
MemoryLimit: "2Gi",
|
||||
CpuRequest: "100m",
|
||||
CpuLimit: "200m",
|
||||
VolumeMounts: []openapi.VolumeMount{},
|
||||
},
|
||||
},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -186,6 +190,7 @@ schemaVersion: 2.2.0
|
||||
},
|
||||
},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -235,6 +240,7 @@ func TestDevfileState_AddCompositeCommand(t *testing.T) {
|
||||
"2Gi",
|
||||
"100m",
|
||||
"200m",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -313,10 +319,12 @@ schemaVersion: 2.2.0
|
||||
MemoryLimit: "2Gi",
|
||||
CpuRequest: "100m",
|
||||
CpuLimit: "200m",
|
||||
VolumeMounts: []openapi.VolumeMount{},
|
||||
},
|
||||
},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -364,6 +372,7 @@ func TestDevfileState_DeleteCommand(t *testing.T) {
|
||||
"2Gi",
|
||||
"100m",
|
||||
"200m",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -412,10 +421,12 @@ schemaVersion: 2.2.0
|
||||
MemoryLimit: "2Gi",
|
||||
CpuRequest: "100m",
|
||||
CpuLimit: "200m",
|
||||
VolumeMounts: []openapi.VolumeMount{},
|
||||
},
|
||||
},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -627,6 +638,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
},
|
||||
},
|
||||
// TODO: Add test cases.
|
||||
@@ -713,6 +725,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
},
|
||||
},
|
||||
// TODO: Add test cases.
|
||||
@@ -801,6 +814,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
},
|
||||
},
|
||||
// TODO: Add test cases.
|
||||
|
||||
@@ -9,7 +9,24 @@ import (
|
||||
. "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
|
||||
)
|
||||
|
||||
func (o *DevfileState) AddContainer(name string, image string, command []string, args []string, memRequest string, memLimit string, cpuRequest string, cpuLimit string) (DevfileContent, error) {
|
||||
func (o *DevfileState) AddContainer(
|
||||
name string,
|
||||
image string,
|
||||
command []string,
|
||||
args []string,
|
||||
memRequest string,
|
||||
memLimit string,
|
||||
cpuRequest string,
|
||||
cpuLimit string,
|
||||
volumeMounts []VolumeMount,
|
||||
) (DevfileContent, error) {
|
||||
v1alpha2VolumeMounts := make([]v1alpha2.VolumeMount, 0, len(volumeMounts))
|
||||
for _, vm := range volumeMounts {
|
||||
v1alpha2VolumeMounts = append(v1alpha2VolumeMounts, v1alpha2.VolumeMount{
|
||||
Name: vm.Name,
|
||||
Path: vm.Path,
|
||||
})
|
||||
}
|
||||
container := v1alpha2.Component{
|
||||
Name: name,
|
||||
ComponentUnion: v1alpha2.ComponentUnion{
|
||||
@@ -22,6 +39,7 @@ func (o *DevfileState) AddContainer(name string, image string, command []string,
|
||||
MemoryLimit: memLimit,
|
||||
CpuRequest: cpuRequest,
|
||||
CpuLimit: cpuLimit,
|
||||
VolumeMounts: v1alpha2VolumeMounts,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -184,3 +202,56 @@ func (o *DevfileState) checkResourceUsed(name string) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (o *DevfileState) AddVolume(name string, ephemeral bool, size string) (DevfileContent, error) {
|
||||
volume := v1alpha2.Component{
|
||||
Name: name,
|
||||
ComponentUnion: v1alpha2.ComponentUnion{
|
||||
Volume: &v1alpha2.VolumeComponent{
|
||||
Volume: v1alpha2.Volume{
|
||||
Ephemeral: &ephemeral,
|
||||
Size: size,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
err := o.Devfile.Data.AddComponents([]v1alpha2.Component{volume})
|
||||
if err != nil {
|
||||
return DevfileContent{}, err
|
||||
}
|
||||
return o.GetContent()
|
||||
}
|
||||
|
||||
func (o *DevfileState) DeleteVolume(name string) (DevfileContent, error) {
|
||||
|
||||
err := o.checkVolumeUsed(name)
|
||||
if err != nil {
|
||||
return DevfileContent{}, fmt.Errorf("error deleting volume %q: %w", name, err)
|
||||
}
|
||||
// TODO check if it is a Volume, not another component
|
||||
|
||||
err = o.Devfile.Data.DeleteComponent(name)
|
||||
if err != nil {
|
||||
return DevfileContent{}, err
|
||||
}
|
||||
return o.GetContent()
|
||||
}
|
||||
|
||||
func (o *DevfileState) checkVolumeUsed(name string) error {
|
||||
containers, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
|
||||
ComponentOptions: common.ComponentOptions{
|
||||
ComponentType: v1alpha2.ContainerComponentType,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, container := range containers {
|
||||
for _, mount := range container.Container.VolumeMounts {
|
||||
if mount.Name == name {
|
||||
return fmt.Errorf("volume %q is mounted by Container %q", name, container.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -5,18 +5,20 @@ import (
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
. "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
|
||||
openapi "github.com/redhat-developer/odo/pkg/apiserver-gen/go"
|
||||
)
|
||||
|
||||
func TestDevfileState_AddContainer(t *testing.T) {
|
||||
type args struct {
|
||||
name string
|
||||
image string
|
||||
command []string
|
||||
args []string
|
||||
memRequest string
|
||||
memLimit string
|
||||
cpuRequest string
|
||||
cpuLimit string
|
||||
name string
|
||||
image string
|
||||
command []string
|
||||
args []string
|
||||
memRequest string
|
||||
memLimit string
|
||||
cpuRequest string
|
||||
cpuLimit string
|
||||
volumeMounts []openapi.VolumeMount
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -39,6 +41,12 @@ func TestDevfileState_AddContainer(t *testing.T) {
|
||||
memLimit: "2Gi",
|
||||
cpuRequest: "100m",
|
||||
cpuLimit: "200m",
|
||||
volumeMounts: []openapi.VolumeMount{
|
||||
{
|
||||
Name: "vol1",
|
||||
Path: "/mnt/volume1",
|
||||
},
|
||||
},
|
||||
},
|
||||
want: DevfileContent{
|
||||
Content: `components:
|
||||
@@ -54,6 +62,9 @@ func TestDevfileState_AddContainer(t *testing.T) {
|
||||
image: an-image
|
||||
memoryLimit: 2Gi
|
||||
memoryRequest: 1Gi
|
||||
volumeMounts:
|
||||
- name: vol1
|
||||
path: /mnt/volume1
|
||||
name: a-name
|
||||
metadata: {}
|
||||
schemaVersion: 2.2.0
|
||||
@@ -69,10 +80,17 @@ schemaVersion: 2.2.0
|
||||
MemoryLimit: "2Gi",
|
||||
CpuRequest: "100m",
|
||||
CpuLimit: "200m",
|
||||
VolumeMounts: []openapi.VolumeMount{
|
||||
{
|
||||
Name: "vol1",
|
||||
Path: "/mnt/volume1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -81,7 +99,7 @@ schemaVersion: 2.2.0
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := tt.state()
|
||||
got, err := o.AddContainer(tt.args.name, tt.args.image, tt.args.command, tt.args.args, tt.args.memRequest, tt.args.memLimit, tt.args.cpuRequest, tt.args.cpuLimit)
|
||||
got, err := o.AddContainer(tt.args.name, tt.args.image, tt.args.command, tt.args.args, tt.args.memRequest, tt.args.memLimit, tt.args.cpuRequest, tt.args.cpuLimit, tt.args.volumeMounts)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("DevfileState.AddContainer() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
@@ -120,6 +138,7 @@ func TestDevfileState_DeleteContainer(t *testing.T) {
|
||||
"2Gi",
|
||||
"100m",
|
||||
"200m",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -137,6 +156,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -153,6 +173,7 @@ schemaVersion: 2.2.0
|
||||
"2Gi",
|
||||
"100m",
|
||||
"200m",
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
@@ -242,6 +263,7 @@ schemaVersion: 2.2.0
|
||||
},
|
||||
},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -304,6 +326,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -389,7 +412,8 @@ schemaVersion: 2.2.0
|
||||
Uri: "an-uri",
|
||||
},
|
||||
},
|
||||
Events: Events{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -418,7 +442,8 @@ schemaVersion: 2.2.0
|
||||
Inlined: "inline resource...",
|
||||
},
|
||||
},
|
||||
Events: Events{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
// TODO: Add test cases.
|
||||
@@ -477,6 +502,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
@@ -519,3 +545,148 @@ schemaVersion: 2.2.0
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevfileState_AddVolume(t *testing.T) {
|
||||
type args struct {
|
||||
name string
|
||||
size string
|
||||
ephemeral bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
state func() DevfileState
|
||||
args args
|
||||
want DevfileContent
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Add a volume",
|
||||
state: func() DevfileState {
|
||||
return NewDevfileState()
|
||||
},
|
||||
args: args{
|
||||
name: "a-name",
|
||||
size: "1Gi",
|
||||
ephemeral: true,
|
||||
},
|
||||
want: DevfileContent{
|
||||
Content: `components:
|
||||
- name: a-name
|
||||
volume:
|
||||
ephemeral: true
|
||||
size: 1Gi
|
||||
metadata: {}
|
||||
schemaVersion: 2.2.0
|
||||
`,
|
||||
Commands: []Command{},
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{
|
||||
{
|
||||
Name: "a-name",
|
||||
Size: "1Gi",
|
||||
Ephemeral: true,
|
||||
},
|
||||
},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := tt.state()
|
||||
got, err := o.AddVolume(tt.args.name, tt.args.ephemeral, tt.args.size)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("DevfileState.AddVolume() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if diff := cmp.Diff(tt.want.Content, got.Content); diff != "" {
|
||||
t.Errorf("DevfileState.AddVolume() mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tt.want, got); diff != "" {
|
||||
t.Errorf("DevfileState.AddVolume() mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestDevfileState_DeleteVolume(t *testing.T) {
|
||||
type args struct {
|
||||
name string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
state func(t *testing.T) DevfileState
|
||||
args args
|
||||
want DevfileContent
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "Delete an existing volume",
|
||||
state: func(t *testing.T) DevfileState {
|
||||
state := NewDevfileState()
|
||||
_, err := state.AddVolume(
|
||||
"a-name",
|
||||
true,
|
||||
"1Gi",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return state
|
||||
},
|
||||
args: args{
|
||||
name: "a-name",
|
||||
},
|
||||
want: DevfileContent{
|
||||
Content: `metadata: {}
|
||||
schemaVersion: 2.2.0
|
||||
`,
|
||||
Commands: []Command{},
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Delete a non existing resource",
|
||||
state: func(t *testing.T) DevfileState {
|
||||
state := NewDevfileState()
|
||||
_, err := state.AddVolume(
|
||||
"a-name",
|
||||
true,
|
||||
"1Gi",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return state
|
||||
},
|
||||
args: args{
|
||||
name: "another-name",
|
||||
},
|
||||
want: DevfileContent{},
|
||||
wantErr: true,
|
||||
},
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
o := tt.state(t)
|
||||
got, err := o.DeleteVolume(tt.args.name)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("DevfileState.DeleteVolume() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if diff := cmp.Diff(tt.want.Content, got.Content); diff != "" {
|
||||
t.Errorf("DevfileState.DeleteVolume() mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
if diff := cmp.Diff(tt.want, got); diff != "" {
|
||||
t.Errorf("DevfileState.DeleteVolume() mismatch (-want +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,97 +16,6 @@ const (
|
||||
SEPARATOR = ","
|
||||
)
|
||||
|
||||
/*
|
||||
type DevfileContent struct {
|
||||
Content string `json:"content"`
|
||||
Commands []Command `json:"commands"`
|
||||
Containers []Container `json:"containers"`
|
||||
Images []Image `json:"images"`
|
||||
Resources []Resource `json:"resources"`
|
||||
Events Events `json:"events"`
|
||||
Metadata Metadata `json:"metadata"`
|
||||
}
|
||||
|
||||
type Metadata struct {
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Description string `json:"description"`
|
||||
Tags string `json:"tags"`
|
||||
Architectures string `json:"architectures"`
|
||||
Icon string `json:"icon"`
|
||||
GlobalMemoryLimit string `json:"globalMemoryLimit"`
|
||||
ProjectType string `json:"projectType"`
|
||||
Language string `json:"language"`
|
||||
Website string `json:"website"`
|
||||
Provider string `json:"provider"`
|
||||
SupportUrl string `json:"supportUrl"`
|
||||
}
|
||||
|
||||
type Command struct {
|
||||
Name string `json:"name"`
|
||||
Group string `json:"group"`
|
||||
Default bool `json:"default"`
|
||||
Type string `json:"type"`
|
||||
Exec *ExecCommand `json:"exec"`
|
||||
Apply *ApplyCommand `json:"apply"`
|
||||
Image *ImageCommand `json:"image"`
|
||||
Composite *CompositeCommand `json:"composite"`
|
||||
}
|
||||
|
||||
type ExecCommand struct {
|
||||
Component string `json:"component"`
|
||||
CommandLine string `json:"commandLine"`
|
||||
WorkingDir string `json:"workingDir"`
|
||||
HotReloadCapable bool `json:"hotReloadCapable"`
|
||||
}
|
||||
|
||||
type ApplyCommand struct {
|
||||
Component string `json:"component"`
|
||||
}
|
||||
|
||||
type ImageCommand struct {
|
||||
Component string `json:"component"`
|
||||
}
|
||||
|
||||
type CompositeCommand struct {
|
||||
Commands []string `json:"commands"`
|
||||
Parallel bool `json:"parallel"`
|
||||
}
|
||||
|
||||
type Container struct {
|
||||
Name string `json:"name"`
|
||||
Image string `json:"image"`
|
||||
Command []string `json:"command"`
|
||||
Args []string `json:"args"`
|
||||
MemoryRequest string `json:"memoryRequest"`
|
||||
MemoryLimit string `json:"memoryLimit"`
|
||||
CpuRequest string `json:"cpuRequest"`
|
||||
CpuLimit string `json:"cpuLimit"`
|
||||
}
|
||||
|
||||
type Image struct {
|
||||
Name string `json:"name"`
|
||||
ImageName string `json:"imageName"`
|
||||
Args []string `json:"args"`
|
||||
BuildContext string `json:"buildContext"`
|
||||
RootRequired bool `json:"rootRequired"`
|
||||
URI string `json:"uri"`
|
||||
}
|
||||
|
||||
type Resource struct {
|
||||
Name string `json:"name"`
|
||||
Inlined string `json:"inlined"`
|
||||
URI string `json:"uri"`
|
||||
}
|
||||
|
||||
type Events struct {
|
||||
PreStart []string `json:"preStart"`
|
||||
PostStart []string `json:"postStart"`
|
||||
PreStop []string `json:"preStop"`
|
||||
PostStop []string `json:"postStop"`
|
||||
}
|
||||
*/
|
||||
// getContent returns the YAML content of the global devfile as string
|
||||
func (o *DevfileState) GetContent() (DevfileContent, error) {
|
||||
err := o.Devfile.WriteYamlDevfile()
|
||||
@@ -137,12 +46,18 @@ func (o *DevfileState) GetContent() (DevfileContent, error) {
|
||||
return DevfileContent{}, errors.New("error getting Kubernetes resources")
|
||||
}
|
||||
|
||||
volumes, err := o.getVolumes()
|
||||
if err != nil {
|
||||
return DevfileContent{}, errors.New("error getting volumes")
|
||||
}
|
||||
|
||||
return DevfileContent{
|
||||
Content: string(result),
|
||||
Commands: commands,
|
||||
Containers: containers,
|
||||
Images: images,
|
||||
Resources: resources,
|
||||
Volumes: volumes,
|
||||
Events: o.getEvents(),
|
||||
Metadata: o.getMetadata(),
|
||||
}, nil
|
||||
@@ -255,11 +170,23 @@ func (o *DevfileState) getContainers() ([]Container, error) {
|
||||
MemoryLimit: container.ComponentUnion.Container.MemoryLimit,
|
||||
CpuRequest: container.ComponentUnion.Container.CpuRequest,
|
||||
CpuLimit: container.ComponentUnion.Container.CpuLimit,
|
||||
VolumeMounts: o.getVolumeMounts(container.Container.Container),
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *DevfileState) getVolumeMounts(container v1alpha2.Container) []VolumeMount {
|
||||
result := make([]VolumeMount, 0, len(container.VolumeMounts))
|
||||
for _, vm := range container.VolumeMounts {
|
||||
result = append(result, VolumeMount{
|
||||
Name: vm.Name,
|
||||
Path: vm.Path,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (o *DevfileState) getImages() ([]Image, error) {
|
||||
images, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
|
||||
ComponentOptions: common.ComponentOptions{
|
||||
@@ -303,6 +230,26 @@ func (o *DevfileState) getResources() ([]Resource, error) {
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *DevfileState) getVolumes() ([]Volume, error) {
|
||||
volumes, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
|
||||
ComponentOptions: common.ComponentOptions{
|
||||
ComponentType: v1alpha2.VolumeComponentType,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := make([]Volume, 0, len(volumes))
|
||||
for _, volume := range volumes {
|
||||
result = append(result, Volume{
|
||||
Name: volume.Name,
|
||||
Ephemeral: *volume.Volume.Ephemeral,
|
||||
Size: volume.Volume.Size,
|
||||
})
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (o *DevfileState) getEvents() Events {
|
||||
events := o.Devfile.Data.GetEvents()
|
||||
return Events{
|
||||
|
||||
@@ -24,6 +24,7 @@ func TestDevfileState_GetContent(t *testing.T) {
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -39,6 +39,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{
|
||||
PreStart: []string{"command1"},
|
||||
},
|
||||
@@ -70,6 +71,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Events: Events{
|
||||
PreStart: []string{"command1"},
|
||||
PostStart: []string{"command2"},
|
||||
|
||||
@@ -75,6 +75,7 @@ schemaVersion: 2.2.0
|
||||
Containers: []Container{},
|
||||
Images: []Image{},
|
||||
Resources: []Resource{},
|
||||
Volumes: []Volume{},
|
||||
Metadata: Metadata{
|
||||
Name: "a-name",
|
||||
Version: "v1.1.1",
|
||||
|
||||
@@ -543,6 +543,11 @@ paths:
|
||||
cpuLimit:
|
||||
description: CPU limit for the deployed container
|
||||
type: string
|
||||
volumeMounts:
|
||||
description: Volume to mount into the container filesystem
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/VolumeMount'
|
||||
responses:
|
||||
'200':
|
||||
description: container was successfully added to the devfile
|
||||
@@ -813,6 +818,101 @@ paths:
|
||||
example:
|
||||
message: "Error deleting the resource"
|
||||
|
||||
/devstate/volume:
|
||||
post:
|
||||
tags:
|
||||
- devstate
|
||||
description: Add a new Volume to the Devfile
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Name of the volume
|
||||
type: string
|
||||
size:
|
||||
description: Minimal size of the volume
|
||||
type: string
|
||||
ephemeral:
|
||||
description: True if the Volume is Ephemeral
|
||||
type: boolean
|
||||
responses:
|
||||
'200':
|
||||
description: volume was successfully added to the devfile
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/DevfileContent'
|
||||
example:
|
||||
{
|
||||
"content": "schemaVersion: 2.2.0\n",
|
||||
"commands": [],
|
||||
"containers": [],
|
||||
"images": [],
|
||||
"resources": [],
|
||||
"events": {
|
||||
"preStart": null,
|
||||
"postStart": null,
|
||||
"preStop": null,
|
||||
"postStop": null
|
||||
},
|
||||
"metadata": {
|
||||
"name": "",
|
||||
"version": "",
|
||||
"displayName": "",
|
||||
description": "",
|
||||
"tags": "",
|
||||
"architectures": "",
|
||||
"icon": "",
|
||||
"globalMemoryLimit": "",
|
||||
"projectType": "",
|
||||
"language": "",
|
||||
"website": "",
|
||||
"provider": "",
|
||||
"supportUrl": ""
|
||||
}
|
||||
}
|
||||
'500':
|
||||
description: Error adding the volume
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
example:
|
||||
message: "Error adding the volume"
|
||||
|
||||
/devstate/volume/{volumeName}:
|
||||
delete:
|
||||
tags:
|
||||
- devstate
|
||||
description: "Delete a volume from the Devfile"
|
||||
parameters:
|
||||
- name: volumeName
|
||||
in: path
|
||||
description: Volume name to delete
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralSuccess'
|
||||
example:
|
||||
message: "Volume has been deleted"
|
||||
description: "Volume has been deleted"
|
||||
'500':
|
||||
description: Error deleting the volume
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
example:
|
||||
message: "Error deleting the volume"
|
||||
|
||||
/devstate/applyCommand:
|
||||
post:
|
||||
tags:
|
||||
@@ -1315,6 +1415,7 @@ components:
|
||||
- containers
|
||||
- images
|
||||
- resources
|
||||
- volumes
|
||||
- events
|
||||
- metadata
|
||||
properties:
|
||||
@@ -1336,6 +1437,10 @@ components:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Resource'
|
||||
volumes:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Volume'
|
||||
events:
|
||||
$ref: '#/components/schemas/Events'
|
||||
metadata:
|
||||
@@ -1416,6 +1521,7 @@ components:
|
||||
- memoryLimit
|
||||
- cpuRequest
|
||||
- cpuLimit
|
||||
- volumeMounts
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
@@ -1437,6 +1543,20 @@ components:
|
||||
type: string
|
||||
cpuLimit:
|
||||
type: string
|
||||
volumeMounts:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/VolumeMount'
|
||||
VolumeMount:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- path
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
path:
|
||||
type: string
|
||||
Image:
|
||||
type: object
|
||||
required:
|
||||
@@ -1472,6 +1592,17 @@ components:
|
||||
type: string
|
||||
uri:
|
||||
type: string
|
||||
Volume:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
ephemeral:
|
||||
type: boolean
|
||||
size:
|
||||
type: string
|
||||
Events:
|
||||
type: object
|
||||
properties:
|
||||
|
||||
2
pkg/apiserver-impl/ui/index.html
generated
2
pkg/apiserver-impl/ui/index.html
generated
@@ -11,6 +11,6 @@
|
||||
<body class="mat-typography">
|
||||
<div id="loading">Loading, please wait...</div>
|
||||
<app-root></app-root>
|
||||
<script src="runtime.1289ea0acffcdc5e.js" type="module"></script><script src="polyfills.8b3b37cedaf377c3.js" type="module"></script><script src="main.ae49ed4fe0fa0670.js" type="module"></script>
|
||||
<script src="runtime.1289ea0acffcdc5e.js" type="module"></script><script src="polyfills.8b3b37cedaf377c3.js" type="module"></script><script src="main.1046d99cec4375b1.js" type="module"></script>
|
||||
|
||||
</body></html>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user