This commit is contained in:
asteam
2025-09-23 14:34:24 +03:00
parent b924e85e49
commit f1ffb4c0fd
1108 changed files with 72020 additions and 0 deletions

View File

@@ -0,0 +1,104 @@
package image
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// CreateRequest struct to create image
type CreateRequest struct {
// Name of the rescue disk
// Required: true
Name string `url:"name" json:"name" validate:"required"`
// URL where to download media from
// Required: true
URL string `url:"url" json:"url" validate:"required,url"`
// Boot type of image bios or UEFI
// Required: true
BootType string `url:"boottype" json:"boottype" validate:"required,imageBootType"`
// Image type
// Should be:
// - linux
// - windows
// - or other
// Required: true
ImageType string `url:"imagetype" json:"imagetype" validate:"required,imageType"`
// Account ID to make the image exclusive
// Required: true
AccountID uint64 `url:"accountId" json:"accountId" validate:"required"`
// Select a network interface naming pattern for your Linux machine. eth - onboard, ens - pci slot naming
// Should be:
// - eth
// - ens (default value)
// Required: false
NetworkInterfaceNaming string `url:"networkInterfaceNaming,omitempty" json:"networkInterfaceNaming,omitempty" validate:"omitempty,networkInterfaceNaming"`
// Does this machine supports hot resize
// Required: false
HotResize bool `url:"hotresize,omitempty" json:"hotresize,omitempty"`
// Optional username for the image
// Required: false
Username string `url:"username,omitempty" json:"username,omitempty"`
// Optional password for the image
// Required: false
Password string `url:"password,omitempty" json:"password,omitempty"`
// Username for upload binary media
// Required: false
UsernameDL string `url:"usernameDL,omitempty" json:"usernameDL,omitempty"`
// Password for upload binary media
// Required: false
PasswordDL string `url:"passwordDL,omitempty" json:"passwordDL,omitempty"`
// Storage endpoint provider ID
// Required: false
SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Pool for image create
// Required: false
Pool string `url:"poolName,omitempty" json:"poolName,omitempty"`
// Binary architecture of this image
// Should be:
// - X86_64
// Required: false
Architecture string `url:"architecture,omitempty" json:"architecture,omitempty" validate:"omitempty,imageArchitecture"`
// List of types of compute suitable for image
// Example: [ "KVM_X86" ]
// Required: true
Drivers []string `url:"drivers" json:"drivers" validate:"min=1,max=2,imageDrivers"`
}
// Create creates image from a media identified by URL
func (i Image) Create(ctx context.Context, req CreateRequest) (uint64, error) {
err := validators.ValidateRequest(req)
if err != nil {
return 0, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/create"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return 0, err
}
result, err := strconv.ParseUint(string(res), 10, 64)
if err != nil {
return 0, err
}
return result, nil
}

View File

@@ -0,0 +1,42 @@
package image
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// CreateVirtualRequest struct to create virtual image
type CreateVirtualRequest struct {
// Name of the virtual image to create
// Required: true
Name string `url:"name" json:"name" validate:"required"`
// ID of real image to link this virtual image to upon creation
// Required: true
TargetID uint64 `url:"targetId" json:"targetId" validate:"required"`
}
// CreateVirtual creates virtual image
func (i Image) CreateVirtual(ctx context.Context, req CreateVirtualRequest) (uint64, error) {
err := validators.ValidateRequest(req)
if err != nil {
return 0, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/createVirtual"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return 0, err
}
result, err := strconv.ParseUint(string(res), 10, 64)
if err != nil {
return 0, err
}
return result, nil
}

View File

