| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- package utils
- import (
- "context"
- "strings"
- "time"
- "yunion.io/x/jsonutils"
- "yunion.io/x/log"
- "yunion.io/x/pkg/errors"
- "yunion.io/x/pkg/util/httputils"
- "yunion.io/x/pkg/utils"
- computeapi "yunion.io/x/onecloud/pkg/apis/compute"
- "yunion.io/x/onecloud/pkg/httperrors"
- "yunion.io/x/onecloud/pkg/mcclient/auth"
- "yunion.io/x/onecloud/pkg/mcclient/modulebase"
- "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
- )
- type ResourceInfo struct {
- Id string
- Name string
- Status string
- }
- func NewResourceInfo(id, name, status string) ResourceInfo {
- return ResourceInfo{
- Id: id,
- Name: name,
- Status: status,
- }
- }
- func GetResource[R any](ctx context.Context, man modulebase.Manager, id string) (*R, error) {
- if len(id) == 0 {
- return nil, errors.Wrapf(httperrors.ErrInvalidStatus, "id is empty")
- }
- s := auth.GetAdminSession(ctx, "")
- resp, err := man.GetById(s, id, jsonutils.Marshal(map[string]interface{}{
- "scope": "max",
- }))
- if err != nil {
- if httputils.ErrorCode(err) == 404 {
- return nil, errors.Wrapf(errors.ErrNotFound, "GetById %s", id)
- }
- return nil, errors.Wrapf(err, "Get")
- }
- res := new(R)
- if err := resp.Unmarshal(res); err != nil {
- return nil, errors.Wrap(err, "Unmarshal")
- }
- return res, nil
- }
- func PerformResourceAction[R any](ctx context.Context, man modulebase.Manager, id string, action string) (*R, error) {
- s := auth.GetAdminSession(ctx, "")
- resp, err := man.PerformAction(s, id, action, nil)
- if err != nil {
- return nil, errors.Wrapf(err, "PerformAction %s %s %s", man.GetKeyword(), id, action)
- }
- res := new(R)
- if err := resp.Unmarshal(res); err != nil {
- return nil, errors.Wrap(err, "Unmarshal")
- }
- return res, nil
- }
- func StopResource[R any](ctx context.Context, man modulebase.Manager, id string) (*R, error) {
- return PerformResourceAction[R](ctx, man, id, "stop")
- }
- func StartResource[R any](ctx context.Context, man modulebase.Manager, id string) (*R, error) {
- return PerformResourceAction[R](ctx, man, id, "start")
- }
- func WaitResourceStatus[R any](
- ctx context.Context,
- man modulebase.Manager,
- id string,
- getResInfo func(*R) ResourceInfo,
- targetStatus []string,
- timeoutSecs int,
- intervalSecs int) (*R, error) {
- expire := time.Now().Add(time.Second * time.Duration(timeoutSecs))
- for time.Now().Before(expire) {
- res, err := GetResource[R](ctx, man, id)
- if err != nil {
- return nil, errors.Wrapf(err, "GetResource")
- }
- resInfo := getResInfo(res)
- log.Debugf("Wait %s status %#v target status %v", man.GetKeyword(), resInfo.Status, targetStatus)
- if utils.IsInStringArray(resInfo.Status, targetStatus) {
- return res, nil
- }
- if strings.Contains(resInfo.Status, "fail") {
- return nil, errors.Wrapf(errors.ErrInvalidStatus, "resource %s status %s", resInfo.Name, resInfo.Status)
- }
- time.Sleep(time.Second * time.Duration(intervalSecs))
- }
- return nil, errors.Wrapf(httperrors.ErrTimeout, "wait %s status %s timeout", man.GetKeyword(), targetStatus)
- }
- func GetContainer(ctx context.Context, id string) (*computeapi.SContainer, error) {
- return GetResource[computeapi.SContainer](ctx, &compute.Containers, id)
- }
- func GetServer(ctx context.Context, id string) (*computeapi.ServerDetails, error) {
- return GetResource[computeapi.ServerDetails](ctx, &compute.Servers, id)
- }
- func WaitContainerStatus(ctx context.Context, id string, targetStatus []string, timeoutSecs int) (*computeapi.SContainer, error) {
- return WaitResourceStatus(ctx, &compute.Containers, id, func(ctr *computeapi.SContainer) ResourceInfo {
- return NewResourceInfo(ctr.Id, ctr.Name, ctr.Status)
- }, targetStatus, timeoutSecs, 1)
- }
- func WaitServerStatus(ctx context.Context, id string, targetStatus []string, timeoutSecs int) (*computeapi.ServerDetails, error) {
- return WaitResourceStatus(ctx, &compute.Servers, id, func(s *computeapi.ServerDetails) ResourceInfo {
- return NewResourceInfo(s.Id, s.Name, s.Status)
- }, targetStatus, timeoutSecs, 2)
- }
- func WaitDelete[R any](ctx context.Context, man modulebase.Manager, id string, timeoutSecs int) error {
- expire := time.Now().Add(time.Second * time.Duration(timeoutSecs))
- for time.Now().Before(expire) {
- _, err := GetResource[R](ctx, man, id)
- if err != nil {
- if errors.Cause(err) == errors.ErrNotFound {
- return nil
- }
- return errors.Wrapf(err, "Get %s %s", man.GetKeyword(), id)
- }
- time.Sleep(2 * time.Second)
- }
- return errors.Wrapf(httperrors.ErrTimeout, "wait %s %s deleted timeout", man.GetKeyword(), id)
- }
- func UpdateContainer(ctx context.Context, id string, getSpec func(*computeapi.SContainer) *computeapi.ContainerSpec) (*computeapi.SContainer, error) {
- s := auth.GetAdminSession(ctx, "")
- ctr, err := GetContainer(ctx, id)
- if err != nil {
- return nil, errors.Wrapf(err, "GetContainer %s", id)
- }
- curSpecStr := jsonutils.Marshal(ctr.Spec).String()
- newSpec := getSpec(ctr)
- newSpecStr := jsonutils.Marshal(newSpec).String()
- if curSpecStr != newSpecStr {
- ctr.Spec = newSpec
- resp, err := compute.Containers.Update(s, id, jsonutils.Marshal(ctr))
- if err != nil {
- return nil, errors.Wrapf(err, "UpdateContainer %s", id)
- }
- respCtr := new(computeapi.SContainer)
- if err := resp.Unmarshal(respCtr); err != nil {
- return nil, errors.Wrapf(err, "Unmarshal")
- }
- return respCtr, nil
- } else {
- log.Debugf("container spec not changed, skip update container %s spec", ctr.Name)
- }
- return ctr, nil
- }
- func ExecSyncContainer(ctx context.Context, containerId string, input *computeapi.ContainerExecSyncInput) (jsonutils.JSONObject, error) {
- session := auth.GetAdminSession(ctx, "")
- output, err := compute.Containers.PerformAction(session, containerId, "exec-sync", jsonutils.Marshal(input))
- if err != nil {
- return nil, errors.Wrap(err, "ExecSync")
- }
- return output, nil
- }
|