Describe pod API (#1861)

This commit is contained in:
adfost
2022-05-02 18:35:36 -07:00
committed by GitHub
parent fef7863810
commit 00bcb54b67
23 changed files with 3811 additions and 2 deletions

View File

@@ -1200,6 +1200,49 @@ func init() {
}
}
},
"/namespaces/{namespace}/tenants/{tenant}/pods/{podName}/describe": {
"get": {
"tags": [
"OperatorAPI"
],
"summary": "Describe Pod",
"operationId": "DescribePod",
"parameters": [
{
"type": "string",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"name": "tenant",
"in": "path",
"required": true
},
{
"type": "string",
"name": "podName",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/describePodWrapper"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/namespaces/{namespace}/tenants/{tenant}/pods/{podName}/events": {
"get": {
"tags": [
@@ -2017,6 +2060,28 @@ func init() {
}
}
},
"condition": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"configMap": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"optional": {
"type": "boolean"
}
}
},
"configureTenantRequest": {
"type": "object",
"properties": {
@@ -2025,6 +2090,65 @@ func init() {
}
}
},
"container": {
"type": "object",
"properties": {
"args": {
"type": "array",
"items": {
"type": "string"
}
},
"containerID": {
"type": "string"
},
"environmentVariables": {
"type": "array",
"items": {
"$ref": "#/definitions/environmentVariable"
}
},
"hostPorts": {
"type": "array",
"items": {
"type": "string"
}
},
"image": {
"type": "string"
},
"imageID": {
"type": "string"
},
"lastState": {
"$ref": "#/definitions/state"
},
"mounts": {
"type": "array",
"items": {
"$ref": "#/definitions/mount"
}
},
"name": {
"type": "string"
},
"ports": {
"type": "array",
"items": {
"type": "string"
}
},
"ready": {
"type": "boolean"
},
"restartCount": {
"type": "integer"
},
"state": {
"$ref": "#/definitions/state"
}
}
},
"createTenantRequest": {
"type": "object",
"required": [
@@ -2157,6 +2281,95 @@ func init() {
}
}
},
"describePodWrapper": {
"type": "object",
"properties": {
"annotations": {
"type": "array",
"items": {
"$ref": "#/definitions/annotation"
}
},
"conditions": {
"type": "array",
"items": {
"$ref": "#/definitions/condition"
}
},
"containers": {
"type": "array",
"items": {
"$ref": "#/definitions/container"
}
},
"controllerRef": {
"type": "string"
},
"deletionGracePeriodSeconds": {
"type": "integer"
},
"deletionTimestamp": {
"type": "string"
},
"labels": {
"type": "array",
"items": {
"$ref": "#/definitions/label"
}
},
"message": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": "string"
},
"nodeName": {
"type": "string"
},
"nodeSelector": {
"type": "array",
"items": {
"$ref": "#/definitions/nodeSelector"
}
},
"phase": {
"type": "string"
},
"podIP": {
"type": "string"
},
"priority": {
"type": "integer"
},
"priorityClassName": {
"type": "string"
},
"qosClass": {
"type": "string"
},
"reason": {
"type": "string"
},
"startTime": {
"type": "string"
},
"tolerations": {
"type": "array",
"items": {
"$ref": "#/definitions/toleration"
}
},
"volumes": {
"type": "array",
"items": {
"$ref": "#/definitions/volume"
}
}
}
},
"directCSIDriveInfo": {
"type": "object",
"properties": {
@@ -2324,6 +2537,17 @@ func init() {
}
]
},
"environmentVariable": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"error": {
"type": "object",
"required": [
@@ -2886,6 +3110,23 @@ func init() {
}
}
},
"mount": {
"type": "object",
"properties": {
"mountPath": {
"type": "string"
},
"name": {
"type": "string"
},
"readOnly": {
"type": "boolean"
},
"subPath": {
"type": "string"
}
}
},
"namespace": {
"type": "object",
"required": [
@@ -3357,6 +3598,34 @@ func init() {
}
}
},
"projectedVolume": {
"type": "object",
"properties": {
"sources": {
"type": "array",
"items": {
"$ref": "#/definitions/projectedVolumeSource"
}
}
}
},
"projectedVolumeSource": {
"type": "object",
"properties": {
"configMap": {
"$ref": "#/definitions/configMap"
},
"downwardApi": {
"type": "boolean"
},
"secret": {
"$ref": "#/definitions/secret"
},
"serviceAccountToken": {
"$ref": "#/definitions/serviceAccountToken"
}
}
},
"prometheusConfiguration": {
"type": "object",
"properties": {
@@ -3383,6 +3652,17 @@ func init() {
}
}
},
"pvc": {
"type": "object",
"properties": {
"claimName": {
"type": "string"
},
"readOnly": {
"type": "boolean"
}
}
},
"pvcsListResponse": {
"type": "object",
"properties": {
@@ -3442,6 +3722,17 @@ func init() {
}
}
},
"secret": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"optional": {
"type": "boolean"
}
}
},
"securityContext": {
"type": "object",
"required": [
@@ -3465,6 +3756,40 @@ func init() {
}
}
},
"serviceAccountToken": {
"type": "object",
"properties": {
"expirationSeconds": {
"type": "integer"
}
}
},
"state": {
"type": "object",
"properties": {
"exitCode": {
"type": "integer"
},
"finished": {
"type": "string"
},
"message": {
"type": "string"
},
"reason": {
"type": "string"
},
"signal": {
"type": "integer"
},
"started": {
"type": "string"
},
"state": {
"type": "string"
}
}
},
"subscriptionValidateRequest": {
"type": "object",
"properties": {
@@ -3901,6 +4226,26 @@ func init() {
}
}
},
"toleration": {
"type": "object",
"properties": {
"effect": {
"type": "string"
},
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"tolerationSeconds": {
"type": "integer"
},
"value": {
"type": "string"
}
}
},
"updateDomainsRequest": {
"type": "object",
"properties": {
@@ -4088,6 +4433,20 @@ func init() {
}
}
}
},
"volume": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"projected": {
"$ref": "#/definitions/projectedVolume"
},
"pvc": {
"$ref": "#/definitions/pvc"
}
}
}
},
"securityDefinitions": {
@@ -5270,6 +5629,49 @@ func init() {
}
}
},
"/namespaces/{namespace}/tenants/{tenant}/pods/{podName}/describe": {
"get": {
"tags": [
"OperatorAPI"
],
"summary": "Describe Pod",
"operationId": "DescribePod",
"parameters": [
{
"type": "string",
"name": "namespace",
"in": "path",
"required": true
},
{
"type": "string",
"name": "tenant",
"in": "path",
"required": true
},
{
"type": "string",
"name": "podName",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "A successful response.",
"schema": {
"$ref": "#/definitions/describePodWrapper"
}
},
"default": {
"description": "Generic error response.",
"schema": {
"$ref": "#/definitions/error"
}
}
}
}
},
"/namespaces/{namespace}/tenants/{tenant}/pods/{podName}/events": {
"get": {
"tags": [
@@ -6930,6 +7332,28 @@ func init() {
}
}
},
"condition": {
"type": "object",
"properties": {
"status": {
"type": "string"
},
"type": {
"type": "string"
}
}
},
"configMap": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"optional": {
"type": "boolean"
}
}
},
"configureTenantRequest": {
"type": "object",
"properties": {
@@ -6938,6 +7362,65 @@ func init() {
}
}
},
"container": {
"type": "object",
"properties": {
"args": {
"type": "array",
"items": {
"type": "string"
}
},
"containerID": {
"type": "string"
},
"environmentVariables": {
"type": "array",
"items": {
"$ref": "#/definitions/environmentVariable"
}
},
"hostPorts": {
"type": "array",
"items": {
"type": "string"
}
},
"image": {
"type": "string"
},
"imageID": {
"type": "string"
},
"lastState": {
"$ref": "#/definitions/state"
},
"mounts": {
"type": "array",
"items": {
"$ref": "#/definitions/mount"
}
},
"name": {
"type": "string"
},
"ports": {
"type": "array",
"items": {
"type": "string"
}
},
"ready": {
"type": "boolean"
},
"restartCount": {
"type": "integer"
},
"state": {
"$ref": "#/definitions/state"
}
}
},
"createTenantRequest": {
"type": "object",
"required": [
@@ -7070,6 +7553,95 @@ func init() {
}
}
},
"describePodWrapper": {
"type": "object",
"properties": {
"annotations": {
"type": "array",
"items": {
"$ref": "#/definitions/annotation"
}
},
"conditions": {
"type": "array",
"items": {
"$ref": "#/definitions/condition"
}
},
"containers": {
"type": "array",
"items": {
"$ref": "#/definitions/container"
}
},
"controllerRef": {
"type": "string"
},
"deletionGracePeriodSeconds": {
"type": "integer"
},
"deletionTimestamp": {
"type": "string"
},
"labels": {
"type": "array",
"items": {
"$ref": "#/definitions/label"
}
},
"message": {
"type": "string"
},
"name": {
"type": "string"
},
"namespace": {
"type": "string"
},
"nodeName": {
"type": "string"
},
"nodeSelector": {
"type": "array",
"items": {
"$ref": "#/definitions/nodeSelector"
}
},
"phase": {
"type": "string"
},
"podIP": {
"type": "string"
},
"priority": {
"type": "integer"
},
"priorityClassName": {
"type": "string"
},
"qosClass": {
"type": "string"
},
"reason": {
"type": "string"
},
"startTime": {
"type": "string"
},
"tolerations": {
"type": "array",
"items": {
"$ref": "#/definitions/toleration"
}
},
"volumes": {
"type": "array",
"items": {
"$ref": "#/definitions/volume"
}
}
}
},
"directCSIDriveInfo": {
"type": "object",
"properties": {
@@ -7237,6 +7809,17 @@ func init() {
}
]
},
"environmentVariable": {
"type": "object",
"properties": {
"key": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"error": {
"type": "object",
"required": [
@@ -7787,6 +8370,23 @@ func init() {
}
}
},
"mount": {
"type": "object",
"properties": {
"mountPath": {
"type": "string"
},
"name": {
"type": "string"
},
"readOnly": {
"type": "boolean"
},
"subPath": {
"type": "string"
}
}
},
"namespace": {
"type": "object",
"required": [
@@ -8123,6 +8723,34 @@ func init() {
}
}
},
"projectedVolume": {
"type": "object",
"properties": {
"sources": {
"type": "array",
"items": {
"$ref": "#/definitions/projectedVolumeSource"
}
}
}
},
"projectedVolumeSource": {
"type": "object",
"properties": {
"configMap": {
"$ref": "#/definitions/configMap"
},
"downwardApi": {
"type": "boolean"
},
"secret": {
"$ref": "#/definitions/secret"
},
"serviceAccountToken": {
"$ref": "#/definitions/serviceAccountToken"
}
}
},
"prometheusConfiguration": {
"type": "object",
"properties": {
@@ -8149,6 +8777,17 @@ func init() {
}
}
},
"pvc": {
"type": "object",
"properties": {
"claimName": {
"type": "string"
},
"readOnly": {
"type": "boolean"
}
}
},
"pvcsListResponse": {
"type": "object",
"properties": {
@@ -8208,6 +8847,17 @@ func init() {
}
}
},
"secret": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"optional": {
"type": "boolean"
}
}
},
"securityContext": {
"type": "object",
"required": [
@@ -8231,6 +8881,40 @@ func init() {
}
}
},
"serviceAccountToken": {
"type": "object",
"properties": {
"expirationSeconds": {
"type": "integer"
}
}
},
"state": {
"type": "object",
"properties": {
"exitCode": {
"type": "integer"
},
"finished": {
"type": "string"
},
"message": {
"type": "string"
},
"reason": {
"type": "string"
},
"signal": {
"type": "integer"
},
"started": {
"type": "string"
},
"state": {
"type": "string"
}
}
},
"subscriptionValidateRequest": {
"type": "object",
"properties": {
@@ -8667,6 +9351,26 @@ func init() {
}
}
},
"toleration": {
"type": "object",
"properties": {
"effect": {
"type": "string"
},
"key": {
"type": "string"
},
"operator": {
"type": "string"
},
"tolerationSeconds": {
"type": "integer"
},
"value": {
"type": "string"
}
}
},
"updateDomainsRequest": {
"type": "object",
"properties": {
@@ -8854,6 +9558,20 @@ func init() {
}
}
}
},
"volume": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"projected": {
"$ref": "#/definitions/projectedVolume"
},
"pvc": {
"$ref": "#/definitions/pvc"
}
}
}
},
"securityDefinitions": {

View File

@@ -82,6 +82,9 @@ func NewOperatorAPI(spec *loads.Document) *OperatorAPI {
OperatorAPIDeleteTenantHandler: operator_api.DeleteTenantHandlerFunc(func(params operator_api.DeleteTenantParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.DeleteTenant has not yet been implemented")
}),
OperatorAPIDescribePodHandler: operator_api.DescribePodHandlerFunc(func(params operator_api.DescribePodParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.DescribePod has not yet been implemented")
}),
OperatorAPIDisableTenantLoggingHandler: operator_api.DisableTenantLoggingHandlerFunc(func(params operator_api.DisableTenantLoggingParams, principal *models.Principal) middleware.Responder {
return middleware.NotImplemented("operation operator_api.DisableTenantLogging has not yet been implemented")
}),
@@ -278,6 +281,8 @@ type OperatorAPI struct {
OperatorAPIDeletePodHandler operator_api.DeletePodHandler
// OperatorAPIDeleteTenantHandler sets the operation handler for the delete tenant operation
OperatorAPIDeleteTenantHandler operator_api.DeleteTenantHandler
// OperatorAPIDescribePodHandler sets the operation handler for the describe pod operation
OperatorAPIDescribePodHandler operator_api.DescribePodHandler
// OperatorAPIDisableTenantLoggingHandler sets the operation handler for the disable tenant logging operation
OperatorAPIDisableTenantLoggingHandler operator_api.DisableTenantLoggingHandler
// OperatorAPIEnableTenantLoggingHandler sets the operation handler for the enable tenant logging operation
@@ -467,6 +472,9 @@ func (o *OperatorAPI) Validate() error {
if o.OperatorAPIDeleteTenantHandler == nil {
unregistered = append(unregistered, "operator_api.DeleteTenantHandler")
}
if o.OperatorAPIDescribePodHandler == nil {
unregistered = append(unregistered, "operator_api.DescribePodHandler")
}
if o.OperatorAPIDisableTenantLoggingHandler == nil {
unregistered = append(unregistered, "operator_api.DisableTenantLoggingHandler")
}
@@ -724,6 +732,10 @@ func (o *OperatorAPI) initHandlerCache() {
o.handlers["DELETE"] = make(map[string]http.Handler)
}
o.handlers["DELETE"]["/namespaces/{namespace}/tenants/{tenant}"] = operator_api.NewDeleteTenant(o.context, o.OperatorAPIDeleteTenantHandler)
if o.handlers["GET"] == nil {
o.handlers["GET"] = make(map[string]http.Handler)
}
o.handlers["GET"]["/namespaces/{namespace}/tenants/{tenant}/pods/{podName}/describe"] = operator_api.NewDescribePod(o.context, o.OperatorAPIDescribePodHandler)
if o.handlers["POST"] == nil {
o.handlers["POST"] = make(map[string]http.Handler)
}

View File

@@ -0,0 +1,88 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"net/http"
"github.com/go-openapi/runtime/middleware"
"github.com/minio/console/models"
)
// DescribePodHandlerFunc turns a function with the right signature into a describe pod handler
type DescribePodHandlerFunc func(DescribePodParams, *models.Principal) middleware.Responder
// Handle executing the request and returning a response
func (fn DescribePodHandlerFunc) Handle(params DescribePodParams, principal *models.Principal) middleware.Responder {
return fn(params, principal)
}
// DescribePodHandler interface for that can handle valid describe pod params
type DescribePodHandler interface {
Handle(DescribePodParams, *models.Principal) middleware.Responder
}
// NewDescribePod creates a new http.Handler for the describe pod operation
func NewDescribePod(ctx *middleware.Context, handler DescribePodHandler) *DescribePod {
return &DescribePod{Context: ctx, Handler: handler}
}
/* DescribePod swagger:route GET /namespaces/{namespace}/tenants/{tenant}/pods/{podName}/describe OperatorAPI describePod
Describe Pod
*/
type DescribePod struct {
Context *middleware.Context
Handler DescribePodHandler
}
func (o *DescribePod) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
route, rCtx, _ := o.Context.RouteInfo(r)
if rCtx != nil {
*r = *rCtx
}
var Params = NewDescribePodParams()
uprinc, aCtx, err := o.Context.Authorize(r, route)
if err != nil {
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
if aCtx != nil {
*r = *aCtx
}
var principal *models.Principal
if uprinc != nil {
principal = uprinc.(*models.Principal) // this is really a models.Principal, I promise
}
if err := o.Context.BindValidRequest(r, route, &Params); err != nil { // bind params
o.Context.Respond(rw, r, route.Produces, route, err)
return
}
res := o.Handler.Handle(Params, principal) // actually handle the request
o.Context.Respond(rw, r, route.Produces, route, res)
}

View File

@@ -0,0 +1,136 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/errors"
"github.com/go-openapi/runtime/middleware"
"github.com/go-openapi/strfmt"
)
// NewDescribePodParams creates a new DescribePodParams object
//
// There are no default values defined in the spec.
func NewDescribePodParams() DescribePodParams {
return DescribePodParams{}
}
// DescribePodParams contains all the bound params for the describe pod operation
// typically these are obtained from a http.Request
//
// swagger:parameters DescribePod
type DescribePodParams struct {
// HTTP Request Object
HTTPRequest *http.Request `json:"-"`
/*
Required: true
In: path
*/
Namespace string
/*
Required: true
In: path
*/
PodName string
/*
Required: true
In: path
*/
Tenant string
}
// BindRequest both binds and validates a request, it assumes that complex things implement a Validatable(strfmt.Registry) error interface
// for simple values it will use straight method calls.
//
// To ensure default values, the struct must have been initialized with NewDescribePodParams() beforehand.
func (o *DescribePodParams) BindRequest(r *http.Request, route *middleware.MatchedRoute) error {
var res []error
o.HTTPRequest = r
rNamespace, rhkNamespace, _ := route.Params.GetOK("namespace")
if err := o.bindNamespace(rNamespace, rhkNamespace, route.Formats); err != nil {
res = append(res, err)
}
rPodName, rhkPodName, _ := route.Params.GetOK("podName")
if err := o.bindPodName(rPodName, rhkPodName, route.Formats); err != nil {
res = append(res, err)
}
rTenant, rhkTenant, _ := route.Params.GetOK("tenant")
if err := o.bindTenant(rTenant, rhkTenant, route.Formats); err != nil {
res = append(res, err)
}
if len(res) > 0 {
return errors.CompositeValidationError(res...)
}
return nil
}
// bindNamespace binds and validates parameter Namespace from path.
func (o *DescribePodParams) bindNamespace(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Namespace = raw
return nil
}
// bindPodName binds and validates parameter PodName from path.
func (o *DescribePodParams) bindPodName(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.PodName = raw
return nil
}
// bindTenant binds and validates parameter Tenant from path.
func (o *DescribePodParams) bindTenant(rawData []string, hasKey bool, formats strfmt.Registry) error {
var raw string
if len(rawData) > 0 {
raw = rawData[len(rawData)-1]
}
// Required: true
// Parameter is provided by construction from the route
o.Tenant = raw
return nil
}

View File

@@ -0,0 +1,133 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"net/http"
"github.com/go-openapi/runtime"
"github.com/minio/console/models"
)
// DescribePodOKCode is the HTTP code returned for type DescribePodOK
const DescribePodOKCode int = 200
/*DescribePodOK A successful response.
swagger:response describePodOK
*/
type DescribePodOK struct {
/*
In: Body
*/
Payload *models.DescribePodWrapper `json:"body,omitempty"`
}
// NewDescribePodOK creates DescribePodOK with default headers values
func NewDescribePodOK() *DescribePodOK {
return &DescribePodOK{}
}
// WithPayload adds the payload to the describe pod o k response
func (o *DescribePodOK) WithPayload(payload *models.DescribePodWrapper) *DescribePodOK {
o.Payload = payload
return o
}
// SetPayload sets the payload to the describe pod o k response
func (o *DescribePodOK) SetPayload(payload *models.DescribePodWrapper) {
o.Payload = payload
}
// WriteResponse to the client
func (o *DescribePodOK) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(200)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}
/*DescribePodDefault Generic error response.
swagger:response describePodDefault
*/
type DescribePodDefault struct {
_statusCode int
/*
In: Body
*/
Payload *models.Error `json:"body,omitempty"`
}
// NewDescribePodDefault creates DescribePodDefault with default headers values
func NewDescribePodDefault(code int) *DescribePodDefault {
if code <= 0 {
code = 500
}
return &DescribePodDefault{
_statusCode: code,
}
}
// WithStatusCode adds the status to the describe pod default response
func (o *DescribePodDefault) WithStatusCode(code int) *DescribePodDefault {
o._statusCode = code
return o
}
// SetStatusCode sets the status to the describe pod default response
func (o *DescribePodDefault) SetStatusCode(code int) {
o._statusCode = code
}
// WithPayload adds the payload to the describe pod default response
func (o *DescribePodDefault) WithPayload(payload *models.Error) *DescribePodDefault {
o.Payload = payload
return o
}
// SetPayload sets the payload to the describe pod default response
func (o *DescribePodDefault) SetPayload(payload *models.Error) {
o.Payload = payload
}
// WriteResponse to the client
func (o *DescribePodDefault) WriteResponse(rw http.ResponseWriter, producer runtime.Producer) {
rw.WriteHeader(o._statusCode)
if o.Payload != nil {
payload := o.Payload
if err := producer.Produce(rw, payload); err != nil {
panic(err) // let the recovery middleware deal with this
}
}
}

