1
0
Fork 0

fix: update lego.

This commit is contained in:
Fernandez Ludovic 2019-04-26 11:08:44 +02:00 committed by Traefiker Bot
parent b8b0c8f3e5
commit 8d848c3d60
169 changed files with 12224 additions and 605 deletions

View file

@ -6,7 +6,6 @@ import (
"crypto/elliptic"
"crypto/rsa"
"encoding/base64"
"errors"
"fmt"
"github.com/go-acme/lego/acme/api/internal/nonces"
@ -118,9 +117,6 @@ func (j *JWS) GetKeyAuthorization(token string) (string, error) {
// Generate the Key Authorization for the challenge
jwk := &jose.JSONWebKey{Key: publicKey}
if jwk == nil {
return "", errors.New("could not generate JWK from key")
}
thumbBytes, err := jwk.Thumbprint(crypto.SHA256)
if err != nil {

View file

@ -5,7 +5,7 @@ package sender
const (
// ourUserAgent is the User-Agent of this underlying library package.
ourUserAgent = "xenolf-acme/2.4.0"
ourUserAgent = "xenolf-acme/2.5.0"
// ourUserAgentComment is part of the UA comment linked to the version status of this underlying library package.
// values: detach|release

View file

@ -114,6 +114,7 @@ func (c *Certifier) Obtain(request ObtainRequest) (*Resource, error) {
err = c.resolver.Solve(authz)
if err != nil {
// If any challenge fails, return. Do not generate partial SAN certificates.
c.deactivateAuthorizations(order)
return nil, err
}
@ -170,6 +171,7 @@ func (c *Certifier) ObtainForCSR(csr x509.CertificateRequest, bundle bool) (*Res
err = c.resolver.Solve(authz)
if err != nil {
// If any challenge fails, return. Do not generate partial SAN certificates.
c.deactivateAuthorizations(order)
return nil, err
}

View file

@ -27,7 +27,7 @@ func NewDefaultConfig() *Config {
return &Config{
PropagationTimeout: env.GetOrDefaultSecond("CLOUDNS_PROPAGATION_TIMEOUT", 120*time.Second),
PollingInterval: env.GetOrDefaultSecond("CLOUDNS_POLLING_INTERVAL", 4*time.Second),
TTL: env.GetOrDefaultInt("CLOUDNS_TTL", dns01.DefaultTTL),
TTL: env.GetOrDefaultInt("CLOUDNS_TTL", 60),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond("CLOUDNS_HTTP_TIMEOUT", 30*time.Second),
},
@ -64,7 +64,7 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
client, err := internal.NewClient(config.AuthID, config.AuthPassword)
if err != nil {
return nil, err
return nil, fmt.Errorf("ClouDNS: %v", err)
}
client.HTTPClient = config.HTTPClient
@ -78,10 +78,15 @@ func (d *DNSProvider) Present(domain, token, keyAuth string) error {
zone, err := d.client.GetZone(fqdn)
if err != nil {
return err
return fmt.Errorf("ClouDNS: %v", err)
}
return d.client.AddTxtRecord(zone.Name, fqdn, value, d.config.TTL)
err = d.client.AddTxtRecord(zone.Name, fqdn, value, d.config.TTL)
if err != nil {
return fmt.Errorf("ClouDNS: %v", err)
}
return nil
}
// CleanUp removes the TXT record matching the specified parameters.
@ -90,15 +95,23 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
zone, err := d.client.GetZone(fqdn)
if err != nil {
return err
return fmt.Errorf("ClouDNS: %v", err)
}
record, err := d.client.FindTxtRecord(zone.Name, fqdn)
if err != nil {
return err
return fmt.Errorf("ClouDNS: %v", err)
}
return d.client.RemoveTxtRecord(record.ID, zone.Name)
if record == nil {
return nil
}
err = d.client.RemoveTxtRecord(record.ID, zone.Name)
if err != nil {
return fmt.Errorf("ClouDNS: %v", err)
}
return nil
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.

View file

@ -2,6 +2,7 @@ package internal
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"net/http"
@ -14,6 +15,11 @@ import (
const defaultBaseURL = "https://api.cloudns.net/dns/"
type apiResponse struct {
Status string `json:"status"`
StatusDescription string `json:"statusDescription"`
}
type Zone struct {
Name string
Type string
@ -37,11 +43,11 @@ type TXTRecords map[string]TXTRecord
// NewClient creates a ClouDNS client
func NewClient(authID string, authPassword string) (*Client, error) {
if authID == "" {
return nil, fmt.Errorf("ClouDNS: credentials missing: authID")
return nil, fmt.Errorf("credentials missing: authID")
}
if authPassword == "" {
return nil, fmt.Errorf("ClouDNS: credentials missing: authPassword")
return nil, fmt.Errorf("credentials missing: authPassword")
}
baseURL, err := url.Parse(defaultBaseURL)
@ -90,7 +96,7 @@ func (c *Client) GetZone(authFQDN string) (*Zone, error) {
if len(result) > 0 {
if err = json.Unmarshal(result, &zone); err != nil {
return nil, fmt.Errorf("ClouDNS: zone unmarshaling error: %v", err)
return nil, fmt.Errorf("zone unmarshaling error: %v", err)
}
}
@ -98,7 +104,7 @@ func (c *Client) GetZone(authFQDN string) (*Zone, error) {
return &zone, nil
}
return nil, fmt.Errorf("ClouDNS: zone %s not found for authFQDN %s", authZoneName, authFQDN)
return nil, fmt.Errorf("zone %s not found for authFQDN %s", authZoneName, authFQDN)
}
// FindTxtRecord return the TXT record a zone ID and a FQDN
@ -119,9 +125,14 @@ func (c *Client) FindTxtRecord(zoneName, fqdn string) (*TXTRecord, error) {
return nil, err
}
// the API returns [] when there is no records.
if string(result) == "[]" {
return nil, nil
}
var records TXTRecords
if err = json.Unmarshal(result, &records); err != nil {
return nil, fmt.Errorf("ClouDNS: TXT record unmarshaling error: %v", err)
return nil, fmt.Errorf("TXT record unmarshaling error: %v: %s", err, string(result))
}
for _, record := range records {
@ -130,7 +141,7 @@ func (c *Client) FindTxtRecord(zoneName, fqdn string) (*TXTRecord, error) {
}
}
return nil, fmt.Errorf("ClouDNS: no existing record found for %q", fqdn)
return nil, nil
}
// AddTxtRecord add a TXT record
@ -144,12 +155,25 @@ func (c *Client) AddTxtRecord(zoneName string, fqdn, value string, ttl int) erro
q.Add("domain-name", zoneName)
q.Add("host", host)
q.Add("record", value)
q.Add("ttl", strconv.Itoa(ttl))
q.Add("ttl", strconv.Itoa(ttlRounder(ttl)))
q.Add("record-type", "TXT")
reqURL.RawQuery = q.Encode()
_, err := c.doRequest(http.MethodPost, &reqURL)
return err
raw, err := c.doRequest(http.MethodPost, &reqURL)
if err != nil {
return err
}
resp := apiResponse{}
if err = json.Unmarshal(raw, &resp); err != nil {
return fmt.Errorf("apiResponse unmarshaling error: %v: %s", err, string(raw))
}
if resp.Status != "Success" {
return fmt.Errorf("fail to add TXT record: %s %s", resp.Status, resp.StatusDescription)
}
return nil
}
// RemoveTxtRecord remove a TXT record
@ -162,8 +186,21 @@ func (c *Client) RemoveTxtRecord(recordID int, zoneName string) error {
q.Add("record-id", strconv.Itoa(recordID))
reqURL.RawQuery = q.Encode()
_, err := c.doRequest(http.MethodPost, &reqURL)
return err
raw, err := c.doRequest(http.MethodPost, &reqURL)
if err != nil {
return err
}
resp := apiResponse{}
if err = json.Unmarshal(raw, &resp); err != nil {
return fmt.Errorf("apiResponse unmarshaling error: %v: %s", err, string(raw))
}
if resp.Status != "Success" {
return fmt.Errorf("fail to add TXT record: %s %s", resp.Status, resp.StatusDescription)
}
return nil
}
func (c *Client) doRequest(method string, url *url.URL) (json.RawMessage, error) {
@ -174,18 +211,18 @@ func (c *Client) doRequest(method string, url *url.URL) (json.RawMessage, error)
resp, err := c.HTTPClient.Do(req)
if err != nil {
return nil, fmt.Errorf("ClouDNS: %v", err)
return nil, err
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("ClouDNS: %s", toUnreadableBodyMessage(req, content))
return nil, errors.New(toUnreadableBodyMessage(req, content))
}
if resp.StatusCode != 200 {
return nil, fmt.Errorf("ClouDNS: invalid code (%v), error: %s", resp.StatusCode, content)
return nil, fmt.Errorf("invalid code (%v), error: %s", resp.StatusCode, content)
}
return content, nil
}
@ -198,7 +235,7 @@ func (c *Client) buildRequest(method string, url *url.URL) (*http.Request, error
req, err := http.NewRequest(method, url.String(), nil)
if err != nil {
return nil, fmt.Errorf("ClouDNS: invalid request: %v", err)
return nil, fmt.Errorf("invalid request: %v", err)
}
return req, nil
@ -207,3 +244,28 @@ func (c *Client) buildRequest(method string, url *url.URL) (*http.Request, error
func toUnreadableBodyMessage(req *http.Request, rawBody []byte) string {
return fmt.Sprintf("the request %s sent a response with a body which is an invalid format: %q", req.URL, string(rawBody))
}
// https://www.cloudns.net/wiki/article/58/
// Available TTL's:
// 60 = 1 minute
// 300 = 5 minutes
// 900 = 15 minutes
// 1800 = 30 minutes
// 3600 = 1 hour
// 21600 = 6 hours
// 43200 = 12 hours
// 86400 = 1 day
// 172800 = 2 days
// 259200 = 3 days
// 604800 = 1 week
// 1209600 = 2 weeks
// 2592000 = 1 month
func ttlRounder(ttl int) int {
for _, validTTL := range []int{60, 300, 900, 1800, 3600, 21600, 43200, 86400, 172800, 259200, 604800, 1209600} {
if ttl <= validTTL {
return validTTL
}
}
return 2592000
}

View file

@ -47,13 +47,13 @@ func (d *DNSProvider) addTXTRecord(domain string, name string, value string, ttl
return err
}
message := &apiResponse{}
err = d.do(req, message)
message := apiResponse{}
err = d.do(req, &message)
if err != nil {
return fmt.Errorf("unable to create TXT record for domain %s and name %s: %v", domain, name, err)
}
if message != nil && len(message.Message) > 0 {
if len(message.Message) > 0 {
log.Infof("API response: %s", message.Message)
}
@ -87,13 +87,13 @@ func (d *DNSProvider) deleteTXTRecord(domain string, name string) error {
return err
}
message := &apiResponse{}
err = d.do(req, message)
message := apiResponse{}
err = d.do(req, &message)
if err != nil {
return fmt.Errorf("unable to delete TXT record for domain %s and name %s: %v", domain, name, err)
}
if message != nil && len(message.Message) > 0 {
if len(message.Message) > 0 {
log.Infof("API response: %s", message.Message)
}

View file

@ -18,6 +18,7 @@ import (
"golang.org/x/oauth2/google"
"google.golang.org/api/dns/v1"
"google.golang.org/api/googleapi"
"google.golang.org/api/option"
)
const (
@ -139,8 +140,11 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
if config == nil {
return nil, errors.New("googlecloud: the configuration of the DNS provider is nil")
}
if config.HTTPClient == nil {
return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: client is nil")
}
svc, err := dns.New(config.HTTPClient)
svc, err := dns.NewService(context.Background(), option.WithHTTPClient(config.HTTPClient))
if err != nil {
return nil, fmt.Errorf("googlecloud: unable to create Google Cloud DNS service: %v", err)
}
@ -306,7 +310,13 @@ func (d *DNSProvider) getHostedZone(domain string) (string, error) {
return "", fmt.Errorf("no matching domain found for domain %s", authZone)
}
return zones.ManagedZones[0].Name, nil
for _, z := range zones.ManagedZones {
if z.Visibility == "public" {
return z.Name, nil
}
}
return "", fmt.Errorf("no public zone found for domain %s", authZone)
}
func (d *DNSProvider) findTxtRecords(zone, fqdn string) ([]*dns.ResourceRecordSet, error) {

View file

@ -0,0 +1,106 @@
package sakuracloud
import (
"fmt"
"net/http"
"strings"
"github.com/go-acme/lego/challenge/dns01"
"github.com/sacloud/libsacloud/api"
"github.com/sacloud/libsacloud/sacloud"
)
const sacloudAPILockKey = "lego/dns/sacloud"
func (d *DNSProvider) addTXTRecord(fqdn, domain, value string, ttl int) error {
sacloud.LockByKey(sacloudAPILockKey)
defer sacloud.UnlockByKey(sacloudAPILockKey)
zone, err := d.getHostedZone(domain)
if err != nil {
return fmt.Errorf("sakuracloud: %v", err)
}
name := d.extractRecordName(fqdn, zone.Name)
zone.AddRecord(zone.CreateNewRecord(name, "TXT", value, ttl))
_, err = d.client.Update(zone.ID, zone)
if err != nil {
return fmt.Errorf("sakuracloud: API call failed: %v", err)
}
return nil
}
func (d *DNSProvider) cleanupTXTRecord(fqdn, domain string) error {
sacloud.LockByKey(sacloudAPILockKey)
defer sacloud.UnlockByKey(sacloudAPILockKey)
zone, err := d.getHostedZone(domain)
if err != nil {
return fmt.Errorf("sakuracloud: %v", err)
}
records := d.findTxtRecords(fqdn, zone)
for _, record := range records {
var updRecords []sacloud.DNSRecordSet
for _, r := range zone.Settings.DNS.ResourceRecordSets {
if !(r.Name == record.Name && r.Type == record.Type && r.RData == record.RData) {
updRecords = append(updRecords, r)
}
}
zone.Settings.DNS.ResourceRecordSets = updRecords
}
_, err = d.client.Update(zone.ID, zone)
if err != nil {
return fmt.Errorf("sakuracloud: API call failed: %v", err)
}
return nil
}
func (d *DNSProvider) getHostedZone(domain string) (*sacloud.DNS, error) {
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
if err != nil {
return nil, err
}
zoneName := dns01.UnFqdn(authZone)
res, err := d.client.Reset().WithNameLike(zoneName).Find()
if err != nil {
if notFound, ok := err.(api.Error); ok && notFound.ResponseCode() == http.StatusNotFound {
return nil, fmt.Errorf("zone %s not found on SakuraCloud DNS: %v", zoneName, err)
}
return nil, fmt.Errorf("API call failed: %v", err)
}
for _, zone := range res.CommonServiceDNSItems {
if zone.Name == zoneName {
return &zone, nil
}
}
return nil, fmt.Errorf("zone %s not found", zoneName)
}
func (d *DNSProvider) findTxtRecords(fqdn string, zone *sacloud.DNS) []sacloud.DNSRecordSet {
recordName := d.extractRecordName(fqdn, zone.Name)
var res []sacloud.DNSRecordSet
for _, record := range zone.Settings.DNS.ResourceRecordSets {
if record.Name == recordName && record.Type == "TXT" {
res = append(res, record)
}
}
return res
}
func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
name := dns01.UnFqdn(fqdn)
if idx := strings.Index(name, "."+domain); idx != -1 {
return name[:idx]
}
return name
}

View file

@ -5,13 +5,11 @@ import (
"errors"
"fmt"
"net/http"
"strings"
"time"
"github.com/go-acme/lego/challenge/dns01"
"github.com/go-acme/lego/platform/config/env"
"github.com/sacloud/libsacloud/api"
"github.com/sacloud/libsacloud/sacloud"
)
// Config is used to configure the creation of the DNSProvider
@ -21,6 +19,7 @@ type Config struct {
PropagationTimeout time.Duration
PollingInterval time.Duration
TTL int
HTTPClient *http.Client
}
// NewDefaultConfig returns a default configuration for the DNSProvider
@ -29,13 +28,16 @@ func NewDefaultConfig() *Config {
TTL: env.GetOrDefaultInt("SAKURACLOUD_TTL", dns01.DefaultTTL),
PropagationTimeout: env.GetOrDefaultSecond("SAKURACLOUD_PROPAGATION_TIMEOUT", dns01.DefaultPropagationTimeout),
PollingInterval: env.GetOrDefaultSecond("SAKURACLOUD_POLLING_INTERVAL", dns01.DefaultPollingInterval),
HTTPClient: &http.Client{
Timeout: env.GetOrDefaultSecond("SAKURACLOUD_HTTP_TIMEOUT", 10*time.Second),
},
}
}
// DNSProvider is an implementation of the acme.ChallengeProvider interface.
type DNSProvider struct {
config *Config
client *api.Client
client *api.DNSAPI
}
// NewDNSProvider returns a DNSProvider instance configured for SakuraCloud.
@ -67,58 +69,29 @@ func NewDNSProviderConfig(config *Config) (*DNSProvider, error) {
return nil, errors.New("sakuracloud: AccessSecret is missing")
}
client := api.NewClient(config.Token, config.Secret, "tk1a")
apiClient := api.NewClient(config.Token, config.Secret, "is1a")
if config.HTTPClient == nil {
apiClient.HTTPClient = http.DefaultClient
} else {
apiClient.HTTPClient = config.HTTPClient
}
return &DNSProvider{client: client, config: config}, nil
return &DNSProvider{
client: apiClient.GetDNSAPI(),
config: config,
}, nil
}
// Present creates a TXT record to fulfill the dns-01 challenge.
func (d *DNSProvider) Present(domain, token, keyAuth string) error {
fqdn, value := dns01.GetRecord(domain, keyAuth)
zone, err := d.getHostedZone(domain)
if err != nil {
return fmt.Errorf("sakuracloud: %v", err)
}
name := d.extractRecordName(fqdn, zone.Name)
zone.AddRecord(zone.CreateNewRecord(name, "TXT", value, d.config.TTL))
_, err = d.client.GetDNSAPI().Update(zone.ID, zone)
if err != nil {
return fmt.Errorf("sakuracloud: API call failed: %v", err)
}
return nil
return d.addTXTRecord(fqdn, domain, value, d.config.TTL)
}
// CleanUp removes the TXT record matching the specified parameters.
func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
fqdn, _ := dns01.GetRecord(domain, keyAuth)
zone, err := d.getHostedZone(domain)
if err != nil {
return fmt.Errorf("sakuracloud: %v", err)
}
records := d.findTxtRecords(fqdn, zone)
for _, record := range records {
var updRecords []sacloud.DNSRecordSet
for _, r := range zone.Settings.DNS.ResourceRecordSets {
if !(r.Name == record.Name && r.Type == record.Type && r.RData == record.RData) {
updRecords = append(updRecords, r)
}
}
zone.Settings.DNS.ResourceRecordSets = updRecords
}
_, err = d.client.GetDNSAPI().Update(zone.ID, zone)
if err != nil {
return fmt.Errorf("sakuracloud: API call failed: %v", err)
}
return nil
return d.cleanupTXTRecord(fqdn, domain)
}
// Timeout returns the timeout and interval to use when checking for DNS propagation.
@ -126,48 +99,3 @@ func (d *DNSProvider) CleanUp(domain, token, keyAuth string) error {
func (d *DNSProvider) Timeout() (timeout, interval time.Duration) {
return d.config.PropagationTimeout, d.config.PollingInterval
}
func (d *DNSProvider) getHostedZone(domain string) (*sacloud.DNS, error) {
authZone, err := dns01.FindZoneByFqdn(dns01.ToFqdn(domain))
if err != nil {
return nil, err
}
zoneName := dns01.UnFqdn(authZone)
res, err := d.client.GetDNSAPI().WithNameLike(zoneName).Find()
if err != nil {
if notFound, ok := err.(api.Error); ok && notFound.ResponseCode() == http.StatusNotFound {
return nil, fmt.Errorf("zone %s not found on SakuraCloud DNS: %v", zoneName, err)
}
return nil, fmt.Errorf("API call failed: %v", err)
}
for _, zone := range res.CommonServiceDNSItems {
if zone.Name == zoneName {
return &zone, nil
}
}
return nil, fmt.Errorf("zone %s not found", zoneName)
}
func (d *DNSProvider) findTxtRecords(fqdn string, zone *sacloud.DNS) []sacloud.DNSRecordSet {
recordName := d.extractRecordName(fqdn, zone.Name)
var res []sacloud.DNSRecordSet
for _, record := range zone.Settings.DNS.ResourceRecordSets {
if record.Name == recordName && record.Type == "TXT" {
res = append(res, record)
}
}
return res
}
func (d *DNSProvider) extractRecordName(fqdn, domain string) string {
name := dns01.UnFqdn(fqdn)
if idx := strings.Index(name, "."+domain); idx != -1 {
return name[:idx]
}
return name
}

View file

@ -2,10 +2,11 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"github.com/sacloud/libsacloud/sacloud/ostype"
"strings"
"time"
"github.com/sacloud/libsacloud/sacloud"
"github.com/sacloud/libsacloud/sacloud/ostype"
)
// ArchiveAPI アーカイブAPI
@ -15,25 +16,30 @@ type ArchiveAPI struct {
}
var (
archiveLatestStableCentOSTags = []string{"current-stable", "distro-centos"}
archiveLatestStableCentOS6Tags = []string{"distro-centos", "distro-ver-6.9"}
archiveLatestStableUbuntuTags = []string{"current-stable", "distro-ubuntu"}
archiveLatestStableDebianTags = []string{"current-stable", "distro-debian"}
archiveLatestStableVyOSTags = []string{"current-stable", "distro-vyos"}
archiveLatestStableCoreOSTags = []string{"current-stable", "distro-coreos"}
archiveLatestStableRancherOSTags = []string{"current-stable", "distro-rancheros"}
archiveLatestStableKusanagiTags = []string{"current-stable", "pkg-kusanagi"}
archiveLatestStableSophosUTMTags = []string{"current-stable", "pkg-sophosutm"}
archiveLatestStableFreeBSDTags = []string{"current-stable", "distro-freebsd"}
archiveLatestStableWindows2012Tags = []string{"os-windows", "distro-ver-2012.2"}
archiveLatestStableWindows2012RDSTags = []string{"os-windows", "distro-ver-2012.2", "windows-rds"}
archiveLatestStableWindows2012RDSOfficeTags = []string{"os-windows", "distro-ver-2012.2", "windows-rds", "with-office"}
archiveLatestStableWindows2016Tags = []string{"os-windows", "distro-ver-2016"}
archiveLatestStableWindows2016RDSTags = []string{"os-windows", "distro-ver-2016", "windows-rds"}
archiveLatestStableWindows2016RDSOfficeTags = []string{"os-windows", "distro-ver-2016", "windows-rds", "with-office"}
archiveLatestStableWindows2016SQLServerWeb = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2016", "edition-web"}
archiveLatestStableWindows2016SQLServerStandard = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2016", "edition-standard"}
archiveLatestStableWindows2016SQLServerStandardAll = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2016", "edition-standard", "windows-rds", "with-office"}
archiveLatestStableCentOSTags = []string{"current-stable", "distro-centos"}
archiveLatestStableCentOS6Tags = []string{"distro-centos", "distro-ver-6.10"}
archiveLatestStableUbuntuTags = []string{"current-stable", "distro-ubuntu"}
archiveLatestStableDebianTags = []string{"current-stable", "distro-debian"}
archiveLatestStableVyOSTags = []string{"current-stable", "distro-vyos"}
archiveLatestStableCoreOSTags = []string{"current-stable", "distro-coreos"}
archiveLatestStableRancherOSTags = []string{"current-stable", "distro-rancheros"}
archiveLatestStableKusanagiTags = []string{"current-stable", "pkg-kusanagi"}
archiveLatestStableSophosUTMTags = []string{"current-stable", "pkg-sophosutm"}
archiveLatestStableFreeBSDTags = []string{"current-stable", "distro-freebsd"}
archiveLatestStableNetwiserTags = []string{"current-stable", "pkg-netwiserve"}
archiveLatestStableOPNsenseTags = []string{"current-stable", "distro-opnsense"}
archiveLatestStableWindows2012Tags = []string{"os-windows", "distro-ver-2012.2"}
archiveLatestStableWindows2012RDSTags = []string{"os-windows", "distro-ver-2012.2", "windows-rds"}
archiveLatestStableWindows2012RDSOfficeTags = []string{"os-windows", "distro-ver-2012.2", "windows-rds", "with-office"}
archiveLatestStableWindows2016Tags = []string{"os-windows", "distro-ver-2016"}
archiveLatestStableWindows2016RDSTags = []string{"os-windows", "distro-ver-2016", "windows-rds"}
archiveLatestStableWindows2016RDSOfficeTags = []string{"os-windows", "distro-ver-2016", "windows-rds", "with-office"}
archiveLatestStableWindows2016SQLServerWeb = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2016", "edition-web"}
archiveLatestStableWindows2016SQLServerStandard = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2016", "edition-standard"}
archiveLatestStableWindows2016SQLServer2017Standard = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2017", "edition-standard"}
archiveLatestStableWindows2016SQLServerStandardAll = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2016", "edition-standard", "windows-rds", "with-office"}
archiveLatestStableWindows2016SQLServer2017StandardAll = []string{"os-windows", "distro-ver-2016", "windows-sqlserver", "sqlserver-2017", "edition-standard", "windows-rds", "with-office"}
archiveLatestStableWindows2019Tags = []string{"os-windows", "distro-ver-2019"}
)
// NewArchiveAPI アーカイブAPI作成
@ -48,25 +54,29 @@ func NewArchiveAPI(client *Client) *ArchiveAPI {
}
api.findFuncMapPerOSType = map[ostype.ArchiveOSTypes]func() (*sacloud.Archive, error){
ostype.CentOS: api.FindLatestStableCentOS,
ostype.CentOS6: api.FindLatestStableCentOS6,
ostype.Ubuntu: api.FindLatestStableUbuntu,
ostype.Debian: api.FindLatestStableDebian,
ostype.VyOS: api.FindLatestStableVyOS,
ostype.CoreOS: api.FindLatestStableCoreOS,
ostype.RancherOS: api.FindLatestStableRancherOS,
ostype.Kusanagi: api.FindLatestStableKusanagi,
ostype.SophosUTM: api.FindLatestStableSophosUTM,
ostype.FreeBSD: api.FindLatestStableFreeBSD,
ostype.Windows2012: api.FindLatestStableWindows2012,
ostype.Windows2012RDS: api.FindLatestStableWindows2012RDS,
ostype.Windows2012RDSOffice: api.FindLatestStableWindows2012RDSOffice,
ostype.Windows2016: api.FindLatestStableWindows2016,
ostype.Windows2016RDS: api.FindLatestStableWindows2016RDS,
ostype.Windows2016RDSOffice: api.FindLatestStableWindows2016RDSOffice,
ostype.Windows2016SQLServerWeb: api.FindLatestStableWindows2016SQLServerWeb,
ostype.Windows2016SQLServerStandard: api.FindLatestStableWindows2016SQLServerStandard,
ostype.Windows2016SQLServerStandardAll: api.FindLatestStableWindows2016SQLServerStandardAll,
ostype.CentOS: api.FindLatestStableCentOS,
ostype.CentOS6: api.FindLatestStableCentOS6,
ostype.Ubuntu: api.FindLatestStableUbuntu,
ostype.Debian: api.FindLatestStableDebian,
ostype.VyOS: api.FindLatestStableVyOS,
ostype.CoreOS: api.FindLatestStableCoreOS,
ostype.RancherOS: api.FindLatestStableRancherOS,
ostype.Kusanagi: api.FindLatestStableKusanagi,
ostype.SophosUTM: api.FindLatestStableSophosUTM,
ostype.FreeBSD: api.FindLatestStableFreeBSD,
ostype.Netwiser: api.FindLatestStableNetwiser,
ostype.OPNsense: api.FindLatestStableOPNsense,
ostype.Windows2012: api.FindLatestStableWindows2012,
ostype.Windows2012RDS: api.FindLatestStableWindows2012RDS,
ostype.Windows2012RDSOffice: api.FindLatestStableWindows2012RDSOffice,
ostype.Windows2016: api.FindLatestStableWindows2016,
ostype.Windows2016RDS: api.FindLatestStableWindows2016RDS,
ostype.Windows2016RDSOffice: api.FindLatestStableWindows2016RDSOffice,
ostype.Windows2016SQLServerWeb: api.FindLatestStableWindows2016SQLServerWeb,
ostype.Windows2016SQLServerStandard: api.FindLatestStableWindows2016SQLServerStandard,
ostype.Windows2016SQLServer2017Standard: api.FindLatestStableWindows2016SQLServer2017Standard,
ostype.Windows2016SQLServerStandardAll: api.FindLatestStableWindows2016SQLServerStandardAll,
ostype.Windows2016SQLServer2017StandardAll: api.FindLatestStableWindows2016SQLServer2017StandardAll,
}
return api
@ -137,6 +147,14 @@ func (api *ArchiveAPI) CanEditDisk(id int64) (bool, error) {
if archive.HasTag("pkg-sophosutm") || archive.IsSophosUTM() {
return false, nil
}
// OPNsenseであれば編集不可
if archive.HasTag("distro-opnsense") {
return false, nil
}
// Netwiser VEであれば編集不可
if archive.HasTag("pkg-netwiserve") {
return false, nil
}
for _, t := range allowDiskEditTags {
if archive.HasTag(t) {
@ -180,6 +198,14 @@ func (api *ArchiveAPI) GetPublicArchiveIDFromAncestors(id int64) (int64, bool) {
if archive.HasTag("pkg-sophosutm") || archive.IsSophosUTM() {
return emptyID, false
}
// OPNsenseであれば編集不可
if archive.HasTag("distro-opnsense") {
return emptyID, false
}
// Netwiser VEであれば編集不可
if archive.HasTag("pkg-netwiserve") {
return emptyID, false
}
for _, t := range allowDiskEditTags {
if archive.HasTag(t) {
@ -249,6 +275,16 @@ func (api *ArchiveAPI) FindLatestStableFreeBSD() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableFreeBSDTags)
}
// FindLatestStableNetwiser 安定版最新のNetwiserパブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableNetwiser() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableNetwiserTags)
}
// FindLatestStableOPNsense 安定版最新のOPNsenseパブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableOPNsense() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableOPNsenseTags)
}
// FindLatestStableWindows2012 安定版最新のWindows2012パブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableWindows2012() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableWindows2012Tags, map[string]interface{}{
@ -305,13 +341,34 @@ func (api *ArchiveAPI) FindLatestStableWindows2016SQLServerStandard() (*sacloud.
})
}
// FindLatestStableWindows2016SQLServer2017Standard 安定版最新のWindows2016 SQLServer2017(Standard) パブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableWindows2016SQLServer2017Standard() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableWindows2016SQLServer2017Standard, map[string]interface{}{
"Name": "Windows Server 2016 for MS SQL 2017(Standard)",
})
}
// FindLatestStableWindows2016SQLServerStandardAll 安定版最新のWindows2016 SQLServer(RDS+Office) パブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableWindows2016SQLServerStandardAll() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableWindows2016SQLServerStandard, map[string]interface{}{
return api.findByOSTags(archiveLatestStableWindows2016SQLServerStandardAll, map[string]interface{}{
"Name": "Windows Server 2016 for MS SQL 2016(Std) with RDS / MS Office",
})
}
// FindLatestStableWindows2016SQLServer2017StandardAll 安定版最新のWindows2016 SQLServer2017(RDS+Office) パブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableWindows2016SQLServer2017StandardAll() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableWindows2016SQLServer2017StandardAll, map[string]interface{}{
"Name": "Windows Server 2016 for MS SQL 2017(Std) with RDS / MS Office",
})
}
// FindLatestStableWindows2019 安定版最新のWindows2019パブリックアーカイブを取得
func (api *ArchiveAPI) FindLatestStableWindows2019() (*sacloud.Archive, error) {
return api.findByOSTags(archiveLatestStableWindows2019Tags, map[string]interface{}{
"Name": "Windows Server 2019 Datacenter Edition",
})
}
// FindByOSType 指定のOS種別の安定版最新のパブリックアーカイブを取得
func (api *ArchiveAPI) FindByOSType(os ostype.ArchiveOSTypes) (*sacloud.Archive, error) {
if f, ok := api.findFuncMapPerOSType[os]; ok {

View file

@ -2,6 +2,7 @@ package api
import (
"encoding/json"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -1,8 +1,8 @@
package api
import (
"encoding/json"
// "strings"
"encoding/json" // "strings"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -3,8 +3,9 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"net/url"
"github.com/sacloud/libsacloud/sacloud"
)
type baseAPI struct {
@ -137,7 +138,7 @@ func (api *baseAPI) filterBy(key string, value interface{}, multiple bool) *base
if f, ok := state.Filter[key]; ok {
if s, ok := f.(string); ok && s != "" {
if v, ok := value.(string); ok {
state.Filter[key] = fmt.Sprintf("%s %s", s, v)
state.Filter[key] = fmt.Sprintf("%s%%20%s", s, v)
return
}
}

View file

@ -4,10 +4,11 @@ import (
"encoding/csv"
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"io"
"strings"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
// BillAPI 請求情報API

View file

@ -2,8 +2,9 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
// CDROMAPI ISOイメージAPI

View file

@ -4,14 +4,15 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud"
"github.com/sacloud/libsacloud/sacloud"
"io"
"io/ioutil"
"log"
"net/http"
"strings"
"time"
"github.com/sacloud/libsacloud"
"github.com/sacloud/libsacloud/sacloud"
)
var (
@ -44,6 +45,8 @@ type Client struct {
RetryMax int
// 503エラー時のリトライ待ち時間
RetryInterval time.Duration
// APIコール時に利用される*http.Client 未指定の場合http.DefaultClientが利用される
HTTPClient *http.Client
}
// NewClient APIクライアント作成
@ -73,8 +76,11 @@ func (c *Client) Clone() *Client {
DefaultTimeoutDuration: c.DefaultTimeoutDuration,
UserAgent: c.UserAgent,
AcceptLanguage: c.AcceptLanguage,
RequestTracer: c.RequestTracer,
ResponseTracer: c.ResponseTracer,
RetryMax: c.RetryMax,
RetryInterval: c.RetryInterval,
HTTPClient: c.HTTPClient,
}
n.API = newAPI(n)
return n
@ -111,6 +117,7 @@ func (c *Client) isOkStatus(code int) bool {
func (c *Client) newRequest(method, uri string, body interface{}) ([]byte, error) {
var (
client = &retryableHTTPClient{
Client: c.HTTPClient,
retryMax: c.RetryMax,
retryInterval: c.RetryInterval,
}
@ -232,12 +239,15 @@ func newRequest(method, url string, body io.ReadSeeker) (*request, error) {
}
type retryableHTTPClient struct {
http.Client
*http.Client
retryInterval time.Duration
retryMax int
}
func (c *retryableHTTPClient) Do(req *request) (*http.Response, error) {
if c.Client == nil {
c.Client = http.DefaultClient
}
for i := 0; ; i++ {
if req.body != nil {
@ -277,6 +287,7 @@ type API struct {
Bill *BillAPI // 請求情報API
Bridge *BridgeAPI // ブリッジAPi
CDROM *CDROMAPI // ISOイメージAPI
Coupon *CouponAPI // クーポンAPI
Database *DatabaseAPI // データベースAPI
Disk *DiskAPI // ディスクAPI
DNS *DNSAPI // DNS API
@ -295,6 +306,7 @@ type API struct {
NFS *NFSAPI // NFS API
Note *NoteAPI // スタートアップスクリプトAPI
PacketFilter *PacketFilterAPI // パケットフィルタAPI
ProxyLB *ProxyLBAPI // プロキシLBAPI
PrivateHost *PrivateHostAPI // 専有ホストAPI
Product *ProductAPI // 製品情報API
Server *ServerAPI // サーバーAPI
@ -337,6 +349,11 @@ func (api *API) GetCDROMAPI() *CDROMAPI {
return api.CDROM
}
// GetCouponAPI クーポン情報API取得
func (api *API) GetCouponAPI() *CouponAPI {
return api.Coupon
}
// GetDatabaseAPI データベースAPI取得
func (api *API) GetDatabaseAPI() *DatabaseAPI {
return api.Database
@ -432,6 +449,11 @@ func (api *API) GetPacketFilterAPI() *PacketFilterAPI {
return api.PacketFilter
}
// GetProxyLBAPI プロキシLBAPI取得
func (api *API) GetProxyLBAPI() *ProxyLBAPI {
return api.ProxyLB
}
// GetPrivateHostAPI 専有ホストAPI取得
func (api *API) GetPrivateHostAPI() *PrivateHostAPI {
return api.PrivateHost
@ -566,6 +588,7 @@ func newAPI(client *Client) *API {
Bill: NewBillAPI(client),
Bridge: NewBridgeAPI(client),
CDROM: NewCDROMAPI(client),
Coupon: NewCouponAPI(client),
Database: NewDatabaseAPI(client),
Disk: NewDiskAPI(client),
DNS: NewDNSAPI(client),
@ -587,6 +610,7 @@ func newAPI(client *Client) *API {
NFS: NewNFSAPI(client),
Note: NewNoteAPI(client),
PacketFilter: NewPacketFilterAPI(client),
ProxyLB: NewProxyLBAPI(client),
PrivateHost: NewPrivateHostAPI(client),
Product: &ProductAPI{
Server: NewProductServerAPI(client),

59
vendor/github.com/sacloud/libsacloud/api/coupon.go generated vendored Normal file
View file

@ -0,0 +1,59 @@
package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)
// CouponAPI クーポン情報API
type CouponAPI struct {
*baseAPI
}
// NewCouponAPI クーポン情報API作成
func NewCouponAPI(client *Client) *CouponAPI {
return &CouponAPI{
&baseAPI{
client: client,
apiRootSuffix: sakuraBillingAPIRootSuffix,
FuncGetResourceURL: func() string {
return "coupon"
},
},
}
}
// CouponResponse クーポン情報レスポンス
type CouponResponse struct {
*sacloud.ResultFlagValue
// AllCount 件数
AllCount int `json:",omitempty"`
// CountPerPage ページあたり件数
CountPerPage int `json:",omitempty"`
// Page 現在のページ番号
Page int `json:",omitempty"`
// Coupons クーポン情報 リスト
Coupons []*sacloud.Coupon
}
// Find クーポン情報 全件取得
func (api *CouponAPI) Find() ([]*sacloud.Coupon, error) {
authStatus, err := api.client.AuthStatus.Read()
if err != nil {
return nil, err
}
accountID := authStatus.Account.GetStrID()
uri := fmt.Sprintf("%s/%s", api.getResourceURL(), accountID)
data, err := api.client.newRequest("GET", uri, nil)
if err != nil {
return nil, err
}
var res CouponResponse
if err := json.Unmarshal(data, &res); err != nil {
return nil, err
}
return res.Coupons, nil
}

View file

@ -3,8 +3,9 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
//HACK: さくらのAPI側仕様: Applianceの内容によってJSONフォーマットが異なるため

View file

@ -2,8 +2,9 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
var (
@ -56,7 +57,50 @@ func (api *DiskAPI) Create(value *sacloud.Disk) (*sacloud.Disk, error) {
Success string `json:",omitempty"`
}
res := &diskResponse{}
err := api.create(api.createRequest(value), res)
rawBody := &sacloud.Request{}
rawBody.Disk = value
if len(value.DistantFrom) > 0 {
rawBody.DistantFrom = value.DistantFrom
value.DistantFrom = []int64{}
}
err := api.create(rawBody, res)
if err != nil {
return nil, err
}
return res.Disk, nil
}
// CreateWithConfig ディスク作成とディスクの修正、サーバ起動(指定されていれば)を回のAPI呼び出しで実行
func (api *DiskAPI) CreateWithConfig(value *sacloud.Disk, config *sacloud.DiskEditValue, bootAtAvailable bool) (*sacloud.Disk, error) {
//HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないため文字列で受ける("Accepted"などが返る)
type diskResponse struct {
*sacloud.Response
// Success
Success string `json:",omitempty"`
}
res := &diskResponse{}
type diskRequest struct {
*sacloud.Request
Config *sacloud.DiskEditValue `json:",omitempty"`
BootAtAvailable bool `json:",omitempty"`
}
rawBody := &diskRequest{
Request: &sacloud.Request{},
BootAtAvailable: bootAtAvailable,
}
rawBody.Disk = value
rawBody.Config = config
if len(value.DistantFrom) > 0 {
rawBody.DistantFrom = value.DistantFrom
value.DistantFrom = []int64{}
}
err := api.create(rawBody, res)
if err != nil {
return nil, err
}
@ -90,7 +134,14 @@ func (api *DiskAPI) install(id int64, body *sacloud.Disk) (bool, error) {
Success string `json:",omitempty"`
}
res := &diskResponse{}
err := api.baseAPI.request(method, uri, body, res)
rawBody := &sacloud.Request{}
rawBody.Disk = body
if len(body.DistantFrom) > 0 {
rawBody.DistantFrom = body.DistantFrom
body.DistantFrom = []int64{}
}
err := api.baseAPI.request(method, uri, rawBody, res)
if err != nil {
return false, err
}
@ -213,6 +264,14 @@ func (api *DiskAPI) CanEditDisk(id int64) (bool, error) {
if disk.HasTag("pkg-sophosutm") || disk.IsSophosUTM() {
return false, nil
}
// OPNsenseであれば編集不可
if disk.HasTag("distro-opnsense") {
return false, nil
}
// Netwiser VEであれば編集不可
if disk.HasTag("pkg-netwiserve") {
return false, nil
}
// ソースアーカイブ/ソースディスクともに持っていない場合
if disk.SourceArchive == nil && disk.SourceDisk == nil {
@ -263,6 +322,14 @@ func (api *DiskAPI) GetPublicArchiveIDFromAncestors(id int64) (int64, bool) {
if disk.HasTag("pkg-sophosutm") || disk.IsSophosUTM() {
return emptyID, false
}
// OPNsenseであれば編集不可
if disk.HasTag("distro-opnsense") {
return emptyID, false
}
// Netwiser VEであれば編集不可
if disk.HasTag("pkg-netwiserve") {
return emptyID, false
}
for _, t := range allowDiskEditTags {
if disk.HasTag(t) {

View file

@ -2,8 +2,9 @@ package api
import (
"encoding/json"
"github.com/sacloud/libsacloud/sacloud"
"strings"
"github.com/sacloud/libsacloud/sacloud"
)
//HACK: さくらのAPI側仕様: CommonServiceItemsの内容によってJSONフォーマットが異なるため

View file

@ -2,6 +2,7 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -1,8 +1,8 @@
package api
import (
"encoding/json"
// "strings"
"encoding/json" // "strings"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -2,6 +2,7 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)
@ -81,3 +82,26 @@ func (api *InterfaceAPI) DisconnectFromPacketFilter(interfaceID int64) (bool, er
)
return api.modify(method, uri, nil)
}
// SetDisplayIPAddress 表示用IPアドレス 設定
func (api *InterfaceAPI) SetDisplayIPAddress(interfaceID int64, ipaddress string) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("/%s/%d", api.getResourceURL(), interfaceID)
)
body := map[string]interface{}{
"Interface": map[string]string{
"UserIPAddress": ipaddress,
},
}
return api.modify(method, uri, body)
}
// DeleteDisplayIPAddress 表示用IPアドレス 削除
func (api *InterfaceAPI) DeleteDisplayIPAddress(interfaceID int64) (bool, error) {
var (
method = "DELETE"
uri = fmt.Sprintf("/%s/%d", api.getResourceURL(), interfaceID)
)
return api.modify(method, uri, nil)
}

View file

@ -2,8 +2,9 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
// InternetAPI ルーターAPI

View file

@ -2,6 +2,7 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -2,6 +2,7 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -3,8 +3,9 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
//HACK: さくらのAPI側仕様: Applianceの内容によってJSONフォーマットが異なるため
@ -38,6 +39,12 @@ type loadBalancerResponse struct {
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
}
type loadBalancerStatusResponse struct {
*sacloud.ResultFlagValue
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
LoadBalancer *sacloud.LoadBalancerStatusResult `json:",omitempty"`
}
// LoadBalancerAPI ロードバランサーAPI
type LoadBalancerAPI struct {
*baseAPI
@ -230,3 +237,20 @@ func (api *LoadBalancerAPI) AsyncSleepWhileCopying(id int64, timeout time.Durati
func (api *LoadBalancerAPI) Monitor(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
return api.baseAPI.applianceMonitorBy(id, "interface", 0, body)
}
// Status ステータス取得
func (api *LoadBalancerAPI) Status(id int64) (*sacloud.LoadBalancerStatusResult, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/status", api.getResourceURL(), id)
res = &loadBalancerStatusResponse{}
)
err := api.baseAPI.request(method, uri, nil, res)
if err != nil {
return nil, err
}
if res.LoadBalancer == nil {
return nil, nil
}
return res.LoadBalancer, nil
}

View file

@ -3,8 +3,9 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
// SearchMobileGatewayResponse モバイルゲートウェイ検索レスポンス
@ -41,6 +42,14 @@ type mobileGatewaySIMResponse struct {
Success interface{} `json:",omitempty"` //HACK: さくらのAPI側仕様: 戻り値:Successがbool値へ変換できないためinterface{}
}
type trafficMonitoringBody struct {
TrafficMonitoring *sacloud.TrafficMonitoringConfig `json:"traffic_monitoring_config"`
}
type trafficStatusBody struct {
TrafficStatus *sacloud.TrafficStatus `json:"traffic_status"`
}
// MobileGatewayAPI モバイルゲートウェイAPI
type MobileGatewayAPI struct {
*baseAPI
@ -322,8 +331,8 @@ func (api *MobileGatewayAPI) AddSIMRoute(id int64, simID int64, prefix string) (
param := &sacloud.MobileGatewaySIMRoutes{
SIMRoutes: routes,
}
added := param.AddSIMRoute(simID, prefix)
if !added {
index, added := param.AddSIMRoute(simID, prefix)
if index < 0 || added == nil {
return false, nil
}
@ -412,3 +421,60 @@ func (api *MobileGatewayAPI) Logs(id int64, body interface{}) ([]sacloud.SIMLog,
}
return res.Logs, nil
}
// GetTrafficMonitoringConfig トラフィックコントロール 取得
func (api *MobileGatewayAPI) GetTrafficMonitoringConfig(id int64) (*sacloud.TrafficMonitoringConfig, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_monitoring", api.getResourceURL(), id)
)
res := &trafficMonitoringBody{}
err := api.baseAPI.request(method, uri, nil, res)
if err != nil {
return nil, err
}
return res.TrafficMonitoring, nil
}
// SetTrafficMonitoringConfig トラフィックコントロール 設定
func (api *MobileGatewayAPI) SetTrafficMonitoringConfig(id int64, trafficMonConfig *sacloud.TrafficMonitoringConfig) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_monitoring", api.getResourceURL(), id)
)
req := &trafficMonitoringBody{
TrafficMonitoring: trafficMonConfig,
}
return api.modify(method, uri, req)
}
// DisableTrafficMonitoringConfig トラフィックコントロール 解除
func (api *MobileGatewayAPI) DisableTrafficMonitoringConfig(id int64) (bool, error) {
var (
method = "DELETE"
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_monitoring", api.getResourceURL(), id)
)
return api.modify(method, uri, nil)
}
// GetTrafficStatus 当月通信量 取得
func (api *MobileGatewayAPI) GetTrafficStatus(id int64) (*sacloud.TrafficStatus, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/mobilegateway/traffic_status", api.getResourceURL(), id)
)
res := &trafficStatusBody{}
err := api.baseAPI.request(method, uri, nil, res)
if err != nil {
return nil, err
}
return res.TrafficStatus, nil
}
// MonitorBy 指定位置のインターフェースのアクティビティーモニター取得
func (api *MobileGatewayAPI) MonitorBy(id int64, nicIndex int, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
return api.baseAPI.applianceMonitorBy(id, "interface", nicIndex, body)
}

View file

@ -2,6 +2,7 @@ package api
import (
"encoding/json"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -2,9 +2,11 @@ package api
import (
"encoding/json"
"errors"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
// SearchNFSResponse NFS検索レスポンス
@ -94,6 +96,58 @@ func (api *NFSAPI) Create(value *sacloud.NFS) (*sacloud.NFS, error) {
})
}
// CreateWithPlan プラン/サイズを指定してNFSを作成
func (api *NFSAPI) CreateWithPlan(value *sacloud.CreateNFSValue, plan sacloud.NFSPlan, size sacloud.NFSSize) (*sacloud.NFS, error) {
nfs := sacloud.NewNFS(value)
// get plan
plans, err := api.GetNFSPlans()
if err != nil {
return nil, err
}
if plans == nil {
return nil, errors.New("NFS plans not found")
}
planID := plans.FindPlanID(plan, size)
if planID < 0 {
return nil, errors.New("NFS plans not found")
}
nfs.Plan = sacloud.NewResource(planID)
nfs.Remark.SetRemarkPlanID(planID)
return api.request(func(res *nfsResponse) error {
return api.create(api.createRequest(nfs), res)
})
}
// GetNFSPlans プラン一覧取得
func (api *NFSAPI) GetNFSPlans() (*sacloud.NFSPlans, error) {
notes, err := api.client.Note.Reset().Find()
if err != nil {
return nil, err
}
for _, note := range notes.Notes {
if note.Class == sacloud.ENoteClass("json") && note.Name == "sys-nfs" {
rawPlans := note.Content
var plans struct {
Plans *sacloud.NFSPlans `json:"plans"`
}
err := json.Unmarshal([]byte(rawPlans), &plans)
if err != nil {
return nil, err
}
return plans.Plans, nil
}
}
return nil, nil
}
// Read 読み取り
func (api *NFSAPI) Read(id int64) (*sacloud.NFS, error) {
return api.request(func(res *nfsResponse) error {
@ -223,9 +277,9 @@ func (api *NFSAPI) AsyncSleepWhileCopying(id int64, timeout time.Duration, maxRe
return poll(handler, timeout)
}
// MonitorNFS NFS固有項目アクティビティモニター取得
func (api *NFSAPI) MonitorNFS(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
return api.baseAPI.applianceMonitorBy(id, "nfs", 0, body)
// MonitorFreeDiskSize NFSディスク残量アクティビティモニター取得
func (api *NFSAPI) MonitorFreeDiskSize(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
return api.baseAPI.applianceMonitorBy(id, "database", 0, body)
}
// MonitorInterface NICアクティビティーモニター取得

View file

@ -21,16 +21,16 @@ func poll(handler pollingHandler, timeout time.Duration) (chan (interface{}), ch
select {
case <-tick:
exit, state, err := handler()
if state != nil {
progChan <- state
}
if err != nil {
errChan <- fmt.Errorf("Failed: poll: %s", err)
return
}
if state != nil {
progChan <- state
if exit {
compChan <- state
return
}
if exit {
compChan <- state
return
}
case <-bomb:
errChan <- fmt.Errorf("Timeout")
@ -65,9 +65,9 @@ type hasFailed interface {
func waitingForAvailableFunc(readFunc func() (hasAvailable, error), maxRetry int) func() (bool, interface{}, error) {
counter := 0
return func() (bool, interface{}, error) {
counter++
v, err := readFunc()
if err != nil {
counter++
if maxRetry > 0 && counter < maxRetry {
return false, nil, nil
}
@ -96,9 +96,9 @@ type hasUpDown interface {
func waitingForUpFunc(readFunc func() (hasUpDown, error), maxRetry int) func() (bool, interface{}, error) {
counter := 0
return func() (bool, interface{}, error) {
counter++
v, err := readFunc()
if err != nil {
counter++
if maxRetry > 0 && counter < maxRetry {
return false, nil, nil
}
@ -118,9 +118,9 @@ func waitingForUpFunc(readFunc func() (hasUpDown, error), maxRetry int) func() (
func waitingForDownFunc(readFunc func() (hasUpDown, error), maxRetry int) func() (bool, interface{}, error) {
counter := 0
return func() (bool, interface{}, error) {
counter++
v, err := readFunc()
if err != nil {
counter++
if maxRetry > 0 && counter < maxRetry {
return false, nil, nil
}
@ -140,9 +140,9 @@ func waitingForDownFunc(readFunc func() (hasUpDown, error), maxRetry int) func()
func waitingForReadFunc(readFunc func() (interface{}, error), maxRetry int) func() (bool, interface{}, error) {
counter := 0
return func() (bool, interface{}, error) {
counter++
v, err := readFunc()
if err != nil {
counter++
if maxRetry > 0 && counter < maxRetry {
return false, nil, nil
}

View file

@ -2,8 +2,8 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"strconv"
)
// ProductServerAPI サーバープランAPI
@ -24,48 +24,50 @@ func NewProductServerAPI(client *Client) *ProductServerAPI {
}
}
func (api *ProductServerAPI) getPlanIDBySpec(core int, memGB int) (int64, error) {
//assert args
if core <= 0 {
return -1, fmt.Errorf("Invalid Parameter: CPU Core")
}
if memGB <= 0 {
return -1, fmt.Errorf("Invalid Parameter: Memory Size(GB)")
}
return strconv.ParseInt(fmt.Sprintf("%d%03d", memGB, core), 10, 64)
}
// IsValidPlan 指定のコア数/メモリサイズのプランが存在し、有効であるか判定
func (api *ProductServerAPI) IsValidPlan(core int, memGB int) (bool, error) {
planID, err := api.getPlanIDBySpec(core, memGB)
if err != nil {
return false, err
}
productServer, err := api.Read(planID)
if err != nil {
return false, err
}
if productServer != nil {
return true, nil
}
return false, fmt.Errorf("Server Plan[%d] Not Found", planID)
}
// GetBySpec 指定のコア数/メモリサイズのサーバープランを取得
func (api *ProductServerAPI) GetBySpec(core int, memGB int) (*sacloud.ProductServer, error) {
planID, err := api.getPlanIDBySpec(core, memGB)
productServer, err := api.Read(planID)
// GetBySpec 指定のコア数/メモリサイズ/世代のプランを取得
func (api *ProductServerAPI) GetBySpec(core int, memGB int, gen sacloud.PlanGenerations) (*sacloud.ProductServer, error) {
plans, err := api.Reset().Find()
if err != nil {
return nil, err
}
var res sacloud.ProductServer
var found bool
for _, plan := range plans.ServerPlans {
if plan.CPU == core && plan.GetMemoryGB() == memGB {
if gen == sacloud.PlanDefault || gen == plan.Generation {
// PlanDefaultの場合は複数ヒットしうる。
// この場合より新しい世代を優先する。
if found && plan.Generation <= res.Generation {
continue
}
res = plan
found = true
}
}
}
return productServer, nil
if !found {
return nil, fmt.Errorf("Server Plan[core:%d, memory:%d, gen:%d] is not found", core, memGB, gen)
}
return &res, nil
}
// IsValidPlan 指定のコア数/メモリサイズ/世代のプランが存在し、有効であるか判定
func (api *ProductServerAPI) IsValidPlan(core int, memGB int, gen sacloud.PlanGenerations) (bool, error) {
productServer, err := api.GetBySpec(core, memGB, gen)
if err != nil {
return false, err
}
if productServer == nil {
return false, fmt.Errorf("Server Plan[core:%d, memory:%d, gen:%d] is not found", core, memGB, gen)
}
if productServer.Availability != sacloud.EAAvailable {
return false, fmt.Errorf("Server Plan[core:%d, memory:%d, gen:%d] is not available", core, memGB, gen)
}
return true, nil
}

224
vendor/github.com/sacloud/libsacloud/api/proxylb.go generated vendored Normal file
View file

@ -0,0 +1,224 @@
package api
import (
"encoding/json" // "strings"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)
//HACK: さくらのAPI側仕様: CommonServiceItemsの内容によってJSONフォーマットが異なるため
// DNS/ProxyLB/シンプル監視それぞれでリクエスト/レスポンスデータ型を定義する。
// SearchProxyLBResponse ProxyLB検索レスポンス
type SearchProxyLBResponse struct {
// Total 総件数
Total int `json:",omitempty"`
// From ページング開始位置
From int `json:",omitempty"`
// Count 件数
Count int `json:",omitempty"`
// CommonServiceProxyLBItems ProxyLBリスト
CommonServiceProxyLBItems []sacloud.ProxyLB `json:"CommonServiceItems,omitempty"`
}
type proxyLBRequest struct {
CommonServiceProxyLBItem *sacloud.ProxyLB `json:"CommonServiceItem,omitempty"`
From int `json:",omitempty"`
Count int `json:",omitempty"`
Sort []string `json:",omitempty"`
Filter map[string]interface{} `json:",omitempty"`
Exclude []string `json:",omitempty"`
Include []string `json:",omitempty"`
}
type proxyLBResponse struct {
*sacloud.ResultFlagValue
*sacloud.ProxyLB `json:"CommonServiceItem,omitempty"`
}
// ProxyLBAPI ProxyLB API
type ProxyLBAPI struct {
*baseAPI
}
// NewProxyLBAPI ProxyLB API作成
func NewProxyLBAPI(client *Client) *ProxyLBAPI {
return &ProxyLBAPI{
&baseAPI{
client: client,
FuncGetResourceURL: func() string {
return "commonserviceitem"
},
FuncBaseSearchCondition: func() *sacloud.Request {
res := &sacloud.Request{}
res.AddFilter("Provider.Class", "proxylb")
return res
},
},
}
}
// Find 検索
func (api *ProxyLBAPI) Find() (*SearchProxyLBResponse, error) {
data, err := api.client.newRequest("GET", api.getResourceURL(), api.getSearchState())
if err != nil {
return nil, err
}
var res SearchProxyLBResponse
if err := json.Unmarshal(data, &res); err != nil {
return nil, err
}
return &res, nil
}
func (api *ProxyLBAPI) request(f func(*proxyLBResponse) error) (*sacloud.ProxyLB, error) {
res := &proxyLBResponse{}
err := f(res)
if err != nil {
return nil, err
}
return res.ProxyLB, nil
}
func (api *ProxyLBAPI) createRequest(value *sacloud.ProxyLB) *proxyLBResponse {
return &proxyLBResponse{ProxyLB: value}
}
// New 新規作成用パラメーター作成
func (api *ProxyLBAPI) New(name string) *sacloud.ProxyLB {
return sacloud.CreateNewProxyLB(name)
}
// Create 新規作成
func (api *ProxyLBAPI) Create(value *sacloud.ProxyLB) (*sacloud.ProxyLB, error) {
return api.request(func(res *proxyLBResponse) error {
return api.create(api.createRequest(value), res)
})
}
// Read 読み取り
func (api *ProxyLBAPI) Read(id int64) (*sacloud.ProxyLB, error) {
return api.request(func(res *proxyLBResponse) error {
return api.read(id, nil, res)
})
}
// Update 更新
func (api *ProxyLBAPI) Update(id int64, value *sacloud.ProxyLB) (*sacloud.ProxyLB, error) {
return api.request(func(res *proxyLBResponse) error {
return api.update(id, api.createRequest(value), res)
})
}
// UpdateSetting 設定更新
func (api *ProxyLBAPI) UpdateSetting(id int64, value *sacloud.ProxyLB) (*sacloud.ProxyLB, error) {
req := &sacloud.ProxyLB{
// Settings
Settings: value.Settings,
}
return api.request(func(res *proxyLBResponse) error {
return api.update(id, api.createRequest(req), res)
})
}
// Delete 削除
func (api *ProxyLBAPI) Delete(id int64) (*sacloud.ProxyLB, error) {
return api.request(func(res *proxyLBResponse) error {
return api.delete(id, nil, res)
})
}
// ChangePlan プラン変更
func (api *ProxyLBAPI) ChangePlan(id int64, newPlan sacloud.ProxyLBPlan) (*sacloud.ProxyLB, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/plan", api.getResourceURL(), id)
)
body := &sacloud.ProxyLB{}
body.SetPlan(newPlan)
realBody := map[string]interface{}{
"CommonServiceItem": map[string]interface{}{
"ServiceClass": body.ServiceClass,
},
}
return api.request(func(res *proxyLBResponse) error {
return api.baseAPI.request(method, uri, realBody, res)
})
}
type proxyLBCertificateResponse struct {
*sacloud.ResultFlagValue
ProxyLB *sacloud.ProxyLBCertificates `json:",omitempty"`
}
// GetCertificates 証明書取得
func (api *ProxyLBAPI) GetCertificates(id int64) (*sacloud.ProxyLBCertificates, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/proxylb/sslcertificate", api.getResourceURL(), id)
res = &proxyLBCertificateResponse{}
)
err := api.baseAPI.request(method, uri, nil, res)
if err != nil {
return nil, err
}
if res.ProxyLB == nil {
return nil, nil
}
return res.ProxyLB, nil
}
// SetCertificates 証明書設定
func (api *ProxyLBAPI) SetCertificates(id int64, certs *sacloud.ProxyLBCertificates) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/proxylb/sslcertificate", api.getResourceURL(), id)
res = &proxyLBCertificateResponse{}
)
err := api.baseAPI.request(method, uri, map[string]interface{}{
"ProxyLB": certs,
}, res)
if err != nil {
return false, err
}
return true, nil
}
// DeleteCertificates 証明書削除
func (api *ProxyLBAPI) DeleteCertificates(id int64) (bool, error) {
var (
method = "DELETE"
uri = fmt.Sprintf("%s/%d/proxylb/sslcertificate", api.getResourceURL(), id)
)
return api.baseAPI.modify(method, uri, nil)
}
type proxyLBHealthResponse struct {
*sacloud.ResultFlagValue
ProxyLB *sacloud.ProxyLBStatus `json:",omitempty"`
}
// Health ヘルスチェックステータス取得
func (api *ProxyLBAPI) Health(id int64) (*sacloud.ProxyLBStatus, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/health", api.getResourceURL(), id)
res = &proxyLBHealthResponse{}
)
err := api.baseAPI.request(method, uri, nil, res)
if err != nil {
return nil, err
}
if res.ProxyLB == nil {
return nil, nil
}
return res.ProxyLB, nil
}
// Monitor アクティビティーモニター取得
func (api *ProxyLBAPI) Monitor(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
return api.baseAPI.applianceMonitorBy(id, "activity/proxylb", 0, body)
}

238
vendor/github.com/sacloud/libsacloud/api/proxylb_gen.go generated vendored Normal file
View file

@ -0,0 +1,238 @@
package api
/************************************************
generated by IDE. for [ProxyLBAPI]
************************************************/
import (
"github.com/sacloud/libsacloud/sacloud"
)
/************************************************
To support fluent interface for Find()
************************************************/
// Reset 検索条件のリセット
func (api *ProxyLBAPI) Reset() *ProxyLBAPI {
api.reset()
return api
}
// Offset オフセット
func (api *ProxyLBAPI) Offset(offset int) *ProxyLBAPI {
api.offset(offset)
return api
}
// Limit リミット
func (api *ProxyLBAPI) Limit(limit int) *ProxyLBAPI {
api.limit(limit)
return api
}
// Include 取得する項目
func (api *ProxyLBAPI) Include(key string) *ProxyLBAPI {
api.include(key)
return api
}
// Exclude 除外する項目
func (api *ProxyLBAPI) Exclude(key string) *ProxyLBAPI {
api.exclude(key)
return api
}
// FilterBy 指定キーでのフィルター
func (api *ProxyLBAPI) FilterBy(key string, value interface{}) *ProxyLBAPI {
api.filterBy(key, value, false)
return api
}
// FilterMultiBy 任意項目でのフィルタ(完全一致 OR条件)
func (api *ProxyLBAPI) FilterMultiBy(key string, value interface{}) *ProxyLBAPI {
api.filterBy(key, value, true)
return api
}
// WithNameLike 名称条件
func (api *ProxyLBAPI) WithNameLike(name string) *ProxyLBAPI {
return api.FilterBy("Name", name)
}
// WithTag タグ条件
func (api *ProxyLBAPI) WithTag(tag string) *ProxyLBAPI {
return api.FilterBy("Tags.Name", tag)
}
// WithTags タグ(複数)条件
func (api *ProxyLBAPI) WithTags(tags []string) *ProxyLBAPI {
return api.FilterBy("Tags.Name", []interface{}{tags})
}
// func (api *ProxyLBAPI) WithSizeGib(size int) *ProxyLBAPI {
// api.FilterBy("SizeMB", size*1024)
// return api
// }
// func (api *ProxyLBAPI) WithSharedScope() *ProxyLBAPI {
// api.FilterBy("Scope", "shared")
// return api
// }
// func (api *ProxyLBAPI) WithUserScope() *ProxyLBAPI {
// api.FilterBy("Scope", "user")
// return api
// }
// SortBy 指定キーでのソート
func (api *ProxyLBAPI) SortBy(key string, reverse bool) *ProxyLBAPI {
api.sortBy(key, reverse)
return api
}
// SortByName 名称でのソート
func (api *ProxyLBAPI) SortByName(reverse bool) *ProxyLBAPI {
api.sortByName(reverse)
return api
}
// func (api *ProxyLBAPI) SortBySize(reverse bool) *ProxyLBAPI {
// api.sortBy("SizeMB", reverse)
// return api
// }
/************************************************
To support Setxxx interface for Find()
************************************************/
// SetEmpty 検索条件のリセット
func (api *ProxyLBAPI) SetEmpty() {
api.reset()
}
// SetOffset オフセット
func (api *ProxyLBAPI) SetOffset(offset int) {
api.offset(offset)
}
// SetLimit リミット
func (api *ProxyLBAPI) SetLimit(limit int) {
api.limit(limit)
}
// SetInclude 取得する項目
func (api *ProxyLBAPI) SetInclude(key string) {
api.include(key)
}
// SetExclude 除外する項目
func (api *ProxyLBAPI) SetExclude(key string) {
api.exclude(key)
}
// SetFilterBy 指定キーでのフィルター
func (api *ProxyLBAPI) SetFilterBy(key string, value interface{}) {
api.filterBy(key, value, false)
}
// SetFilterMultiBy 任意項目でのフィルタ(完全一致 OR条件)
func (api *ProxyLBAPI) SetFilterMultiBy(key string, value interface{}) {
api.filterBy(key, value, true)
}
// SetNameLike 名称条件
func (api *ProxyLBAPI) SetNameLike(name string) {
api.FilterBy("Name", name)
}
// SetTag タグ条件
func (api *ProxyLBAPI) SetTag(tag string) {
api.FilterBy("Tags.Name", tag)
}
// SetTags タグ(複数)条件
func (api *ProxyLBAPI) SetTags(tags []string) {
api.FilterBy("Tags.Name", []interface{}{tags})
}
// func (api *ProxyLBAPI) SetSizeGib(size int) {
// api.FilterBy("SizeMB", size*1024)
// }
// func (api *ProxyLBAPI) SetSharedScope() {
// api.FilterBy("Scope", "shared")
// }
// func (api *ProxyLBAPI) SetUserScope() {
// api.FilterBy("Scope", "user")
// }
// SetSortBy 指定キーでのソート
func (api *ProxyLBAPI) SetSortBy(key string, reverse bool) {
api.sortBy(key, reverse)
}
// SetSortByName 名称でのソート
func (api *ProxyLBAPI) SetSortByName(reverse bool) {
api.sortByName(reverse)
}
// func (api *ProxyLBAPI) SetSortBySize(reverse bool) {
// api.sortBy("SizeMB", reverse)
// }
/************************************************
To support CRUD(Create/Read/Update/Delete)
************************************************/
// func (api *ProxyLBAPI) New() *sacloud.ProxyLB {
// return &sacloud.ProxyLB{}
// }
// func (api *ProxyLBAPI) Create(value *sacloud.ProxyLB) (*sacloud.ProxyLB, error) {
// return api.request(func(res *sacloud.Response) error {
// return api.create(api.createRequest(value), res)
// })
// }
// func (api *ProxyLBAPI) Read(id string) (*sacloud.ProxyLB, error) {
// return api.request(func(res *sacloud.Response) error {
// return api.read(id, nil, res)
// })
// }
// func (api *ProxyLBAPI) Update(id string, value *sacloud.ProxyLB) (*sacloud.ProxyLB, error) {
// return api.request(func(res *sacloud.Response) error {
// return api.update(id, api.createRequest(value), res)
// })
// }
// func (api *ProxyLBAPI) Delete(id string) (*sacloud.ProxyLB, error) {
// return api.request(func(res *sacloud.Response) error {
// return api.delete(id, nil, res)
// })
// }
/************************************************
Inner functions
************************************************/
func (api *ProxyLBAPI) setStateValue(setFunc func(*sacloud.Request)) *ProxyLBAPI {
api.baseAPI.setStateValue(setFunc)
return api
}
//func (api *ProxyLBAPI) request(f func(*sacloud.Response) error) (*sacloud.ProxyLB, error) {
// res := &sacloud.Response{}
// err := f(res)
// if err != nil {
// return nil, err
// }
// return res.ProxyLB, nil
//}
//
//func (api *ProxyLBAPI) createRequest(value *sacloud.ProxyLB) *sacloud.Request {
// req := &sacloud.Request{}
// req.ProxyLB = value
// return req
//}

View file

@ -0,0 +1,32 @@
package api
import (
"go.uber.org/ratelimit"
"net/http"
"sync"
)
// RateLimitRoundTripper 秒間アクセス数を制限するためのhttp.RoundTripper実装
type RateLimitRoundTripper struct {
// Transport 親となるhttp.RoundTripper、nilの場合http.DefaultTransportが利用される
Transport http.RoundTripper
// RateLimitPerSec 秒あたりのリクエスト数
RateLimitPerSec int
once sync.Once
rateLimit ratelimit.Limiter
}
// RoundTrip http.RoundTripperの実装
func (r *RateLimitRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
r.once.Do(func() {
r.rateLimit = ratelimit.New(r.RateLimitPerSec)
})
if r.Transport == nil {
r.Transport = http.DefaultTransport
}
r.rateLimit.Take()
return r.Transport.RoundTrip(req)
}

View file

@ -2,8 +2,9 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
// ServerAPI サーバーAPI
@ -150,14 +151,18 @@ func (api *ServerAPI) SleepUntilDown(id int64, timeout time.Duration) error {
}
// ChangePlan サーバープラン変更(サーバーIDが変更となるため注意)
func (api *ServerAPI) ChangePlan(serverID int64, planID string) (*sacloud.Server, error) {
func (api *ServerAPI) ChangePlan(serverID int64, plan *sacloud.ProductServer) (*sacloud.Server, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/to/plan/%s", api.getResourceURL(), serverID, planID)
uri = fmt.Sprintf("%s/%d/plan", api.getResourceURL(), serverID)
body = &sacloud.ProductServer{}
)
body.CPU = plan.CPU
body.MemoryMB = plan.MemoryMB
body.Generation = plan.Generation
return api.request(func(res *sacloud.Response) error {
return api.baseAPI.request(method, uri, nil, res)
return api.baseAPI.request(method, uri, body, res)
})
}

View file

@ -204,6 +204,37 @@ func (api *SIMAPI) Logs(id int64, body interface{}) ([]sacloud.SIMLog, error) {
return res.Logs, nil
}
// GetNetworkOperator 通信キャリア 取得
func (api *SIMAPI) GetNetworkOperator(id int64) (*sacloud.SIMNetworkOperatorConfigs, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/sim/network_operator_config", api.getResourceURL(), id)
)
res := &sacloud.SIMNetworkOperatorConfigs{}
err := api.baseAPI.request(method, uri, nil, res)
if err != nil {
return nil, err
}
return res, nil
}
// SetNetworkOperator 通信キャリア 設定
func (api *SIMAPI) SetNetworkOperator(id int64, opConfig ...*sacloud.SIMNetworkOperatorConfig) (bool, error) {
var (
method = "PUT"
uri = fmt.Sprintf("%s/%d/sim/network_operator_config", api.getResourceURL(), id)
)
err := api.baseAPI.request(method, uri, &sacloud.SIMNetworkOperatorConfigs{NetworkOperatorConfigs: opConfig}, nil)
if err != nil {
return false, err
}
return true, nil
}
// Monitor アクティビティーモニター(Up/Down link BPS)取得
func (api *SIMAPI) Monitor(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
var (

View file

@ -1,9 +1,9 @@
package api
import (
"encoding/json"
// "strings"
"encoding/json" // "strings"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)
@ -118,6 +118,25 @@ func (api *SimpleMonitorAPI) Delete(id int64) (*sacloud.SimpleMonitor, error) {
})
}
// Health ヘルスチェック
//
// まだチェックが行われていない場合nilを返す
func (api *SimpleMonitorAPI) Health(id int64) (*sacloud.SimpleMonitorHealthCheckStatus, error) {
var (
method = "GET"
uri = fmt.Sprintf("%s/%d/health", api.getResourceURL(), id)
)
res := struct {
SimpleMonitor *sacloud.SimpleMonitorHealthCheckStatus `json:",omitempty"`
}{}
err := api.baseAPI.request(method, uri, nil, &res)
if err != nil {
return nil, err
}
return res.SimpleMonitor, nil
}
// MonitorResponseTimeSec アクティビティーモニター(レスポンスタイム)取得
func (api *SimpleMonitorAPI) MonitorResponseTimeSec(id int64, body *sacloud.ResourceMonitorRequest) (*sacloud.MonitorValues, error) {
var (

View file

@ -2,6 +2,7 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -2,6 +2,7 @@ package api
import (
"fmt"
"github.com/sacloud/libsacloud/sacloud"
)

View file

@ -3,8 +3,9 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"time"
"github.com/sacloud/libsacloud/sacloud"
)
//HACK: さくらのAPI側仕様: Applianceの内容によってJSONフォーマットが異なるため

View file

@ -3,8 +3,9 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"strings"
"github.com/sacloud/libsacloud/sacloud"
)
// WebAccelAPI ウェブアクセラレータAPI

View file

@ -3,9 +3,10 @@ package api
import (
"encoding/json"
"fmt"
"github.com/sacloud/libsacloud/sacloud"
"net/url"
"strings"
"github.com/sacloud/libsacloud/sacloud"
)
// Reset 検索条件のリセット

View file

@ -2,4 +2,4 @@
package libsacloud
// Version バージョン
const Version = "1.0.0-rc5"
const Version = "1.21.1"

View file

@ -138,6 +138,36 @@ var (
// EDiskConnection ディスク接続方法
type EDiskConnection string
// EUpstreamNetworkType 上流ネットワーク種別
type EUpstreamNetworkType string
// String EUpstreamNetworkTypeの文字列表現
func (t EUpstreamNetworkType) String() string {
return string(t)
}
var (
// EUpstreamNetworkUnknown 不明
EUpstreamNetworkUnknown = EUpstreamNetworkType("unknown")
// EUpstreamNetworkShared 共有セグメント
EUpstreamNetworkShared = EUpstreamNetworkType("shared")
// EUpstreamNetworkSwitch スイッチ(非スイッチ+ルータ)
EUpstreamNetworkSwitch = EUpstreamNetworkType("switch")
// EUpstreamNetworkRouter ルータ(スイッチ+ルータのスイッチ)
EUpstreamNetworkRouter = EUpstreamNetworkType("router")
// EUpstreamNetworkNone 接続なし
EUpstreamNetworkNone = EUpstreamNetworkType("none")
// UpstreamNetworks 文字列とEUpstreamNetworkTypeのマッピング
UpstreamNetworks = map[string]EUpstreamNetworkType{
"unknown": EUpstreamNetworkUnknown,
"shared": EUpstreamNetworkShared,
"switch": EUpstreamNetworkSwitch,
"router": EUpstreamNetworkRouter,
"none": EUpstreamNetworkNone,
}
)
// SakuraCloudResources さくらのクラウド上のリソース種別一覧
type SakuraCloudResources struct {
Server *Server `json:",omitempty"` // サーバー
@ -213,7 +243,7 @@ type Request struct {
Filter map[string]interface{} `json:",omitempty"` // フィルタ
Exclude []string `json:",omitempty"` // 除外する項目
Include []string `json:",omitempty"` // 取得する項目
DistantFrom []int64 `json:",omitempty"` // ストレージ隔離対象ディスク
}
// AddFilter フィルタの追加
@ -324,3 +354,15 @@ var (
// DatetimeLayout さくらのクラウドAPIで利用される日付型のレイアウト(RFC3339)
var DatetimeLayout = "2006-01-02T15:04:05-07:00"
// PlanGenerations サーバプラン世代
type PlanGenerations int
var (
// PlanDefault デフォルト
PlanDefault = PlanGenerations(0)
// PlanG1 第1世代(Generation:100)
PlanG1 = PlanGenerations(100)
// PlanG2 第2世代(Generation:200)
PlanG2 = PlanGenerations(200)
)

14
vendor/github.com/sacloud/libsacloud/sacloud/coupon.go generated vendored Normal file
View file

@ -0,0 +1,14 @@
package sacloud
import "time"
// Coupon クーポン情報
type Coupon struct {
CouponID string `json:",omitempty"` // クーポンID
MemberID string `json:",omitempty"` // メンバーID
ContractID int64 `json:",omitempty"` // 契約ID
ServiceClassID int64 `json:",omitempty"` // サービスクラスID
Discount int64 `json:",omitempty"` // クーポン残高
AppliedAt time.Time `json:",omitempty"` // 適用開始日
UntilAt time.Time `json:",omitempty"` // 有効期限
}

View file

@ -2,9 +2,15 @@ package sacloud
import (
"encoding/json"
"fmt"
"strings"
)
// AllowDatabaseBackupWeekdays データベースバックアップ実行曜日リスト
func AllowDatabaseBackupWeekdays() []string {
return []string{"mon", "tue", "wed", "thu", "fri", "sat", "sun"}
}
// Database データベース(appliance)
type Database struct {
*Appliance // アプライアンス共通属性
@ -64,8 +70,6 @@ type DatabaseCommonRemark struct {
DatabaseRevision string `json:",omitempty"` // リビジョン
DatabaseTitle string `json:",omitempty"` // タイトル
DatabaseVersion string `json:",omitempty"` // バージョン
ReplicaPassword string `json:",omitempty"` // レプリケーションパスワード
ReplicaUser string `json:",omitempty"` // レプリケーションユーザー
}
// DatabaseSettings データベース設定リスト
@ -75,8 +79,9 @@ type DatabaseSettings struct {
// DatabaseSetting データベース設定
type DatabaseSetting struct {
Backup *DatabaseBackupSetting `json:",omitempty"` // バックアップ設定
Common *DatabaseCommonSetting `json:",oitempty"` // 共通設定
Backup *DatabaseBackupSetting `json:",omitempty"` // バックアップ設定
Common *DatabaseCommonSetting `json:",oitempty"` // 共通設定
Replication *DatabaseReplicationSetting `json:",omitempty"` // レプリケーション設定
}
// DatabaseServer データベースサーバー情報
@ -122,17 +127,20 @@ func AllowDatabasePlans() []int {
// DatabaseBackupSetting バックアップ設定
type DatabaseBackupSetting struct {
Rotate int `json:",omitempty"` // ローテーション世代数
Time string `json:",omitempty"` // 開始時刻
Rotate int `json:",omitempty"` // ローテーション世代数
Time string `json:",omitempty"` // 開始時刻
DayOfWeek []string `json:",omitempty"` // 取得曜日
}
// DatabaseCommonSetting 共通設定
type DatabaseCommonSetting struct {
DefaultUser string `json:",omitempty"` // ユーザー名
UserPassword string `json:",omitempty"` // ユーザーパスワード
WebUI interface{} `json:",omitempty"` // WebUIのIPアドレス or FQDN
ServicePort string // ポート番号
SourceNetwork SourceNetwork // 接続許可ネットワーク
DefaultUser string `json:",omitempty"` // ユーザー名
UserPassword string `json:",omitempty"` // ユーザーパスワード
WebUI interface{} `json:",omitempty"` // WebUIのIPアドレス or FQDN
ReplicaPassword string `json:",omitempty"` // レプリケーションパスワード
ReplicaUser string `json:",omitempty"` // レプリケーションユーザー
ServicePort json.Number `json:",omitempty"` // ポート番号
SourceNetwork SourceNetwork // 接続許可ネットワーク
}
// SourceNetwork 接続許可ネットワーク
@ -168,32 +176,84 @@ func (s *SourceNetwork) MarshalJSON() ([]byte, error) {
return json.Marshal(list)
}
// DatabaseReplicationSetting レプリケーション設定
type DatabaseReplicationSetting struct {
// Model レプリケーションモデル
Model DatabaseReplicationModels `json:",omitempty"`
// Appliance マスター側アプライアンス
Appliance *struct {
ID string
} `json:",omitempty"`
// IPAddress IPアドレス
IPAddress string `json:",omitempty"`
// Port ポート
Port int `json:",omitempty"`
// User ユーザー
User string `json:",omitempty"`
// Password パスワード
Password string `json:",omitempty"`
}
// DatabaseReplicationModels データベースのレプリケーションモデル
type DatabaseReplicationModels string
const (
// DatabaseReplicationModelMasterSlave レプリケーションモデル: Master-Slave(マスター側)
DatabaseReplicationModelMasterSlave = "Master-Slave"
// DatabaseReplicationModelAsyncReplica レプリケーションモデル: Async-Replica(スレーブ側)
DatabaseReplicationModelAsyncReplica = "Async-Replica"
)
// CreateDatabaseValue データベース作成用パラメータ
type CreateDatabaseValue struct {
Plan DatabasePlan // プラン
AdminPassword string // 管理者パスワード
DefaultUser string // ユーザー名
UserPassword string // パスワード
SourceNetwork []string // 接続許可ネットワーク
ServicePort string // ポート
// BackupRotate int // バックアップ世代数
BackupTime string // バックアップ開始時間
SwitchID string // 接続先スイッチ
IPAddress1 string // IPアドレス1
MaskLen int // ネットワークマスク長
DefaultRoute string // デフォルトルート
Name string // 名称
Description string // 説明
Tags []string // タグ
Icon *Resource // アイコン
WebUI bool // WebUI有効
DatabaseName string // データベース名
DatabaseRevision string // リビジョン
DatabaseTitle string // データベースタイトル
DatabaseVersion string // データベースバージョン
ReplicaUser string // ReplicaUser レプリケーションユーザー
SourceAppliance *Resource // クローン元DB
//ReplicaPassword string // in current API version , setted admin password
Plan DatabasePlan // プラン
AdminPassword string // 管理者パスワード
DefaultUser string // ユーザー名
UserPassword string // パスワード
SourceNetwork []string // 接続許可ネットワーク
ServicePort int // ポート
EnableBackup bool // バックアップ有効化
BackupRotate int // バックアップ世代数
BackupTime string // バックアップ開始時間
BackupDayOfWeek []string // バックアップ取得曜日
SwitchID string // 接続先スイッチ
IPAddress1 string // IPアドレス1
MaskLen int // ネットワークマスク長
DefaultRoute string // デフォルトルート
Name string // 名称
Description string // 説明
Tags []string // タグ
Icon *Resource // アイコン
WebUI bool // WebUI有効
DatabaseName string // データベース名
DatabaseRevision string // リビジョン
DatabaseTitle string // データベースタイトル
DatabaseVersion string // データベースバージョン
// ReplicaUser string // レプリケーションユーザー 現在はreplica固定
ReplicaPassword string // レプリケーションパスワード
SourceAppliance *Resource // クローン元DB
}
// SlaveDatabaseValue スレーブデータベース作成用パラメータ
type SlaveDatabaseValue struct {
Plan DatabasePlan // プラン
DefaultUser string // ユーザー名
UserPassword string // パスワード
SwitchID string // 接続先スイッチ
IPAddress1 string // IPアドレス1
MaskLen int // ネットワークマスク長
DefaultRoute string // デフォルトルート
Name string // 名称
Description string // 説明
Tags []string // タグ
Icon *Resource // アイコン
DatabaseName string // データベース名
DatabaseVersion string // データベースバージョン
// ReplicaUser string // レプリケーションユーザー 現在はreplica固定
ReplicaPassword string // レプリケーションパスワード
MasterApplianceID int64 // クローン元DB
MasterIPAddress string // マスターIPアドレス
MasterPort int // マスターポート
}
// NewCreatePostgreSQLDatabaseValue PostgreSQL作成用パラメーター
@ -267,10 +327,6 @@ func CreateNewDatabase(values *CreateDatabaseValue) *Database {
DatabaseTitle: values.DatabaseTitle,
// DatabaseVersion
DatabaseVersion: values.DatabaseVersion,
// ReplicaUser
// ReplicaUser: values.ReplicaUser,
// ReplicaPassword
// ReplicaPassword: values.AdminPassword,
},
},
// Plan
@ -288,6 +344,8 @@ func CreateNewDatabase(values *CreateDatabaseValue) *Database {
Rotate: 8,
// Time
Time: values.BackupTime,
// DayOfWeek
DayOfWeek: values.BackupDayOfWeek,
},
// Common
Common: &DatabaseCommonSetting{
@ -297,13 +355,19 @@ func CreateNewDatabase(values *CreateDatabaseValue) *Database {
UserPassword: values.UserPassword,
// SourceNetwork
SourceNetwork: SourceNetwork(values.SourceNetwork),
// ServicePort
ServicePort: values.ServicePort,
},
},
},
}
if values.ServicePort > 0 {
db.Settings.DBConf.Common.ServicePort = json.Number(fmt.Sprintf("%d", values.ServicePort))
}
if !values.EnableBackup {
db.Settings.DBConf.Backup = nil
}
db.Remark.Switch = &ApplianceRemarkSwitch{
// ID
ID: values.SwitchID,
@ -323,11 +387,19 @@ func CreateNewDatabase(values *CreateDatabaseValue) *Database {
db.Settings.DBConf.Common.WebUI = values.WebUI
}
if values.ReplicaPassword != "" {
db.Settings.DBConf.Common.ReplicaUser = "replica"
db.Settings.DBConf.Common.ReplicaPassword = values.ReplicaPassword
db.Settings.DBConf.Replication = &DatabaseReplicationSetting{
Model: DatabaseReplicationModelMasterSlave,
}
}
return db
}
// CloneNewDatabase データベース作成
func CloneNewDatabase(values *CreateDatabaseValue) *Database {
// NewSlaveDatabaseValue スレーブ向けパラメータ作成
func NewSlaveDatabaseValue(values *SlaveDatabaseValue) *Database {
db := &Database{
// Appliance
Appliance: &Appliance{
@ -363,32 +435,34 @@ func CloneNewDatabase(values *CreateDatabaseValue) *Database {
DBConf: &DatabaseCommonRemarks{
// Common
Common: &DatabaseCommonRemark{
DatabaseName: values.DatabaseName,
// DatabaseName
DatabaseName: values.DatabaseName,
// DatabaseVersion
DatabaseVersion: values.DatabaseVersion,
},
},
// Plan
propPlanID: propPlanID{Plan: &Resource{ID: int64(values.Plan)}},
SourceAppliance: values.SourceAppliance,
propPlanID: propPlanID{Plan: &Resource{ID: int64(values.Plan)}},
},
// Settings
Settings: &DatabaseSettings{
// DBConf
DBConf: &DatabaseSetting{
// Backup
Backup: &DatabaseBackupSetting{
// Rotate
// Rotate: values.BackupRotate,
Rotate: 8,
// Time
Time: values.BackupTime,
},
// Common
Common: &DatabaseCommonSetting{
// SourceNetwork
SourceNetwork: SourceNetwork(values.SourceNetwork),
// ServicePort
ServicePort: values.ServicePort,
// DefaultUser
DefaultUser: values.DefaultUser,
// UserPassword
UserPassword: values.UserPassword,
},
// Replication
Replication: &DatabaseReplicationSetting{
Model: DatabaseReplicationModelAsyncReplica,
Appliance: &struct{ ID string }{ID: fmt.Sprintf("%d", values.MasterApplianceID)},
IPAddress: values.MasterIPAddress,
Port: values.MasterPort,
User: "replica",
Password: values.ReplicaPassword,
},
},
},
@ -409,10 +483,6 @@ func CloneNewDatabase(values *CreateDatabaseValue) *Database {
map[string]interface{}{"IPAddress": values.IPAddress1},
}
if values.WebUI {
db.Settings.DBConf.Common.WebUI = values.WebUI
}
return db
}
@ -433,3 +503,71 @@ func (s *Database) DeleteSourceNetwork(nw string) {
}
s.Settings.DBConf.Common.SourceNetwork = SourceNetwork(res)
}
// IsReplicationMaster レプリケーションが有効かつマスターとして構成されているか
func (s *Database) IsReplicationMaster() bool {
return s.IsReplicationEnabled() && s.Settings.DBConf.Replication.Model == DatabaseReplicationModelMasterSlave
}
// IsReplicationEnabled レプリケーションが有効な場合はTrueを返す
func (s *Database) IsReplicationEnabled() bool {
return s.Settings.DBConf.Replication != nil
}
// DatabaseName MariaDB or PostgreSQLの何れかを返す
func (s *Database) DatabaseName() string {
return s.Remark.DBConf.Common.DatabaseName
}
// DatabaseRevision データベースのリビジョンを返す
//
// 例: MariaDBの場合 => 10.2.15 / PostgreSQLの場合 => 10.3
func (s *Database) DatabaseRevision() string {
return s.Remark.DBConf.Common.DatabaseRevision
}
// DatabaseVersion データベースのバージョンを返す
//
// 例: MariaDBの場合 => 10.2 / PostgreSQLの場合 => 10
func (s *Database) DatabaseVersion() string {
return s.Remark.DBConf.Common.DatabaseVersion
}
// WebUIAddress WebUIが有効な場合、IPアドレス or FQDNを返す、無効な場合は空文字を返す
func (s *Database) WebUIAddress() string {
webUI := s.Settings.DBConf.Common.WebUI
if webUI != nil {
if v, ok := webUI.(string); ok {
return v
}
}
return ""
}
// IPAddress IPアドレスを取得
func (s *Database) IPAddress() string {
if len(s.Remark.Servers) < 1 {
return ""
}
v, ok := s.Remark.Servers[0].(map[string]string)
if !ok {
return ""
}
return v["IPAddress"]
}
// NetworkMaskLen ネットワークマスク長を取得
func (s *Database) NetworkMaskLen() int {
if s.Remark.Network == nil {
return -1
}
return s.Remark.Network.NetworkMaskLen
}
// DefaultRoute デフォルトゲートウェイアドレスを取得
func (s *Database) DefaultRoute() string {
if s.Remark.Network == nil {
return ""
}
return s.Remark.Network.DefaultRoute
}

View file

@ -4,22 +4,23 @@ import "fmt"
// Disk ディスク
type Disk struct {
*Resource // ID
propAvailability // 有功状態
propName // 名称
propDescription // 説明
propSizeMB // サイズ(MB単位)
propMigratedMB // コピー済みデータサイズ(MB単位)
propCopySource // コピー元情報
propJobStatus // マイグレーションジョブステータス
propBundleInfo // バンドル情報
propServer // サーバー
propIcon // アイコン
propTags // タグ
propCreatedAt // 作成日時
propPlanID // プランID
propDiskConnection // ディスク接続情報
propDistantFrom // ストレージ隔離対象ディスク
*Resource // ID
propAvailability // 有功状態
propName // 名称
propDescription // 説明
propSizeMB // サイズ(MB単位)
propMigratedMB // コピー済みデータサイズ(MB単位)
propCopySource // コピー元情報
propJobStatus // マイグレーションジョブステータス
propBundleInfo // バンドル情報
propServer // サーバー
propIcon // アイコン
propTags // タグ
propCreatedAt // 作成日時
propPlanID // プランID
propDiskConnection // ディスク接続情報
propDistantFrom // ストレージ隔離対象ディスク
Generation PlanGenerations `json:",omitempty"` // プラン世代
ReinstallCount int `json:",omitempty"` // 再インストール回数

View file

@ -50,7 +50,9 @@ func CreateNewDNS(zoneName string) *DNS {
Class: "dns",
},
Settings: DNSSettings{
DNS: DNSRecordSets{},
DNS: DNSRecordSets{
ResourceRecordSets: []DNSRecordSet{},
},
},
}
}
@ -135,7 +137,9 @@ func (d *DNS) AddRecord(record *DNSRecordSet) {
// ClearRecords レコード クリア
func (d *DNS) ClearRecords() {
d.Settings.DNS = DNSRecordSets{}
d.Settings.DNS = DNSRecordSets{
ResourceRecordSets: []DNSRecordSet{},
}
}
// DNSRecordSets DNSレコード設定リスト

View file

@ -41,3 +41,21 @@ func (i *Interface) GetHostName() string {
func (i *Interface) GetPacketFilter() *PacketFilter {
return i.PacketFilter
}
// UpstreamType 上流ネットワーク種別
func (i *Interface) UpstreamType() EUpstreamNetworkType {
sw := i.Switch
if sw == nil {
return EUpstreamNetworkNone
}
if sw.Subnet == nil {
return EUpstreamNetworkSwitch
}
if sw.Scope == ESCopeShared {
return EUpstreamNetworkShared
}
return EUpstreamNetworkRouter
}

View file

@ -41,7 +41,7 @@ func (i *Internet) SetNetworkMaskLen(v int) {
// AllowInternetBandWidth 設定可能な帯域幅の値リスト
func AllowInternetBandWidth() []int {
return []int{100, 250, 500, 1000, 1500, 2000, 2500, 3000}
return []int{100, 250, 500, 1000, 1500, 2000, 2500, 3000, 5000}
}
// AllowInternetNetworkMaskLen 設定可能なネットワークマスク長の値リスト

View file

@ -1,5 +1,7 @@
package sacloud
import "strconv"
// LoadBalancer ロードバランサー
type LoadBalancer struct {
*Appliance // アプライアンス共通属性
@ -8,6 +10,43 @@ type LoadBalancer struct {
Settings *LoadBalancerSettings `json:",omitempty"` // ロードバランサー設定
}
// IsHA 冗長化されている場合にtrueを返す
func (l *LoadBalancer) IsHA() bool {
isHA := false
if len(l.Remark.Servers) > 1 {
if v, ok := l.Remark.Servers[1].(map[string]string); ok {
if _, ok := v["IPAddress"]; ok {
isHA = true
}
}
}
return isHA
}
// IPAddress1 ロードバランサ本体のIPアドレス(1番目)を返す
func (l *LoadBalancer) IPAddress1() string {
if len(l.Remark.Servers) > 0 {
if v, ok := l.Remark.Servers[0].(map[string]string); ok {
if v, ok := v["IPAddress"]; ok {
return v
}
}
}
return ""
}
// IPAddress2 ロードバランサ本体のIPアドレス(2番目)を返す
func (l *LoadBalancer) IPAddress2() string {
if len(l.Remark.Servers) > 1 {
if v, ok := l.Remark.Servers[1].(map[string]string); ok {
if v, ok := v["IPAddress"]; ok {
return v
}
}
}
return ""
}
// LoadBalancerRemark リマーク
type LoadBalancerRemark struct {
*ApplianceRemarkBase
@ -17,7 +56,7 @@ type LoadBalancerRemark struct {
// LoadBalancerSettings ロードバランサー設定リスト
type LoadBalancerSettings struct {
LoadBalancer []*LoadBalancerSetting `json:",omitempty"` // ロードバランサー設定リスト
LoadBalancer []*LoadBalancerSetting // ロードバランサー設定リスト
}
// LoadBalancerSetting ロードバランサー仮想IP設定
@ -26,6 +65,7 @@ type LoadBalancerSetting struct {
Port string `json:",omitempty"` // ポート番号
DelayLoop string `json:",omitempty"` // 監視間隔
SorryServer string `json:",omitempty"` // ソーリーサーバー
Description string `json:",omitempty"` // 説明
Servers []*LoadBalancerServer `json:",omitempty"` // 仮想IP配下の実サーバー
}
@ -179,3 +219,73 @@ func (s *LoadBalancerSetting) DeleteServer(ip string, port string) {
s.Servers = res
}
// LoadBalancerStatusResult ロードバランサーのステータスAPI戻り値
type LoadBalancerStatusResult []*LoadBalancerStatus
// Get VIPに対応するステータスを取得
func (l *LoadBalancerStatusResult) Get(vip string) *LoadBalancerStatus {
for _, v := range *l {
if v.VirtualIPAddress == vip {
return v
}
}
return nil
}
// LoadBalancerStatus ロードバランサーのステータス
type LoadBalancerStatus struct {
VirtualIPAddress string
Port string
Servers []*LoadBalancerServerStatus `json:",omitempty"`
CPS string
}
// Get IPアドレスに対応する実サーバのステータスを取得
func (l *LoadBalancerStatus) Get(ip string) *LoadBalancerServerStatus {
for _, v := range l.Servers {
if v.IPAddress == ip {
return v
}
}
return nil
}
// NumCPS CPSを数値にして返す
func (l *LoadBalancerStatus) NumCPS() int {
v, _ := strconv.Atoi(l.CPS) // nolint - ignore error
return v
}
// NumPort Portを数値にして返す
func (l *LoadBalancerStatus) NumPort() int {
v, _ := strconv.Atoi(l.Port) // nolint - ignore error
return v
}
// LoadBalancerServerStatus ロードバランサーのVIP配下の実サーバのステータス
type LoadBalancerServerStatus struct {
ActiveConn string
IPAddress string
Status string
Port string
CPS string
}
// NumActiveConn ActiveConnを数値にして返す
func (l *LoadBalancerServerStatus) NumActiveConn() int {
v, _ := strconv.Atoi(l.ActiveConn) // nolint - ignore error
return v
}
// NumCPS CPSを数値にして返す
func (l *LoadBalancerServerStatus) NumCPS() int {
v, _ := strconv.Atoi(l.CPS) // nolint - ignore error
return v
}
// NumPort Portを数値にして返す
func (l *LoadBalancerServerStatus) NumPort() int {
v, _ := strconv.Atoi(l.Port) // nolint - ignore error
return v
}

29
vendor/github.com/sacloud/libsacloud/sacloud/lock.go generated vendored Normal file
View file

@ -0,0 +1,29 @@
package sacloud
import (
"fmt"
"github.com/sacloud/libsacloud/utils/mutexkv"
)
var resourceMu = mutexkv.NewMutexKV()
// LockByKey 任意のキーでのMutexロック
func LockByKey(key string) {
resourceMu.Lock(key)
}
// UnlockByKey 任意のキーでのMutexアンロック
func UnlockByKey(key string) {
resourceMu.Unlock(key)
}
// LockByResourceID リソース単位でのMutexロック
func LockByResourceID(resourceID int64) {
resourceMu.Lock(fmt.Sprintf("%d", resourceID))
}
// UnlockByResourceID リソース単位でのMutexアンロック
func UnlockByResourceID(resourceID int64) {
resourceMu.Unlock(fmt.Sprintf("%d", resourceID))
}

View file

@ -3,6 +3,7 @@ package sacloud
import (
"encoding/json"
"fmt"
"strconv"
"strings"
)
@ -28,9 +29,71 @@ type MobileGatewaySettings struct {
// MobileGatewaySetting モバイルゲートウェイ設定
type MobileGatewaySetting struct {
InternetConnection *MGWInternetConnection `json:",omitempty"` // インターネット接続
Interfaces []*MGWInterface `json:",omitempty"` // インターフェース
StaticRoutes []*MGWStaticRoute `json:",omitempty"` // スタティックルート
InternetConnection *MGWInternetConnection `json:",omitempty"` // インターネット接続
InterDeviceCommunication *MGWInterDeviceCommunication `json:",omitempty"` // デバイス間通信
Interfaces []*MGWInterface `json:",omitempty"` // インターフェース
StaticRoutes []*MGWStaticRoute `json:",omitempty"` // スタティックルート
}
// HasStaticRoutes スタティックルートを保持しているか
func (m *MobileGatewaySetting) HasStaticRoutes() bool {
return m.StaticRoutes != nil && len(m.StaticRoutes) > 0
}
// AddStaticRoute スタティックルート設定 追加
func (m *MobileGatewaySetting) AddStaticRoute(prefix string, nextHop string) (int, *MGWStaticRoute) {
if m.StaticRoutes == nil {
m.StaticRoutes = []*MGWStaticRoute{}
}
s := &MGWStaticRoute{
Prefix: prefix,
NextHop: nextHop,
}
m.StaticRoutes = append(m.StaticRoutes, s)
return len(m.StaticRoutes) - 1, s
}
// RemoveStaticRoute スタティックルート設定 削除
func (m *MobileGatewaySetting) RemoveStaticRoute(prefix string, nextHop string) {
if m.StaticRoutes == nil {
return
}
dest := []*MGWStaticRoute{}
for _, s := range m.StaticRoutes {
if s.Prefix != prefix || s.NextHop != nextHop {
dest = append(dest, s)
}
}
m.StaticRoutes = dest
}
// RemoveStaticRouteAt スタティックルート設定 削除
func (m *MobileGatewaySetting) RemoveStaticRouteAt(index int) {
if m.StaticRoutes == nil {
return
}
if index < len(m.StaticRoutes) {
s := m.StaticRoutes[index]
m.RemoveStaticRoute(s.Prefix, s.NextHop)
}
}
// FindStaticRoute スタティックルート設定 検索
func (m *MobileGatewaySetting) FindStaticRoute(prefix string, nextHop string) (int, *MGWStaticRoute) {
for i, s := range m.StaticRoutes {
if s.Prefix == prefix && s.NextHop == nextHop {
return i, s
}
}
return -1, nil
}
// MGWInterDeviceCommunication デバイス間通信
type MGWInterDeviceCommunication struct {
Enabled string `json:",omitempty"`
}
// MGWInternetConnection インターネット接続
@ -121,6 +184,68 @@ func (m *MobileGateway) ClearPrivateInterface() {
m.Settings.MobileGateway.Interfaces = []*MGWInterface{nil}
}
// HasSetting モバイルゲートウェイ設定を保持しているか
func (m *MobileGateway) HasSetting() bool {
return m.Settings != nil && m.Settings.MobileGateway != nil
}
// HasStaticRoutes スタティックルートを保持しているか
func (m *MobileGateway) HasStaticRoutes() bool {
return m.HasSetting() && m.Settings.MobileGateway.HasStaticRoutes()
}
// InternetConnection インターネット接続が有効な場合にTrueを返す
func (m *MobileGateway) InternetConnection() bool {
return m.HasSetting() &&
m.Settings.MobileGateway.InternetConnection != nil &&
m.Settings.MobileGateway.InternetConnection.Enabled == "True"
}
// InterDeviceCommunication デバイス間通信が有効な場合にTrueを返す
func (m *MobileGateway) InterDeviceCommunication() bool {
return m.HasSetting() &&
m.Settings.MobileGateway.InterDeviceCommunication != nil &&
m.Settings.MobileGateway.InterDeviceCommunication.Enabled == "True"
}
// IPAddress 0番目のNICのIPアドレスを取得
func (m *MobileGateway) IPAddress() string {
return m.IPAddressAt(0)
}
// IPAddressAt IPアドレスを取得
func (m *MobileGateway) IPAddressAt(index int) string {
if len(m.Interfaces) <= index {
return ""
}
if index == 0 {
return m.Interfaces[0].IPAddress
}
ipaddresses := m.Settings.MobileGateway.Interfaces[index].IPAddress
if len(ipaddresses) < 1 {
return ""
}
return ipaddresses[0]
}
// NetworkMaskLen 0番目のNICのネットワークマスク長を取得
func (m *MobileGateway) NetworkMaskLen() int {
return m.NetworkMaskLenAt(0)
}
// NetworkMaskLenAt ネットワークマスク長を取得
func (m *MobileGateway) NetworkMaskLenAt(index int) int {
if len(m.Interfaces) <= index {
return -1
}
if index == 0 {
return m.Interfaces[0].Switch.UserSubnet.NetworkMaskLen
}
return m.Settings.MobileGateway.Interfaces[0].NetworkMaskLen
}
// NewMobileGatewayResolver DNS登録用パラメータ作成
func NewMobileGatewayResolver(dns1, dns2 string) *MobileGatewayResolver {
return &MobileGatewayResolver{
@ -175,7 +300,7 @@ type MobileGatewaySIMRoutes struct {
}
// AddSIMRoute SIMルート追加
func (m *MobileGatewaySIMRoutes) AddSIMRoute(simID int64, prefix string) bool {
func (m *MobileGatewaySIMRoutes) AddSIMRoute(simID int64, prefix string) (int, *MobileGatewaySIMRoute) {
var exists bool
for _, route := range m.SIMRoutes {
if route.ResourceID == fmt.Sprintf("%d", simID) && route.Prefix == prefix {
@ -184,12 +309,14 @@ func (m *MobileGatewaySIMRoutes) AddSIMRoute(simID int64, prefix string) bool {
}
}
if !exists {
m.SIMRoutes = append(m.SIMRoutes, &MobileGatewaySIMRoute{
r := &MobileGatewaySIMRoute{
ResourceID: fmt.Sprintf("%d", simID),
Prefix: prefix,
})
}
m.SIMRoutes = append(m.SIMRoutes, r)
return len(m.SIMRoutes) - 1, r
}
return !exists
return -1, nil
}
// DeleteSIMRoute SIMルート削除
@ -207,3 +334,79 @@ func (m *MobileGatewaySIMRoutes) DeleteSIMRoute(simID int64, prefix string) bool
m.SIMRoutes = routes
return exists
}
// DeleteSIMRouteAt SIMルート削除
func (m *MobileGatewaySIMRoutes) DeleteSIMRouteAt(index int) bool {
if m.SIMRoutes == nil {
return false
}
if index < len(m.SIMRoutes) {
s := m.SIMRoutes[index]
if simID, err := strconv.ParseInt(s.ResourceID, 10, 64); err == nil {
return m.DeleteSIMRoute(simID, s.Prefix)
}
}
return false
}
// FindSIMRoute SIMルート設定 検索
func (m *MobileGatewaySIMRoutes) FindSIMRoute(simID int64, prefix string) (int, *MobileGatewaySIMRoute) {
for i, r := range m.SIMRoutes {
if r.Prefix == prefix && r.ResourceID == fmt.Sprintf("%d", simID) {
return i, r
}
}
return -1, nil
}
// TrafficStatus トラフィックコントロール 当月通信量
type TrafficStatus struct {
UplinkBytes uint64 `json:"uplink_bytes,omitempty"`
DownlinkBytes uint64 `json:"downlink_bytes,omitempty"`
TrafficShaping bool `json:"traffic_shaping"` // 帯域制限
}
// UnmarshalJSON JSONアンマーシャル(uint64文字列対応)
func (s *TrafficStatus) UnmarshalJSON(data []byte) error {
tmp := &struct {
UplinkBytes string `json:"uplink_bytes,omitempty"`
DownlinkBytes string `json:"downlink_bytes,omitempty"`
TrafficShaping bool `json:"traffic_shaping"`
}{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
var err error
s.UplinkBytes, err = strconv.ParseUint(tmp.UplinkBytes, 10, 64)
if err != nil {
return err
}
s.DownlinkBytes, err = strconv.ParseUint(tmp.DownlinkBytes, 10, 64)
if err != nil {
return err
}
s.TrafficShaping = tmp.TrafficShaping
return nil
}
// TrafficMonitoringConfig トラフィックコントロール 設定
type TrafficMonitoringConfig struct {
TrafficQuotaInMB int `json:"traffic_quota_in_mb"`
BandWidthLimitInKbps int `json:"bandwidth_limit_in_kbps"`
EMailConfig *TrafficMonitoringNotifyEmail `json:"email_config"`
SlackConfig *TrafficMonitoringNotifySlack `json:"slack_config"`
AutoTrafficShaping bool `json:"auto_traffic_shaping"`
}
// TrafficMonitoringNotifyEmail トラフィックコントロール通知設定
type TrafficMonitoringNotifyEmail struct {
Enabled bool `json:"enabled"` // 有効/無効
}
// TrafficMonitoringNotifySlack トラフィックコントロール通知設定
type TrafficMonitoringNotifySlack struct {
Enabled bool `json:"enabled"` // 有効/無効
IncomingWebhooksURL string `json:"slack_url,omitempty"` // Slack通知の場合のWebhook URL
}

View file

@ -9,23 +9,27 @@ import (
// MonitorValue アクティビティモニター
type MonitorValue struct {
CPUTime *float64 `json:"CPU-TIME,omitempty"` // CPU時間
Write *float64 `json:",omitempty"` // ディスク書き込み
Read *float64 `json:",omitempty"` // ディスク読み取り
Receive *float64 `json:",omitempty"` // パケット受信
Send *float64 `json:",omitempty"` // パケット送信
In *float64 `json:",omitempty"` // パケット受信
Out *float64 `json:",omitempty"` // パケット送信
TotalMemorySize *float64 `json:"Total-Memory-Size,omitempty"` // 総メモリサイズ
UsedMemorySize *float64 `json:"Used-Memory-Size,omitempty"` // 使用済みメモリサイズ
TotalDisk1Size *float64 `json:"Total-Disk1-Size,omitempty"` // 総ディスクサイズ
UsedDisk1Size *float64 `json:"Used-Disk1-Size,omitempty"` // 使用済みディスクサイズ
TotalDisk2Size *float64 `json:"Total-Disk2-Size,omitempty"` // 総ディスクサイズ
UsedDisk2Size *float64 `json:"Used-Disk2-Size,omitempty"` // 使用済みディスクサイズ
FreeDiskSize *float64 `json:"Free-Disk-Size,omitempty"` // 空きディスクサイズ(NFS)
ResponseTimeSec *float64 `json:"responsetimesec,omitempty"` // レスポンスタイム(シンプル監視)
UplinkBPS *float64 `json:"UplinkBps,omitempty"` // 上り方向トラフィック
DownlinkBPS *float64 `json:"DownlinkBps"` // 下り方向トラフィック
CPUTime *float64 `json:"CPU-TIME,omitempty"` // CPU時間
Write *float64 `json:",omitempty"` // ディスク書き込み
Read *float64 `json:",omitempty"` // ディスク読み取り
Receive *float64 `json:",omitempty"` // パケット受信
Send *float64 `json:",omitempty"` // パケット送信
In *float64 `json:",omitempty"` // パケット受信
Out *float64 `json:",omitempty"` // パケット送信
TotalMemorySize *float64 `json:"Total-Memory-Size,omitempty"` // 総メモリサイズ
UsedMemorySize *float64 `json:"Used-Memory-Size,omitempty"` // 使用済みメモリサイズ
TotalDisk1Size *float64 `json:"Total-Disk1-Size,omitempty"` // 総ディスクサイズ
UsedDisk1Size *float64 `json:"Used-Disk1-Size,omitempty"` // 使用済みディスクサイズ
TotalDisk2Size *float64 `json:"Total-Disk2-Size,omitempty"` // 総ディスクサイズ
UsedDisk2Size *float64 `json:"Used-Disk2-Size,omitempty"` // 使用済みディスクサイズ
BinlogUsedSizeKiB *float64 `json:"binlogUsedSizeKiB,omitempty"` // バイナリログのサイズ(レプリケーション有効時のみ、master/slave両方で利用可能)
DelayTimeSec *float64 `json:"delayTimeSec,omitempty"` // レプリケーション遅延時間(レプリケーション有効時のみ、slave側のみ)
FreeDiskSize *float64 `json:"Free-Disk-Size,omitempty"` // 空きディスクサイズ(NFS)
ResponseTimeSec *float64 `json:"responsetimesec,omitempty"` // レスポンスタイム(シンプル監視)
UplinkBPS *float64 `json:"UplinkBps,omitempty"` // 上り方向トラフィック
DownlinkBPS *float64 `json:"DownlinkBps,omitempty"` // 下り方向トラフィック
ActiveConnections *float64 `json:"activeConnections,omitempty"` // アクティブコネクション(プロキシLB)
ConnectionsPerSec *float64 `json:"connectionsPerSec,omitempty"` // 秒間コネクション数
}
// UnmarshalJSON JSONアンマーシャル(配列、オブジェクトが混在するためここで対応)
@ -36,23 +40,27 @@ func (m *MonitorValue) UnmarshalJSON(data []byte) error {
}
tmp := &struct {
CPUTime *float64 `json:"CPU-TIME,omitempty"`
Write *float64 `json:",omitempty"`
Read *float64 `json:",omitempty"`
Receive *float64 `json:",omitempty"`
Send *float64 `json:",omitempty"`
In *float64 `json:",omitempty"`
Out *float64 `json:",omitempty"`
TotalMemorySize *float64 `json:"Total-Memory-Size,omitempty"`
UsedMemorySize *float64 `json:"Used-Memory-Size,omitempty"`
TotalDisk1Size *float64 `json:"Total-Disk1-Size,omitempty"`
UsedDisk1Size *float64 `json:"Used-Disk1-Size,omitempty"`
TotalDisk2Size *float64 `json:"Total-Disk2-Size,omitempty"`
UsedDisk2Size *float64 `json:"Used-Disk2-Size,omitempty"`
FreeDiskSize *float64 `json:"Free-Disk-Size,omitempty"`
ResponseTimeSec *float64 `json:"responsetimesec,omitempty"`
UplinkBPS *float64 `json:"UplinkBps,omitempty"`
DownlinkBPS *float64 `json:"DownlinkBps"`
CPUTime *float64 `json:"CPU-TIME,omitempty"`
Write *float64 `json:",omitempty"`
Read *float64 `json:",omitempty"`
Receive *float64 `json:",omitempty"`
Send *float64 `json:",omitempty"`
In *float64 `json:",omitempty"`
Out *float64 `json:",omitempty"`
TotalMemorySize *float64 `json:"Total-Memory-Size,omitempty"`
UsedMemorySize *float64 `json:"Used-Memory-Size,omitempty"`
TotalDisk1Size *float64 `json:"Total-Disk1-Size,omitempty"`
UsedDisk1Size *float64 `json:"Used-Disk1-Size,omitempty"`
TotalDisk2Size *float64 `json:"Total-Disk2-Size,omitempty"`
UsedDisk2Size *float64 `json:"Used-Disk2-Size,omitempty"`
BinlogUsedSizeKiB *float64 `json:"binlogUsedSizeKiB,omitempty"`
DelayTimeSec *float64 `json:"delayTimeSec,omitempty"`
FreeDiskSize *float64 `json:"Free-Disk-Size,omitempty"`
ResponseTimeSec *float64 `json:"responsetimesec,omitempty"`
UplinkBPS *float64 `json:"UplinkBps,omitempty"`
DownlinkBPS *float64 `json:"DownlinkBps,omitempty"`
ActiveConnections *float64 `json:"activeConnections,omitempty"`
ConnectionsPerSec *float64 `json:"connectionsPerSec,omitempty"`
}{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
@ -71,10 +79,14 @@ func (m *MonitorValue) UnmarshalJSON(data []byte) error {
m.UsedDisk1Size = tmp.UsedDisk1Size
m.TotalDisk2Size = tmp.TotalDisk2Size
m.UsedDisk2Size = tmp.UsedDisk2Size
m.BinlogUsedSizeKiB = tmp.BinlogUsedSizeKiB
m.DelayTimeSec = tmp.DelayTimeSec
m.FreeDiskSize = tmp.FreeDiskSize
m.ResponseTimeSec = tmp.ResponseTimeSec
m.UplinkBPS = tmp.UplinkBPS
m.DownlinkBPS = tmp.DownlinkBPS
m.ActiveConnections = tmp.ActiveConnections
m.ConnectionsPerSec = tmp.ConnectionsPerSec
return nil
}
@ -104,6 +116,23 @@ type ResourceMonitorResponse struct {
Data *MonitorValues `json:",omitempty"` // メトリクス
}
// UnmarshalJSON JSONアンマーシャル(配列、オブジェクトが混在するためここで対応)
func (m *MonitorValues) UnmarshalJSON(data []byte) error {
targetData := strings.Replace(strings.Replace(string(data), " ", "", -1), "\n", "", -1)
if targetData == `[]` {
return nil
}
tmp := map[string]*MonitorValue{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
value := MonitorValues(tmp)
*m = value
return nil
}
// MonitorSummaryData メトリクスサマリー
type MonitorSummaryData struct {
Max float64 // 最大値
@ -242,6 +271,16 @@ func (m *MonitorValues) FlattenUsedDisk2SizeValue() ([]FlatMonitorValue, error)
return m.flattenValue(func(v *MonitorValue) *float64 { return v.UsedDisk2Size })
}
// FlattenBinlogUsedSizeKiBValue フラット化 バイナリログサイズ
func (m *MonitorValues) FlattenBinlogUsedSizeKiBValue() ([]FlatMonitorValue, error) {
return m.flattenValue(func(v *MonitorValue) *float64 { return v.BinlogUsedSizeKiB })
}
// FlattenDelayTimeSecValue フラット化 レプリケーション遅延時間
func (m *MonitorValues) FlattenDelayTimeSecValue() ([]FlatMonitorValue, error) {
return m.flattenValue(func(v *MonitorValue) *float64 { return v.DelayTimeSec })
}
// FlattenFreeDiskSizeValue フラット化 空きディスクサイズ(NFS)
func (m *MonitorValues) FlattenFreeDiskSizeValue() ([]FlatMonitorValue, error) {
return m.flattenValue(func(v *MonitorValue) *float64 { return v.FreeDiskSize })
@ -262,6 +301,16 @@ func (m *MonitorValues) FlattenDownlinkBPSValue() ([]FlatMonitorValue, error) {
return m.flattenValue(func(v *MonitorValue) *float64 { return v.DownlinkBPS })
}
// FlattenActiveConnections フラット化 アクティブコネクション
func (m *MonitorValues) FlattenActiveConnections() ([]FlatMonitorValue, error) {
return m.flattenValue(func(v *MonitorValue) *float64 { return v.ActiveConnections })
}
// FlattenConnectionsPerSec フラット化 秒間接続数
func (m *MonitorValues) FlattenConnectionsPerSec() ([]FlatMonitorValue, error) {
return m.flattenValue(func(v *MonitorValue) *float64 { return v.ConnectionsPerSec })
}
func (m *MonitorValues) flattenValue(f func(*MonitorValue) *float64) ([]FlatMonitorValue, error) {
var res []FlatMonitorValue
@ -293,8 +342,10 @@ func (m *MonitorValue) HasValue() bool {
m.TotalMemorySize, m.UsedMemorySize,
m.TotalDisk1Size, m.UsedDisk1Size,
m.TotalDisk2Size, m.UsedDisk2Size,
m.BinlogUsedSizeKiB, m.DelayTimeSec,
m.FreeDiskSize, m.ResponseTimeSec,
m.UplinkBPS, m.DownlinkBPS,
m.ActiveConnections, m.ConnectionsPerSec,
}
for _, v := range values {
if v != nil {

View file

@ -1,5 +1,9 @@
package sacloud
import (
"encoding/json"
)
// NFS NFS
type NFS struct {
*Appliance // アプライアンス共通属性
@ -11,47 +15,97 @@ type NFS struct {
// NFSRemark リマーク
type NFSRemark struct {
*ApplianceRemarkBase
propPlanID
Plan *struct {
ID json.Number `json:",omitempty"`
} `json:",omitempty"` // プラン
// TODO Zone
//Zone *Resource
//SourceAppliance *Resource // クローン元DB
}
// SetRemarkPlanID プランID設定
func (n NFSRemark) SetRemarkPlanID(planID int64) {
if n.Plan == nil {
n.Plan = &struct {
ID json.Number `json:",omitempty"`
}{}
}
n.Plan.ID = json.Number(planID)
}
// NFSSettings NFS設定リスト
type NFSSettings struct {
}
// NFSPlan NFSプラン
// NFSPlan プラン(HDD/SSD)
type NFSPlan int
var (
// NFSPlan100G 100Gプラン
NFSPlan100G = NFSPlan(100)
// NFSPlan500G 500Gプラン
NFSPlan500G = NFSPlan(500)
// NFSPlan1T 1T(1024GB)プラン
NFSPlan1T = NFSPlan(1024 * 1)
// NFSPlan2T 2T(2048GB)プラン
NFSPlan2T = NFSPlan(1024 * 2)
// NFSPlan4T 4T(4096GB)プラン
NFSPlan4T = NFSPlan(1024 * 4)
// NFSPlanHDD 標準プラン(HDD)
NFSPlanHDD = NFSPlan(1)
// NFSPlanSSD SSHプラン
NFSPlanSSD = NFSPlan(2)
)
// AllowNFSPlans 指定可能なNFSプラン
func AllowNFSPlans() []int {
// String NFSプランの文字列表現
func (p NFSPlan) String() string {
switch p {
case NFSPlanHDD:
return "HDD"
case NFSPlanSSD:
return "SSD"
default:
return ""
}
}
// NFSSize NFSサイズ
type NFSSize int
var (
// NFSSize100G 100Gプラン
NFSSize100G = NFSSize(100)
// NFSSize500G 500Gプラン
NFSSize500G = NFSSize(500)
// NFSSize1T 1T(1024GB)プラン
NFSSize1T = NFSSize(1024 * 1)
// NFSSize2T 2T(2048GB)プラン
NFSSize2T = NFSSize(1024 * 2)
// NFSSize4T 4T(4096GB)プラン
NFSSize4T = NFSSize(1024 * 4)
// NFSSize8T 8TBプラン
NFSSize8T = NFSSize(1024 * 8)
// NFSSize12T 12TBプラン
NFSSize12T = NFSSize(1024 * 12)
)
// AllowNFSNormalPlanSizes 指定可能なNFSサイズ(標準プラン)
func AllowNFSNormalPlanSizes() []int {
return []int{
int(NFSPlan100G),
int(NFSPlan500G),
int(NFSPlan1T),
int(NFSPlan2T),
int(NFSPlan4T),
int(NFSSize100G),
int(NFSSize500G),
int(NFSSize1T),
int(NFSSize2T),
int(NFSSize4T),
int(NFSSize8T),
int(NFSSize12T),
}
}
// AllowNFSSSDPlanSizes 指定可能なNFSサイズ(SSDプラン)
func AllowNFSSSDPlanSizes() []int {
return []int{
int(NFSSize100G),
int(NFSSize500G),
int(NFSSize1T),
int(NFSSize2T),
int(NFSSize4T),
}
}
// CreateNFSValue NFS作成用パラメーター
type CreateNFSValue struct {
SwitchID string // 接続先スイッチID
Plan NFSPlan // プラン
IPAddress string // IPアドレス
MaskLen int // ネットワークマスク長
DefaultRoute string // デフォルトルート
@ -62,27 +116,16 @@ type CreateNFSValue struct {
SourceAppliance *Resource // クローン元NFS
}
// NewCreateNFSValue NFS作成用パラメーター
func NewCreateNFSValue() *CreateNFSValue {
return &CreateNFSValue{
Plan: NFSPlan100G,
}
}
// NewNFS NFS作成(冗長化なし)
func NewNFS(values *CreateNFSValue) *NFS {
if int(values.Plan) == 0 {
values.Plan = NFSPlan100G
}
return &NFS{
Appliance: &Appliance{
Class: "nfs",
propName: propName{Name: values.Name},
propDescription: propDescription{Description: values.Description},
propTags: propTags{Tags: values.Tags},
propPlanID: propPlanID{Plan: &Resource{ID: int64(values.Plan)}},
//propPlanID: propPlanID{Plan: &Resource{ID: int64(values.Plan)}},
propIcon: propIcon{
&Icon{
Resource: values.Icon,
@ -99,12 +142,107 @@ func NewNFS(values *CreateNFSValue) *NFS {
DefaultRoute: values.DefaultRoute,
},
Servers: []interface{}{
map[string]string{"IPAddress": values.IPAddress},
map[string]interface{}{"IPAddress": values.IPAddress},
},
},
propPlanID: propPlanID{Plan: &Resource{ID: int64(values.Plan)}},
//SourceAppliance: values.SourceAppliance,
//propPlanID: propPlanID{Plan: &Resource{ID: int64(values.Plan)}},
},
}
}
// IPAddress IPアドレスを取得
func (n *NFS) IPAddress() string {
if len(n.Remark.Servers) < 1 {
return ""
}
v, ok := n.Remark.Servers[0].(map[string]interface{})
if !ok {
return ""
}
if ip, ok := v["IPAddress"]; ok {
return ip.(string)
}
return ""
}
// NetworkMaskLen ネットワークマスク長を取得
func (n *NFS) NetworkMaskLen() int {
if n.Remark.Network == nil {
return -1
}
return n.Remark.Network.NetworkMaskLen
}
// DefaultRoute デフォルトゲートウェイを取得
func (n *NFS) DefaultRoute() string {
if n.Remark.Network == nil {
return ""
}
return n.Remark.Network.DefaultRoute
}
// NFSPlans NFSプラン
type NFSPlans struct {
HDD []NFSPlanValue
SSD []NFSPlanValue
}
// FindPlanID プランとサイズからプランIDを取得
func (p NFSPlans) FindPlanID(plan NFSPlan, size NFSSize) int64 {
var plans []NFSPlanValue
switch plan {
case NFSPlanHDD:
plans = p.HDD
case NFSPlanSSD:
plans = p.SSD
default:
return -1
}
for _, plan := range plans {
if plan.Availability == "available" && plan.Size == int(size) {
res, err := plan.PlanID.Int64()
if err != nil {
return -1
}
return res
}
}
return -1
}
// FindByPlanID プランIDから該当プランを取得
func (p NFSPlans) FindByPlanID(planID int64) (NFSPlan, *NFSPlanValue) {
for _, plan := range p.SSD {
id, err := plan.PlanID.Int64()
if err != nil {
continue
}
if id == planID {
return NFSPlanSSD, &plan
}
}
for _, plan := range p.HDD {
id, err := plan.PlanID.Int64()
if err != nil {
continue
}
if id == planID {
return NFSPlanHDD, &plan
}
}
return NFSPlan(-1), nil
}
// NFSPlanValue NFSプラン
type NFSPlanValue struct {
Size int `json:"size"`
Availability string `json:"availability"`
PlanID json.Number `json:"planId"`
}

View file

@ -27,6 +27,10 @@ const (
SophosUTM
// FreeBSD OS種別:FreeBSD
FreeBSD
// Netwiser OS種別: Netwiser Virtual Edition
Netwiser
// OPNsense OS種別: OPNsense
OPNsense
// Windows2012 OS種別:Windows Server 2012 R2 Datacenter Edition
Windows2012
// Windows2012RDS OS種別:Windows Server 2012 R2 for RDS
@ -41,10 +45,16 @@ const (
Windows2016RDSOffice
// Windows2016SQLServerWeb OS種別:Windows Server 2016 SQLServer(Web)
Windows2016SQLServerWeb
// Windows2016SQLServerStandard OS種別:Windows Server 2016 SQLServer(Standard)
// Windows2016SQLServerStandard OS種別:Windows Server 2016 SQLServer 2016(Standard)
Windows2016SQLServerStandard
// Windows2016SQLServer2017Standard OS種別:Windows Server 2016 SQLServer 2017(Standard)
Windows2016SQLServer2017Standard
// Windows2016SQLServerStandardAll OS種別:Windows Server 2016 SQLServer(Standard) + RDS + Office
Windows2016SQLServerStandardAll
// Windows2016SQLServer2017StandardAll OS種別:Windows Server 2016 SQLServer 2017(Standard) + RDS + Office
Windows2016SQLServer2017StandardAll
// Windows2019 OS種別:Windows Server 2019 Datacenter Edition
Windows2019
// Custom OS種別:カスタム
Custom
)
@ -53,9 +63,12 @@ const (
var OSTypeShortNames = []string{
"centos", "centos6", "ubuntu", "debian", "vyos", "coreos",
"rancheros", "kusanagi", "sophos-utm", "freebsd",
"netwiser", "opnsense",
"windows2012", "windows2012-rds", "windows2012-rds-office",
"windows2016", "windows2016-rds", "windows2016-rds-office",
"windows2016-sql-web", "windows2016-sql-standard", "windows2016-sql-standard-all",
"windows2016-sql2017-standard", "windows2016-sql2017-standard-all",
"windows2019",
}
// IsWindows Windowsか
@ -63,7 +76,9 @@ func (o ArchiveOSTypes) IsWindows() bool {
switch o {
case Windows2012, Windows2012RDS, Windows2012RDSOffice,
Windows2016, Windows2016RDS, Windows2016RDSOffice,
Windows2016SQLServerWeb, Windows2016SQLServerStandard, Windows2016SQLServerStandardAll:
Windows2016SQLServerWeb, Windows2016SQLServerStandard, Windows2016SQLServerStandardAll,
Windows2016SQLServer2017Standard, Windows2016SQLServer2017StandardAll,
Windows2019:
return true
default:
return false
@ -103,6 +118,10 @@ func StrToOSType(osType string) ArchiveOSTypes {
return SophosUTM
case "freebsd":
return FreeBSD
case "netwiser":
return Netwiser
case "opnsense":
return OPNsense
case "windows2012":
return Windows2012
case "windows2012-rds":
@ -119,8 +138,14 @@ func StrToOSType(osType string) ArchiveOSTypes {
return Windows2016SQLServerWeb
case "windows2016-sql-standard":
return Windows2016SQLServerStandard
case "windows2016-sql2017-standard":
return Windows2016SQLServer2017Standard
case "windows2016-sql-standard-all":
return Windows2016SQLServerStandardAll
case "windows2016-sql2017-standard-all":
return Windows2016SQLServer2017StandardAll
case "windows2019":
return Windows2019
default:
return Custom
}

View file

@ -4,9 +4,9 @@ package ostype
import "strconv"
const _ArchiveOSTypes_name = "CentOSCentOS6UbuntuDebianVyOSCoreOSRancherOSKusanagiSophosUTMFreeBSDWindows2012Windows2012RDSWindows2012RDSOfficeWindows2016Windows2016RDSWindows2016RDSOfficeWindows2016SQLServerWebWindows2016SQLServerStandardWindows2016SQLServerStandardAllCustom"
const _ArchiveOSTypes_name = "CentOSCentOS6UbuntuDebianVyOSCoreOSRancherOSKusanagiSophosUTMFreeBSDNetwiserOPNsenseWindows2012Windows2012RDSWindows2012RDSOfficeWindows2016Windows2016RDSWindows2016RDSOfficeWindows2016SQLServerWebWindows2016SQLServerStandardWindows2016SQLServer2017StandardWindows2016SQLServerStandardAllWindows2016SQLServer2017StandardAllWindows2019Custom"
var _ArchiveOSTypes_index = [...]uint8{0, 6, 13, 19, 25, 29, 35, 44, 52, 61, 68, 79, 93, 113, 124, 138, 158, 181, 209, 240, 246}
var _ArchiveOSTypes_index = [...]uint16{0, 6, 13, 19, 25, 29, 35, 44, 52, 61, 68, 76, 84, 95, 109, 129, 140, 154, 174, 197, 225, 257, 288, 323, 334, 340}
func (i ArchiveOSTypes) String() string {
if i < 0 || i >= ArchiveOSTypes(len(_ArchiveOSTypes_index)-1) {

View file

@ -2,11 +2,12 @@ package sacloud
// ProductServer サーバープラン
type ProductServer struct {
*Resource // ID
propName // 名称
propDescription // 説明
propAvailability // 有功状態
propCPU // CPUコア数
propMemoryMB // メモリサイズ(MB単位)
propServiceClass // サービスクラス
*Resource // ID
propName // 名称
propDescription // 説明
propAvailability // 有功状態
propCPU // CPUコア数
propMemoryMB // メモリサイズ(MB単位)
propServiceClass // サービスクラス
Generation PlanGenerations `json:",omitempty"` // 世代
}

View file

@ -17,3 +17,8 @@ func (p *propMemoryMB) GetMemoryGB() int {
}
return p.MemoryMB / 1024
}
// SetMemoryGB サイズ(GB単位) 設定
func (p *propMemoryMB) SetMemoryGB(memoryGB int) {
p.MemoryMB = memoryGB * 1024
}

View file

@ -23,6 +23,15 @@ func (p *propServerPlan) SetServerPlanByID(planID string) {
p.ServerPlan.Resource = NewResourceByStringID(planID)
}
// SetServerPlanByValue サーバープラン設定(値指定)
func (p *propServerPlan) SetServerPlanByValue(cpu int, memoryGB int, gen PlanGenerations) {
plan := &ProductServer{}
plan.CPU = cpu
plan.SetMemoryGB(memoryGB)
plan.Generation = gen
p.ServerPlan = plan
}
// GetCPU CPUコア数 取得
func (p *propServerPlan) GetCPU() int {
if p.ServerPlan == nil {
@ -49,3 +58,7 @@ func (p *propServerPlan) GetMemoryGB() int {
return p.ServerPlan.GetMemoryGB()
}
func (p *propServerPlan) SetMemoryGB(memoryGB int) {
p.ServerPlan.SetMemoryGB(memoryGB)
}

View file

@ -0,0 +1,16 @@
package sacloud
// propWaitDiskMigration ディスク作成待ちフラグ内包型
type propWaitDiskMigration struct {
WaitDiskMigration bool `json:",omitempty"`
}
// GetWaitDiskMigration ディスク作成待ちフラグ 取得
func (p *propWaitDiskMigration) GetWaitDiskMigration() bool {
return p.WaitDiskMigration
}
// SetWaitDiskMigration ディスク作成待ちフラグ 設定
func (p *propWaitDiskMigration) SetWaitDiskMigration(f bool) {
p.WaitDiskMigration = f
}

517
vendor/github.com/sacloud/libsacloud/sacloud/proxylb.go generated vendored Normal file
View file

@ -0,0 +1,517 @@
package sacloud
import (
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"strconv"
"strings"
"time"
)
// ProxyLB ProxyLB(CommonServiceItem)
type ProxyLB struct {
*Resource // ID
propName // 名称
propDescription // 説明
propServiceClass // サービスクラス
propIcon // アイコン
propTags // タグ
propCreatedAt // 作成日時
propModifiedAt // 変更日時
propAvailability // 有効状態
Status *ProxyLBStatus `json:",omitempty"` // ステータス
Provider ProxyLBProvider `json:",omitempty"` // プロバイダ
Settings ProxyLBSettings `json:",omitempty"` // ProxyLB設定
}
// ProxyLBSettings ProxyLB設定
type ProxyLBSettings struct {
ProxyLB ProxyLBSetting `json:",omitempty"` // ProxyLB ProxyLBエントリー
}
// ProxyLBStatus ProxyLBステータス
type ProxyLBStatus struct {
FQDN string `json:",omitempty"` // 割り当てられたFQDN(site-*******.proxylb?.sakura.ne.jp) UseVIPFailoverがtrueの場合のみ有効
VirtualIPAddress string `json:",omitempty"` // 割り当てられたVIP UseVIPFailoverがfalseの場合のみ有効
ProxyNetworks []string `json:",omitempty"` // プロキシ元ネットワークアドレス(CIDR)
UseVIPFailover bool // VIPフェイルオーバ
}
// ProxyLBProvider プロバイダ
type ProxyLBProvider struct {
Class string `json:",omitempty"` // クラス
}
// CreateNewProxyLB ProxyLB作成
func CreateNewProxyLB(name string) *ProxyLB {
return &ProxyLB{
Resource: &Resource{},
propName: propName{Name: name},
Provider: ProxyLBProvider{
Class: "proxylb",
},
Settings: ProxyLBSettings{
ProxyLB: ProxyLBSetting{
HealthCheck: defaultProxyLBHealthCheck,
SorryServer: ProxyLBSorryServer{},
Servers: []ProxyLBServer{},
},
},
}
}
// ProxyLBPlan ProxyLBプラン
type ProxyLBPlan int
var (
// ProxyLBPlan1000 1,000cpsプラン
ProxyLBPlan1000 = ProxyLBPlan(1000)
// ProxyLBPlan5000 5,000cpsプラン
ProxyLBPlan5000 = ProxyLBPlan(5000)
// ProxyLBPlan10000 10,000cpsプラン
ProxyLBPlan10000 = ProxyLBPlan(10000)
// ProxyLBPlan50000 50,000cpsプラン
ProxyLBPlan50000 = ProxyLBPlan(50000)
// ProxyLBPlan100000 100,000cpsプラン
ProxyLBPlan100000 = ProxyLBPlan(100000)
)
// AllowProxyLBPlans 有効なプランIDリスト
var AllowProxyLBPlans = []int{
int(ProxyLBPlan1000),
int(ProxyLBPlan5000),
int(ProxyLBPlan10000),
int(ProxyLBPlan50000),
int(ProxyLBPlan100000),
}
// GetPlan プラン取得(デフォルト: 1000cps)
func (p *ProxyLB) GetPlan() ProxyLBPlan {
classes := strings.Split(p.ServiceClass, "/")
class, err := strconv.Atoi(classes[len(classes)-1])
if err != nil {
return ProxyLBPlan1000
}
return ProxyLBPlan(class)
}
// SetPlan プラン指定
func (p *ProxyLB) SetPlan(plan ProxyLBPlan) {
p.ServiceClass = fmt.Sprintf("cloud/proxylb/plain/%d", plan)
}
// SetHTTPHealthCheck HTTPヘルスチェック 設定
func (p *ProxyLB) SetHTTPHealthCheck(hostHeader, path string, delayLoop int) {
if delayLoop <= 0 {
delayLoop = 10
}
p.Settings.ProxyLB.HealthCheck.Protocol = "http"
p.Settings.ProxyLB.HealthCheck.Host = hostHeader
p.Settings.ProxyLB.HealthCheck.Path = path
p.Settings.ProxyLB.HealthCheck.DelayLoop = delayLoop
}
// SetTCPHealthCheck TCPヘルスチェック 設定
func (p *ProxyLB) SetTCPHealthCheck(delayLoop int) {
if delayLoop <= 0 {
delayLoop = 10
}
p.Settings.ProxyLB.HealthCheck.Protocol = "tcp"
p.Settings.ProxyLB.HealthCheck.Host = ""
p.Settings.ProxyLB.HealthCheck.Path = ""
p.Settings.ProxyLB.HealthCheck.DelayLoop = delayLoop
}
// SetSorryServer ソーリーサーバ 設定
func (p *ProxyLB) SetSorryServer(ipaddress string, port int) {
var pt *int
if port > 0 {
pt = &port
}
p.Settings.ProxyLB.SorryServer = ProxyLBSorryServer{
IPAddress: ipaddress,
Port: pt,
}
}
// ClearSorryServer ソーリーサーバ クリア
func (p *ProxyLB) ClearSorryServer() {
p.SetSorryServer("", 0)
}
// HasProxyLBServer ProxyLB配下にサーバーを保持しているか判定
func (p *ProxyLB) HasProxyLBServer() bool {
return len(p.Settings.ProxyLB.Servers) > 0
}
// ClearProxyLBServer ProxyLB配下のサーバーをクリア
func (p *ProxyLB) ClearProxyLBServer() {
p.Settings.ProxyLB.Servers = []ProxyLBServer{}
}
// AddBindPort バインドポート追加
func (p *ProxyLB) AddBindPort(mode string, port int) {
p.Settings.ProxyLB.AddBindPort(mode, port)
}
// DeleteBindPort バインドポート削除
func (p *ProxyLB) DeleteBindPort(mode string, port int) {
p.Settings.ProxyLB.DeleteBindPort(mode, port)
}
// ClearBindPorts バインドポート クリア
func (p *ProxyLB) ClearBindPorts() {
p.Settings.ProxyLB.BindPorts = []*ProxyLBBindPorts{}
}
// AddServer ProxyLB配下のサーバーを追加
func (p *ProxyLB) AddServer(ip string, port int, enabled bool) {
p.Settings.ProxyLB.AddServer(ip, port, enabled)
}
// DeleteServer ProxyLB配下のサーバーを削除
func (p *ProxyLB) DeleteServer(ip string, port int) {
p.Settings.ProxyLB.DeleteServer(ip, port)
}
// ProxyLBSetting ProxyLBセッティング
type ProxyLBSetting struct {
HealthCheck ProxyLBHealthCheck `json:",omitempty"` // ヘルスチェック
SorryServer ProxyLBSorryServer `json:",omitempty"` // ソーリーサーバー
BindPorts []*ProxyLBBindPorts `json:",omitempty"` // プロキシ方式(プロトコル&ポート)
Servers []ProxyLBServer `json:",omitempty"` // サーバー
}
// ProxyLBSorryServer ソーリーサーバ
type ProxyLBSorryServer struct {
IPAddress string // IPアドレス
Port *int // ポート
}
// AddBindPort バインドポート追加
func (s *ProxyLBSetting) AddBindPort(mode string, port int) {
var isExist bool
for i := range s.BindPorts {
if s.BindPorts[i].ProxyMode == mode && s.BindPorts[i].Port == port {
isExist = true
}
}
if !isExist {
s.BindPorts = append(s.BindPorts, &ProxyLBBindPorts{
ProxyMode: mode,
Port: port,
})
}
}
// DeleteBindPort バインドポート削除
func (s *ProxyLBSetting) DeleteBindPort(mode string, port int) {
var res []*ProxyLBBindPorts
for i := range s.BindPorts {
if s.BindPorts[i].ProxyMode != mode || s.BindPorts[i].Port != port {
res = append(res, s.BindPorts[i])
}
}
s.BindPorts = res
}
// AddServer ProxyLB配下のサーバーを追加
func (s *ProxyLBSetting) AddServer(ip string, port int, enabled bool) {
var record ProxyLBServer
var isExist = false
for i := range s.Servers {
if s.Servers[i].IPAddress == ip && s.Servers[i].Port == port {
isExist = true
s.Servers[i].Enabled = enabled
}
}
if !isExist {
record = ProxyLBServer{
IPAddress: ip,
Port: port,
Enabled: enabled,
}
s.Servers = append(s.Servers, record)
}
}
// DeleteServer ProxyLB配下のサーバーを削除
func (s *ProxyLBSetting) DeleteServer(ip string, port int) {
var res []ProxyLBServer
for i := range s.Servers {
if s.Servers[i].IPAddress != ip || s.Servers[i].Port != port {
res = append(res, s.Servers[i])
}
}
s.Servers = res
}
// AllowProxyLBBindModes プロキシ方式
var AllowProxyLBBindModes = []string{"http", "https"}
// ProxyLBBindPorts プロキシ方式
type ProxyLBBindPorts struct {
ProxyMode string `json:",omitempty"` // モード(プロトコル)
Port int `json:",omitempty"` // ポート
}
// ProxyLBServer ProxyLB配下のサーバー
type ProxyLBServer struct {
IPAddress string `json:",omitempty"` // IPアドレス
Port int `json:",omitempty"` // ポート
Enabled bool `json:",omitempty"` // 有効/無効
}
// NewProxyLBServer ProxyLB配下のサーバ作成
func NewProxyLBServer(ipaddress string, port int) *ProxyLBServer {
return &ProxyLBServer{
IPAddress: ipaddress,
Port: port,
Enabled: true,
}
}
// AllowProxyLBHealthCheckProtocols プロキシLBで利用できるヘルスチェックプロトコル
var AllowProxyLBHealthCheckProtocols = []string{"http", "tcp"}
// ProxyLBHealthCheck ヘルスチェック
type ProxyLBHealthCheck struct {
Protocol string `json:",omitempty"` // プロトコル
Host string `json:",omitempty"` // 対象ホスト
Path string `json:",omitempty"` // HTTPの場合のリクエストパス
DelayLoop int `json:",omitempty"` // 監視間隔
}
var defaultProxyLBHealthCheck = ProxyLBHealthCheck{
Protocol: "http",
Host: "",
Path: "/",
DelayLoop: 10,
}
// ProxyLBAdditionalCerts additional certificates
type ProxyLBAdditionalCerts []*ProxyLBCertificate
// ProxyLBCertificates ProxyLBのSSL証明書
type ProxyLBCertificates struct {
ServerCertificate string // サーバ証明書
IntermediateCertificate string // 中間証明書
PrivateKey string // 秘密鍵
CertificateEndDate time.Time `json:",omitempty"` // 有効期限
CertificateCommonName string `json:",omitempty"` // CommonName
AdditionalCerts ProxyLBAdditionalCerts
}
// UnmarshalJSON UnmarshalJSON(AdditionalCertsが空の場合に空文字を返す問題への対応)
func (p *ProxyLBAdditionalCerts) UnmarshalJSON(data []byte) error {
targetData := strings.Replace(strings.Replace(string(data), " ", "", -1), "\n", "", -1)
if targetData == `` {
return nil
}
var certs []*ProxyLBCertificate
if err := json.Unmarshal(data, &certs); err != nil {
return err
}
*p = certs
return nil
}
// SetPrimaryCert PrimaryCertを設定
func (p *ProxyLBCertificates) SetPrimaryCert(cert *ProxyLBCertificate) {
p.ServerCertificate = cert.ServerCertificate
p.IntermediateCertificate = cert.IntermediateCertificate
p.PrivateKey = cert.PrivateKey
p.CertificateEndDate = cert.CertificateEndDate
p.CertificateCommonName = cert.CertificateCommonName
}
// SetPrimaryCertValue PrimaryCertを設定
func (p *ProxyLBCertificates) SetPrimaryCertValue(serverCert, intermediateCert, privateKey string) {
p.ServerCertificate = serverCert
p.IntermediateCertificate = intermediateCert
p.PrivateKey = privateKey
}
// AddAdditionalCert AdditionalCertを追加
func (p *ProxyLBCertificates) AddAdditionalCert(serverCert, intermediateCert, privateKey string) {
p.AdditionalCerts = append(p.AdditionalCerts, &ProxyLBCertificate{
ServerCertificate: serverCert,
IntermediateCertificate: intermediateCert,
PrivateKey: privateKey,
})
}
// RemoveAdditionalCertAt 指定のインデックスを持つAdditionalCertを削除
func (p *ProxyLBCertificates) RemoveAdditionalCertAt(index int) {
var certs []*ProxyLBCertificate
for i, cert := range p.AdditionalCerts {
if i != index {
certs = append(certs, cert)
}
}
p.AdditionalCerts = certs
}
// RemoveAdditionalCert 指定の内容を持つAdditionalCertを削除
func (p *ProxyLBCertificates) RemoveAdditionalCert(serverCert, intermediateCert, privateKey string) {
var certs []*ProxyLBCertificate
for _, cert := range p.AdditionalCerts {
if !(cert.ServerCertificate == serverCert && cert.IntermediateCertificate == intermediateCert && cert.PrivateKey == privateKey) {
certs = append(certs, cert)
}
}
p.AdditionalCerts = certs
}
// RemoveAdditionalCerts AdditionalCertsを全て削除
func (p *ProxyLBCertificates) RemoveAdditionalCerts() {
p.AdditionalCerts = []*ProxyLBCertificate{}
}
// UnmarshalJSON UnmarshalJSON(CertificateEndDateのtime.TimeへのUnmarshal対応)
func (p *ProxyLBCertificates) UnmarshalJSON(data []byte) error {
var tmp map[string]interface{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
p.ServerCertificate = tmp["ServerCertificate"].(string)
p.IntermediateCertificate = tmp["IntermediateCertificate"].(string)
p.PrivateKey = tmp["PrivateKey"].(string)
p.CertificateCommonName = tmp["CertificateCommonName"].(string)
endDate := tmp["CertificateEndDate"].(string)
if endDate != "" {
date, err := time.Parse("Jan _2 15:04:05 2006 MST", endDate)
if err != nil {
return err
}
p.CertificateEndDate = date
}
if _, ok := tmp["AdditionalCerts"].(string); !ok {
rawCerts, err := json.Marshal(tmp["AdditionalCerts"])
if err != nil {
return err
}
var additionalCerts ProxyLBAdditionalCerts
if err := json.Unmarshal(rawCerts, &additionalCerts); err != nil {
return err
}
p.AdditionalCerts = additionalCerts
}
return nil
}
// ParseServerCertificate サーバ証明書のパース
func (p *ProxyLBCertificates) ParseServerCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.ServerCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
// ParseIntermediateCertificate 中間証明書のパース
func (p *ProxyLBCertificates) ParseIntermediateCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.IntermediateCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
func (p *ProxyLBCertificates) parseCertificate(certPEM string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(certPEM))
if block != nil {
return x509.ParseCertificate(block.Bytes)
}
return nil, fmt.Errorf("can't decode certificate")
}
// ProxyLBCertificate ProxyLBのSSL証明書詳細
type ProxyLBCertificate struct {
ServerCertificate string // サーバ証明書
IntermediateCertificate string // 中間証明書
PrivateKey string // 秘密鍵
CertificateEndDate time.Time `json:",omitempty"` // 有効期限
CertificateCommonName string `json:",omitempty"` // CommonName
}
// UnmarshalJSON UnmarshalJSON(CertificateEndDateのtime.TimeへのUnmarshal対応)
func (p *ProxyLBCertificate) UnmarshalJSON(data []byte) error {
var tmp map[string]interface{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
p.ServerCertificate = tmp["ServerCertificate"].(string)
p.IntermediateCertificate = tmp["IntermediateCertificate"].(string)
p.PrivateKey = tmp["PrivateKey"].(string)
p.CertificateCommonName = tmp["CertificateCommonName"].(string)
endDate := tmp["CertificateEndDate"].(string)
if endDate != "" {
date, err := time.Parse("Jan _2 15:04:05 2006 MST", endDate)
if err != nil {
return err
}
p.CertificateEndDate = date
}
return nil
}
// ParseServerCertificate サーバ証明書のパース
func (p *ProxyLBCertificate) ParseServerCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.ServerCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
// ParseIntermediateCertificate 中間証明書のパース
func (p *ProxyLBCertificate) ParseIntermediateCertificate() (*x509.Certificate, error) {
cert, e := p.parseCertificate(p.IntermediateCertificate)
if e != nil {
return nil, e
}
return cert, nil
}
func (p *ProxyLBCertificate) parseCertificate(certPEM string) (*x509.Certificate, error) {
block, _ := pem.Decode([]byte(certPEM))
if block != nil {
return x509.ParseCertificate(block.Bytes)
}
return nil, fmt.Errorf("can't decode certificate")
}
// ProxyLBHealth ProxyLBのヘルスチェック戻り値
type ProxyLBHealth struct {
ActiveConn int // アクティブなコネクション数
CPS int // 秒あたりコネクション数
Servers []*ProxyLBHealthServer // 実サーバのステータス
CurrentVIP string // 現在のVIP
}
// ProxyLBHealthServer ProxyLBの実サーバのステータス
type ProxyLBHealthServer struct {
ActiveConn int // アクティブなコネクション数
Status string // ステータス(UP or DOWN)
IPAddress string // IPアドレス
Port string // ポート
CPS int // 秒あたりコネクション数
}

View file

@ -21,6 +21,7 @@ type Server struct {
propIcon // アイコン
propTags // タグ
propCreatedAt // 作成日時
propWaitDiskMigration // サーバ作成時のディスク作成待ち
}
// DNSServers サーバの所属するリージョンの推奨ネームサーバリスト
@ -43,10 +44,13 @@ func (s *Server) IPAddress() string {
// Gateway デフォルトゲートウェイアドレス
func (s *Server) Gateway() string {
if len(s.Interfaces) == 0 || s.Interfaces[0].Switch == nil || s.Interfaces[0].Switch.UserSubnet == nil {
if len(s.Interfaces) == 0 || s.Interfaces[0].Switch == nil {
return ""
}
return s.Interfaces[0].Switch.UserSubnet.DefaultRoute
if s.Interfaces[0].Switch.UserSubnet != nil {
return s.Interfaces[0].Switch.UserSubnet.DefaultRoute
}
return s.Interfaces[0].Switch.Subnet.DefaultRoute
}
// DefaultRoute デフォルトゲートウェイアドレス(Gatewayのエイリアス)
@ -56,10 +60,13 @@ func (s *Server) DefaultRoute() string {
// NetworkMaskLen サーバの1番目のNIC(eth0)のネットワークマスク長
func (s *Server) NetworkMaskLen() int {
if len(s.Interfaces) == 0 || s.Interfaces[0].Switch == nil || s.Interfaces[0].Switch.UserSubnet == nil {
if len(s.Interfaces) == 0 || s.Interfaces[0].Switch == nil {
return 0
}
return s.Interfaces[0].Switch.UserSubnet.NetworkMaskLen
if s.Interfaces[0].Switch.UserSubnet != nil {
return s.Interfaces[0].Switch.UserSubnet.NetworkMaskLen
}
return s.Interfaces[0].Switch.Subnet.NetworkMaskLen
}
// NetworkAddress サーバの1番目のNIC(eth0)のネットワークアドレス
@ -79,6 +86,119 @@ func (s *Server) CIDRIPAddress() string {
return ""
}
// UpstreamType 1番目(0番目)のNICの上流ネットワーク種別
func (s *Server) UpstreamType() EUpstreamNetworkType {
return s.UpstreamTypeAt(0)
}
// UpstreamTypeAt 指定インデックスのNICの上流ネットワーク種別
func (s *Server) UpstreamTypeAt(index int) EUpstreamNetworkType {
if len(s.Interfaces) <= index {
return EUpstreamNetworkUnknown
}
return s.Interfaces[index].UpstreamType()
}
// SwitchID 上流のスイッチのID
//
// NICがない、上流スイッチが見つからない、上流が共有セグメントの場合は-1を返す
func (s *Server) SwitchID() int64 {
return s.SwitchIDAt(0)
}
// SwitchIDAt 上流ネットワークのスイッチのID
//
// NICがない、上流スイッチが見つからない、上流が共有セグメントの場合は-1を返す
func (s *Server) SwitchIDAt(index int) int64 {
if len(s.Interfaces) <= index {
return -1
}
nic := s.Interfaces[index]
if nic.Switch == nil || nic.Switch.Scope == ESCopeShared {
return -1
}
return nic.Switch.ID
}
// SwitchName 上流のスイッチのID
//
// NICがない、上流スイッチが見つからない、上流が共有セグメントの場合は空文字を返す
func (s *Server) SwitchName() string {
return s.SwitchNameAt(0)
}
// SwitchNameAt 上流ネットワークのスイッチのID
//
// NICがない、上流スイッチが見つからない、上流が共有セグメントの場合は空文字を返す
func (s *Server) SwitchNameAt(index int) string {
if len(s.Interfaces) <= index {
return ""
}
nic := s.Interfaces[index]
if nic.Switch == nil || nic.Switch.Scope == ESCopeShared {
return ""
}
return nic.Switch.Name
}
// Bandwidth 上流ネットワークの帯域幅(単位:Mbps)
//
// -1: 1番目(0番目)のNICが存在しない場合 or 切断されている場合
// 0 : 制限なしの場合
// 以外: 帯域幅(Mbps)
func (s *Server) Bandwidth() int {
return s.BandwidthAt(0)
}
// BandwidthAt 上流ネットワークの帯域幅(単位:Mbps)
//
// -1: 存在しないインデックスを取得した場合 or 切断されている場合
// 0 : 制限なしの場合
// 以外: 帯域幅(Mbps)
func (s *Server) BandwidthAt(index int) int {
if len(s.Interfaces) <= index {
return -1
}
nic := s.Interfaces[index]
switch nic.UpstreamType() {
case EUpstreamNetworkNone:
return -1
case EUpstreamNetworkShared:
return 100
case EUpstreamNetworkSwitch, EUpstreamNetworkRouter:
//
// 上流ネットワークがスイッチだった場合の帯域制限
// https://manual.sakura.ad.jp/cloud/support/technical/network.html#support-network-03
//
// 専有ホストの場合は制限なし
if s.PrivateHost != nil {
return 0
}
// メモリに応じた制限
memory := s.GetMemoryGB()
switch {
case memory < 32:
return 1000
case 32 <= memory && memory < 128:
return 2000
case 128 <= memory && memory < 224:
return 5000
case 224 <= memory:
return 10000
default:
return -1
}
default:
return -1
}
}
const (
// ServerMaxInterfaceLen サーバーに接続できるNICの最大数
ServerMaxInterfaceLen = 10

View file

@ -2,10 +2,20 @@ package sacloud
import (
"encoding/json"
"strconv"
"strings"
"time"
)
const (
// SIMOperatorsKDDI KDDI
SIMOperatorsKDDI = "KDDI"
// SIMOperatorsDOCOMO Docomo
SIMOperatorsDOCOMO = "NTT DOCOMO"
// SIMOperatorsSoftBank SoftBank
SIMOperatorsSoftBank = "SoftBank"
)
// SIM SIM(CommonServiceItem)
type SIM struct {
*Resource // ID
@ -49,8 +59,8 @@ type SIMInfo struct {
// SIMTrafficBytes 当月通信量
type SIMTrafficBytes struct {
UplinkBytes int64 `json:"uplink_bytes,omitempty"`
DownlinkBytes int64 `json:"downlink_bytes,omitempty"`
UplinkBytes uint64 `json:"uplink_bytes,omitempty"`
DownlinkBytes uint64 `json:"downlink_bytes,omitempty"`
}
// UnmarshalJSON JSONアンマーシャル(配列、オブジェクトが混在するためここで対応)
@ -60,15 +70,22 @@ func (s *SIMTrafficBytes) UnmarshalJSON(data []byte) error {
return nil
}
tmp := &struct {
UplinkBytes int64 `json:"uplink_bytes,omitempty"`
DownlinkBytes int64 `json:"downlink_bytes,omitempty"`
UplinkBytes string `json:"uplink_bytes,omitempty"`
DownlinkBytes string `json:"downlink_bytes,omitempty"`
}{}
if err := json.Unmarshal(data, &tmp); err != nil {
return err
}
s.UplinkBytes = tmp.UplinkBytes
s.DownlinkBytes = tmp.DownlinkBytes
var err error
s.UplinkBytes, err = strconv.ParseUint(tmp.UplinkBytes, 10, 64)
if err != nil {
return err
}
s.DownlinkBytes, err = strconv.ParseUint(tmp.DownlinkBytes, 10, 64)
if err != nil {
return err
}
return nil
}
@ -93,6 +110,18 @@ type SIMLog struct {
IMSI string `json:"imsi,omitempty"`
}
// SIMNetworkOperatorConfig SIM通信キャリア設定
type SIMNetworkOperatorConfig struct {
Allow bool `json:"allow,omitempty"`
CountryCode string `json:"country_code,omitempty"`
Name string `json:"name,omitempty"`
}
// SIMNetworkOperatorConfigs SIM通信キャリア設定 リクエストパラメータ
type SIMNetworkOperatorConfigs struct {
NetworkOperatorConfigs []*SIMNetworkOperatorConfig `json:"network_operator_config,omitempty"`
}
// CreateNewSIM SIM作成
func CreateNewSIM(name string, iccID string, passcode string) *SIM {
return &SIM{

View file

@ -1,5 +1,7 @@
package sacloud
import "time"
// SimpleMonitor シンプル監視
type SimpleMonitor struct {
*Resource // ID
@ -47,18 +49,20 @@ type SimpleMonitorProvider struct {
// SimpleMonitorHealthCheck ヘルスチェック
type SimpleMonitorHealthCheck struct {
Protocol string `json:",omitempty"` // プロトコル
Port string `json:",omitempty"` // ポート
Path string `json:",omitempty"` // HTTP/HTTPS監視の場合のリクエストパス
Status string `json:",omitempty"` // HTTP/HTTPS監視の場合の期待ステータスコード
SNI string `json:",omitempty"` // HTTPS監視時のSNI有効/無効
Host string `json:",omitempty"` // 対象ホスト(IP or FQDN)
QName string `json:",omitempty"` // DNS監視の場合の問い合わせFQDN
ExpectedData string `json:",omitempty"` // 期待値
Community string `json:",omitempty"` // SNMP監視の場合のコミュニティ名
SNMPVersion string `json:",omitempty"` // SNMP監視 SNMPバージョン
OID string `json:",omitempty"` // SNMP監視 OID
RemainingDays int `json:",omitempty"` // SSL証明書 有効残日数
Protocol string `json:",omitempty"` // プロトコル
Port string `json:",omitempty"` // ポート
Path string `json:",omitempty"` // HTTP/HTTPS監視の場合のリクエストパス
Status string `json:",omitempty"` // HTTP/HTTPS監視の場合の期待ステータスコード
SNI string `json:",omitempty"` // HTTPS監視時のSNI有効/無効
Host string `json:",omitempty"` // 対象ホスト(IP or FQDN)
BasicAuthUsername string `json:",omitempty"` // HTTP/HTTPS監視の場合のBASIC認証 ユーザー名
BasicAuthPassword string `json:",omitempty"` // HTTP/HTTPS監視の場合のBASIC認証 パスワード
QName string `json:",omitempty"` // DNS監視の場合の問い合わせFQDN
ExpectedData string `json:",omitempty"` // 期待値
Community string `json:",omitempty"` // SNMP監視の場合のコミュニティ名
SNMPVersion string `json:",omitempty"` // SNMP監視 SNMPバージョン
OID string `json:",omitempty"` // SNMP監視 OID
RemainingDays int `json:",omitempty"` // SSL証明書 有効残日数
}
// SimpleMonitorNotify シンプル監視通知
@ -68,6 +72,33 @@ type SimpleMonitorNotify struct {
IncomingWebhooksURL string `json:",omitempty"` // Slack通知の場合のWebhook URL
}
// ESimpleMonitorHealth シンプル監視ステータス
type ESimpleMonitorHealth string
var (
// EHealthUp Up
EHealthUp = ESimpleMonitorHealth("UP")
// EHealthDown Down
EHealthDown = ESimpleMonitorHealth("DOWN")
)
// IsUp アップ
func (e ESimpleMonitorHealth) IsUp() bool {
return e == EHealthUp
}
// IsDown ダウン
func (e ESimpleMonitorHealth) IsDown() bool {
return e == EHealthDown
}
// SimpleMonitorHealthCheckStatus シンプル監視ステータス
type SimpleMonitorHealthCheckStatus struct {
LastCheckedAt time.Time
LastHealthChangedAt time.Time
Health ESimpleMonitorHealth
}
// CreateNewSimpleMonitor シンプル監視作成
func CreateNewSimpleMonitor(target string) *SimpleMonitor {
return &SimpleMonitor{
@ -142,29 +173,33 @@ func (s *SimpleMonitor) SetHealthCheckTCP(port string) {
}
// SetHealthCheckHTTP HTTPでのヘルスチェック設定
func (s *SimpleMonitor) SetHealthCheckHTTP(port string, path string, status string, host string) {
func (s *SimpleMonitor) SetHealthCheckHTTP(port string, path string, status string, host string, user, pass string) {
s.Settings.SimpleMonitor.HealthCheck = &SimpleMonitorHealthCheck{
Protocol: "http",
Port: port,
Path: path,
Status: status,
Host: host,
Protocol: "http",
Port: port,
Path: path,
Status: status,
Host: host,
BasicAuthUsername: user,
BasicAuthPassword: pass,
}
}
// SetHealthCheckHTTPS HTTPSでのヘルスチェック設定
func (s *SimpleMonitor) SetHealthCheckHTTPS(port string, path string, status string, host string, sni bool) {
func (s *SimpleMonitor) SetHealthCheckHTTPS(port string, path string, status string, host string, sni bool, user, pass string) {
strSNI := "False"
if sni {
strSNI = "True"
}
s.Settings.SimpleMonitor.HealthCheck = &SimpleMonitorHealthCheck{
Protocol: "https",
Port: port,
Path: path,
Status: status,
Host: host,
SNI: strSNI,
Protocol: "https",
Port: port,
Path: path,
Status: status,
Host: host,
SNI: strSNI,
BasicAuthUsername: user,
BasicAuthPassword: pass,
}
}

View file

@ -15,6 +15,7 @@ type Switch struct {
propIcon // アイコン
propTags // タグ
propCreatedAt // 作成日時
propZone // ゾーン
ServerCount int `json:",omitempty"` // 接続サーバー数
ApplianceCount int `json:",omitempty"` // 接続アプライアンス数

View file

@ -236,3 +236,134 @@ func (v *VPCRouter) FindBelongsInterface(ip net.IP) (int, *VPCRouterInterface) {
}
return -1, nil
}
// IPAddress1 1番目(0番目)のNICのIPアドレス1
func (v *VPCRouter) IPAddress1() string {
return v.IPAddress1At(0)
}
// IPAddress1At 指定インデックスのNICのIPアドレス1
func (v *VPCRouter) IPAddress1At(index int) string {
if len(v.Interfaces) <= index {
return ""
}
if index == 0 {
if v.IsStandardPlan() {
return v.Interfaces[0].IPAddress
}
if !v.HasInterfaces() {
return ""
}
if len(v.Settings.Router.Interfaces[0].IPAddress) < 1 {
return ""
}
return v.Settings.Router.Interfaces[0].IPAddress[0]
}
nic := v.Settings.Router.Interfaces[index]
if len(nic.IPAddress) < 1 {
return ""
}
return nic.IPAddress[0]
}
// IPAddress2 1番目(0番目)のNICのIPアドレス2
func (v *VPCRouter) IPAddress2() string {
return v.IPAddress2At(0)
}
// IPAddress2At 指定インデックスのNICのIPアドレス2
func (v *VPCRouter) IPAddress2At(index int) string {
if v.IsStandardPlan() {
return ""
}
if len(v.Interfaces) <= index {
return ""
}
if index == 0 {
if !v.HasInterfaces() {
return ""
}
if len(v.Settings.Router.Interfaces[0].IPAddress) < 2 {
return ""
}
return v.Settings.Router.Interfaces[0].IPAddress[1]
}
nic := v.Settings.Router.Interfaces[index]
if len(nic.IPAddress) < 2 {
return ""
}
return nic.IPAddress[1]
}
// VirtualIPAddress 1番目(0番目)のNICのVIP
func (v *VPCRouter) VirtualIPAddress() string {
return v.VirtualIPAddressAt(0)
}
// VirtualIPAddressAt 指定インデックスのNICのVIP
func (v *VPCRouter) VirtualIPAddressAt(index int) string {
if v.IsStandardPlan() {
return ""
}
if len(v.Interfaces) <= index {
return ""
}
return v.Settings.Router.Interfaces[0].VirtualIPAddress
}
// NetworkMaskLen 1番目(0番目)のNICのネットワークマスク長
func (v *VPCRouter) NetworkMaskLen() int {
return v.NetworkMaskLenAt(0)
}
// NetworkMaskLenAt 指定インデックスのNICのネットワークマスク長
func (v *VPCRouter) NetworkMaskLenAt(index int) int {
if !v.HasInterfaces() {
return -1
}
if len(v.Interfaces) <= index {
return -1
}
if index == 0 {
return v.Interfaces[0].Switch.Subnet.NetworkMaskLen
}
return v.Settings.Router.Interfaces[index].NetworkMaskLen
}
// Zone スイッチから現在のゾーン名を取得
//
// Note: 共有セグメント接続時は取得不能
func (v *VPCRouter) Zone() string {
if v.Switch != nil {
return v.Switch.GetZoneName()
}
if len(v.Interfaces) > 0 && v.Interfaces[0].Switch != nil {
return v.Interfaces[0].Switch.GetZoneName()
}
return ""
}
// VRID VRIDを取得
//
// スタンダードプラン、またはVRIDの参照に失敗した場合は-1を返す
func (v *VPCRouter) VRID() int {
if v.IsStandardPlan() {
return -1
}
if !v.HasSetting() || v.Settings.Router.VRID == nil {
return -1
}
return *v.Settings.Router.VRID
}

View file

@ -22,6 +22,7 @@ type VPCRouterSetting struct {
RemoteAccessUsers *VPCRouterRemoteAccessUsers `json:",omitempty"` // リモートアクセスユーザー設定
SiteToSiteIPsecVPN *VPCRouterSiteToSiteIPsecVPN `json:",omitempty"` // サイト間VPN設定
StaticRoutes *VPCRouterStaticRoutes `json:",omitempty"` // スタティックルート設定
InternetConnection *VPCRouterInternetConnection `json:",omitempty"` // インターネット接続
VRID *int `json:",omitempty"` // VRID
SyslogHost string `json:",omitempty"` // syslog転送先ホスト
@ -1156,3 +1157,22 @@ func (s *VPCRouterSetting) FindStaticRoute(prefix string, nextHop string) (int,
}
return -1, nil
}
// VPCRouterInternetConnection インターネット接続
type VPCRouterInternetConnection struct {
Enabled string `json:",omitempty"` // 有効/無効
}
// SetInternetConnection インターネット接続 有効/無効 設定
func (s *VPCRouterSetting) SetInternetConnection(enabled bool) {
if s.InternetConnection == nil {
s.InternetConnection = &VPCRouterInternetConnection{
Enabled: "True",
}
}
if enabled {
s.InternetConnection.Enabled = "True"
} else {
s.InternetConnection.Enabled = "False"
}
}

View file

@ -5,4 +5,23 @@ type VPCRouterStatus struct {
FirewallReceiveLogs []string
FirewallSendLogs []string
VPNLogs []string
SessionCount int
DHCPServerLeases []struct {
IPAddress string
MACAddress string
}
L2TPIPsecServerSessions []struct {
User string
IPAddress string
TimeSec int
}
PPTPServerSessions []struct {
User string
IPAddress string
TimeSec int
}
SiteToSiteIPsecVPNPeers []struct {
Status string
Peer string
}
}

View file

@ -0,0 +1,43 @@
package mutexkv
import (
"sync"
)
// MutexKV is a simple key/value store for arbitrary mutexes. It can be used to
// serialize changes across arbitrary collaborators that share knowledge of the
// keys they must serialize on.
type MutexKV struct {
lock sync.Mutex
store map[string]*sync.Mutex
}
// Lock the mutex for the given key. Caller is responsible for calling Unlock
// for the same key
func (m *MutexKV) Lock(key string) {
m.get(key).Lock()
}
// Unlock the mutex for the given key. Caller must have called Lock for the same key first
func (m *MutexKV) Unlock(key string) {
m.get(key).Unlock()
}
// Returns a mutex for the given key, no guarantee of its lock status
func (m *MutexKV) get(key string) *sync.Mutex {
m.lock.Lock()
defer m.lock.Unlock()
mutex, ok := m.store[key]
if !ok {
mutex = &sync.Mutex{}
m.store[key] = mutex
}
return mutex
}
// NewMutexKV Returns a properly initalized MutexKV
func NewMutexKV() *MutexKV {
return &MutexKV{
store: make(map[string]*sync.Mutex),
}
}