@@ -0,0 +1,38 @@
package image
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// DeleteRequest struct to delete image
type DeleteRequest struct {
// ID of the image to delete
// Required: true
ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
}
// Delete deletes image by ID
func (i Image) Delete(ctx context.Context, req DeleteRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
return false, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/delete"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,62 @@
package image
// FilterByID returns ListImages with specified ID.
func (li ListImages) FilterByID(id uint64) ListImages {
predicate := func(ii ItemImage) bool {
return ii.ID == id
}
return li.FilterFunc(predicate)
}
// FilterByName returns ListImages with specified Name.
func (li ListImages) FilterByName(name string) ListImages {
predicate := func(ii ItemImage) bool {
return ii.Name == name
}
return li.FilterFunc(predicate)
}
// FilterByStatus returns ListImages with specified Status.
func (li ListImages) FilterByStatus(status string) ListImages {
predicate := func(ii ItemImage) bool {
return ii.Status == status
}
return li.FilterFunc(predicate)
}
// FilterByBootType returns ListImages with specified BootType.
func (li ListImages) FilterByBootType(bootType string) ListImages {
predicate := func(ii ItemImage) bool {
return ii.BootType == bootType
}
return li.FilterFunc(predicate)
}
// FilterFunc allows filtering ListImages based on a user-specified predicate.
func (li ListImages) FilterFunc(predicate func(ItemImage) bool) ListImages {
var result ListImages
for _, item := range li.Data {
if predicate(item) {
result.Data = append(result.Data, item)
}
}
result.EntryCount = uint64(len(result.Data))
return result
}
// FindOne returns first found ItemImage
// If none was found, returns an empty struct.
func (li ListImages) FindOne() ItemImage {
if len(li.Data) == 0 {
return ItemImage{}
}
return li.Data[0]
}

View File

@@ -0,0 +1,127 @@
package image
import "testing"
var images = ListImages{
Data: []ItemImage{
{
AccountID: 0,
Architecture: "X86_64",
BootType: "bios",
Bootable: true,
Description: "",
Drivers: []string{
"KVM_X86",
},
HotResize: true,
ID: 9882,
LinkTo: 0,
Name: "u16",
Pool: "vmstor",
Size: 5,
Status: "CREATED",
Type: "linux",
Username: "",
Virtual: false,
},
{
AccountID: 0,
Architecture: "X86_64",
BootType: "bois",
Bootable: true,
Description: "",
Drivers: []string{
"KVM_X86",
},
HotResize: false,
ID: 9884,
LinkTo: 0,
Name: "alpine-virt-3.17",
Pool: "vmstor",
Size: 1,
Status: "CREATED",
Type: "linux",
Username: "",
Virtual: true,
},
{
AccountID: 1,
Architecture: "X86_64",
BootType: "bios",
Bootable: true,
Description: "",
Drivers: []string{
"KVM_X86",
},
HotResize: true,
ID: 9885,
LinkTo: 0,
Name: "test",
Pool: "vmstor",
Size: 4,
Status: "DESTROYED",
Type: "linux",
Username: "",
Virtual: false,
},
},
EntryCount: 3,
}
func TestFilterByID(t *testing.T) {
actual := images.FilterByID(9885).FindOne()
if actual.ID != 9885 {
t.Fatal("expected ID 9885, found: ", actual.ID)
}
}
func TestFilterByName(t *testing.T) {
actual := images.FilterByName("u16").FindOne()
if actual.Name != "u16" {
t.Fatal("expected Name 'u16', found: ", actual.Name)
}
}
func TestFilterByStatus(t *testing.T) {
actual := images.FilterByStatus("CREATED")
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual.Data {
if item.Status != "CREATED" {
t.Fatal("expected Status 'CREATED', found: ", item.Status)
}
}
}
func TestFilterByBootType(t *testing.T) {
actual := images.FilterByBootType("bios")
if len(actual.Data) != 2 {
t.Fatal("expected 2 found, actual: ", len(actual.Data))
}
for _, item := range actual.Data {
if item.BootType != "bios" {
t.Fatal("expected BootType 'bios', found: ", item.BootType)
}
}
}
func TestFilterFunc(t *testing.T) {
actual := images.FilterFunc(func(ii ItemImage) bool {
return ii.Virtual == true
})
if len(actual.Data) != 1 {
t.Fatal("expected 1 found, actual: ", len(actual.Data))
}
if actual.Data[0].Virtual != true {
t.Fatal("expected Virtual true, found false")
}
}

52
pkg/cloudapi/image/get.go Normal file
View File

@@ -0,0 +1,52 @@
package image
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// GetRequest struct to get detailed information about image
type GetRequest struct {
// ID of image to get
// Required: true
ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
// If set to False returns only images in status CREATED
// Required: false
ShowAll bool `url:"showAll,omitempty" json:"showAll,omitempty"`
}
// Get gets image by ID.
// Returns image as a RecordImage struct if user has rights on it
func (i Image) Get(ctx context.Context, req GetRequest) (*RecordImage, error) {
res, err := i.GetRaw(ctx, req)
if err != nil {
return nil, err
}
info := RecordImage{}
err = json.Unmarshal(res, &info)
if err != nil {
return nil, err
}
return &info, nil
}
// GetRaw gets image by ID.
// Returns image as an array of bytes if user has rights on it
func (i Image) GetRaw(ctx context.Context, req GetRequest) ([]byte, error) {
err := validators.ValidateRequest(req)
if err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/get"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
return res, err
}

19
pkg/cloudapi/image/ids.go Normal file
View File

@@ -0,0 +1,19 @@
package image
// IDs gets array of ImageIDs from ListImages struct
func (li ListImages) IDs() []uint64 {
res := make([]uint64, 0, len(li.Data))
for _, i := range li.Data {
res = append(res, i.ID)
}
return res
}
// IDs gets array of HistoryIDs from ListHistories struct
func (lh ListHistories) IDs() []uint64 {
res := make([]uint64, 0, len(lh))
for _, h := range lh {
res = append(res, h.ID)
}
return res
}

View File

@@ -0,0 +1,18 @@
// Lists all the images. A image is a template which can be used to deploy machines
package image
import (
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/interfaces"
)
// Structure for creating request to image
type Image struct {
client interfaces.Caller
}
// Builder for image endpoints
func New(client interfaces.Caller) *Image {
return &Image{
client,
}
}

View File

@@ -0,0 +1,42 @@
package image
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// LinkRequest struct to link virtual image to another image
type LinkRequest struct {
// ID of the virtual image
// Required: true
ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
// ID of real image to link this virtual image to
// Required: true
TargetID uint64 `url:"targetId" json:"targetId" validate:"required"`
}
// Link links virtual image to another image in the platform
func (i Image) Link(ctx context.Context, req LinkRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
return false, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/link"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

107
pkg/cloudapi/image/list.go Normal file
View File

@@ -0,0 +1,107 @@
package image
import (
"context"
"encoding/json"
"net/http"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// ListRequest struct to get list of available images
type ListRequest struct {
// Find by storage endpoint provider ID
// Required: false
SEPID uint64 `url:"sepId,omitempty" json:"sepId,omitempty"`
// Find by id
// Required: false
ByID uint64 `url:"by_id,omitempty" json:"by_id,omitempty"`
// Find by ID
// Required: false
Name string `url:"name,omitempty" json:"name,omitempty"`
// Find by status
// Required: false
Status string `url:"status,omitempty" json:"status,omitempty"`
// Find by architecture
// Required: false
Architecture string `url:"architecture,omitempty" json:"architecture,omitempty"`
// Find by type
// Required: false
TypeImage string `url:"typeImage,omitempty" json:"typeImage,omitempty"`
// Find by image size
// Required: false
ImageSize uint64 `url:"imageSize,omitempty" json:"imageSize,omitempty"`
// Find by SEP name
// Required: false
SEPName string `url:"sepName,omitempty" json:"sepName,omitempty"`
// Find by pool
// Required: false
Pool string `url:"pool,omitempty" json:"pool,omitempty"`
// Find by public True or False
// Required: false
Public interface{} `url:"public,omitempty" json:"public,omitempty" validate:"omitempty,isBool"`
// Find by hot resize True or False
// Required: false
HotResize interface{} `url:"hotResize,omitempty" json:"hotResize,omitempty" validate:"omitempty,isBool"`
// Find by bootable True or False
// Required: false
Bootable interface{} `url:"bootable,omitempty" json:"bootable,omitempty" validate:"omitempty,isBool"`
// Sort by one of supported fields, format +|-(field)
// Required: false
SortBy string `url:"sortBy,omitempty" json:"sortBy,omitempty" validate:"omitempty,sortBy"`
// Page number
// Required: false
Page uint64 `url:"page,omitempty" json:"page,omitempty"`
// Page size
// Required: false
Size uint64 `url:"size,omitempty" json:"size,omitempty"`
// Find by enabled True or False
// Required: false
Enabled interface{} `url:"enabled,omitempty" json:"enabled,omitempty" validate:"omitempty,isBool"`
}
// List gets list of available images as a ListImages struct, optionally filtering by account ID
func (i Image) List(ctx context.Context, req ListRequest) (*ListImages, error) {
res, err := i.ListRaw(ctx, req)
if err != nil {
return nil, err
}
list := ListImages{}
err = json.Unmarshal(res, &list)
if err != nil {
return nil, err
}
return &list, nil
}
// ListRaw gets list of available images as an array of bytes
func (i Image) ListRaw(ctx context.Context, req ListRequest) ([]byte, error) {
if err := validators.ValidateRequest(req); err != nil {
return nil, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/list"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
return res, err
}

View File

@@ -0,0 +1,202 @@
package image
// Main information about image
type ItemImage struct {
// Account ID
AccountID uint64 `json:"accountId"`
// Architecture
Architecture string `json:"architecture"`
// Boot type
BootType string `json:"bootType"`
// Bootable
Bootable bool `json:"bootable"`
// CDROM
CDROM bool `json:"cdrom"`
// Description
Description string `json:"desc"`
// List drivers
Drivers []string `json:"drivers"`
// HotResize
HotResize bool `json:"hotResize"`
// ID
ID uint64 `json:"id"`
// Link to
LinkTo uint64 `json:"linkTo"`
// Name
Name string `json:"name"`
// NetworkInterfaceNaming
NetworkInterfaceNaming string `json:"networkInterfaceNaming"`
// Pool
Pool string `json:"pool"`
// SepID
SepID uint64 `json:"sepId"`
// Size
Size uint64 `json:"size"`
// Status
Status string `json:"status"`
// Type
Type string `json:"type"`
// Username
Username string `json:"username"`
// Virtual
Virtual bool `json:"virtual"`
}
// List of information about images
type ListImages struct {
// Data
Data []ItemImage `json:"data"`
// Entry count
EntryCount uint64 `json:"entryCount"`
}
// ListHistories of record image
type ListHistories []History
// History of record image
type History struct {
// GUID
GUID string `json:"guid"`
// ID
ID uint64 `json:"id"`
// Timestamp
Timestamp uint64 `json:"timestamp"`
}
// Detailed information about image
type RecordImage struct {
// UNCPathj
UNCPath string `json:"UNCPath"`
// CKey
CKey string `json:"_ckey"`
// Account ID
AccountID uint64 `json:"accountId"`
// Access Control List
ACL interface{} `json:"acl"`
// Architecture
Architecture string `json:"architecture"`
// Boot type
BootType string `json:"bootType"`
// Bootable
Bootable bool `json:"bootable"`
// CdPresentedTo
CdPresentedTo interface{} `json:"cdPresentedTo"`
// ComputeCI ID
ComputeCIID uint64 `json:"computeciId"`
// Deleted time
DeletedTime uint64 `json:"deletedTime"`
// Description
Description string `json:"desc"`
// List of drivers
Drivers []string `json:"drivers"`
// Enabled
Enabled bool `json:"enabled"`
// Grid ID
GID uint64 `json:"gid"`
// GUID
GUID uint64 `json:"guid"`
// History
History ListHistories `json:"history"`
// HotResize
HotResize bool `json:"hotResize"`
// ID
ID uint64 `json:"id"`
// Last modified
LastModified uint64 `json:"lastModified"`
// Link to
LinkTo uint64 `json:"linkTo"`
// Milestones
Milestones uint64 `json:"milestones"`
// Name
Name string `json:"name"`
// NetworkInterfaceNaming
NetworkInterfaceNaming string `json:"networkInterfaceNaming"`
// Password
Password string `json:"password"`
// Pool
Pool string `json:"pool"`
// Present to
PresentTo []uint64 `json:"presentTo"`
// ProviderName
ProviderName string `json:"provider_name"`
// Purge attempts
PurgeAttempts uint64 `json:"purgeAttempts"`
// Resource ID
ResID string `json:"resId"`
// RescueCD
RescueCD bool `json:"rescuecd"`
// SepID
SepID uint64 `json:"sepId"`
// SharedWith list
SharedWith []uint64 `json:"sharedWith"`
// Size
Size uint64 `json:"size"`
// Status
Status string `json:"status"`
// Tech status
TechStatus string `json:"techStatus"`
// Type
Type string `json:"type"`
// Username
Username string `json:"username"`
// Version
Version string `json:"version"`
}

View File

@@ -0,0 +1,42 @@
package image
import (
"context"
"net/http"
"strconv"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/validators"
)
// RenameRequest struct to rename image
type RenameRequest struct {
// ID of the virtual image to rename
// Required: true
ImageID uint64 `url:"imageId" json:"imageId" validate:"required"`
// New name
// Required: true
Name string `url:"name" json:"name" validate:"required"`
}
// Rename renames image
func (i Image) Rename(ctx context.Context, req RenameRequest) (bool, error) {
err := validators.ValidateRequest(req)
if err != nil {
return false, validators.ValidationErrors(validators.GetErrors(err))
}
url := "/cloudapi/image/rename"
res, err := i.client.DecortApiCall(ctx, http.MethodPost, url, req)
if err != nil {
return false, err
}
result, err := strconv.ParseBool(string(res))
if err != nil {
return false, err
}
return result, nil
}

View File

@@ -0,0 +1,43 @@
package image
import (
"encoding/json"
"repository.basistech.ru/BASIS/dynamix-golang-sdk/v9/internal/serialization"
)
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
//
// In order to serialize with indent make sure to follow these guidelines:
// - First argument -> prefix
// - Second argument -> indent
func (li ListImages) Serialize(params ...string) (serialization.Serialized, error) {
if len(li.Data) == 0 {
return []byte{}, nil
}
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(li, prefix, indent)
}
return json.Marshal(li)
}
// Serialize returns JSON-serialized []byte. Used as a wrapper over json.Marshal and json.MarshalIndent functions.
//
// In order to serialize with indent make sure to follow these guidelines:
// - First argument -> prefix
// - Second argument -> indent
func (ii ItemImage) Serialize(params ...string) (serialization.Serialized, error) {
if len(params) > 1 {
prefix := params[0]
indent := params[1]
return json.MarshalIndent(ii, prefix, indent)
}
return json.Marshal(ii)
}