mirror of
https://github.com/redhat-developer/odo.git
synced 2025-10-19 03:06:19 +03:00
[ui] Edit container (#7077)
* [api] patch container * [ui] edit container * [ui] Initialize endpoint component * e2e tests * static ui files
This commit is contained in:
1
pkg/apiserver-gen/.openapi-generator/FILES
generated
1
pkg/apiserver-gen/.openapi-generator/FILES
generated
@@ -16,6 +16,7 @@ go/model__devstate_command__command_name__move_post_request.go
|
||||
go/model__devstate_command__command_name__set_default_post_request.go
|
||||
go/model__devstate_composite_command__command_name__patch_request.go
|
||||
go/model__devstate_composite_command_post_request.go
|
||||
go/model__devstate_container__container_name__patch_request.go
|
||||
go/model__devstate_container_post_request.go
|
||||
go/model__devstate_events_put_request.go
|
||||
go/model__devstate_exec_command__command_name__patch_request.go
|
||||
|
||||
2
pkg/apiserver-gen/go/api.go
generated
2
pkg/apiserver-gen/go/api.go
generated
@@ -41,6 +41,7 @@ type DevstateApiRouter interface {
|
||||
DevstateCompositeCommandCommandNamePatch(http.ResponseWriter, *http.Request)
|
||||
DevstateCompositeCommandPost(http.ResponseWriter, *http.Request)
|
||||
DevstateContainerContainerNameDelete(http.ResponseWriter, *http.Request)
|
||||
DevstateContainerContainerNamePatch(http.ResponseWriter, *http.Request)
|
||||
DevstateContainerPost(http.ResponseWriter, *http.Request)
|
||||
DevstateDevfileDelete(http.ResponseWriter, *http.Request)
|
||||
DevstateDevfileGet(http.ResponseWriter, *http.Request)
|
||||
@@ -90,6 +91,7 @@ type DevstateApiServicer interface {
|
||||
DevstateCompositeCommandCommandNamePatch(context.Context, string, DevstateCompositeCommandCommandNamePatchRequest) (ImplResponse, error)
|
||||
DevstateCompositeCommandPost(context.Context, DevstateCompositeCommandPostRequest) (ImplResponse, error)
|
||||
DevstateContainerContainerNameDelete(context.Context, string) (ImplResponse, error)
|
||||
DevstateContainerContainerNamePatch(context.Context, string, DevstateContainerContainerNamePatchRequest) (ImplResponse, error)
|
||||
DevstateContainerPost(context.Context, DevstateContainerPostRequest) (ImplResponse, error)
|
||||
DevstateDevfileDelete(context.Context) (ImplResponse, error)
|
||||
DevstateDevfileGet(context.Context) (ImplResponse, error)
|
||||
|
||||
32
pkg/apiserver-gen/go/api_devstate.go
generated
32
pkg/apiserver-gen/go/api_devstate.go
generated
@@ -110,6 +110,12 @@ func (c *DevstateApiController) Routes() Routes {
|
||||
"/api/v1/devstate/container/{containerName}",
|
||||
c.DevstateContainerContainerNameDelete,
|
||||
},
|
||||
{
|
||||
"DevstateContainerContainerNamePatch",
|
||||
strings.ToUpper("Patch"),
|
||||
"/api/v1/devstate/container/{containerName}",
|
||||
c.DevstateContainerContainerNamePatch,
|
||||
},
|
||||
{
|
||||
"DevstateContainerPost",
|
||||
strings.ToUpper("Post"),
|
||||
@@ -431,6 +437,32 @@ func (c *DevstateApiController) DevstateContainerContainerNameDelete(w http.Resp
|
||||
|
||||
}
|
||||
|
||||
// DevstateContainerContainerNamePatch -
|
||||
func (c *DevstateApiController) DevstateContainerContainerNamePatch(w http.ResponseWriter, r *http.Request) {
|
||||
params := mux.Vars(r)
|
||||
containerNameParam := params["containerName"]
|
||||
devstateContainerContainerNamePatchRequestParam := DevstateContainerContainerNamePatchRequest{}
|
||||
d := json.NewDecoder(r.Body)
|
||||
d.DisallowUnknownFields()
|
||||
if err := d.Decode(&devstateContainerContainerNamePatchRequestParam); err != nil {
|
||||
c.errorHandler(w, r, &ParsingError{Err: err}, nil)
|
||||
return
|
||||
}
|
||||
if err := AssertDevstateContainerContainerNamePatchRequestRequired(devstateContainerContainerNamePatchRequestParam); err != nil {
|
||||
c.errorHandler(w, r, err, nil)
|
||||
return
|
||||
}
|
||||
result, err := c.service.DevstateContainerContainerNamePatch(r.Context(), containerNameParam, devstateContainerContainerNamePatchRequestParam)
|
||||
// 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)
|
||||
|
||||
}
|
||||
|
||||
// DevstateContainerPost -
|
||||
func (c *DevstateApiController) DevstateContainerPost(w http.ResponseWriter, r *http.Request) {
|
||||
devstateContainerPostRequestParam := DevstateContainerPostRequest{}
|
||||
|
||||
98
pkg/apiserver-gen/go/model__devstate_container__container_name__patch_request.go
generated
Normal file
98
pkg/apiserver-gen/go/model__devstate_container__container_name__patch_request.go
generated
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* odo dev
|
||||
*
|
||||
* API interface for 'odo dev'
|
||||
*
|
||||
* API version: 0.1
|
||||
* Generated by: OpenAPI Generator (https://openapi-generator.tech)
|
||||
*/
|
||||
|
||||
package openapi
|
||||
|
||||
type DevstateContainerContainerNamePatchRequest struct {
|
||||
|
||||
// Container image
|
||||
Image string `json:"image"`
|
||||
|
||||
// Entrypoint of the container
|
||||
Command []string `json:"command,omitempty"`
|
||||
|
||||
// Args passed to the Container entrypoint
|
||||
Args []string `json:"args,omitempty"`
|
||||
|
||||
// Environment variables to define
|
||||
Env []Env `json:"env,omitempty"`
|
||||
|
||||
// Requested memory for the deployed container
|
||||
MemReq string `json:"memReq,omitempty"`
|
||||
|
||||
// Memory limit for the deployed container
|
||||
MemLimit string `json:"memLimit,omitempty"`
|
||||
|
||||
// Requested CPU for the deployed container
|
||||
CpuReq string `json:"cpuReq,omitempty"`
|
||||
|
||||
// CPU limit for the deployed container
|
||||
CpuLimit string `json:"cpuLimit,omitempty"`
|
||||
|
||||
// Volume to mount into the container filesystem
|
||||
VolumeMounts []VolumeMount `json:"volumeMounts,omitempty"`
|
||||
|
||||
// If false, mountSources and sourceMapping values are not considered
|
||||
ConfigureSources bool `json:"configureSources,omitempty"`
|
||||
|
||||
// If true, sources are mounted into container's filesystem
|
||||
MountSources bool `json:"mountSources,omitempty"`
|
||||
|
||||
// Specific directory on which to mount sources
|
||||
SourceMapping string `json:"sourceMapping,omitempty"`
|
||||
|
||||
Annotation Annotation `json:"annotation,omitempty"`
|
||||
|
||||
// Endpoints exposed by the container
|
||||
Endpoints []Endpoint `json:"endpoints,omitempty"`
|
||||
}
|
||||
|
||||
// AssertDevstateContainerContainerNamePatchRequestRequired checks if the required fields are not zero-ed
|
||||
func AssertDevstateContainerContainerNamePatchRequestRequired(obj DevstateContainerContainerNamePatchRequest) error {
|
||||
elements := map[string]interface{}{
|
||||
"image": obj.Image,
|
||||
}
|
||||
for name, el := range elements {
|
||||
if isZero := IsZeroValue(el); isZero {
|
||||
return &RequiredError{Field: name}
|
||||
}
|
||||
}
|
||||
|
||||
for _, el := range obj.Env {
|
||||
if err := AssertEnvRequired(el); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
for _, el := range obj.VolumeMounts {
|
||||
if err := AssertVolumeMountRequired(el); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := AssertAnnotationRequired(obj.Annotation); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, el := range obj.Endpoints {
|
||||
if err := AssertEndpointRequired(el); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AssertRecurseDevstateContainerContainerNamePatchRequestRequired recursively checks if required fields are not zero-ed in a nested slice.
|
||||
// Accepts only nested slice of DevstateContainerContainerNamePatchRequest (e.g. [][]DevstateContainerContainerNamePatchRequest), otherwise ErrTypeAssertionError is thrown.
|
||||
func AssertRecurseDevstateContainerContainerNamePatchRequestRequired(objSlice interface{}) error {
|
||||
return AssertRecurseInterfaceRequired(objSlice, func(obj interface{}) error {
|
||||
aDevstateContainerContainerNamePatchRequest, ok := obj.(DevstateContainerContainerNamePatchRequest)
|
||||
if !ok {
|
||||
return ErrTypeAssertionError
|
||||
}
|
||||
return AssertDevstateContainerContainerNamePatchRequestRequired(aDevstateContainerContainerNamePatchRequest)
|
||||
})
|
||||
}
|
||||
@@ -384,7 +384,33 @@ func (s *DevstateApiService) DevstateCompositeCommandCommandNamePatch(ctx contex
|
||||
)
|
||||
if err != nil {
|
||||
return openapi.Response(http.StatusInternalServerError, openapi.GeneralError{
|
||||
Message: fmt.Sprintf("Error updating the Image Command: %s", err),
|
||||
Message: fmt.Sprintf("Error updating the Composite Command: %s", err),
|
||||
}), nil
|
||||
}
|
||||
return openapi.Response(http.StatusOK, newContent), nil
|
||||
}
|
||||
|
||||
func (s *DevstateApiService) DevstateContainerContainerNamePatch(ctx context.Context, name string, patch openapi.DevstateContainerContainerNamePatchRequest) (openapi.ImplResponse, error) {
|
||||
newContent, err := s.devfileState.PatchContainer(
|
||||
name,
|
||||
patch.Image,
|
||||
patch.Command,
|
||||
patch.Args,
|
||||
patch.Env,
|
||||
patch.MemReq,
|
||||
patch.MemLimit,
|
||||
patch.CpuReq,
|
||||
patch.CpuLimit,
|
||||
patch.VolumeMounts,
|
||||
patch.ConfigureSources,
|
||||
patch.MountSources,
|
||||
patch.SourceMapping,
|
||||
patch.Annotation,
|
||||
patch.Endpoints,
|
||||
)
|
||||
if err != nil {
|
||||
return openapi.Response(http.StatusInternalServerError, openapi.GeneralError{
|
||||
Message: fmt.Sprintf("Error updating the container: %s", err),
|
||||
}), nil
|
||||
}
|
||||
return openapi.Response(http.StatusOK, newContent), nil
|
||||
|
||||
@@ -27,44 +27,6 @@ func (o *DevfileState) AddContainer(
|
||||
annotation Annotation,
|
||||
endpoints []Endpoint,
|
||||
) (DevfileContent, error) {
|
||||
v1alpha2VolumeMounts := make([]v1alpha2.VolumeMount, 0, len(volumeMounts))
|
||||
for _, vm := range volumeMounts {
|
||||
v1alpha2VolumeMounts = append(v1alpha2VolumeMounts, v1alpha2.VolumeMount{
|
||||
Name: vm.Name,
|
||||
Path: vm.Path,
|
||||
})
|
||||
}
|
||||
|
||||
v1alpha2Envs := make([]v1alpha2.EnvVar, 0, len(envs))
|
||||
for _, env := range envs {
|
||||
v1alpha2Envs = append(v1alpha2Envs, v1alpha2.EnvVar{
|
||||
Name: env.Name,
|
||||
Value: env.Value,
|
||||
})
|
||||
}
|
||||
var annotations *v1alpha2.Annotation
|
||||
if len(annotation.Deployment) > 0 || len(annotation.Service) > 0 {
|
||||
annotations = &v1alpha2.Annotation{}
|
||||
if len(annotation.Deployment) > 0 {
|
||||
annotations.Deployment = annotation.Deployment
|
||||
}
|
||||
if len(annotation.Service) > 0 {
|
||||
annotations.Service = annotation.Service
|
||||
}
|
||||
}
|
||||
|
||||
v1alpha2Endpoints := make([]v1alpha2.Endpoint, 0, len(endpoints))
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
v1alpha2Endpoints = append(v1alpha2Endpoints, v1alpha2.Endpoint{
|
||||
Name: endpoint.Name,
|
||||
TargetPort: int(endpoint.TargetPort),
|
||||
Exposure: v1alpha2.EndpointExposure(endpoint.Exposure),
|
||||
Protocol: v1alpha2.EndpointProtocol(endpoint.Protocol),
|
||||
Secure: &endpoint.Secure,
|
||||
Path: endpoint.Path,
|
||||
})
|
||||
}
|
||||
|
||||
container := v1alpha2.Component{
|
||||
Name: name,
|
||||
@@ -74,15 +36,15 @@ func (o *DevfileState) AddContainer(
|
||||
Image: image,
|
||||
Command: command,
|
||||
Args: args,
|
||||
Env: v1alpha2Envs,
|
||||
Env: tov1alpha2EnvVars(envs),
|
||||
MemoryRequest: memRequest,
|
||||
MemoryLimit: memLimit,
|
||||
CpuRequest: cpuRequest,
|
||||
CpuLimit: cpuLimit,
|
||||
VolumeMounts: v1alpha2VolumeMounts,
|
||||
Annotation: annotations,
|
||||
VolumeMounts: tov1alpha2VolumeMounts(volumeMounts),
|
||||
Annotation: tov1alpha2Annotation(annotation),
|
||||
},
|
||||
Endpoints: v1alpha2Endpoints,
|
||||
Endpoints: tov1alpha2Endpoints(endpoints),
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -97,6 +59,115 @@ func (o *DevfileState) AddContainer(
|
||||
return o.GetContent()
|
||||
}
|
||||
|
||||
func (o *DevfileState) PatchContainer(
|
||||
name string,
|
||||
image string,
|
||||
command []string,
|
||||
args []string,
|
||||
envs []Env,
|
||||
memRequest string,
|
||||
memLimit string,
|
||||
cpuRequest string,
|
||||
cpuLimit string,
|
||||
volumeMounts []VolumeMount,
|
||||
configureSources bool,
|
||||
mountSources bool,
|
||||
sourceMapping string,
|
||||
annotation Annotation,
|
||||
endpoints []Endpoint,
|
||||
) (DevfileContent, error) {
|
||||
found, err := o.Devfile.Data.GetComponents(common.DevfileOptions{
|
||||
ComponentOptions: common.ComponentOptions{
|
||||
ComponentType: v1alpha2.ContainerComponentType,
|
||||
},
|
||||
FilterByName: name,
|
||||
})
|
||||
if err != nil {
|
||||
return DevfileContent{}, err
|
||||
}
|
||||
if len(found) != 1 {
|
||||
return DevfileContent{}, fmt.Errorf("%d Container found with name %q", len(found), name)
|
||||
}
|
||||
|
||||
container := found[0]
|
||||
container.Container.Image = image
|
||||
container.Container.Command = command
|
||||
container.Container.Args = args
|
||||
container.Container.Env = tov1alpha2EnvVars(envs)
|
||||
container.Container.MemoryRequest = memRequest
|
||||
container.Container.MemoryLimit = memLimit
|
||||
container.Container.CpuRequest = cpuRequest
|
||||
container.Container.CpuLimit = cpuLimit
|
||||
container.Container.VolumeMounts = tov1alpha2VolumeMounts(volumeMounts)
|
||||
|
||||
container.Container.MountSources = nil
|
||||
container.Container.SourceMapping = ""
|
||||
if configureSources {
|
||||
container.Container.MountSources = &mountSources
|
||||
container.Container.SourceMapping = sourceMapping
|
||||
}
|
||||
container.Container.Annotation = tov1alpha2Annotation(annotation)
|
||||
container.Container.Endpoints = tov1alpha2Endpoints(endpoints)
|
||||
|
||||
err = o.Devfile.Data.UpdateComponent(container)
|
||||
if err != nil {
|
||||
return DevfileContent{}, err
|
||||
}
|
||||
return o.GetContent()
|
||||
}
|
||||
|
||||
func tov1alpha2EnvVars(envs []Env) []v1alpha2.EnvVar {
|
||||
result := make([]v1alpha2.EnvVar, 0, len(envs))
|
||||
for _, env := range envs {
|
||||
result = append(result, v1alpha2.EnvVar{
|
||||
Name: env.Name,
|
||||
Value: env.Value,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func tov1alpha2VolumeMounts(volumeMounts []VolumeMount) []v1alpha2.VolumeMount {
|
||||
result := make([]v1alpha2.VolumeMount, 0, len(volumeMounts))
|
||||
for _, vm := range volumeMounts {
|
||||
result = append(result, v1alpha2.VolumeMount{
|
||||
Name: vm.Name,
|
||||
Path: vm.Path,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func tov1alpha2Annotation(annotation Annotation) *v1alpha2.Annotation {
|
||||
var result *v1alpha2.Annotation
|
||||
if len(annotation.Deployment) > 0 || len(annotation.Service) > 0 {
|
||||
result = &v1alpha2.Annotation{}
|
||||
if len(annotation.Deployment) > 0 {
|
||||
result.Deployment = annotation.Deployment
|
||||
}
|
||||
if len(annotation.Service) > 0 {
|
||||
result.Service = annotation.Service
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func tov1alpha2Endpoints(endpoints []Endpoint) []v1alpha2.Endpoint {
|
||||
result := make([]v1alpha2.Endpoint, 0, len(endpoints))
|
||||
for _, endpoint := range endpoints {
|
||||
endpoint := endpoint
|
||||
result = append(result, v1alpha2.Endpoint{
|
||||
Name: endpoint.Name,
|
||||
TargetPort: int(endpoint.TargetPort),
|
||||
Exposure: v1alpha2.EndpointExposure(endpoint.Exposure),
|
||||
Protocol: v1alpha2.EndpointProtocol(endpoint.Protocol),
|
||||
Secure: &endpoint.Secure,
|
||||
Path: endpoint.Path,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (o *DevfileState) DeleteContainer(name string) (DevfileContent, error) {
|
||||
|
||||
err := o.checkContainerUsed(name)
|
||||
|
||||
@@ -649,6 +649,126 @@ paths:
|
||||
example:
|
||||
message: "Error deleting the container"
|
||||
|
||||
patch:
|
||||
tags:
|
||||
- devstate
|
||||
description: Update a container
|
||||
parameters:
|
||||
- name: containerName
|
||||
in: path
|
||||
description: Container name to update
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- image
|
||||
properties:
|
||||
image:
|
||||
description: Container image
|
||||
type: string
|
||||
command:
|
||||
description: Entrypoint of the container
|
||||
type: array
|
||||
items: {
|
||||
type: string
|
||||
}
|
||||
args:
|
||||
description: Args passed to the Container entrypoint
|
||||
type: array
|
||||
items: {
|
||||
type: string
|
||||
}
|
||||
env:
|
||||
description: Environment variables to define
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Env'
|
||||
memReq:
|
||||
description: Requested memory for the deployed container
|
||||
type: string
|
||||
memLimit:
|
||||
description: Memory limit for the deployed container
|
||||
type: string
|
||||
cpuReq:
|
||||
description: Requested CPU for the deployed container
|
||||
type: string
|
||||
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'
|
||||
configureSources:
|
||||
description: If false, mountSources and sourceMapping values are not considered
|
||||
type: boolean
|
||||
mountSources:
|
||||
description: If true, sources are mounted into container's filesystem
|
||||
type: boolean
|
||||
sourceMapping:
|
||||
description: Specific directory on which to mount sources
|
||||
type: string
|
||||
annotation:
|
||||
description: Annotations added to the resources created for this container
|
||||
$ref: '#/components/schemas/Annotation'
|
||||
endpoints:
|
||||
description: Endpoints exposed by the container
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Endpoint'
|
||||
|
||||
responses:
|
||||
'200':
|
||||
description: container was successfully updated
|
||||
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 updating the container
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GeneralError'
|
||||
example:
|
||||
message: "Error updating the container"
|
||||
|
||||
/devstate/image:
|
||||
post:
|
||||
tags:
|
||||
|
||||
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.30e0dd4eb9375796.js" type="module"></script>
|
||||
<script src="runtime.1289ea0acffcdc5e.js" type="module"></script><script src="polyfills.8b3b37cedaf377c3.js" type="module"></script><script src="main.d81b67faa7ca223c.js" type="module"></script>
|
||||
|
||||
</body></html>
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user