github.com/sacloud/iaas-api-go@v1.12.0/naked/database.go (about)

     1  // Copyright 2022-2023 The sacloud/iaas-api-go Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package naked
    16  
    17  import (
    18  	"encoding/json"
    19  	"strconv"
    20  	"strings"
    21  	"time"
    22  
    23  	"github.com/sacloud/iaas-api-go/types"
    24  )
    25  
    26  // Database データベース
    27  type Database struct {
    28  	ID           types.ID            `json:",omitempty" yaml:"id,omitempty" structs:",omitempty"`
    29  	Name         string              `json:",omitempty" yaml:"name,omitempty" structs:",omitempty"`
    30  	Description  string              `yaml:"description"`
    31  	Tags         types.Tags          `yaml:"tags"`
    32  	Icon         *Icon               `json:",omitempty" yaml:"icon,omitempty" structs:",omitempty"`
    33  	CreatedAt    *time.Time          `json:",omitempty" yaml:"created_at,omitempty" structs:",omitempty"`
    34  	ModifiedAt   *time.Time          `json:",omitempty" yaml:"modified_at,omitempty" structs:",omitempty"`
    35  	Availability types.EAvailability `json:",omitempty" yaml:"availability,omitempty" structs:",omitempty"`
    36  	Class        string              `json:",omitempty" yaml:"class,omitempty" structs:",omitempty"`
    37  	ServiceClass string              `json:",omitempty" yaml:"service_class,omitempty" structs:",omitempty"`
    38  	Plan         *AppliancePlan      `json:",omitempty" yaml:"plan,omitempty" structs:",omitempty"`
    39  	Instance     *Instance           `json:",omitempty" yaml:"instance,omitempty" structs:",omitempty"`
    40  	Interfaces   []*Interface        `json:",omitempty" yaml:"interfaces,omitempty" structs:",omitempty"`
    41  	Switch       *Switch             `json:",omitempty" yaml:"switch,omitempty" structs:",omitempty"`
    42  	Settings     *DatabaseSettings   `json:",omitempty" yaml:"settings,omitempty" structs:",omitempty"`
    43  	SettingsHash string              `json:",omitempty" yaml:"settings_hash,omitempty" structs:",omitempty"`
    44  	Remark       *ApplianceRemark    `json:",omitempty" yaml:"remark,omitempty" structs:",omitempty"`
    45  
    46  	Generation interface{}
    47  }
    48  
    49  // DatabaseSettingsUpdate データベース
    50  type DatabaseSettingsUpdate struct {
    51  	Settings     *DatabaseSettings `json:",omitempty" yaml:"settings,omitempty" structs:",omitempty"`
    52  	SettingsHash string            `json:",omitempty" yaml:"settings_hash,omitempty" structs:",omitempty"`
    53  }
    54  
    55  // DatabaseSettings データベース設定
    56  type DatabaseSettings struct {
    57  	DBConf *DatabaseSetting `json:",omitempty" yaml:"db_conf,omitempty" structs:",omitempty"`
    58  }
    59  
    60  // DatabaseSetting データベース設定
    61  type DatabaseSetting struct {
    62  	Common      *DatabaseSettingCommon      `json:",omitempty" yaml:"common,omitempty" structs:",omitempty"`
    63  	Backup      *DatabaseSettingBackup      `json:",omitempty" yaml:"backup,omitempty" structs:",omitempty"`
    64  	Replication *DatabaseSettingReplication `json:",omitempty" yaml:"replication,omitempty" structs:",omitempty"`
    65  	Interfaces  DatabaseSettingInterfaces   `json:",omitempty" yaml:"common,omitempty" structs:",omitempty"`
    66  }
    67  
    68  // DatabaseSettingCommon データベース設定 汎用項目設定
    69  type DatabaseSettingCommon struct {
    70  	// WebUI WebUIの有効/無効、またはアクセスするためのアドレス
    71  	//
    72  	// [HACK] Create時はbool型、Read/Update時は文字列(FQDN or IP)となる。
    73  	// また、無効にするにはJSONで要素自体を指定しないことで行う。
    74  	WebUI           interface{}                   `yaml:"web_ui"`
    75  	ServicePort     int                           `json:",omitempty" yaml:"service_port,omitempty" structs:",omitempty"`
    76  	SourceNetwork   DatabaseSettingSourceNetworks `yaml:"source_network"`
    77  	DefaultUser     string                        `json:",omitempty" yaml:"default_user,omitempty" structs:",omitempty"`
    78  	UserPassword    string                        `json:",omitempty" yaml:"user_password,omitempty" structs:",omitempty"`
    79  	ReplicaUser     string                        `json:",omitempty" yaml:"replica_user,omitempty" structs:",omitempty"`
    80  	ReplicaPassword string                        `json:",omitempty" yaml:"replica_password,omitempty" structs:",omitempty"`
    81  }
    82  
    83  // DatabaseSettingSourceNetworks データベースへのアクセスを許可するCIDRリスト
    84  //
    85  // Note: すべての接続先を許可する場合は"0.0.0.0/0"を指定する。
    86  // この処理はMarshalJSON時にDatabaseSettingSourceNetwork側で行われるため、
    87  // APIクライアント側は許可したいCIDRブロックのリストを指定する。
    88  // libsacloudではすべての接続を拒否する設定はサポートしない。
    89  type DatabaseSettingSourceNetworks []string
    90  
    91  // MarshalJSON すべての接続先を許可する場合は"0.0.0.0/0"を指定するための対応
    92  func (d DatabaseSettingSourceNetworks) MarshalJSON() ([]byte, error) {
    93  	type alias DatabaseSettingSourceNetworks
    94  	dest := alias(d)
    95  
    96  	if len(dest) == 0 {
    97  		dest = append(dest, "0.0.0.0/0")
    98  	}
    99  
   100  	return json.Marshal(dest)
   101  }
   102  
   103  func (d *DatabaseSettingSourceNetworks) UnmarshalJSON(b []byte) error {
   104  	if string(b) == `""` || string(b) == "" {
   105  		return nil
   106  	}
   107  	type alias DatabaseSettingSourceNetworks
   108  
   109  	var a alias
   110  	if err := json.Unmarshal(b, &a); err != nil {
   111  		return err
   112  	}
   113  	if len(a) == 1 && a[0] == "0.0.0.0/0" {
   114  		return nil
   115  	}
   116  	*d = DatabaseSettingSourceNetworks(a)
   117  	return nil
   118  }
   119  
   120  // DatabaseSettingBackup データベース設定 バックアップ設定
   121  type DatabaseSettingBackup struct {
   122  	Rotate    int                   `json:",omitempty" yaml:"rotate,omitempty" structs:",omitempty"`
   123  	Time      string                `json:",omitempty" yaml:"time,omitempty" structs:",omitempty"`
   124  	DayOfWeek []types.EDayOfTheWeek `json:",omitempty" yaml:"day_of_week,omitempty" structs:",omitempty"`
   125  	Connect   string                // 冗長化オプション有効時のバックアップ先NFS 例:`nfs://192.168.0.41/export`
   126  }
   127  
   128  // UnmarshalJSON 配列/オブジェクトが混在することへの対応
   129  func (d *DatabaseSettingBackup) UnmarshalJSON(b []byte) error {
   130  	if string(b) == "[]" {
   131  		return nil
   132  	}
   133  	type alias DatabaseSettingBackup
   134  
   135  	var a alias
   136  	if err := json.Unmarshal(b, &a); err != nil {
   137  		return err
   138  	}
   139  	*d = DatabaseSettingBackup(a)
   140  	return nil
   141  }
   142  
   143  // DatabaseSettingReplication レプリケーション設定
   144  type DatabaseSettingReplication struct {
   145  	Model     types.EDatabaseReplicationModel `json:",omitempty" yaml:"model,omitempty" structs:",omitempty"`
   146  	Appliance *struct {
   147  		ID types.ID
   148  	} `json:",omitempty" yaml:"appliance,omitempty" structs:",omitempty"`
   149  	IPAddress string `json:",omitempty" yaml:"ip_address,omitempty" structs:",omitempty"`
   150  	Port      int    `json:",omitempty" yaml:"port,omitempty" structs:",omitempty"`
   151  	User      string `json:",omitempty" yaml:"user,omitempty" structs:",omitempty"`
   152  	Password  string `json:",omitempty" yaml:"password,omitempty" structs:",omitempty"`
   153  }
   154  
   155  type DatabaseSettingInterfaces []*DatabaseSettingInterface
   156  
   157  type DatabaseSettingInterface struct {
   158  	VirtualIPAddress string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   159  	// Index 仮想フィールド、VPCルータなどでInterfaces(実体は[]*Interface)を扱う場合にUnmarshalJSONの中で設定される
   160  	//
   161  	// Findした際のAPIからの応答にも同名のフィールドが含まれるが無関係。
   162  	Index int `json:"-"`
   163  }
   164  
   165  // UnmarshalJSON 配列中にnullが返ってくる(VPCルータなど)への対応
   166  //
   167  // Note: この実装は要素として`[]`が来た場合にゼロ値として返している。
   168  //
   169  //	クライアント側では必要に応じてnil判定ではなくゼロ値である事の判定を行う。
   170  func (i *DatabaseSettingInterfaces) UnmarshalJSON(b []byte) error {
   171  	type alias DatabaseSettingInterfaces
   172  	var a alias
   173  	if err := json.Unmarshal(b, &a); err != nil {
   174  		return err
   175  	}
   176  
   177  	var dest []*DatabaseSettingInterface
   178  	for i, v := range a {
   179  		if v != nil {
   180  			if v.Index == 0 {
   181  				v.Index = i
   182  			}
   183  			dest = append(dest, v)
   184  		}
   185  	}
   186  
   187  	*i = DatabaseSettingInterfaces(dest)
   188  	return nil
   189  }
   190  
   191  // MarshalJSON 配列中にnullが入る場合(VPCルータなど)への対応
   192  func (i *DatabaseSettingInterfaces) MarshalJSON() ([]byte, error) {
   193  	max := 0
   194  	for _, iface := range *i {
   195  		if max < iface.Index {
   196  			max = iface.Index
   197  		}
   198  	}
   199  
   200  	var dest = make([]*DatabaseSettingInterface, max+1)
   201  	for _, iface := range *i {
   202  		dest[iface.Index] = iface
   203  	}
   204  
   205  	return json.Marshal(dest)
   206  }
   207  
   208  // MarshalJSON JSON
   209  func (i *DatabaseSettingInterface) MarshalJSON() ([]byte, error) {
   210  	type alias struct {
   211  		IPAddress        []string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   212  		VirtualIPAddress string   `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   213  		IPAliases        []string `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   214  		NetworkMaskLen   int      `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   215  	}
   216  
   217  	tmp := alias{
   218  		VirtualIPAddress: i.VirtualIPAddress,
   219  	}
   220  	return json.Marshal(tmp)
   221  }
   222  
   223  func (i *DatabaseSettingInterface) UnmarshalJSON(b []byte) error {
   224  	if string(b) == "[]" {
   225  		return nil
   226  	}
   227  	type alias DatabaseSettingInterface
   228  
   229  	var a alias
   230  	if err := json.Unmarshal(b, &a); err != nil {
   231  		return err
   232  	}
   233  	*i = DatabaseSettingInterface(a)
   234  	return nil
   235  }
   236  
   237  // DatabaseStatusResponse Status APIの戻り値
   238  type DatabaseStatusResponse struct {
   239  	SettingsResponse *DatabaseStatus `json:",omitempty" yaml:"settings_response,omitempty" structs:",omitempty"`
   240  }
   241  
   242  // DatabaseStatus データベースのステータス
   243  type DatabaseStatus struct {
   244  	Status  types.EServerInstanceStatus `json:",omitempty" yaml:"status,omitempty" structs:",omitempty"`
   245  	IsFatal bool                        `json:"is_fatal"`
   246  	DBConf  *DatabaseStatusDBConf       `json:",omitempty" yaml:"db_conf,omitempty" structs:",omitempty"`
   247  }
   248  
   249  // DatabaseStatusDBConf データベース設定
   250  type DatabaseStatusDBConf struct {
   251  	Version  *DatabaseStatusVersion    `json:"version,omitempty" yaml:"version,omitempty" structs:",omitempty"`
   252  	Log      []*DatabaseLog            `json:"log,omitempty" yaml:"log,omitempty" structs:",omitempty"`
   253  	Backup   *DatabaseBackupInfo       `json:"backup,omitempty" yaml:"backup,omitempty" structs:",omitempty"`
   254  	MariaDB  *DatabaseStatusMariaDB    `json:",omitempty" yaml:"maria_db,omitempty" structs:",omitempty"`
   255  	Postgres *DatabaseStatusPostgreSQL `json:"postgres,omitempty" yaml:"postgres,omitempty" structs:",omitempty"`
   256  
   257  	// 以下フィールドはサポートしない
   258  	// Replication
   259  }
   260  
   261  type DatabaseStatusMariaDB struct {
   262  	Status string `json:"status,omitempty"`
   263  }
   264  type DatabaseStatusPostgreSQL struct {
   265  	Status string `json:"status,omitempty"`
   266  }
   267  
   268  // DatabaseStatusVersion データベース設定バージョン情報
   269  type DatabaseStatusVersion struct {
   270  	LastModified string      `json:"lastmodified,omitempty" yaml:"last_modified,omitempty" structs:",omitempty"`
   271  	CommitHash   string      `json:"commithash,omitempty" yaml:"commit_hash,omitempty" structs:",omitempty"`
   272  	Status       string      `json:"status,omitempty" yaml:"status,omitempty" structs:",omitempty"`
   273  	Tag          interface{} `json:"tag,omitempty" yaml:"tag,omitempty" structs:",omitempty"` // Note: `1.1`や`"1.1"`などと表記揺れがあるためここではinterface{}で受け取る
   274  	Expire       string      `json:"expire,omitempty" yaml:"expire,omitempty" structs:",omitempty"`
   275  }
   276  
   277  // DatabaseLog データベースログ
   278  type DatabaseLog struct {
   279  	Name string             `json:"name,omitempty" yaml:"name,omitempty" structs:",omitempty"`
   280  	Data string             `json:"data,omitempty" yaml:"data,omitempty" structs:",omitempty"`
   281  	Size types.StringNumber `json:"size,omitempty" yaml:"size,omitempty" structs:",omitempty"`
   282  }
   283  
   284  // IsSystemdLog systemctlのログか判定
   285  func (l *DatabaseLog) IsSystemdLog() bool {
   286  	return l.Name == "systemctl"
   287  }
   288  
   289  // Logs ログボディ取得
   290  func (l *DatabaseLog) Logs() []string {
   291  	return strings.Split(l.Data, "\n")
   292  }
   293  
   294  // ID ログのID取得
   295  func (l *DatabaseLog) ID() string {
   296  	return l.Name
   297  }
   298  
   299  // DatabaseBackupInfo データベースバックアップ情報
   300  type DatabaseBackupInfo struct {
   301  	History []*DatabaseBackupHistory `json:"history,omitempty" yaml:"history,omitempty" structs:",omitempty"`
   302  }
   303  
   304  // DatabaseBackupHistory データベースバックアップ履歴情報
   305  type DatabaseBackupHistory struct {
   306  	CreatedAt    time.Time  `json:"createdat,omitempty" yaml:"created_at,omitempty" structs:",omitempty"`
   307  	Availability string     `json:"availability,omitempty" yaml:"availability,omitempty" structs:",omitempty"`
   308  	RecoveredAt  *time.Time `json:"recoveredat,omitempty" yaml:"recovered_at,omitempty" structs:",omitempty"`
   309  	Size         int64      `json:"size,omitempty" yaml:"size,omitempty" structs:",omitempty"`
   310  }
   311  
   312  // ID バックアップ履歴のID取得
   313  func (h *DatabaseBackupHistory) ID() string {
   314  	return h.CreatedAt.Format(time.RFC3339)
   315  }
   316  
   317  // FormatCreatedAt 指定のレイアウトで作成日時を文字列化
   318  func (h *DatabaseBackupHistory) FormatCreatedAt(layout string) string {
   319  	return h.CreatedAt.Format(layout)
   320  }
   321  
   322  // FormatRecoveredAt 指定のレイアウトで復元日時を文字列化
   323  //
   324  // 復元日時がnilの場合は空の文字列を返す
   325  func (h *DatabaseBackupHistory) FormatRecoveredAt(layout string) string {
   326  	if h.RecoveredAt == nil {
   327  		return ""
   328  	}
   329  	return h.RecoveredAt.Format(layout)
   330  }
   331  
   332  // UnmarshalJSON JSON復号処理
   333  func (h *DatabaseBackupHistory) UnmarshalJSON(data []byte) error {
   334  	var tmpMap = map[string]interface{}{}
   335  	if err := json.Unmarshal(data, &tmpMap); err != nil {
   336  		return err
   337  	}
   338  
   339  	if recoveredAt, ok := tmpMap["recoveredat"]; ok {
   340  		if strRecoveredAt, ok := recoveredAt.(string); ok {
   341  			if _, err := time.Parse(time.RFC3339, strRecoveredAt); err != nil {
   342  				tmpMap["recoveredat"] = nil
   343  			}
   344  		}
   345  	}
   346  
   347  	data, err := json.Marshal(tmpMap)
   348  	if err != nil {
   349  		return err
   350  	}
   351  
   352  	tmp := &struct {
   353  		CreatedAt    time.Time  `json:"createdat,omitempty"`
   354  		Availability string     `json:"availability,omitempty"`
   355  		RecoveredAt  *time.Time `json:"recoveredat,omitempty"`
   356  		Size         string     `json:"size,omitempty"`
   357  	}{}
   358  	if err := json.Unmarshal(data, &tmp); err != nil {
   359  		return err
   360  	}
   361  
   362  	h.CreatedAt = tmp.CreatedAt
   363  	h.Availability = tmp.Availability
   364  	h.RecoveredAt = tmp.RecoveredAt
   365  	s, err := strconv.ParseInt(tmp.Size, 10, 64)
   366  	if err == nil {
   367  		h.Size = s
   368  	} else {
   369  		return err
   370  	}
   371  
   372  	return nil
   373  }
   374  
   375  // DatabaseParameter RDBMSごとに固有のパラメータ設定
   376  type DatabaseParameter struct {
   377  	Parameter *DatabaseParameterSetting `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   378  	Remark    *DatabaseParameterRemark  `json:",omitempty" yaml:",omitempty" structs:",omitempty"`
   379  }
   380  
   381  type DatabaseParameterSetting struct {
   382  	NoteID types.ID                     `json:",omitempty" yaml:"note_id,omitempty" structs:",omitempty"`
   383  	Attr   DatabaseParameterSettingAttr `json:",omitempty" yaml:"attr,omitempty" structs:",omitempty"`
   384  }
   385  
   386  type DatabaseParameterSettingAttr map[string]interface{}
   387  
   388  // UnmarshalJSON 配列/オブジェクトが混在することへの対応
   389  func (d *DatabaseParameterSettingAttr) UnmarshalJSON(b []byte) error {
   390  	if string(b) == "[]" {
   391  		return nil
   392  	}
   393  	type alias map[string]interface{}
   394  
   395  	var a alias
   396  	if err := json.Unmarshal(b, &a); err != nil {
   397  		return err
   398  	}
   399  	*d = DatabaseParameterSettingAttr(a)
   400  	return nil
   401  }
   402  
   403  type DatabaseParameterRemark struct {
   404  	Settings []interface{}                // どのような値が入るのか不明
   405  	Form     []*DatabaseParameterFormMeta `json:",omitempty" yaml:"form,omitempty" structs:",omitempty"`
   406  }
   407  
   408  type DatabaseParameterFormMeta struct {
   409  	Type    string                            `json:"type" yaml:"yaml"`
   410  	Name    string                            `json:"name" yaml:"name"`
   411  	Label   string                            `json:"label" yaml:"label"`
   412  	Options *DatabaseParameterFormMetaOptions `json:"options" yaml:"options"`
   413  	Items   [][]interface{}                   `json:"items,omitempty" yaml:"items,omitempty" structs:",omitempty"` // 例: [["value1", "text1"],[ "value2", "text2"]] ※ valueは数値となる可能性がある
   414  }
   415  
   416  type DatabaseParameterFormMetaOptions struct {
   417  	Validator string  `json:"validator" yaml:"validator"`
   418  	Example   string  `json:"ex" yaml:"ex"`
   419  	Min       float64 `json:"min" yaml:"min"`
   420  	Max       float64 `json:"max" yaml:"max"`
   421  	MaxLen    int     `json:"maxlen" yaml:"maxlen"`
   422  	Text      string  `json:"text" yaml:"text"`
   423  	Reboot    string  `json:"reboot" yaml:"reboot"`
   424  	Type      string  `json:"type" yaml:"type"`
   425  	Integer   bool    `json:"integer" yaml:"integer"` // postgres用のパラメータにだけ存在する模様
   426  }