View File

@@ -0,0 +1,132 @@
// Code generated by go-swagger; DO NOT EDIT.
// This file is part of MinIO Console Server
// Copyright (c) 2022 MinIO, Inc.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
package operator_api
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the generate command
import (
"errors"
"net/url"
golangswaggerpaths "path"
"strings"
)
// DescribePodURL generates an URL for the describe pod operation
type DescribePodURL struct {
Namespace string
PodName string
Tenant string
_basePath string
// avoid unkeyed usage
_ struct{}
}
// WithBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *DescribePodURL) WithBasePath(bp string) *DescribePodURL {
o.SetBasePath(bp)
return o
}
// SetBasePath sets the base path for this url builder, only required when it's different from the
// base path specified in the swagger spec.
// When the value of the base path is an empty string
func (o *DescribePodURL) SetBasePath(bp string) {
o._basePath = bp
}
// Build a url path and query string
func (o *DescribePodURL) Build() (*url.URL, error) {
var _result url.URL
var _path = "/namespaces/{namespace}/tenants/{tenant}/pods/{podName}/describe"
namespace := o.Namespace
if namespace != "" {
_path = strings.Replace(_path, "{namespace}", namespace, -1)
} else {
return nil, errors.New("namespace is required on DescribePodURL")
}
podName := o.PodName
if podName != "" {
_path = strings.Replace(_path, "{podName}", podName, -1)
} else {
return nil, errors.New("podName is required on DescribePodURL")
}
tenant := o.Tenant
if tenant != "" {
_path = strings.Replace(_path, "{tenant}", tenant, -1)
} else {
return nil, errors.New("tenant is required on DescribePodURL")
}
_basePath := o._basePath
if _basePath == "" {
_basePath = "/api/v1"
}
_result.Path = golangswaggerpaths.Join(_basePath, _path)
return &_result, nil
}
// Must is a helper function to panic when the url builder returns an error
func (o *DescribePodURL) Must(u *url.URL, err error) *url.URL {
if err != nil {
panic(err)
}
if u == nil {
panic("url can't be nil")
}
return u
}
// String returns the string representation of the path with query string
func (o *DescribePodURL) String() string {
return o.Must(o.Build()).String()
}
// BuildFull builds a full url with scheme, host, path and query string
func (o *DescribePodURL) BuildFull(scheme, host string) (*url.URL, error) {
if scheme == "" {
return nil, errors.New("scheme is required for a full url on DescribePodURL")
}
if host == "" {
return nil, errors.New("host is required for a full url on DescribePodURL")
}
base, err := o.Build()
if err != nil {
return nil, err
}
base.Scheme = scheme
base.Host = host
return base, nil
}
// StringFull returns the string representation of a complete url
func (o *DescribePodURL) StringFull(scheme, host string) string {
return o.Must(o.BuildFull(scheme, host)).String()
}

