mirror of
https://github.com/certimate-go/certimate.git
synced 2026-08-29 02:02:04 +08:00
feat(provider): add iBMC Redfish certificate deployer
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
package deployers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/domain"
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
dplyimpl "github.com/certimate-go/certimate/pkg/core/deployer/providers/huaweiibmc"
|
||||
xmaps "github.com/certimate-go/certimate/pkg/utils/maps"
|
||||
)
|
||||
|
||||
func init() {
|
||||
Registries.MustRegister(domain.DeploymentProviderTypeHuaweiIBMC, func(options *ProviderFactoryOptions) (core.Deployer, error) {
|
||||
credentials := domain.AccessConfigForHuaweiIBMC{}
|
||||
if err := xmaps.Populate(options.ProviderAccessConfig, &credentials); err != nil {
|
||||
return nil, fmt.Errorf("failed to populate Huawei iBMC access config: %w", err)
|
||||
}
|
||||
provider, err := dplyimpl.NewDeployer(&dplyimpl.DeployerConfig{
|
||||
Host: credentials.Host,
|
||||
Username: credentials.Username,
|
||||
Password: credentials.Password,
|
||||
AllowInsecureConnections: credentials.AllowInsecureConnections,
|
||||
AutoRestart: xmaps.GetBool(options.ProviderExtendedConfig, "autoRestart"),
|
||||
})
|
||||
return provider, err
|
||||
})
|
||||
}
|
||||
@@ -353,6 +353,13 @@ type AccessConfigForHuaweiCloud struct {
|
||||
EnterpriseProjectId string `json:"enterpriseProjectId,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForHuaweiIBMC struct {
|
||||
Host string `json:"host"`
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
}
|
||||
|
||||
type AccessConfigForInfomaniak struct {
|
||||
AccessToken string `json:"accessToken"`
|
||||
}
|
||||
|
||||
@@ -77,6 +77,7 @@ const (
|
||||
AccessProviderTypeHostingde = AccessProviderType("hostingde")
|
||||
AccessProviderTypeHostinger = AccessProviderType("hostinger")
|
||||
AccessProviderTypeHuaweiCloud = AccessProviderType("huaweicloud")
|
||||
AccessProviderTypeHuaweiIBMC = AccessProviderType("huaweiibmc")
|
||||
AccessProviderTypeInfomaniak = AccessProviderType("infomaniak")
|
||||
AccessProviderTypeIONOS = AccessProviderType("ionos")
|
||||
AccessProviderTypeJDCloud = AccessProviderType("jdcloud")
|
||||
@@ -396,6 +397,7 @@ const (
|
||||
DeploymentProviderTypeHuaweiCloudSCM = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-scm")
|
||||
DeploymentProviderTypeHuaweiCloudVOD = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-vod")
|
||||
DeploymentProviderTypeHuaweiCloudWAF = DeploymentProviderType(AccessProviderTypeHuaweiCloud + "-waf")
|
||||
DeploymentProviderTypeHuaweiIBMC = DeploymentProviderType(AccessProviderTypeHuaweiIBMC)
|
||||
DeploymentProviderTypeJDCloudALB = DeploymentProviderType(AccessProviderTypeJDCloud + "-alb")
|
||||
DeploymentProviderTypeJDCloudCDN = DeploymentProviderType(AccessProviderTypeJDCloud + "-cdn")
|
||||
DeploymentProviderTypeJDCloudLive = DeploymentProviderType(AccessProviderTypeJDCloud + "-live")
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net"
|
||||
"strings"
|
||||
|
||||
"github.com/certimate-go/certimate/pkg/core"
|
||||
ibmcsdk "github.com/certimate-go/certimate/pkg/sdk3rd/huaweiibmc"
|
||||
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
|
||||
xloop "github.com/certimate-go/certimate/pkg/utils/loop"
|
||||
)
|
||||
|
||||
type (
|
||||
Provider = core.Deployer
|
||||
DeployResult = core.DeployerDeployResult
|
||||
)
|
||||
|
||||
type DeployerConfig struct {
|
||||
// iBMC 主机。
|
||||
Host string `json:"host"`
|
||||
// iBMC 用户名。
|
||||
Username string `json:"username"`
|
||||
// iBMC 密码。
|
||||
Password string `json:"password"`
|
||||
// 是否允许不安全的连接。
|
||||
AllowInsecureConnections bool `json:"allowInsecureConnections,omitempty"`
|
||||
// 是否自动重启。
|
||||
AutoRestart bool `json:"autoRestart,omitempty"`
|
||||
}
|
||||
|
||||
type Deployer struct {
|
||||
config *DeployerConfig
|
||||
logger *slog.Logger
|
||||
}
|
||||
|
||||
var _ Provider = (*Deployer)(nil)
|
||||
|
||||
func NewDeployer(config *DeployerConfig) (*Deployer, error) {
|
||||
if config == nil {
|
||||
return nil, fmt.Errorf("the configuration of the iBMC deployer is nil")
|
||||
}
|
||||
|
||||
return &Deployer{
|
||||
config: config,
|
||||
logger: slog.Default(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *Deployer) SetLogger(logger *slog.Logger) {
|
||||
if logger == nil {
|
||||
d.logger = slog.New(slog.DiscardHandler)
|
||||
} else {
|
||||
d.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*DeployResult, error) {
|
||||
// 转换证书格式
|
||||
certPFXPwd := make([]byte, 24)
|
||||
if _, err := rand.Read(certPFXPwd); err != nil {
|
||||
return nil, fmt.Errorf("failed to generate PFX password: %w", err)
|
||||
}
|
||||
certPFXPwdHex := hex.EncodeToString(certPFXPwd)
|
||||
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, certPFXPwdHex, nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err)
|
||||
}
|
||||
|
||||
// 创建 iBMC 客户端
|
||||
client, err := createSDKClient(d.config.Host, d.config.Username, d.config.Password, d.config.AllowInsecureConnections)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not create client: %w", err)
|
||||
}
|
||||
|
||||
// 创建会话
|
||||
createSessionResp, err := client.CreateSessionWithContext(ctx)
|
||||
d.logger.Debug("sdk request 'SessionService.CreateSession'", slog.Any("response", createSessionResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'SessionService.CreateSession': %w", err)
|
||||
} else {
|
||||
defer client.DeleteSessionWithContext(ctx)
|
||||
}
|
||||
|
||||
// 查询管理集合资源信息
|
||||
listManagersResp, err := client.ListManagersWithContext(ctx)
|
||||
d.logger.Debug("sdk request 'Managers.ListManagers'", slog.Any("response", listManagersResp))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to execute sdk request 'Managers.ListManagers': %w", err)
|
||||
}
|
||||
|
||||
// 批量更新管理证书
|
||||
if len(listManagersResp.Members) == 0 {
|
||||
d.logger.Info("no ibmc managers to deploy")
|
||||
} else {
|
||||
d.logger.Info("found ibmc managers to deploy", slog.Any("managers", listManagersResp.Members))
|
||||
|
||||
if err := xloop.ForRangeAllWithContext(ctx, listManagersResp.Members, func(ctx context.Context, managerInfo *ibmcsdk.Entity, _ int) error {
|
||||
importCustomCertificateReq := &ibmcsdk.ImportCustomCertificateToManagerRequest{
|
||||
ManagerID: managerInfo.ID,
|
||||
ManagerLocation: managerInfo.ODataID,
|
||||
Certificate: base64.StdEncoding.EncodeToString(certPFX),
|
||||
Password: certPFXPwdHex,
|
||||
}
|
||||
importCustomCertificateResp, err := client.ImportCustomCertificateToManagerWithContext(ctx, importCustomCertificateReq)
|
||||
d.logger.Debug("sdk request 'Managers.SecurityService.HttpsCert.ImportCustomCertificateToManager'", slog.String("params.managerODataId", managerInfo.ODataID), slog.Any("request", importCustomCertificateReq), slog.Any("response", importCustomCertificateResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'Managers.SecurityService.HttpsCert.ImportCustomCertificateToManager': %w", err)
|
||||
}
|
||||
|
||||
if d.config.AutoRestart {
|
||||
resetManagerReq := &ibmcsdk.ResetManagerRequest{
|
||||
ManagerID: managerInfo.ID,
|
||||
ManagerLocation: managerInfo.ODataID,
|
||||
ResetType: "ForceRestart",
|
||||
}
|
||||
resetManagerResp, err := client.ResetManagerWithContext(ctx, resetManagerReq)
|
||||
d.logger.Debug("sdk request 'Managers.ResetManager'", slog.String("params.managerODataId", managerInfo.ODataID), slog.Any("request", resetManagerReq), slog.Any("response", resetManagerResp))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to execute sdk request 'Managers.ResetManager': %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &DeployResult{}, nil
|
||||
}
|
||||
|
||||
func createSDKClient(host, username, password string, skipTlsVerify bool) (*ibmcsdk.Client, error) {
|
||||
serverUrl := ""
|
||||
if strings.Contains(host, "://") {
|
||||
serverUrl = host
|
||||
} else {
|
||||
if net.ParseIP(host) != nil && strings.Contains(host, ":") {
|
||||
host = "[" + host + "]"
|
||||
}
|
||||
serverUrl = "https://" + host
|
||||
}
|
||||
|
||||
client, err := ibmcsdk.NewClient(
|
||||
serverUrl,
|
||||
ibmcsdk.WithLogins(username, password),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if skipTlsVerify {
|
||||
client.SetTLSConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func generateCertificatePassword() (string, error) {
|
||||
password := make([]byte, 24)
|
||||
if _, err := rand.Read(password); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return hex.EncodeToString(password), nil
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package huaweiibmc_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
impl "github.com/certimate-go/certimate/pkg/core/deployer/providers/huaweiibmc"
|
||||
it "github.com/certimate-go/certimate/pkg/core/deployer/testing"
|
||||
)
|
||||
|
||||
var (
|
||||
fp = it.Args("HUAWEIIBMC_")
|
||||
fTestCertPath string
|
||||
fTestKeyPath string
|
||||
fHost string
|
||||
fUsername string
|
||||
fPassword string
|
||||
)
|
||||
|
||||
func init() {
|
||||
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
|
||||
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
|
||||
fp.DefineString(&fHost, "HOST")
|
||||
fp.DefineString(&fUsername, "USERNAME")
|
||||
fp.DefineString(&fPassword, "PASSWORD")
|
||||
}
|
||||
|
||||
/*
|
||||
Shell command to run this test:
|
||||
|
||||
go test -v ./huaweiibmc_test.go -args \
|
||||
--HUAWEIIBMC_TESTCERTPATH="/path/to/your-test-cert.pem" \
|
||||
--HUAWEIIBMC_TESTKEYPATH="/path/to/your-test-key.pem" \
|
||||
--HUAWEIIBMC_HOST="localhost" \
|
||||
--HUAWEIIBMC_USERNAME="admin" \
|
||||
--HUAWEIIBMC_PASSWORD="password"
|
||||
*/
|
||||
func TestProvider(t *testing.T) {
|
||||
fp.Parse()
|
||||
|
||||
t.Run("Deploy", func(t *testing.T) {
|
||||
provider, err := impl.NewDeployer(&impl.DeployerConfig{
|
||||
Host: fHost,
|
||||
Username: fUsername,
|
||||
Password: fPassword,
|
||||
AutoRestart: true,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
it.TestDeploy(t, provider, it.TestDeployArgs{CertPath: fTestCertPath, KeyPath: fTestKeyPath})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
type GetManagersResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Members []*Entity `json:"Members"`
|
||||
}
|
||||
|
||||
type ListManagersResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
Members []*Entity `json:"Members"`
|
||||
}
|
||||
|
||||
func (c *Client) ListManagers() (*ListManagersResponse, error) {
|
||||
return c.ListManagersWithContext(context.Background())
|
||||
}
|
||||
|
||||
func (c *Client) ListManagersWithContext(ctx context.Context) (*ListManagersResponse, error) {
|
||||
httpreq, err := c.newRequest(http.MethodGet, "/redfish/v1/Managers")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ListManagersResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
for _, member := range result.Members {
|
||||
if member.ODataID == "" && member.ID != "" {
|
||||
member.ODataID = "/redfish/v1/Managers/" + url.PathEscape(member.ID)
|
||||
}
|
||||
if member.ID == "" && member.ODataID != "" {
|
||||
re := regexp.MustCompile(`/redfish/v1/Managers/([^/]+)$`)
|
||||
matches := re.FindStringSubmatch(member.ODataID)
|
||||
if len(matches) == 2 {
|
||||
member.ID = matches[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ResetManagerRequest struct {
|
||||
sdkResponseBase
|
||||
|
||||
ManagerID string `json:"-"`
|
||||
ManagerLocation string `json:"-"`
|
||||
ResetType string `json:"ResetType,omitempty"`
|
||||
}
|
||||
|
||||
type ResetManagerResponse struct {
|
||||
sdkResponseBase
|
||||
}
|
||||
|
||||
func (r *ResetManagerResponse) GetAPIError() error {
|
||||
if r.isSuccessfulResponse() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.sdkResponseBase.GetAPIError()
|
||||
}
|
||||
|
||||
func (r *ResetManagerResponse) isSuccessfulResponse() bool {
|
||||
if r.Error == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var extendedInfo []struct {
|
||||
MessageID string `json:"MessageId"`
|
||||
}
|
||||
if err := json.Unmarshal(r.Error.MessageExtendedInfo, &extendedInfo); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, info := range extendedInfo {
|
||||
if info.MessageID == "Base.1.0.Success" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Client) ResetManager(req *ResetManagerRequest) (*ResetManagerResponse, error) {
|
||||
return c.ResetManagerWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) ResetManagerWithContext(ctx context.Context, req *ResetManagerRequest) (*ResetManagerResponse, error) {
|
||||
managerLoc := strings.TrimRight(req.ManagerLocation, "/")
|
||||
if managerLoc == "" && req.ManagerID != "" {
|
||||
managerLoc = "/redfish/v1/Managers/" + url.PathEscape(req.ManagerID)
|
||||
}
|
||||
if managerLoc == "" {
|
||||
return nil, fmt.Errorf("sdkerr: bad request: unset managerId")
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, managerLoc+"/Actions/Manager.Reset")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ResetManagerResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type ImportCustomCertificateToManagerRequest struct {
|
||||
sdkResponseBase
|
||||
|
||||
ManagerID string `json:"-"`
|
||||
ManagerLocation string `json:"-"`
|
||||
Certificate string `json:"Certificate,omitempty"`
|
||||
Password string `json:"Password,omitempty"`
|
||||
}
|
||||
|
||||
type ImportCustomCertificateToManagerResponse struct {
|
||||
sdkResponseBase
|
||||
}
|
||||
|
||||
func (r *ImportCustomCertificateToManagerResponse) GetAPIError() error {
|
||||
if r.isSuccessfulResponse() {
|
||||
return nil
|
||||
}
|
||||
|
||||
return r.sdkResponseBase.GetAPIError()
|
||||
}
|
||||
|
||||
func (r *ImportCustomCertificateToManagerResponse) isSuccessfulResponse() bool {
|
||||
if r.Error == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var extendedInfo []struct {
|
||||
MessageID string `json:"MessageId"`
|
||||
}
|
||||
if err := json.Unmarshal(r.Error.MessageExtendedInfo, &extendedInfo); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, info := range extendedInfo {
|
||||
if info.MessageID == "iBMC.1.0.CertImportOK" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Client) ImportCustomCertificateToManager(req *ImportCustomCertificateToManagerRequest) (*ImportCustomCertificateToManagerResponse, error) {
|
||||
return c.ImportCustomCertificateToManagerWithContext(context.Background(), req)
|
||||
}
|
||||
|
||||
func (c *Client) ImportCustomCertificateToManagerWithContext(ctx context.Context, req *ImportCustomCertificateToManagerRequest) (*ImportCustomCertificateToManagerResponse, error) {
|
||||
managerLoc := strings.TrimRight(req.ManagerLocation, "/")
|
||||
if managerLoc == "" && req.ManagerID != "" {
|
||||
managerLoc = "/redfish/v1/Managers/" + url.PathEscape(req.ManagerID)
|
||||
}
|
||||
if managerLoc == "" {
|
||||
return nil, fmt.Errorf("sdkerr: bad request: unset managerId")
|
||||
}
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, managerLoc+"/SecurityService/HttpsCert/Actions/HttpsCert.ImportCustomCertificate")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(req)
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &ImportCustomCertificateToManagerResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type CreateSessionResponse struct {
|
||||
sdkResponseBase
|
||||
|
||||
XToken string `json:"-"`
|
||||
XLocation string `json:"-"`
|
||||
}
|
||||
|
||||
func (c *Client) CreateSession() (*CreateSessionResponse, error) {
|
||||
return c.CreateSessionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func (c *Client) CreateSessionWithContext(ctx context.Context) (*CreateSessionResponse, error) {
|
||||
c.tokenMu.Lock()
|
||||
if c.token != "" {
|
||||
c.tokenMu.Unlock()
|
||||
return nil, fmt.Errorf("sdkerr: auth error: session already created")
|
||||
}
|
||||
|
||||
c.tokenMu.Unlock()
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodPost, "/redfish/v1/SessionService/Sessions")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetBody(map[string]string{
|
||||
"UserName": c.username,
|
||||
"Password": c.password,
|
||||
})
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &CreateSessionResponse{}
|
||||
if httpresp, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
token := httpresp.Header().Get("X-Auth-Token")
|
||||
location := httpresp.Header().Get("Location")
|
||||
result.XToken = token
|
||||
result.XLocation = c.resolveLocation(location)
|
||||
|
||||
if result.XToken == "" {
|
||||
return result, fmt.Errorf("sdkerr: auth error: received empty token")
|
||||
}
|
||||
|
||||
c.tokenMu.Lock()
|
||||
c.token = result.XToken
|
||||
c.tokenLoc = result.XLocation
|
||||
c.tokenMu.Unlock()
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type DeleteSessionResponse struct {
|
||||
sdkResponseBase
|
||||
}
|
||||
|
||||
func (c *Client) DeleteSession() (*DeleteSessionResponse, error) {
|
||||
return c.DeleteSessionWithContext(context.Background())
|
||||
}
|
||||
|
||||
func (c *Client) DeleteSessionWithContext(ctx context.Context) (*DeleteSessionResponse, error) {
|
||||
c.tokenMu.Lock()
|
||||
if c.token == "" {
|
||||
c.tokenMu.Unlock()
|
||||
return nil, fmt.Errorf("sdkerr: auth error: session not created")
|
||||
}
|
||||
if c.tokenLoc == "" {
|
||||
c.tokenMu.Unlock()
|
||||
return &DeleteSessionResponse{}, nil
|
||||
}
|
||||
|
||||
c.tokenMu.Unlock()
|
||||
|
||||
httpreq, err := c.newRequest(http.MethodDelete, c.tokenLoc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
httpreq.SetContext(ctx)
|
||||
}
|
||||
|
||||
result := &DeleteSessionResponse{}
|
||||
if _, err := c.doRequestWithResult(httpreq, result); err != nil {
|
||||
return result, err
|
||||
} else {
|
||||
c.tokenMu.Lock()
|
||||
c.token = ""
|
||||
c.tokenLoc = ""
|
||||
c.tokenMu.Unlock()
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
// A simple SDK client for Huawei iBMC Redfish.
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/certimate-go/certimate/internal/app"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
username string
|
||||
password string
|
||||
|
||||
token string
|
||||
tokenLoc string
|
||||
tokenMu sync.Mutex
|
||||
|
||||
rc *resty.Client
|
||||
}
|
||||
|
||||
type sdkSuccessfulResponse interface {
|
||||
isSuccessfulResponse() bool
|
||||
}
|
||||
|
||||
func NewClient(serverUrl string, optFns ...OptionsFunc) (*Client, error) {
|
||||
opts := &Options{}
|
||||
for _, fn := range optFns {
|
||||
fn(opts)
|
||||
}
|
||||
|
||||
if serverUrl == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset serverUrl")
|
||||
}
|
||||
if _, err := url.Parse(serverUrl); err != nil {
|
||||
return nil, fmt.Errorf("sdkerr: invalid serverUrl: %w", err)
|
||||
}
|
||||
if opts.Username == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset username")
|
||||
}
|
||||
if opts.Password == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset password")
|
||||
}
|
||||
|
||||
client := &Client{
|
||||
username: opts.Username,
|
||||
password: opts.Password,
|
||||
}
|
||||
client.rc = resty.New().
|
||||
SetBaseURL(strings.TrimRight(serverUrl, "/")).
|
||||
SetHeader("Accept", "application/json").
|
||||
SetHeader("Content-Type", "application/json").
|
||||
SetHeader("User-Agent", app.AppUserAgent).
|
||||
SetPreRequestHook(func(_ *resty.Client, req *http.Request) error {
|
||||
if client.token != "" {
|
||||
req.Header.Set("X-Auth-Token", client.token)
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func (c *Client) SetTimeout(timeout time.Duration) *Client {
|
||||
c.rc.SetTimeout(timeout)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) SetTLSConfig(config *tls.Config) *Client {
|
||||
c.rc.SetTLSClientConfig(config)
|
||||
return c
|
||||
}
|
||||
|
||||
func (c *Client) newRequest(method string, path string) (*resty.Request, error) {
|
||||
if method == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset method")
|
||||
}
|
||||
if path == "" {
|
||||
return nil, fmt.Errorf("sdkerr: unset path")
|
||||
}
|
||||
|
||||
req := c.rc.R()
|
||||
req.Method = method
|
||||
req.URL = path
|
||||
|
||||
// WARN:
|
||||
// DO NOT CALL `req.SetResult` or `req.SetError` AGAIN! USE `doRequestWithResult` INSTEAD.
|
||||
return req, nil
|
||||
}
|
||||
|
||||
func (c *Client) doRequest(req *resty.Request) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := req.Send()
|
||||
if err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to send request: %w", err)
|
||||
} else if resp.IsError() {
|
||||
return resp, fmt.Errorf("sdkerr: unexpected status code: %d (resp: %s)", resp.StatusCode(), resp.String())
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) doRequestWithResult(req *resty.Request, res sdkResponse) (*resty.Response, error) {
|
||||
if req == nil {
|
||||
return nil, fmt.Errorf("sdkerr: nil request")
|
||||
}
|
||||
|
||||
resp, err := c.doRequest(req)
|
||||
if err != nil {
|
||||
if resp != nil {
|
||||
json.Unmarshal(resp.Body(), &res)
|
||||
if successful, ok := res.(sdkSuccessfulResponse); ok && successful.isSuccessfulResponse() {
|
||||
return resp, nil
|
||||
}
|
||||
}
|
||||
return resp, err
|
||||
}
|
||||
|
||||
if len(resp.Body()) != 0 {
|
||||
if err := json.Unmarshal(resp.Body(), &res); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: failed to unmarshal response: %w (resp: %s)", err, resp.String())
|
||||
} else {
|
||||
if err := res.GetAPIError(); err != nil {
|
||||
return resp, fmt.Errorf("sdkerr: api error: %s", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func (c *Client) resolveLocation(location string) string {
|
||||
u, err := url.Parse(location)
|
||||
if err != nil || u.IsAbs() {
|
||||
return location
|
||||
}
|
||||
|
||||
base, err := url.Parse(c.rc.BaseURL)
|
||||
if err != nil {
|
||||
return location
|
||||
}
|
||||
|
||||
return base.ResolveReference(u).String()
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package huaweiibmc
|
||||
|
||||
type Entity struct {
|
||||
ID string `json:"Id,omitempty"`
|
||||
ODataID string `json:"@odata.id,omitempty"`
|
||||
ODataType string `json:"@odata.type,omitempty"`
|
||||
Name string `json:"Name,omitempty"`
|
||||
Description string `json:"Description"`
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package huaweiibmc
|
||||
|
||||
type Options struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
type OptionsFunc func(*Options)
|
||||
|
||||
func WithLogins(username, password string) OptionsFunc {
|
||||
return func(o *Options) {
|
||||
o.Username = username
|
||||
o.Password = password
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package huaweiibmc
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type sdkResponse interface {
|
||||
GetAPIError() error
|
||||
}
|
||||
|
||||
type sdkResponseBase struct {
|
||||
ODataContext string `json:"@odata.context,omitempty"`
|
||||
Error *sdkAPIError `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
type sdkAPIError struct {
|
||||
Code string `json:"code"`
|
||||
Message string `json:"message"`
|
||||
MessageExtendedInfo json.RawMessage `json:"@Message.ExtendedInfo,omitempty"`
|
||||
}
|
||||
|
||||
func (e sdkAPIError) Error() string {
|
||||
return fmt.Sprintf("[%s] %s", e.Code, e.Message)
|
||||
}
|
||||
|
||||
func (r *sdkResponseBase) GetAPIError() error {
|
||||
if r.Error != nil {
|
||||
return *r.Error
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ sdkResponse = (*sdkResponseBase)(nil)
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 1027 1024"><path fill="#c71f1e" d="M378.88 143.36c20.48-6.827 40.96-10.24 61.44-13.653 23.893 30.72 30.72 71.68 40.96 109.226 6.827 40.96 13.653 81.92 13.653 122.88 6.827 27.307 3.414 58.027 3.414 85.334s-3.414 51.2 0 78.506c0 37.547-3.414 71.68-3.414 109.227-6.826 23.893 0 47.787-6.826 71.68-10.24-3.413-13.654-13.653-17.067-20.48-40.96-61.44-78.507-122.88-112.64-187.733-34.133-68.267-68.267-136.534-71.68-215.04-6.827-61.44 34.133-119.467 92.16-139.947m211.627-10.24c6.826-3.413 10.24 0 17.066 0 27.307 6.827 58.027 10.24 81.92 27.307s44.374 40.96 51.2 68.266c10.24 34.134 6.827 71.68 0 105.814-10.24 44.373-30.72 85.333-51.2 126.293-6.826 13.653-13.653 23.893-20.48 37.547-10.24 23.893-27.306 47.786-40.96 71.68-23.893 40.96-47.786 75.093-71.68 116.053-3.413 3.413-6.826 13.653-13.653 6.827-3.413-40.96-6.827-81.92-10.24-126.294-6.827-54.613-3.413-105.813-3.413-160.426 3.413-34.134 3.413-71.68 6.826-105.814 6.827-40.96 13.654-85.333 27.307-126.293 13.653-10.24 13.653-30.72 27.307-40.96m-430.08 133.12c3.413 0 6.826 6.827 10.24 10.24C269.653 406.187 358.4 542.72 430.08 689.493c6.827 10.24 13.653 23.894 13.653 37.547-13.653-3.413-23.893-10.24-34.133-17.067-64.853-34.133-129.707-71.68-194.56-109.226-23.893-17.067-47.787-34.134-68.267-51.2-40.96-27.307-68.266-78.507-64.853-129.707 3.413-61.44 37.547-112.64 78.507-153.6m706.56 0h6.826c17.067 23.893 40.96 47.787 54.614 75.093 13.653 23.894 20.48 54.614 23.893 81.92 0 30.72-10.24 64.854-34.133 88.747-13.654 13.653-23.894 27.307-40.96 37.547-78.507 61.44-163.84 109.226-252.587 153.6-13.653 6.826-23.893 17.066-40.96 17.066 3.413-17.066 13.653-34.133 20.48-47.786C662.187 552.96 733.867 440.32 812.373 331.093c17.067-17.066 37.547-40.96 54.614-64.853M10.24 539.307c3.413-3.414 0-10.24 6.827-13.654 10.24 3.414 20.48 10.24 27.306 13.654 122.88 68.266 245.76 136.533 365.227 211.626 3.413 3.414 6.827 6.827 6.827 10.24h-235.52c-47.787 0-92.16-20.48-126.294-54.613C27.307 675.84 3.413 634.88 0 593.92c6.827-17.067 3.413-34.133 10.24-54.613m983.04-3.414c6.827-3.413 17.067-10.24 23.893-6.826 0 17.066 6.827 37.546 6.827 54.613-3.413 23.893-3.413 44.373-13.653 64.853-6.827 17.067-17.067 37.547-30.72 51.2-17.067 13.654-27.307 30.72-47.787 40.96-20.48 17.067-51.2 20.48-75.093 23.894h-245.76c3.413-3.414 3.413-6.827 6.826-10.24C740.693 675.84 866.987 604.16 993.28 535.893M184.32 798.72c44.373-3.413 88.747 0 133.12-6.827 30.72 0 64.853-3.413 95.573 0-6.826 13.654-23.893 20.48-34.133 27.307-34.133 23.893-68.267 44.373-105.813 61.44s-81.92 10.24-112.64-13.653c-23.894-17.067-44.374-44.374-58.027-68.267zm433.493-6.827c30.72-3.413 61.44 0 95.574 0 40.96 3.414 85.333 0 129.706 6.827 30.72 3.413 61.44 0 88.747 3.413-10.24 20.48-27.307 40.96-44.373 58.027-27.307 27.307-68.267 40.96-105.814 34.133-34.133-10.24-61.44-30.72-92.16-47.786-17.066-10.24-30.72-20.48-47.786-30.72-10.24-10.24-17.067-13.654-23.894-23.894"/></svg>
|
||||
@@ -64,6 +64,7 @@ import AccessConfigFieldsProviderHetzner from "./AccessConfigFieldsProviderHetzn
|
||||
import AccessConfigFieldsProviderHostingde from "./AccessConfigFieldsProviderHostingde";
|
||||
import AccessConfigFieldsProviderHostinger from "./AccessConfigFieldsProviderHostinger";
|
||||
import AccessConfigFieldsProviderHuaweiCloud from "./AccessConfigFieldsProviderHuaweiCloud";
|
||||
import AccessConfigFieldsProviderHuaweiIBMC from "./AccessConfigFieldsProviderHuaweiIBMC";
|
||||
import AccessConfigFieldsProviderInfomaniak from "./AccessConfigFieldsProviderInfomaniak";
|
||||
import AccessConfigFieldsProviderIONOS from "./AccessConfigFieldsProviderIONOS";
|
||||
import AccessConfigFieldsProviderJDCloud from "./AccessConfigFieldsProviderJDCloud";
|
||||
@@ -193,6 +194,7 @@ const providerComponentMap: Partial<Record<AccessProviderType, React.ComponentTy
|
||||
[ACCESS_PROVIDERS.HOSTINGDE]: AccessConfigFieldsProviderHostingde,
|
||||
[ACCESS_PROVIDERS.HOSTINGER]: AccessConfigFieldsProviderHostinger,
|
||||
[ACCESS_PROVIDERS.HUAWEICLOUD]: AccessConfigFieldsProviderHuaweiCloud,
|
||||
[ACCESS_PROVIDERS.HUAWEIIBMC]: AccessConfigFieldsProviderHuaweiIBMC,
|
||||
[ACCESS_PROVIDERS.IONOS]: AccessConfigFieldsProviderIONOS,
|
||||
[ACCESS_PROVIDERS.JDCLOUD]: AccessConfigFieldsProviderJDCloud,
|
||||
[ACCESS_PROVIDERS.KONG]: AccessConfigFieldsProviderKong,
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Input, Switch } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { isHostname, isUrlWithHttpOrHttps } from "@/utils/validator";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const AccessConfigFieldsProviderHuaweiIBMC = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({ [parentNamePath]: getSchema({ i18n }) });
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form.Item name={[parentNamePath, "host"]} initialValue={initialValues.host} label={t("access.form.huaweiibmc_host.label")} rules={[formRule]}>
|
||||
<Input placeholder={t("access.form.huaweiibmc_host.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "username"]}
|
||||
initialValue={initialValues.username}
|
||||
label={t("access.form.huaweiibmc_username.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input autoComplete="new-password" placeholder={t("access.form.huaweiibmc_username.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "password"]}
|
||||
initialValue={initialValues.password}
|
||||
label={t("access.form.huaweiibmc_password.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Input.Password autoComplete="new-password" placeholder={t("access.form.huaweiibmc_password.placeholder")} />
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
name={[parentNamePath, "allowInsecureConnections"]}
|
||||
initialValue={initialValues.allowInsecureConnections}
|
||||
label={t("access.form.shared_allow_insecure_conns.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
host: "",
|
||||
username: "",
|
||||
password: "",
|
||||
allowInsecureConnections: true,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n: ReturnType<typeof getI18n> }) => {
|
||||
const { t } = i18n;
|
||||
|
||||
return z.object({
|
||||
host: z.string().refine((v) => isHostname(v) || isUrlWithHttpOrHttps(v), t("common.errmsg.host_invalid")),
|
||||
username: z.string().nonempty(),
|
||||
password: z.string().nonempty(),
|
||||
allowInsecureConnections: z.boolean().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
export default Object.assign(AccessConfigFieldsProviderHuaweiIBMC, { getInitialValues, getSchema });
|
||||
@@ -74,6 +74,7 @@ import BizDeployNodeConfigFieldsProviderHuaweiCloudLive from "./BizDeployNodeCon
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudOBS from "./BizDeployNodeConfigFieldsProviderHuaweiCloudOBS";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudVOD from "./BizDeployNodeConfigFieldsProviderHuaweiCloudVOD";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiCloudWAF from "./BizDeployNodeConfigFieldsProviderHuaweiCloudWAF";
|
||||
import BizDeployNodeConfigFieldsProviderHuaweiIBMC from "./BizDeployNodeConfigFieldsProviderHuaweiIBMC";
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudALB from "./BizDeployNodeConfigFieldsProviderJDCloudALB";
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudCDN from "./BizDeployNodeConfigFieldsProviderJDCloudCDN";
|
||||
import BizDeployNodeConfigFieldsProviderJDCloudLive from "./BizDeployNodeConfigFieldsProviderJDCloudLive";
|
||||
@@ -226,6 +227,7 @@ const providerComponentMap: Partial<Record<DeploymentProviderType, React.Compone
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_OBS]: BizDeployNodeConfigFieldsProviderHuaweiCloudOBS,
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_VOD]: BizDeployNodeConfigFieldsProviderHuaweiCloudVOD,
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEICLOUD_WAF]: BizDeployNodeConfigFieldsProviderHuaweiCloudWAF,
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEIIBMC]: BizDeployNodeConfigFieldsProviderHuaweiIBMC,
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_ALB]: BizDeployNodeConfigFieldsProviderJDCloudALB,
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_CDN]: BizDeployNodeConfigFieldsProviderJDCloudCDN,
|
||||
[DEPLOYMENT_PROVIDERS.JDCLOUD_LIVE]: BizDeployNodeConfigFieldsProviderJDCloudLive,
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
import { getI18n, useTranslation } from "react-i18next";
|
||||
import { Form, Switch } from "antd";
|
||||
import { createSchemaFieldRule } from "antd-zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { useFormNestedFieldsContext } from "./_context";
|
||||
|
||||
const BizDeployNodeConfigFieldsProviderHuaweiIBMC = () => {
|
||||
const { i18n, t } = useTranslation();
|
||||
const { parentNamePath } = useFormNestedFieldsContext();
|
||||
const formSchema = z.object({ [parentNamePath]: getSchema({ i18n }) });
|
||||
const formRule = createSchemaFieldRule(formSchema);
|
||||
const initialValues = getInitialValues();
|
||||
|
||||
return (
|
||||
<Form.Item
|
||||
name={[parentNamePath, "autoRestart"]}
|
||||
initialValue={initialValues.autoRestart}
|
||||
label={t("workflow_node.deploy.form.huaweiibmc_auto_restart.label")}
|
||||
rules={[formRule]}
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
);
|
||||
};
|
||||
|
||||
const getInitialValues = (): Nullish<z.infer<ReturnType<typeof getSchema>>> => {
|
||||
return {
|
||||
autoRestart: true,
|
||||
};
|
||||
};
|
||||
|
||||
const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> }) => {
|
||||
const { t: _ } = i18n;
|
||||
|
||||
return z.object({
|
||||
autoRestart: z.boolean().nullish(),
|
||||
});
|
||||
};
|
||||
|
||||
export default Object.assign(BizDeployNodeConfigFieldsProviderHuaweiIBMC, { getInitialValues, getSchema });
|
||||
@@ -79,6 +79,7 @@ export const ACCESS_PROVIDERS = Object.freeze({
|
||||
HOSTINGDE: "hostingde",
|
||||
HOSTINGER: "hostinger",
|
||||
HUAWEICLOUD: "huaweicloud",
|
||||
HUAWEIIBMC: "huaweiibmc",
|
||||
INFOMANIAK: "infomaniak",
|
||||
IONOS: "ionos",
|
||||
JDCLOUD: "jdcloud",
|
||||
@@ -230,6 +231,7 @@ export const accessProvidersMap: Map<AccessProvider["type"] | string, AccessProv
|
||||
[ACCESS_PROVIDERS.SAFELINE, "provider.safeline", "/imgs/providers/safeline.svg", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.SAMWAF, "provider.samwaf", "/imgs/providers/samwaf.png", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.SYNOLOGYDSM, "provider.synologydsm", "/imgs/providers/synologydsm.svg", [ACCESS_USAGES.HOSTING]],
|
||||
[ACCESS_PROVIDERS.HUAWEIIBMC, "provider.huaweiibmc", "/imgs/providers/huawei.svg", [ACCESS_USAGES.HOSTING]],
|
||||
|
||||
[ACCESS_PROVIDERS.AKAMAI, "provider.akamai", "/imgs/providers/akamai.svg", [ACCESS_USAGES.DNS]],
|
||||
[ACCESS_PROVIDERS.ARVANCLOUD, "provider.arvancloud", "/imgs/providers/arvancloud.svg", [ACCESS_USAGES.DNS]],
|
||||
@@ -692,6 +694,7 @@ export const DEPLOYMENT_PROVIDERS = Object.freeze({
|
||||
HUAWEICLOUD_SCM: `${ACCESS_PROVIDERS.HUAWEICLOUD}-scm`,
|
||||
HUAWEICLOUD_VOD: `${ACCESS_PROVIDERS.HUAWEICLOUD}-vod`,
|
||||
HUAWEICLOUD_WAF: `${ACCESS_PROVIDERS.HUAWEICLOUD}-waf`,
|
||||
HUAWEIIBMC: `${ACCESS_PROVIDERS.HUAWEIIBMC}`,
|
||||
JDCLOUD_ALB: `${ACCESS_PROVIDERS.JDCLOUD}-alb`,
|
||||
JDCLOUD_CDN: `${ACCESS_PROVIDERS.JDCLOUD}-cdn`,
|
||||
JDCLOUD_LIVE: `${ACCESS_PROVIDERS.JDCLOUD}-live`,
|
||||
@@ -960,6 +963,7 @@ export const deploymentProvidersMap: Map<DeploymentProvider["type"] | string, De
|
||||
[DEPLOYMENT_PROVIDERS.PROXMOXBS, "provider.proxmoxbs", DEPLOYMENT_CATEGORIES.OTHER],
|
||||
[DEPLOYMENT_PROVIDERS.PROXMOXVE, "provider.proxmoxve", DEPLOYMENT_CATEGORIES.OTHER],
|
||||
[DEPLOYMENT_PROVIDERS.SYNOLOGYDSM, "provider.synologydsm", DEPLOYMENT_CATEGORIES.OTHER],
|
||||
[DEPLOYMENT_PROVIDERS.HUAWEIIBMC, "provider.huaweiibmc", DEPLOYMENT_CATEGORIES.OTHER],
|
||||
] satisfies Array<[DeploymentProviderType, string, DeploymentCategoryType, "builtin"] | [DeploymentProviderType, string, DeploymentCategoryType]>
|
||||
).map(([type, name, category, builtin]) => [
|
||||
type,
|
||||
|
||||
@@ -796,6 +796,18 @@
|
||||
"placeholder": "Please enter Huawei Cloud enterprise project ID",
|
||||
"tooltip": "For more information, see <a href=\"https://support.huaweicloud.com/intl/en-us/usermanual-em/em_03_0000.html\" target=\"_blank\">https://support.huaweicloud.com/intl/en-us/usermanual-em/em_03_0000.html</a>"
|
||||
},
|
||||
"huaweiibmc_host": {
|
||||
"label": "iBMC Redfish server host",
|
||||
"placeholder": "Please enter iBMC Redfish server host"
|
||||
},
|
||||
"huaweiibmc_username": {
|
||||
"label": "iBMC username",
|
||||
"placeholder": "Please enter the iBMC username"
|
||||
},
|
||||
"huaweiibmc_password": {
|
||||
"label": "iBMC password",
|
||||
"placeholder": "Please enter the iBMC password"
|
||||
},
|
||||
"infomaniak_access_token": {
|
||||
"label": "Infomaniak access token",
|
||||
"placeholder": "Please enter Infomaniak access token",
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
"huaweicloud_scm_upload": "Huawei Cloud - Upload to SCM (SSL Certificate Manager)",
|
||||
"huaweicloud_vod": "Huawei Cloud - VOD (Video on Demand)",
|
||||
"huaweicloud_waf": "Huawei Cloud - WAF (Web Application Firewall)",
|
||||
"huaweiibmc": "Huawei iBMC",
|
||||
"infomaniak": "Infomaniak",
|
||||
"ionos": "IONOS",
|
||||
"jdcloud": "JD Cloud",
|
||||
|
||||
@@ -1717,6 +1717,9 @@
|
||||
"placeholder": "Please enter Huawei Cloud WAF certificate ID",
|
||||
"tooltip": "For more information, see <a href=\"https://console-intl.huaweicloud.com/console/#/waf/certificateManagement\" target=\"_blank\">https://console-intl.huaweicloud.com/console/#/waf/certificateManagement</a>"
|
||||
},
|
||||
"huaweiibmc_auto_restart": {
|
||||
"label": "Auto restart iBMC after deployment"
|
||||
},
|
||||
"jdcloud_alb_region_id": {
|
||||
"label": "JD Cloud region ID",
|
||||
"placeholder": "Please enter JD Cloud ALB region ID (e.g. cn-north-1)",
|
||||
|
||||
@@ -796,6 +796,18 @@
|
||||
"placeholder": "请输入华为云企业项目 ID",
|
||||
"tooltip": "这是什么?请参阅 <a href=\"https://support.huaweicloud.com/usermanual-em/zh-cn_topic_0126101490.html\" target=\"_blank\">https://support.huaweicloud.com/usermanual-em/zh-cn_topic_0126101490.html</a>"
|
||||
},
|
||||
"huaweiibmc_host": {
|
||||
"label": "iBMC Redfish 服务器地址",
|
||||
"placeholder": "请输入 iBMC Redfish 服务器地址"
|
||||
},
|
||||
"huaweiibmc_username": {
|
||||
"label": "iBMC 用户名",
|
||||
"placeholder": "请输入 iBMC 用户名"
|
||||
},
|
||||
"huaweiibmc_password": {
|
||||
"label": "iBMC 密码",
|
||||
"placeholder": "请输入 iBMC 密码"
|
||||
},
|
||||
"infomaniak_access_token": {
|
||||
"label": "Infomaniak AccessToken",
|
||||
"placeholder": "请输入 Infomaniak AccessToken",
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
"huaweicloud_scm_upload": "华为云 - 上传到云证书管理服务 SCM",
|
||||
"huaweicloud_vod": "华为云 - 视频点播 VOD",
|
||||
"huaweicloud_waf": "华为云 - Web 应用防火墙 WAF",
|
||||
"huaweiibmc": "华为 iBMC",
|
||||
"infomaniak": "Infomaniak",
|
||||
"ionos": "IONOS",
|
||||
"jdcloud": "京东云",
|
||||
|
||||
@@ -1716,6 +1716,9 @@
|
||||
"placeholder": "请输入华为云 WAF 证书 ID",
|
||||
"tooltip": "这是什么?请参阅 <a href=\"https://console.huaweicloud.com/console/#/waf/certificateManagement\" target=\"_blank\">https://console.huaweicloud.com/console/#/waf/certificateManagement</a>"
|
||||
},
|
||||
"huaweiibmc_auto_restart": {
|
||||
"label": "部署后自动重启 iBMC 服务"
|
||||
},
|
||||
"jdcloud_alb_region_id": {
|
||||
"label": "京东云服务地域 ID",
|
||||
"placeholder": "请输入京东云 ALB 服务地域 ID(例如:cn-north-1)",
|
||||
|
||||
Reference in New Issue
Block a user