View File

@@ -44,11 +44,13 @@ import (
"github.com/minio/console/pkg/auth/utils"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"k8s.io/apimachinery/pkg/api/resource"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/utils/strings/slices"
corev1 "k8s.io/api/core/v1"
@@ -256,6 +258,14 @@ func registerTenantHandlers(api *operations.OperatorAPI) {
return operator_api.NewGetPodEventsOK().WithPayload(payload)
})
api.OperatorAPIDescribePodHandler = operator_api.DescribePodHandlerFunc(func(params operator_api.DescribePodParams, session *models.Principal) middleware.Responder {
payload, err := getDescribePodResponse(session, params)
if err != nil {
return operator_api.NewDescribePodDefault(int(err.Code)).WithPayload(err)
}
return operator_api.NewDescribePodOK().WithPayload(payload)
})
//Get tenant monitoring info
api.OperatorAPIGetTenantMonitoringHandler = operator_api.GetTenantMonitoringHandlerFunc(func(params operator_api.GetTenantMonitoringParams, session *models.Principal) middleware.Responder {
payload, err := getTenantMonitoringResponse(session, params)
@@ -1800,6 +1810,289 @@ func getPodEventsResponse(session *models.Principal, params operator_api.GetPodE
return retval, nil
}
func getDescribePodResponse(session *models.Principal, params operator_api.DescribePodParams) (*models.DescribePodWrapper, *models.Error) {
ctx := context.Background()
clientset, err := cluster.K8sClient(session.STSSessionToken)
if err != nil {
return nil, restapi.ErrorWithContext(ctx, err)
}
pod, err := clientset.CoreV1().Pods(params.Namespace).Get(ctx, params.PodName, metav1.GetOptions{})
if err != nil {
return nil, restapi.ErrorWithContext(ctx, err)
}
retval := &models.DescribePodWrapper{
Name: pod.Name,
Namespace: pod.Namespace,
PriorityClassName: pod.Spec.PriorityClassName,
NodeName: pod.Spec.NodeName,
}
if pod.Spec.Priority != nil {
retval.Priority = int64(*pod.Spec.Priority)
}
if pod.Status.StartTime != nil {
retval.StartTime = pod.Status.StartTime.Time.String()
}
labelArray := make([]*models.Label, len(pod.Labels))
i := 0
for key := range pod.Labels {
labelArray[i] = &models.Label{Key: key, Value: pod.Labels[key]}
i++
}
retval.Labels = labelArray
annotationArray := make([]*models.Annotation, len(pod.Annotations))
i = 0
for key := range pod.Annotations {
annotationArray[i] = &models.Annotation{Key: key, Value: pod.Annotations[key]}
i++
}
retval.Annotations = annotationArray
if pod.DeletionTimestamp != nil {
retval.DeletionTimestamp = translateTimestampSince(*pod.DeletionTimestamp)
retval.DeletionGracePeriodSeconds = *pod.DeletionGracePeriodSeconds
}
retval.Phase = string(pod.Status.Phase)
retval.Reason = pod.Status.Reason
retval.Message = pod.Status.Message
retval.PodIP = pod.Status.PodIP
retval.ControllerRef = metav1.GetControllerOf(pod).String()
retval.Containers = make([]*models.Container, len(pod.Spec.Containers))
statusMap := map[string]corev1.ContainerStatus{}
statusKeys := make([]string, len(pod.Status.ContainerStatuses))
for i, status := range pod.Status.ContainerStatuses {
statusMap[status.Name] = status
statusKeys[i] = status.Name
}
for i := range pod.Spec.Containers {
retval.Containers[i] = &models.Container{
Name: pod.Spec.Containers[i].Name,
Image: pod.Spec.Containers[i].Image,
Ports: describeContainerPorts(pod.Spec.Containers[i].Ports),
HostPorts: describeContainerHostPorts(pod.Spec.Containers[i].Ports),
Args: pod.Spec.Containers[i].Args,
}
if slices.Contains(statusKeys, pod.Spec.Containers[i].Name) {
retval.Containers[i].ContainerID = statusMap[pod.Spec.Containers[i].Name].ContainerID
retval.Containers[i].ImageID = statusMap[pod.Spec.Containers[i].Name].ImageID
retval.Containers[i].Ready = statusMap[pod.Spec.Containers[i].Name].Ready
retval.Containers[i].RestartCount = int64(statusMap[pod.Spec.Containers[i].Name].RestartCount)
retval.Containers[i].State, retval.Containers[i].LastState = describeStatus(statusMap[pod.Spec.Containers[i].Name])
}
retval.Containers[i].EnvironmentVariables = make([]*models.EnvironmentVariable, len(pod.Spec.Containers[0].Env))
for j := range pod.Spec.Containers[i].Env {
retval.Containers[i].EnvironmentVariables[j] = &models.EnvironmentVariable{
Key: pod.Spec.Containers[i].Env[j].Name,
Value: pod.Spec.Containers[i].Env[j].Value,
}
}
retval.Containers[i].Mounts = make([]*models.Mount, len(pod.Spec.Containers[i].VolumeMounts))
for j := range pod.Spec.Containers[i].VolumeMounts {
retval.Containers[i].Mounts[j] = &models.Mount{
Name: pod.Spec.Containers[i].VolumeMounts[j].Name,
MountPath: pod.Spec.Containers[i].VolumeMounts[j].MountPath,
SubPath: pod.Spec.Containers[i].VolumeMounts[j].SubPath,
ReadOnly: pod.Spec.Containers[i].VolumeMounts[j].ReadOnly,
}
}
}
retval.Conditions = make([]*models.Condition, len(pod.Status.Conditions))
for i := range pod.Status.Conditions {
retval.Conditions[i] = &models.Condition{
Type: string(pod.Status.Conditions[i].Type),
Status: string(pod.Status.Conditions[i].Status),
}
}
retval.Volumes = make([]*models.Volume, len(pod.Spec.Volumes))
for i := range pod.Spec.Volumes {
retval.Volumes[i] = &models.Volume{
Name: pod.Spec.Volumes[i].Name,
}
if pod.Spec.Volumes[i].PersistentVolumeClaim != nil {
retval.Volumes[i].Pvc = &models.Pvc{
ReadOnly: pod.Spec.Volumes[i].PersistentVolumeClaim.ReadOnly,
ClaimName: pod.Spec.Volumes[i].PersistentVolumeClaim.ClaimName,
}
} else if pod.Spec.Volumes[i].Projected != nil {
retval.Volumes[i].Projected = &models.ProjectedVolume{}
retval.Volumes[i].Projected.Sources = make([]*models.ProjectedVolumeSource, len(pod.Spec.Volumes[i].Projected.Sources))
for j := range pod.Spec.Volumes[i].Projected.Sources {
retval.Volumes[i].Projected.Sources[j] = &models.ProjectedVolumeSource{}
if pod.Spec.Volumes[i].Projected.Sources[j].Secret != nil {
retval.Volumes[i].Projected.Sources[j].Secret = &models.Secret{Name: pod.Spec.Volumes[i].Projected.Sources[j].Secret.Name,
Optional: pod.Spec.Volumes[i].Projected.Sources[j].Secret.Optional != nil}
}
if pod.Spec.Volumes[i].Projected.Sources[j].DownwardAPI != nil {
retval.Volumes[i].Projected.Sources[j].DownwardAPI = true
}
if pod.Spec.Volumes[i].Projected.Sources[j].ConfigMap != nil {
retval.Volumes[i].Projected.Sources[j].ConfigMap = &models.ConfigMap{Name: pod.Spec.Volumes[i].Projected.Sources[j].ConfigMap.Name,
Optional: pod.Spec.Volumes[i].Projected.Sources[j].ConfigMap.Optional != nil}
}
if pod.Spec.Volumes[i].Projected.Sources[j].ServiceAccountToken != nil {
retval.Volumes[i].Projected.Sources[j].ServiceAccountToken =
&models.ServiceAccountToken{ExpirationSeconds: *pod.Spec.Volumes[i].Projected.Sources[j].ServiceAccountToken.ExpirationSeconds}
}
}
}
}
retval.QosClass = string(getPodQOS(pod))
nodeSelectorArray := make([]*models.NodeSelector, len(pod.Spec.NodeSelector))
i = 0
for key := range pod.Spec.NodeSelector {
nodeSelectorArray[i] = &models.NodeSelector{Key: key, Value: pod.Spec.NodeSelector[key]}
i++
}
retval.NodeSelector = nodeSelectorArray
retval.Tolerations = make([]*models.Toleration, len(pod.Spec.Tolerations))
for i := range pod.Spec.Tolerations {
retval.Tolerations[i] = &models.Toleration{
Effect: string(pod.Spec.Tolerations[i].Effect),
Key: pod.Spec.Tolerations[i].Key,
Value: pod.Spec.Tolerations[i].Value,
Operator: string(pod.Spec.Tolerations[i].Operator),
TolerationSeconds: *pod.Spec.Tolerations[i].TolerationSeconds,
}
}
return retval, nil
}
func describeStatus(status corev1.ContainerStatus) (*models.State, *models.State) {
retval := &models.State{}
last := &models.State{}
state := status.State
lastState := status.LastTerminationState
switch {
case state.Running != nil:
retval.State = "Running"
retval.Started = state.Running.StartedAt.Time.Format(time.RFC1123Z)
case state.Waiting != nil:
retval.State = "Waiting"
retval.Reason = state.Waiting.Reason
case state.Terminated != nil:
retval.State = "Terminated"
retval.Message = state.Terminated.Message
retval.ExitCode = int64(state.Terminated.ExitCode)
retval.Signal = int64(state.Terminated.Signal)
retval.Started = state.Terminated.StartedAt.Time.Format(time.RFC1123Z)
retval.Finished = state.Terminated.FinishedAt.Time.Format(time.RFC1123Z)
switch {
case lastState.Running != nil:
last.State = "Running"
last.Started = lastState.Running.StartedAt.Time.Format(time.RFC1123Z)
case lastState.Waiting != nil:
last.State = "Waiting"
last.Reason = lastState.Waiting.Reason
case lastState.Terminated != nil:
last.State = "Terminated"
last.Message = lastState.Terminated.Message
last.ExitCode = int64(lastState.Terminated.ExitCode)
last.Signal = int64(lastState.Terminated.Signal)
last.Started = lastState.Terminated.StartedAt.Time.Format(time.RFC1123Z)
last.Finished = lastState.Terminated.FinishedAt.Time.Format(time.RFC1123Z)
default:
last.State = "Waiting"
}
default:
retval.State = "Waiting"
}
return retval, last
}
func describeContainerPorts(cPorts []corev1.ContainerPort) []string {
ports := make([]string, 0, len(cPorts))
for _, cPort := range cPorts {
ports = append(ports, fmt.Sprintf("%d/%s", cPort.ContainerPort, cPort.Protocol))
}
return ports
}
func describeContainerHostPorts(cPorts []corev1.ContainerPort) []string {
ports := make([]string, 0, len(cPorts))
for _, cPort := range cPorts {
ports = append(ports, fmt.Sprintf("%d/%s", cPort.HostPort, cPort.Protocol))
}
return ports
}
func getPodQOS(pod *corev1.Pod) corev1.PodQOSClass {
requests := corev1.ResourceList{}
limits := corev1.ResourceList{}
zeroQuantity := resource.MustParse("0")
isGuaranteed := true
allContainers := []corev1.Container{}
allContainers = append(allContainers, pod.Spec.Containers...)
allContainers = append(allContainers, pod.Spec.InitContainers...)
for _, container := range allContainers {
// process requests
for name, quantity := range container.Resources.Requests {
if !isSupportedQoSComputeResource(name) {
continue
}
if quantity.Cmp(zeroQuantity) == 1 {
delta := quantity.DeepCopy()
if _, exists := requests[name]; !exists {
requests[name] = delta
} else {
delta.Add(requests[name])
requests[name] = delta
}
}
}
// process limits
qosLimitsFound := sets.NewString()
for name, quantity := range container.Resources.Limits {
if !isSupportedQoSComputeResource(name) {
continue
}
if quantity.Cmp(zeroQuantity) == 1 {
qosLimitsFound.Insert(string(name))
delta := quantity.DeepCopy()
if _, exists := limits[name]; !exists {
limits[name] = delta
} else {
delta.Add(limits[name])
limits[name] = delta
}
}
}
if !qosLimitsFound.HasAll(string(corev1.ResourceMemory), string(corev1.ResourceCPU)) {
isGuaranteed = false
}
}
if len(requests) == 0 && len(limits) == 0 {
return corev1.PodQOSBestEffort
}
// Check is requests match limits for all resources.
if isGuaranteed {
for name, req := range requests {
if lim, exists := limits[name]; !exists || lim.Cmp(req) != 0 {
isGuaranteed = false
break
}
}
}
if isGuaranteed &&
len(requests) == len(limits) {
return corev1.PodQOSGuaranteed
}
return corev1.PodQOSBurstable
}
var supportedQoSComputeResources = sets.NewString(string(corev1.ResourceCPU), string(corev1.ResourceMemory))
func isSupportedQoSComputeResource(name corev1.ResourceName) bool {
return supportedQoSComputeResources.Has(string(name))
}
func translateTimestampSince(timestamp metav1.Time) string {
if timestamp.IsZero() {
return "<unknown>"
}
return duration.HumanDuration(time.Since(timestamp.Time))
}
//get values for prometheus metrics
func getTenantMonitoringResponse(session *models.Principal, params operator_api.GetTenantMonitoringParams) (*models.TenantMonitoringInfo, *models.Error) {
ctx, cancel := context.WithCancel(params.HTTPRequest.Context())