From 5189d65467d9fe857fe1f286c2649c1e1f0063ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Thu, 11 Jan 2018 18:57:53 +0900 Subject: [PATCH 01/17] Support Naver Cloud Platform --- builder/ncloud/artifact.go | 46 +++ builder/ncloud/builder.go | 117 ++++++++ builder/ncloud/config.go | 114 ++++++++ builder/ncloud/config_test.go | 149 ++++++++++ builder/ncloud/ssh.go | 30 ++ builder/ncloud/step.go | 16 ++ .../step_create_block_storage_instance.go | 101 +++++++ ...step_create_block_storage_instance_test.go | 62 +++++ builder/ncloud/step_create_login_key.go | 71 +++++ builder/ncloud/step_create_login_key_test.go | 53 ++++ .../ncloud/step_create_public_ip_instance.go | 167 +++++++++++ .../step_create_public_ip_instance_test.go | 62 +++++ builder/ncloud/step_create_server_image.go | 77 +++++ .../ncloud/step_create_server_image_test.go | 58 ++++ builder/ncloud/step_create_server_instance.go | 129 +++++++++ .../step_create_server_instance_test.go | 58 ++++ .../step_delete_block_storage_instance.go | 95 +++++++ ...step_delete_block_storage_instance_test.go | 57 ++++ builder/ncloud/step_delete_login_key.go | 51 ++++ builder/ncloud/step_delete_login_key_test.go | 55 ++++ .../ncloud/step_delete_public_ip_instance.go | 78 ++++++ .../step_delete_public_ip_instance_test.go | 57 ++++ builder/ncloud/step_get_rootpassword.go | 57 ++++ builder/ncloud/step_get_rootpassword_test.go | 56 ++++ builder/ncloud/step_stop_server_instance.go | 64 +++++ .../ncloud/step_stop_server_instance_test.go | 55 ++++ .../ncloud/step_terminate_server_instance.go | 81 ++++++ .../step_terminate_server_instance_test.go | 54 ++++ builder/ncloud/step_validate_template.go | 263 ++++++++++++++++++ builder/ncloud/step_validate_template_test.go | 54 ++++ .../ncloud/waiter_block_storage_instance.go | 80 ++++++ builder/ncloud/waiter_server_image_status.go | 43 +++ .../ncloud/waiter_server_instance_status.go | 43 +++ command/plugin.go | 2 + 34 files changed, 2555 insertions(+) create mode 100644 builder/ncloud/artifact.go create mode 100644 builder/ncloud/builder.go create mode 100644 builder/ncloud/config.go create mode 100644 builder/ncloud/config_test.go create mode 100644 builder/ncloud/ssh.go create mode 100644 builder/ncloud/step.go create mode 100644 builder/ncloud/step_create_block_storage_instance.go create mode 100644 builder/ncloud/step_create_block_storage_instance_test.go create mode 100644 builder/ncloud/step_create_login_key.go create mode 100644 builder/ncloud/step_create_login_key_test.go create mode 100644 builder/ncloud/step_create_public_ip_instance.go create mode 100644 builder/ncloud/step_create_public_ip_instance_test.go create mode 100644 builder/ncloud/step_create_server_image.go create mode 100644 builder/ncloud/step_create_server_image_test.go create mode 100644 builder/ncloud/step_create_server_instance.go create mode 100644 builder/ncloud/step_create_server_instance_test.go create mode 100644 builder/ncloud/step_delete_block_storage_instance.go create mode 100644 builder/ncloud/step_delete_block_storage_instance_test.go create mode 100644 builder/ncloud/step_delete_login_key.go create mode 100644 builder/ncloud/step_delete_login_key_test.go create mode 100644 builder/ncloud/step_delete_public_ip_instance.go create mode 100644 builder/ncloud/step_delete_public_ip_instance_test.go create mode 100644 builder/ncloud/step_get_rootpassword.go create mode 100644 builder/ncloud/step_get_rootpassword_test.go create mode 100644 builder/ncloud/step_stop_server_instance.go create mode 100644 builder/ncloud/step_stop_server_instance_test.go create mode 100644 builder/ncloud/step_terminate_server_instance.go create mode 100644 builder/ncloud/step_terminate_server_instance_test.go create mode 100644 builder/ncloud/step_validate_template.go create mode 100644 builder/ncloud/step_validate_template_test.go create mode 100644 builder/ncloud/waiter_block_storage_instance.go create mode 100644 builder/ncloud/waiter_server_image_status.go create mode 100644 builder/ncloud/waiter_server_instance_status.go diff --git a/builder/ncloud/artifact.go b/builder/ncloud/artifact.go new file mode 100644 index 000000000..52624e437 --- /dev/null +++ b/builder/ncloud/artifact.go @@ -0,0 +1,46 @@ +package ncloud + +import ( + "bytes" + "fmt" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" +) + +const BuilderID = "ncloud.server.image" + +type Artifact struct { + ServerImage *ncloud.ServerImage +} + +func (*Artifact) BuilderId() string { + return BuilderID +} + +func (a *Artifact) Files() []string { + /* no file */ + return nil +} + +func (a *Artifact) Id() string { + return a.ServerImage.MemberServerImageNo +} + +func (a *Artifact) String() string { + var buf bytes.Buffer + + // TODO : Logging artifact information + buf.WriteString(fmt.Sprintf("%s:\n\n", a.BuilderId())) + buf.WriteString(fmt.Sprintf("Member Server Image Name: %s\n", a.ServerImage.MemberServerImageName)) + buf.WriteString(fmt.Sprintf("Member Server Image No: %s\n", a.ServerImage.MemberServerImageNo)) + + return buf.String() +} + +func (a *Artifact) State(name string) interface{} { + return a.ServerImage.MemberServerImageStatus +} + +func (a *Artifact) Destroy() error { + return nil +} diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go new file mode 100644 index 000000000..580514d53 --- /dev/null +++ b/builder/ncloud/builder.go @@ -0,0 +1,117 @@ +package ncloud + +import ( + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +const version = "1.0.0" + +// Builder assume this implements packer.Builder +type Builder struct { + config *Config + stateBag multistep.StateBag + runner multistep.Runner +} + +func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { + c, warnings, errs := NewConfig(raws...) + if errs != nil { + return warnings, errs + } + b.config = c + + b.stateBag = new(multistep.BasicStateBag) + + return warnings, nil +} + +func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { + ui.Say("Running builder for Naver Cloud Platform (version: " + version + ") ...") + + ui.Message("Creating Naver Cloud Platform Connection ...") + conn := ncloud.NewConnection(b.config.AccessKey, b.config.SecretKey) + + b.stateBag.Put("hook", hook) + b.stateBag.Put("ui", ui) + + var steps []multistep.Step + + steps = []multistep.Step{} + + if b.config.OSType == "Linux" { + steps = []multistep.Step{ + NewStepValidateTemplate(conn, ui, b.config), + NewStepCreateLoginKey(conn, ui), + NewStepCreateServerInstance(conn, ui, b.config), + NewStepCreateBlockStorageInstance(conn, ui, b.config), + NewStepGetRootPassword(conn, ui), + NewStepCreatePublicIPInstance(conn, ui, b.config), + &communicator.StepConnectSSH{ + Config: &b.config.Comm, + Host: SSHHost, + SSHConfig: SSHConfig(b.config.Comm.SSHUsername), + }, + &common.StepProvision{}, + NewStepStopServerInstance(conn, ui), + NewStepCreateServerImage(conn, ui, b.config), + NewStepDeleteBlockStorageInstance(conn, ui, b.config), + NewStepTerminateServerInstance(conn, ui), + NewStepDeleteLoginKey(conn, ui), + NewStepDeletePublicIPInstance(conn, ui), + } + } else if b.config.OSType == "Windows" { + steps = []multistep.Step{ + NewStepValidateTemplate(conn, ui, b.config), + NewStepCreateLoginKey(conn, ui), + NewStepCreateServerInstance(conn, ui, b.config), + NewStepCreateBlockStorageInstance(conn, ui, b.config), + NewStepGetRootPassword(conn, ui), + NewStepCreatePublicIPInstance(conn, ui, b.config), + &communicator.StepConnectWinRM{ + Config: &b.config.Comm, + Host: func(stateBag multistep.StateBag) (string, error) { + return stateBag.Get("WinRMHost").(string), nil + }, + WinRMConfig: func(state multistep.StateBag) (*communicator.WinRMConfig, error) { + return &communicator.WinRMConfig{ + Username: b.config.Comm.WinRMUser, + Password: state.Get("Password").(string), + }, nil + }, + }, + &common.StepProvision{}, + NewStepStopServerInstance(conn, ui), + NewStepCreateServerImage(conn, ui, b.config), + NewStepDeleteBlockStorageInstance(conn, ui, b.config), + NewStepTerminateServerInstance(conn, ui), + NewStepDeleteLoginKey(conn, ui), + NewStepDeletePublicIPInstance(conn, ui), + } + } + + // Run! + b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) + b.runner.Run(b.stateBag) + + // If there was an error, return that + if rawErr, ok := b.stateBag.GetOk("Error"); ok { + return nil, rawErr.(error) + } + + // Build the artifact and return it + artifact := &Artifact{} + + if serverImage, ok := b.stateBag.GetOk("memberServerImage"); ok { + artifact.ServerImage = serverImage.(*ncloud.ServerImage) + } + + return artifact, nil +} + +func (b *Builder) Cancel() { + b.runner.Cancel() +} diff --git a/builder/ncloud/config.go b/builder/ncloud/config.go new file mode 100644 index 000000000..e18ab822d --- /dev/null +++ b/builder/ncloud/config.go @@ -0,0 +1,114 @@ +package ncloud + +import ( + "errors" + + "github.com/hashicorp/packer/common" + "github.com/hashicorp/packer/helper/communicator" + "github.com/hashicorp/packer/helper/config" + "github.com/hashicorp/packer/packer" + "github.com/hashicorp/packer/template/interpolate" +) + +// Config is structure to use packer builder plugin for Naver Cloud Platform +type Config struct { + common.PackerConfig `mapstructure:",squash"` + + AccessKey string `mapstructure:"access_key"` + SecretKey string `mapstructure:"secret_key"` + OSType string `mapstructure:"os_type"` + ServerImageProductCode string `mapstructure:"server_image_product_code"` + ServerProductCode string `mapstructure:"server_product_code"` + MemberServerImageNo string `mapstructure:"member_server_image_no"` + ServerImageName string `mapstructure:"server_image_name"` + ServerImageDescription string `mapstructure:"server_image_description"` + UserData string `mapstructure:"user_data"` + BlockStorageSize int `mapstructure:"block_storage_size"` + Region string `mapstructure:"region"` + AccessControlGroupConfigurationNo string `mapstructure:"access_control_group_configuration_no"` + FeeSystemTypeCode string `mapstructure:"-"` + + Comm communicator.Config `mapstructure:",squash"` + ctx *interpolate.Context +} + +// NewConfig checks parameters +func NewConfig(raws ...interface{}) (*Config, []string, error) { + c := new(Config) + warnings := []string{} + + err := config.Decode(c, &config.DecodeOpts{ + Interpolate: true, + InterpolateFilter: &interpolate.RenderFilter{ + Exclude: []string{}, + }, + }, raws...) + if err != nil { + return nil, warnings, err + } + + var errs *packer.MultiError + if es := c.Comm.Prepare(nil); len(es) > 0 { + errs = packer.MultiErrorAppend(errs, es...) + } + + if c.AccessKey == "" { + errs = packer.MultiErrorAppend(errs, errors.New("access_key is required")) + } + + if c.SecretKey == "" { + errs = packer.MultiErrorAppend(errs, errors.New("secret_key is required")) + } + + if c.OSType != "Linux" && c.OSType != "Windows" { + errs = packer.MultiErrorAppend(errs, errors.New("os_type is required. ('Linux' or 'Windows')")) + } + + if c.MemberServerImageNo == "" && c.ServerImageProductCode == "" { + errs = packer.MultiErrorAppend(errs, errors.New("server_image_product_code or member_server_image_no is required")) + } + + if c.MemberServerImageNo != "" && c.ServerImageProductCode != "" { + errs = packer.MultiErrorAppend(errs, errors.New("Only one of server_image_product_code and member_server_image_no can be set")) + } + + if c.ServerImageProductCode != "" && len(c.ServerImageProductCode) > 20 { + errs = packer.MultiErrorAppend(errs, errors.New("If server_image_product_code field is set, length of server_image_product_code should be max 20")) + } + + if c.ServerProductCode != "" && len(c.ServerProductCode) > 20 { + errs = packer.MultiErrorAppend(errs, errors.New("If server_product_code field is set, length of server_product_code should be max 20")) + } + + if c.ServerImageName != "" && (len(c.ServerImageName) < 3 || len(c.ServerImageName) > 30) { + errs = packer.MultiErrorAppend(errs, errors.New("If server_image_name field is set, length of server_image_name should be min 3 and max 20")) + } + + if c.ServerImageDescription != "" && len(c.ServerImageDescription) > 1000 { + errs = packer.MultiErrorAppend(errs, errors.New("If server_image_description field is set, length of server_image_description should be max 1000")) + } + + if c.BlockStorageSize != 0 { + if c.BlockStorageSize < 10 || c.BlockStorageSize > 2000 { + errs = packer.MultiErrorAppend(errs, errors.New("The size of BlockStorageSize is at least 10 GB and up to 2000GB")) + } else if int(c.BlockStorageSize/10)*10 != c.BlockStorageSize { + return nil, nil, errors.New("BlockStorageSize must be a multiple of 10 GB") + } + } + + if c.UserData != "" && len(c.UserData) > 21847 { + errs = packer.MultiErrorAppend(errs, errors.New("If user_data field is set, length of UserData should be max 21847")) + } + + if c.OSType == "Windows" && c.AccessControlGroupConfigurationNo == "" { + errs = packer.MultiErrorAppend(errs, errors.New("If os_type is Windows, access_control_group_configuration_no is required")) + } + + c.FeeSystemTypeCode = "MTRAT" + + if errs != nil && len(errs.Errors) > 0 { + return nil, warnings, errs + } + + return c, warnings, nil +} diff --git a/builder/ncloud/config_test.go b/builder/ncloud/config_test.go new file mode 100644 index 000000000..7907c7ee1 --- /dev/null +++ b/builder/ncloud/config_test.go @@ -0,0 +1,149 @@ +package ncloud + +import ( + "strings" + "testing" +) + +func testConfig() map[string]interface{} { + return map[string]interface{}{ + "access_key": "access_key", + "secret_key": "secret_key", + "os_type": "Windows", + "server_image_product_code": "SPSW0WINNT000016", + "server_product_code": "SPSVRSSD00000011", + "server_image_name": "packer-test {{timestamp}}", + "server_image_description": "server description", + "block_storage_size": 100, + "user_data": "#!/bin/sh\nyum install -y httpd\ntouch /var/www/html/index.html\nchkconfig --level 2345 httpd on", + "region": "Korea", + "access_control_group_configuration_no": "33", + "communicator": "ssh", + "ssh_username": "root", + } +} + +func testConfigForMemberServerImage() map[string]interface{} { + return map[string]interface{}{ + "access_key": "access_key", + "secret_key": "secret_key", + "os_type": "Windows", + "server_product_code": "SPSVRSSD00000011", + "member_server_image_no": "2440", + "server_image_name": "packer-test {{timestamp}}", + "server_image_description": "server description", + "block_storage_size": 100, + "user_data": "#!/bin/sh\nyum install -y httpd\ntouch /var/www/html/index.html\nchkconfig --level 2345 httpd on", + "region": "Korea", + "access_control_group_configuration_no": "33", + "communicator": "ssh", + "ssh_username": "root", + } +} + +func TestConfigWithServerImageProductCode(t *testing.T) { + raw := testConfig() + + c, _, _ := NewConfig(raw) + + if c.AccessKey != "access_key" { + t.Errorf("Expected 'access_key' to be set to '%s', but got '%s'.", raw["access_key"], c.AccessKey) + } + + if c.SecretKey != "secret_key" { + t.Errorf("Expected 'secret_key' to be set to '%s', but got '%s'.", raw["secret_key"], c.SecretKey) + } + + if c.ServerImageProductCode != "SPSW0WINNT000016" { + t.Errorf("Expected 'server_image_product_code' to be set to '%s', but got '%s'.", raw["server_image_product_code"], c.ServerImageProductCode) + } + + if c.ServerProductCode != "SPSVRSSD00000011" { + t.Errorf("Expected 'server_product_code' to be set to '%s', but got '%s'.", raw["server_product_code"], c.ServerProductCode) + } + + if c.BlockStorageSize != 100 { + t.Errorf("Expected 'block_storage_size' to be set to '%d', but got '%d'.", raw["block_storage_size"], c.BlockStorageSize) + } + + if c.ServerImageDescription != "server description" { + t.Errorf("Expected 'server_image_description_key' to be set to '%s', but got '%s'.", raw["server_image_description"], c.ServerImageDescription) + } + + if c.Region != "Korea" { + t.Errorf("Expected 'region' to be set to '%s', but got '%s'.", raw["server_image_description"], c.Region) + } +} + +func TestConfigWithMemberServerImageCode(t *testing.T) { + raw := testConfigForMemberServerImage() + + c, _, _ := NewConfig(raw) + + if c.AccessKey != "access_key" { + t.Errorf("Expected 'access_key' to be set to '%s', but got '%s'.", raw["access_key"], c.AccessKey) + } + + if c.SecretKey != "secret_key" { + t.Errorf("Expected 'secret_key' to be set to '%s', but got '%s'.", raw["secret_key"], c.SecretKey) + } + + if c.MemberServerImageNo != "2440" { + t.Errorf("Expected 'member_server_image_no' to be set to '%s', but got '%s'.", raw["member_server_image_no"], c.MemberServerImageNo) + } + + if c.ServerProductCode != "SPSVRSSD00000011" { + t.Errorf("Expected 'server_product_code' to be set to '%s', but got '%s'.", raw["server_product_code"], c.ServerProductCode) + } + + if c.BlockStorageSize != 100 { + t.Errorf("Expected 'block_storage_size' to be set to '%d', but got '%d'.", raw["block_storage_size"], c.BlockStorageSize) + } + + if c.ServerImageDescription != "server description" { + t.Errorf("Expected 'server_image_description_key' to be set to '%s', but got '%s'.", raw["server_image_description"], c.ServerImageDescription) + } + + if c.Region != "Korea" { + t.Errorf("Expected 'region' to be set to '%s', but got '%s'.", raw["server_image_description"], c.Region) + } +} + +func TestEmptyConfig(t *testing.T) { + raw := new(map[string]interface{}) + + _, _, err := NewConfig(raw) + + if err == nil { + t.Error("Expected Config to require 'access_key', 'secret_key' and some mendatory fields, but it did not") + } + + if !strings.Contains(err.Error(), "access_key is required") { + t.Error("Expected Config to require 'access_key', but it did not") + } + + if !strings.Contains(err.Error(), "secret_key is required") { + t.Error("Expected Config to require 'secret_key', but it did not") + } + + if !strings.Contains(err.Error(), "server_image_product_code or member_server_image_no is required") { + t.Error("Expected Config to require 'server_image_product_code' or 'member_server_image_no', but it did not") + } +} + +func TestExistsBothServerImageProductCodeAndMemberServerImageNoConfig(t *testing.T) { + raw := map[string]interface{}{ + "access_key": "access_key", + "secret_key": "secret_key", + "os_type": "Windows", + "server_image_product_code": "SPSW0WINNT000016", + "server_product_code": "SPSVRSSD00000011", + "member_server_image_no": "2440", + } + + _, _, err := NewConfig(raw) + + if !strings.Contains(err.Error(), "Only one of server_image_product_code and member_server_image_no can be set") { + t.Error("Expected Config to require Only one of 'server_image_product_code' and 'member_server_image_no' can be set, but it did not") + } +} diff --git a/builder/ncloud/ssh.go b/builder/ncloud/ssh.go new file mode 100644 index 000000000..ee7d99226 --- /dev/null +++ b/builder/ncloud/ssh.go @@ -0,0 +1,30 @@ +package ncloud + +import ( + packerssh "github.com/hashicorp/packer/communicator/ssh" + "github.com/mitchellh/multistep" + "golang.org/x/crypto/ssh" +) + +func SSHHost(state multistep.StateBag) (string, error) { + host := state.Get("SSHHost").(string) + return host, nil +} + +// SSHConfig returns a function that can be used for the SSH communicator +// config for connecting to the specified host via SSH +func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, error) { + return func(state multistep.StateBag) (*ssh.ClientConfig, error) { + password := state.Get("Password").(string) + + return &ssh.ClientConfig{ + User: username, + Auth: []ssh.AuthMethod{ + ssh.Password(password), + ssh.KeyboardInteractive( + packerssh.PasswordKeyboardInteractive(password)), + }, + HostKeyCallback: ssh.InsecureIgnoreHostKey(), + }, nil + } +} diff --git a/builder/ncloud/step.go b/builder/ncloud/step.go new file mode 100644 index 000000000..ba71efbee --- /dev/null +++ b/builder/ncloud/step.go @@ -0,0 +1,16 @@ +package ncloud + +import ( + "github.com/mitchellh/multistep" +) + +func processStepResult(err error, sayError func(error), state multistep.StateBag) multistep.StepAction { + if err != nil { + state.Put("Error", err) + sayError(err) + + return multistep.ActionHalt + } + + return multistep.ActionContinue +} diff --git a/builder/ncloud/step_create_block_storage_instance.go b/builder/ncloud/step_create_block_storage_instance.go new file mode 100644 index 000000000..ef7306264 --- /dev/null +++ b/builder/ncloud/step_create_block_storage_instance.go @@ -0,0 +1,101 @@ +package ncloud + +import ( + "errors" + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +// StepCreateBlockStorageInstance struct is for making extra block storage +type StepCreateBlockStorageInstance struct { + Conn *ncloud.Conn + CreateBlockStorageInstance func(serverInstanceNo string) (string, error) + Say func(message string) + Error func(e error) + Config *Config +} + +// NewStepCreateBlockStorageInstance make StepCreateBlockStorage struct to make extra block storage +func NewStepCreateBlockStorageInstance(conn *ncloud.Conn, ui packer.Ui, config *Config) *StepCreateBlockStorageInstance { + var step = &StepCreateBlockStorageInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + Config: config, + } + + step.CreateBlockStorageInstance = step.createBlockStorageInstance + + return step +} + +func (s *StepCreateBlockStorageInstance) createBlockStorageInstance(serverInstanceNo string) (string, error) { + + reqParams := new(ncloud.RequestBlockStorageInstance) + reqParams.BlockStorageSize = s.Config.BlockStorageSize + reqParams.ServerInstanceNo = serverInstanceNo + + blockStorageInstanceList, err := s.Conn.CreateBlockStorageInstance(reqParams) + if err != nil { + return "", fmt.Errorf("error code: %d, error message: %s", blockStorageInstanceList.ReturnCode, blockStorageInstanceList.ReturnMessage) + } + + log.Println("Block Storage Instance information : ", blockStorageInstanceList.BlockStorageInstance[0]) + + if err := waiterBlockStorageInstanceStatus(s.Conn, blockStorageInstanceList.BlockStorageInstance[0].BlockStorageInstanceNo, "ATTAC", 10*time.Minute); err != nil { + return "", errors.New("TIMEOUT : Block Storage instance status is not attached") + } + + return blockStorageInstanceList.BlockStorageInstance[0].BlockStorageInstanceNo, nil +} + +func (s *StepCreateBlockStorageInstance) Run(state multistep.StateBag) multistep.StepAction { + if s.Config.BlockStorageSize == 0 { + return processStepResult(nil, s.Error, state) + } + + s.Say("Create extra block storage instance") + + serverInstanceNo := state.Get("InstanceNo").(string) + + blockStorageInstanceNo, err := s.CreateBlockStorageInstance(serverInstanceNo) + if err == nil { + state.Put("BlockStorageInstanceNo", blockStorageInstanceNo) + } + + return processStepResult(err, s.Error, state) +} + +func (s *StepCreateBlockStorageInstance) Cleanup(state multistep.StateBag) { + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + + if !cancelled && !halted { + return + } + + if s.Config.BlockStorageSize == 0 { + return + } + + if blockStorageInstanceNo, ok := state.GetOk("BlockStorageInstanceNo"); ok { + s.Say("Clean up Block Storage Instance") + no := blockStorageInstanceNo.(string) + blockStorageInstanceList, err := s.Conn.DeleteBlockStorageInstances([]string{no}) + if err != nil { + return + } + + s.Say(fmt.Sprintf("Block Storage Instance is deleted. Block Storage InstanceNo is %s", no)) + log.Println("Block Storage Instance information : ", blockStorageInstanceList.BlockStorageInstance[0]) + + if err := waiterBlockStorageInstanceStatus(s.Conn, no, "DETAC", time.Minute); err != nil { + s.Say("TIMEOUT : Block Storage instance status is not deattached") + } + } +} diff --git a/builder/ncloud/step_create_block_storage_instance_test.go b/builder/ncloud/step_create_block_storage_instance_test.go new file mode 100644 index 000000000..101e94658 --- /dev/null +++ b/builder/ncloud/step_create_block_storage_instance_test.go @@ -0,0 +1,62 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepCreateBlockStorageInstanceShouldFailIfOperationCreateBlockStorageInstanceFails(t *testing.T) { + + var testSubject = &StepCreateBlockStorageInstance{ + CreateBlockStorageInstance: func(serverInstanceNo string) (string, error) { return "", fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + Config: new(Config), + } + + testSubject.Config.BlockStorageSize = 10 + + stateBag := createTestStateBagStepCreateBlockStorageInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepCreateBlockStorageInstanceShouldPassIfOperationCreateBlockStorageInstancePasses(t *testing.T) { + var testSubject = &StepCreateBlockStorageInstance{ + CreateBlockStorageInstance: func(serverInstanceNo string) (string, error) { return "a", nil }, + Say: func(message string) {}, + Error: func(e error) {}, + Config: new(Config), + } + + testSubject.Config.BlockStorageSize = 10 + + stateBag := createTestStateBagStepCreateBlockStorageInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepCreateBlockStorageInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("InstanceNo", "a") + + return stateBag +} diff --git a/builder/ncloud/step_create_login_key.go b/builder/ncloud/step_create_login_key.go new file mode 100644 index 000000000..7dddebd25 --- /dev/null +++ b/builder/ncloud/step_create_login_key.go @@ -0,0 +1,71 @@ +package ncloud + +import ( + "fmt" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type LoginKey struct { + KeyName string + PrivateKey string +} + +type StepCreateLoginKey struct { + Conn *ncloud.Conn + CreateLoginKey func() (*LoginKey, error) + Say func(message string) + Error func(e error) +} + +func NewStepCreateLoginKey(conn *ncloud.Conn, ui packer.Ui) *StepCreateLoginKey { + var step = &StepCreateLoginKey{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + } + + step.CreateLoginKey = step.createLoginKey + + return step +} + +func (s *StepCreateLoginKey) createLoginKey() (*LoginKey, error) { + KeyName := fmt.Sprintf("packer-%d", time.Now().Unix()) + + privateKey, err := s.Conn.CreateLoginKey(KeyName) + if err != nil { + return nil, fmt.Errorf("error code: %d , error message: %s", privateKey.ReturnCode, privateKey.ReturnMessage) + } + + return &LoginKey{KeyName, privateKey.PrivateKey}, nil +} + +func (s *StepCreateLoginKey) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Create Login Key") + + loginKey, err := s.CreateLoginKey() + if err == nil { + state.Put("LoginKey", loginKey) + s.Say(fmt.Sprintf("Login Key[%s] is created", loginKey.KeyName)) + } + + return processStepResult(err, s.Error, state) +} + +func (s *StepCreateLoginKey) Cleanup(state multistep.StateBag) { + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + + if !cancelled && !halted { + return + } + + if loginKey, ok := state.GetOk("LoginKey"); ok { + s.Say("Clean up login key") + s.Conn.DeleteLoginKey(loginKey.(*LoginKey).KeyName) + } +} diff --git a/builder/ncloud/step_create_login_key_test.go b/builder/ncloud/step_create_login_key_test.go new file mode 100644 index 000000000..374d10330 --- /dev/null +++ b/builder/ncloud/step_create_login_key_test.go @@ -0,0 +1,53 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepCreateLoginKeyShouldFailIfOperationCreateLoginKeyFails(t *testing.T) { + var testSubject = &StepCreateLoginKey{ + CreateLoginKey: func() (*LoginKey, error) { return nil, fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateLoginKey() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepCreateLoginKeyShouldPassIfOperationCreateLoginKeyPasses(t *testing.T) { + var testSubject = &StepCreateLoginKey{ + CreateLoginKey: func() (*LoginKey, error) { return &LoginKey{"a", "b"}, nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateLoginKey() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepCreateLoginKey() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + return stateBag +} diff --git a/builder/ncloud/step_create_public_ip_instance.go b/builder/ncloud/step_create_public_ip_instance.go new file mode 100644 index 000000000..88d98eb6c --- /dev/null +++ b/builder/ncloud/step_create_public_ip_instance.go @@ -0,0 +1,167 @@ +package ncloud + +import ( + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepCreatePublicIPInstance struct { + Conn *ncloud.Conn + CreatePublicIPInstance func(serverInstanceNo string) (*ncloud.PublicIPInstance, error) + WaiterAssociatePublicIPToServerInstance func(serverInstanceNo string, publicIP string) error + Say func(message string) + Error func(e error) + Config *Config +} + +func NewStepCreatePublicIPInstance(conn *ncloud.Conn, ui packer.Ui, config *Config) *StepCreatePublicIPInstance { + var step = &StepCreatePublicIPInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + Config: config, + } + + step.CreatePublicIPInstance = step.createPublicIPInstance + step.WaiterAssociatePublicIPToServerInstance = step.waiterAssociatePublicIPToServerInstance + + return step +} + +func (s *StepCreatePublicIPInstance) waiterAssociatePublicIPToServerInstance(serverInstanceNo string, publicIP string) error { + reqParams := new(ncloud.RequestGetServerInstanceList) + reqParams.ServerInstanceNoList = []string{serverInstanceNo} + + c1 := make(chan error, 1) + + go func() { + for { + serverInstanceList, err := s.Conn.GetServerInstanceList(reqParams) + + if err != nil { + c1 <- err + return + } + + if publicIP == serverInstanceList.ServerInstanceList[0].PublicIP { + c1 <- nil + return + } + + s.Say("Wait to associate public ip serverInstance") + time.Sleep(time.Second * 3) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(time.Second * 60): + return fmt.Errorf("TIMEOUT : association public ip[%s] to server instance[%s] Failed", publicIP, serverInstanceNo) + } +} + +func (s *StepCreatePublicIPInstance) createPublicIPInstance(serverInstanceNo string) (*ncloud.PublicIPInstance, error) { + reqParams := new(ncloud.RequestCreatePublicIPInstance) + reqParams.ServerInstanceNo = serverInstanceNo + + publicIPInstanceList, err := s.Conn.CreatePublicIPInstance(reqParams) + if err != nil { + return nil, fmt.Errorf("error code: %d, error message: %s", publicIPInstanceList.ReturnCode, publicIPInstanceList.ReturnMessage) + } + + publicIPInstance := publicIPInstanceList.PublicIPInstanceList[0] + publicIP := publicIPInstance.PublicIP + s.Say(fmt.Sprintf("Public IP Instance [%s:%s] is created", publicIPInstance.PublicIPInstanceNo, publicIP)) + + err = s.waiterAssociatePublicIPToServerInstance(serverInstanceNo, publicIP) + + return &publicIPInstance, nil +} + +func (s *StepCreatePublicIPInstance) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Create Public IP Instance") + + serverInstanceNo := state.Get("InstanceNo").(string) + + publicIPInstance, err := s.CreatePublicIPInstance(serverInstanceNo) + if err == nil { + switch s.Config.OSType { + case "Linux": + state.Put("SSHHost", publicIPInstance.PublicIP) + case "Windows": + state.Put("WinRMHost", publicIPInstance.PublicIP) + } + + state.Put("PublicIPInstance", publicIPInstance) + } + + return processStepResult(err, s.Error, state) +} + +func (s *StepCreatePublicIPInstance) Cleanup(state multistep.StateBag) { + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + + if !cancelled && !halted { + return + } + + publicIPInstance, ok := state.GetOk("PublicIPInstance") + if !ok { + return + } + + s.Say("Clean up Public IP Instance") + publicIPInstanceNo := publicIPInstance.(*ncloud.PublicIPInstance).PublicIPInstanceNo + s.waitPublicIPInstanceStatus(publicIPInstanceNo, "USED") + + log.Println("Disassociate Public IP Instance ", publicIPInstanceNo) + s.Conn.DisassociatePublicIP(publicIPInstanceNo) + + s.waitPublicIPInstanceStatus(publicIPInstanceNo, "CREAT") + + reqParams := new(ncloud.RequestDeletePublicIPInstances) + reqParams.PublicIPInstanceNoList = []string{publicIPInstanceNo} + + log.Println("Delete Public IP Instance ", publicIPInstanceNo) + s.Conn.DeletePublicIPInstances(reqParams) +} + +func (s *StepCreatePublicIPInstance) waitPublicIPInstanceStatus(publicIPInstanceNo string, status string) { + c1 := make(chan error, 1) + + go func() { + reqParams := new(ncloud.RequestPublicIPInstanceList) + reqParams.PublicIPInstanceNoList = []string{publicIPInstanceNo} + + for { + resp, err := s.Conn.GetPublicIPInstanceList(reqParams) + if err != nil { + log.Printf("error code: %d, error message: %s", resp.ReturnCode, resp.ReturnMessage) + c1 <- err + return + } + + instance := resp.PublicIPInstanceList[0] + if instance.PublicIPInstanceStatus.Code == status && instance.PublicIPInstanceOperation.Code == "NULL" { + c1 <- nil + return + } + + time.Sleep(time.Second * 2) + } + }() + + select { + case <-c1: + return + case <-time.After(time.Second * 60): + return + } +} diff --git a/builder/ncloud/step_create_public_ip_instance_test.go b/builder/ncloud/step_create_public_ip_instance_test.go new file mode 100644 index 000000000..30eaca017 --- /dev/null +++ b/builder/ncloud/step_create_public_ip_instance_test.go @@ -0,0 +1,62 @@ +package ncloud + +import ( + "fmt" + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "testing" + + "github.com/mitchellh/multistep" +) + +func TestStepCreatePublicIPInstanceShouldFailIfOperationCreatePublicIPInstanceFails(t *testing.T) { + var testSubject = &StepCreatePublicIPInstance{ + CreatePublicIPInstance: func(serverInstanceNo string) (*ncloud.PublicIPInstance, error) { + return nil, fmt.Errorf("!! Unit Test FAIL !!") + }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateServerImage() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepCreatePublicIPInstanceShouldPassIfOperationCreatePublicIPInstancePasses(t *testing.T) { + var testSubject = &StepCreatePublicIPInstance{ + CreatePublicIPInstance: func(serverInstanceNo string) (*ncloud.PublicIPInstance, error) { + return &ncloud.PublicIPInstance{PublicIPInstanceNo: "a", PublicIP: "b"}, nil + }, + Say: func(message string) {}, + Error: func(e error) {}, + Config: &Config{OSType: "Windows"}, + } + + stateBag := createTestStateBagStepCreatePublicIPInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepCreatePublicIPInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("InstanceNo", "a") + + return stateBag +} diff --git a/builder/ncloud/step_create_server_image.go b/builder/ncloud/step_create_server_image.go new file mode 100644 index 000000000..4256664f4 --- /dev/null +++ b/builder/ncloud/step_create_server_image.go @@ -0,0 +1,77 @@ +package ncloud + +import ( + "errors" + "fmt" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepCreateServerImage struct { + Conn *ncloud.Conn + CreateServerImage func(serverInstanceNo string) (*ncloud.ServerImage, error) + Say func(message string) + Error func(e error) + Config *Config +} + +func NewStepCreateServerImage(conn *ncloud.Conn, ui packer.Ui, config *Config) *StepCreateServerImage { + var step = &StepCreateServerImage{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + Config: config, + } + + step.CreateServerImage = step.createServerImage + + return step +} + +func (s *StepCreateServerImage) createServerImage(serverInstanceNo string) (*ncloud.ServerImage, error) { + // 서버 인스턴스 상태가 정지 중일 경우에는 서버 이미지 생성할 수 없음. + if err := waiterServerInstanceStatus(s.Conn, serverInstanceNo, "NSTOP", 1*time.Minute); err != nil { + return nil, err + } + + reqParams := new(ncloud.RequestCreateServerImage) + reqParams.MemberServerImageName = s.Config.ServerImageName + reqParams.MemberServerImageDescription = s.Config.ServerImageDescription + reqParams.ServerInstanceNo = serverInstanceNo + + memberServerImageList, err := s.Conn.CreateMemberServerImage(reqParams) + if err != nil { + return nil, fmt.Errorf("error code: %d , error message: %s", memberServerImageList.ReturnCode, memberServerImageList.ReturnMessage) + } + + serverImage := memberServerImageList.MemberServerImageList[0] + + s.Say(fmt.Sprintf("Server Image[%s:%s] is creating...", serverImage.MemberServerImageName, serverImage.MemberServerImageNo)) + + if err := waiterMemberServerImageStatus(s.Conn, serverImage.MemberServerImageNo, "CREAT", 6*time.Hour); err != nil { + return nil, errors.New("TIMEOUT : Server Image is not created") + } + + s.Say(fmt.Sprintf("Server Image[%s:%s] is created", serverImage.MemberServerImageName, serverImage.MemberServerImageNo)) + + return &serverImage, nil +} + +func (s *StepCreateServerImage) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Create Server Image") + + serverInstanceNo := state.Get("InstanceNo").(string) + + serverImage, err := s.CreateServerImage(serverInstanceNo) + if err == nil { + state.Put("memberServerImage", serverImage) + } + + return processStepResult(err, s.Error, state) +} + +func (*StepCreateServerImage) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_create_server_image_test.go b/builder/ncloud/step_create_server_image_test.go new file mode 100644 index 000000000..41a40971a --- /dev/null +++ b/builder/ncloud/step_create_server_image_test.go @@ -0,0 +1,58 @@ +package ncloud + +import ( + "fmt" + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "testing" + + "github.com/mitchellh/multistep" +) + +func TestStepCreateServerImageShouldFailIfOperationCreateServerImageFails(t *testing.T) { + var testSubject = &StepCreateServerImage{ + CreateServerImage: func(serverInstanceNo string) (*ncloud.ServerImage, error) { + return nil, fmt.Errorf("!! Unit Test FAIL !!") + }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateServerImage() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} +func TestStepCreateServerImageShouldPassIfOperationCreateServerImagePasses(t *testing.T) { + var testSubject = &StepCreateServerImage{ + CreateServerImage: func(serverInstanceNo string) (*ncloud.ServerImage, error) { return nil, nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateServerImage() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepCreateServerImage() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("InstanceNo", "a") + + return stateBag +} diff --git a/builder/ncloud/step_create_server_instance.go b/builder/ncloud/step_create_server_instance.go new file mode 100644 index 000000000..040e72eb1 --- /dev/null +++ b/builder/ncloud/step_create_server_instance.go @@ -0,0 +1,129 @@ +package ncloud + +import ( + "errors" + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepCreateServerInstance struct { + Conn *ncloud.Conn + CreateServerInstance func(loginKeyName string, zoneNo string) (string, error) + CheckServerInstanceStatusIsRunning func(serverInstanceNo string) error + Say func(message string) + Error func(e error) + Config *Config + serverInstanceNo string +} + +func NewStepCreateServerInstance(conn *ncloud.Conn, ui packer.Ui, config *Config) *StepCreateServerInstance { + var step = &StepCreateServerInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + Config: config, + } + + step.CreateServerInstance = step.createServerInstance + + return step +} + +func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zoneNo string) (string, error) { + reqParams := new(ncloud.RequestCreateServerInstance) + reqParams.ServerProductCode = s.Config.ServerProductCode + reqParams.MemberServerImageNo = s.Config.MemberServerImageNo + if s.Config.MemberServerImageNo == "" { + reqParams.ServerImageProductCode = s.Config.ServerImageProductCode + } + reqParams.LoginKeyName = loginKeyName + reqParams.ZoneNo = zoneNo + reqParams.FeeSystemTypeCode = s.Config.FeeSystemTypeCode + + if s.Config.UserData != "" { + reqParams.UserData = s.Config.UserData + } + + if s.Config.AccessControlGroupConfigurationNo != "" { + reqParams.AccessControlGroupConfigurationNoList = []string{s.Config.AccessControlGroupConfigurationNo} + } + + serverInstanceList, err := s.Conn.CreateServerInstances(reqParams) + if err != nil { + return "", fmt.Errorf("error code: %d, error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + } + + s.serverInstanceNo = serverInstanceList.ServerInstanceList[0].ServerInstanceNo + s.Say(fmt.Sprintf("Server Instance is creating. Server InstanceNo is %s", s.serverInstanceNo)) + log.Println("Server Instance information : ", serverInstanceList.ServerInstanceList[0]) + + if err := waiterServerInstanceStatus(s.Conn, s.serverInstanceNo, "RUN", 30*time.Minute); err != nil { + return "", errors.New("TIMEOUT : server instance status is not running") + } + + s.Say(fmt.Sprintf("Server Instance is created. Server InstanceNo is %s", s.serverInstanceNo)) + + return s.serverInstanceNo, nil +} + +func (s *StepCreateServerInstance) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Create Server Instance") + + var loginKey = state.Get("LoginKey").(*LoginKey) + var zoneNo = state.Get("ZoneNo").(string) + + serverInstanceNo, err := s.CreateServerInstance(loginKey.KeyName, zoneNo) + if err == nil { + state.Put("InstanceNo", serverInstanceNo) + } + + return processStepResult(err, s.Error, state) +} + +func (s *StepCreateServerInstance) Cleanup(state multistep.StateBag) { + _, cancelled := state.GetOk(multistep.StateCancelled) + _, halted := state.GetOk(multistep.StateHalted) + + if !cancelled && !halted { + return + } + + if s.serverInstanceNo == "" { + return + } + + reqParams := new(ncloud.RequestGetServerInstanceList) + reqParams.ServerInstanceNoList = []string{s.serverInstanceNo} + + serverInstanceList, err := s.Conn.GetServerInstanceList(reqParams) + if err != nil || serverInstanceList.TotalRows == 0 { + return + } + + s.Say("Clean up Server Instance") + + serverInstance := serverInstanceList.ServerInstanceList[0] + // stop server instance + if serverInstance.ServerInstanceStatus.Code != "NSTOP" && serverInstance.ServerInstanceStatus.Code != "TERMT" { + reqParams := new(ncloud.RequestStopServerInstances) + reqParams.ServerInstanceNoList = []string{s.serverInstanceNo} + + log.Println("Stop Server Instance") + s.Conn.StopServerInstances(reqParams) + waiterServerInstanceStatus(s.Conn, s.serverInstanceNo, "NSTOP", time.Minute) + } + + // terminate server instance + if serverInstance.ServerInstanceStatus.Code != "TERMT" { + reqParams := new(ncloud.RequestTerminateServerInstances) + reqParams.ServerInstanceNoList = []string{s.serverInstanceNo} + + log.Println("Terminate Server Instance") + s.Conn.TerminateServerInstances(reqParams) + } +} diff --git a/builder/ncloud/step_create_server_instance_test.go b/builder/ncloud/step_create_server_instance_test.go new file mode 100644 index 000000000..327228b75 --- /dev/null +++ b/builder/ncloud/step_create_server_instance_test.go @@ -0,0 +1,58 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepCreateServerInstanceShouldFailIfOperationCreateFails(t *testing.T) { + var testSubject = &StepCreateServerInstance{ + CreateServerInstance: func(loginKeyName string, zoneNo string) (string, error) { + return "", fmt.Errorf("!! Unit Test FAIL !!") + }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateServerInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepCreateServerInstanceShouldPassIfOperationCreatePasses(t *testing.T) { + var testSubject = &StepCreateServerInstance{ + CreateServerInstance: func(loginKeyName string, zoneNo string) (string, error) { return "", nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepCreateServerInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepCreateServerInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("LoginKey", &LoginKey{"a", "b"}) + stateBag.Put("ZoneNo", "1") + + return stateBag +} diff --git a/builder/ncloud/step_delete_block_storage_instance.go b/builder/ncloud/step_delete_block_storage_instance.go new file mode 100644 index 000000000..3c6c44b82 --- /dev/null +++ b/builder/ncloud/step_delete_block_storage_instance.go @@ -0,0 +1,95 @@ +package ncloud + +import ( + "errors" + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepDeleteBlockStorageInstance struct { + Conn *ncloud.Conn + DeleteBlockStorageInstance func(blockStorageInstanceNo string) error + Say func(message string) + Error func(e error) + Config *Config +} + +func NewStepDeleteBlockStorageInstance(conn *ncloud.Conn, ui packer.Ui, config *Config) *StepDeleteBlockStorageInstance { + var step = &StepDeleteBlockStorageInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + Config: config, + } + + step.DeleteBlockStorageInstance = step.deleteBlockStorageInstance + + return step +} + +func (s *StepDeleteBlockStorageInstance) getBlockInstanceList(serverInstanceNo string) []string { + reqParams := new(ncloud.RequestBlockStorageInstanceList) + reqParams.ServerInstanceNo = serverInstanceNo + + blockStorageInstanceList, err := s.Conn.GetBlockStorageInstance(reqParams) + if err != nil { + return nil + } + + if blockStorageInstanceList.TotalRows == 1 { + return nil + } + + var instanceList []string + + for _, blockStorageInstance := range blockStorageInstanceList.BlockStorageInstance { + log.Println(blockStorageInstance) + if blockStorageInstance.BlockStorageType.Code != "BASIC" { + instanceList = append(instanceList, blockStorageInstance.BlockStorageInstanceNo) + } + } + + return instanceList +} + +func (s *StepDeleteBlockStorageInstance) deleteBlockStorageInstance(serverInstanceNo string) error { + blockStorageInstanceList := s.getBlockInstanceList(serverInstanceNo) + if blockStorageInstanceList == nil || len(blockStorageInstanceList) == 0 { + return nil + } + + result, err := s.Conn.DeleteBlockStorageInstances(blockStorageInstanceList) + if err != nil { + return fmt.Errorf("error code: %d , error message: %s", result.ReturnCode, result.ReturnMessage) + } + + s.Say(fmt.Sprintf("Block Storage Instance is deleted. Block Storage InstanceNo is %s", blockStorageInstanceList)) + + if err := waiterDetachedBlockStorageInstance(s.Conn, serverInstanceNo, time.Minute); err != nil { + return errors.New("TIMEOUT : Block Storage instance status is not deattached") + } + + return nil +} + +func (s *StepDeleteBlockStorageInstance) Run(state multistep.StateBag) multistep.StepAction { + if s.Config.BlockStorageSize == 0 { + return processStepResult(nil, s.Error, state) + } + + s.Say("Delete Block Storage Instance") + + var serverInstanceNo = state.Get("InstanceNo").(string) + + err := s.DeleteBlockStorageInstance(serverInstanceNo) + + return processStepResult(err, s.Error, state) +} + +func (*StepDeleteBlockStorageInstance) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_delete_block_storage_instance_test.go b/builder/ncloud/step_delete_block_storage_instance_test.go new file mode 100644 index 000000000..ce0f0cb09 --- /dev/null +++ b/builder/ncloud/step_delete_block_storage_instance_test.go @@ -0,0 +1,57 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepDeleteBlockStorageInstanceShouldFailIfOperationDeleteBlockStorageInstanceFails(t *testing.T) { + var testSubject = &StepDeleteBlockStorageInstance{ + DeleteBlockStorageInstance: func(blockStorageInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + Config: &Config{BlockStorageSize: 10}, + } + + stateBag := createTestStateBagStepDeleteBlockStorageInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepDeleteBlockStorageInstanceShouldPassIfOperationDeleteBlockStorageInstancePasses(t *testing.T) { + var testSubject = &StepDeleteBlockStorageInstance{ + DeleteBlockStorageInstance: func(blockStorageInstanceNo string) error { return nil }, + Say: func(message string) {}, + Error: func(e error) {}, + Config: &Config{BlockStorageSize: 10}, + } + + stateBag := createTestStateBagStepDeleteBlockStorageInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepDeleteBlockStorageInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("InstanceNo", "1") + + return stateBag +} diff --git a/builder/ncloud/step_delete_login_key.go b/builder/ncloud/step_delete_login_key.go new file mode 100644 index 000000000..b0cfbf7a1 --- /dev/null +++ b/builder/ncloud/step_delete_login_key.go @@ -0,0 +1,51 @@ +package ncloud + +import ( + "fmt" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepDeleteLoginKey struct { + Conn *ncloud.Conn + DeleteLoginKey func(keyName string) error + Say func(message string) + Error func(e error) +} + +func NewStepDeleteLoginKey(conn *ncloud.Conn, ui packer.Ui) *StepDeleteLoginKey { + var step = &StepDeleteLoginKey{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + } + + step.DeleteLoginKey = step.deleteLoginKey + + return step +} + +func (s *StepDeleteLoginKey) deleteLoginKey(keyName string) error { + resp, err := s.Conn.DeleteLoginKey(keyName) + if err != nil { + return fmt.Errorf("error code: %d , error message: %s", resp.ReturnCode, resp.ReturnMessage) + } + + return nil +} + +func (s *StepDeleteLoginKey) Run(state multistep.StateBag) multistep.StepAction { + var loginKey = state.Get("LoginKey").(*LoginKey) + + err := s.DeleteLoginKey(loginKey.KeyName) + if err == nil { + s.Say(fmt.Sprintf("Login Key[%s] is deleted", loginKey.KeyName)) + } + + return processStepResult(err, s.Error, state) +} + +func (*StepDeleteLoginKey) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_delete_login_key_test.go b/builder/ncloud/step_delete_login_key_test.go new file mode 100644 index 000000000..38ce1e22c --- /dev/null +++ b/builder/ncloud/step_delete_login_key_test.go @@ -0,0 +1,55 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepDeleteLoginKeyShouldFailIfOperationDeleteLoginKeyFails(t *testing.T) { + var testSubject = &StepDeleteLoginKey{ + DeleteLoginKey: func(keyName string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := DeleteTestStateBagStepDeleteLoginKey() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepDeleteLoginKeyShouldPassIfOperationDeleteLoginKeyPasses(t *testing.T) { + var testSubject = &StepDeleteLoginKey{ + DeleteLoginKey: func(keyName string) error { return nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := DeleteTestStateBagStepDeleteLoginKey() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func DeleteTestStateBagStepDeleteLoginKey() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("LoginKey", &LoginKey{"a", "b"}) + + return stateBag +} diff --git a/builder/ncloud/step_delete_public_ip_instance.go b/builder/ncloud/step_delete_public_ip_instance.go new file mode 100644 index 000000000..4a1401984 --- /dev/null +++ b/builder/ncloud/step_delete_public_ip_instance.go @@ -0,0 +1,78 @@ +package ncloud + +import ( + "errors" + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepDeletePublicIPInstance struct { + Conn *ncloud.Conn + DeletePublicIPInstance func(publicIPInstanceNo string) error + Say func(message string) + Error func(e error) +} + +func NewStepDeletePublicIPInstance(conn *ncloud.Conn, ui packer.Ui) *StepDeletePublicIPInstance { + var step = &StepDeletePublicIPInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + } + + step.DeletePublicIPInstance = step.deletePublicIPInstance + + return step +} + +func (s *StepDeletePublicIPInstance) deletePublicIPInstance(publicIPInstanceNo string) error { + reqParams := new(ncloud.RequestDeletePublicIPInstances) + reqParams.PublicIPInstanceNoList = []string{publicIPInstanceNo} + + c1 := make(chan error, 1) + + go func() { + for { + resp, err := s.Conn.DeletePublicIPInstances(reqParams) + if err != nil && (resp.ReturnCode == 24073 || resp.ReturnCode == 25032) { + // error code : 24073 : Unable to destroy the server since a public IP is associated with the server. First, please disassociate a public IP from the server. + // error code : 25032 : You may not delete sk since (other) user is changing the target official IP settings. + log.Println(resp.ReturnCode, resp.ReturnMessage) + } else if err != nil { + c1 <- fmt.Errorf("error code: %d, error message: %s", resp.ReturnCode, resp.ReturnMessage) + return + } else if err == nil { + s.Say(fmt.Sprintf("Public IP Instance [%s] is deleted.", publicIPInstanceNo)) + c1 <- nil + return + } + + time.Sleep(time.Second * 5) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(time.Second * 60): + return errors.New("TIMEOUT : Can't delete server instance") + } +} + +func (s *StepDeletePublicIPInstance) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Delete Public IP Instance") + + publicIPInstance := state.Get("PublicIPInstance").(*ncloud.PublicIPInstance) + + err := s.DeletePublicIPInstance(publicIPInstance.PublicIPInstanceNo) + + return processStepResult(err, s.Error, state) +} + +func (*StepDeletePublicIPInstance) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_delete_public_ip_instance_test.go b/builder/ncloud/step_delete_public_ip_instance_test.go new file mode 100644 index 000000000..b9fa04ec8 --- /dev/null +++ b/builder/ncloud/step_delete_public_ip_instance_test.go @@ -0,0 +1,57 @@ +package ncloud + +import ( + "fmt" + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "testing" + + "github.com/mitchellh/multistep" +) + +func TestStepDeletePublicIPInstanceShouldFailIfOperationDeletePublicIPInstanceFails(t *testing.T) { + var testSubject = &StepDeletePublicIPInstance{ + DeletePublicIPInstance: func(publicIPInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepDeletePublicIPInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepDeletePublicIPInstanceShouldPassIfOperationDeletePublicIPInstancePasses(t *testing.T) { + var testSubject = &StepDeletePublicIPInstance{ + DeletePublicIPInstance: func(publicIPInstanceNo string) error { return nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepDeletePublicIPInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepDeletePublicIPInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("PublicIPInstance", &ncloud.PublicIPInstance{PublicIPInstanceNo: "22"}) + + return stateBag +} diff --git a/builder/ncloud/step_get_rootpassword.go b/builder/ncloud/step_get_rootpassword.go new file mode 100644 index 000000000..c5070d179 --- /dev/null +++ b/builder/ncloud/step_get_rootpassword.go @@ -0,0 +1,57 @@ +package ncloud + +import ( + "fmt" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepGetRootPassword struct { + Conn *ncloud.Conn + GetRootPassword func(serverInstanceNo string, privateKey string) (string, error) + Say func(message string) + Error func(e error) +} + +func NewStepGetRootPassword(conn *ncloud.Conn, ui packer.Ui) *StepGetRootPassword { + var step = &StepGetRootPassword{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + } + + step.GetRootPassword = step.getRootPassword + + return step +} + +func (s *StepGetRootPassword) getRootPassword(serverInstanceNo string, privateKey string) (string, error) { + reqParams := new(ncloud.RequestGetRootPassword) + reqParams.ServerInstanceNo = serverInstanceNo + reqParams.PrivateKey = privateKey + + rootPassword, err := s.Conn.GetRootPassword(reqParams) + if err != nil { + return "", fmt.Errorf("error code: %d, error message: %s", rootPassword.ReturnCode, rootPassword.ReturnMessage) + } + + return rootPassword.RootPassword, nil +} + +func (s *StepGetRootPassword) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Get Root Password") + + serverInstanceNo := state.Get("InstanceNo").(string) + loginKey := state.Get("LoginKey").(*LoginKey) + + rootPassword, err := s.GetRootPassword(serverInstanceNo, loginKey.PrivateKey) + + state.Put("Password", rootPassword) + + return processStepResult(err, s.Error, state) +} + +func (*StepGetRootPassword) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_get_rootpassword_test.go b/builder/ncloud/step_get_rootpassword_test.go new file mode 100644 index 000000000..b9ed6aa56 --- /dev/null +++ b/builder/ncloud/step_get_rootpassword_test.go @@ -0,0 +1,56 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepGetRootPasswordShouldFailIfOperationGetRootPasswordFails(t *testing.T) { + var testSubject = &StepGetRootPassword{ + GetRootPassword: func(string, string) (string, error) { return "", fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := DeleteTestStateBagStepGetRootPassword() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepGetRootPasswordShouldPassIfOperationGetRootPasswordPasses(t *testing.T) { + var testSubject = &StepGetRootPassword{ + GetRootPassword: func(string, string) (string, error) { return "a", nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := DeleteTestStateBagStepGetRootPassword() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func DeleteTestStateBagStepGetRootPassword() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("LoginKey", &LoginKey{"a", "b"}) + stateBag.Put("InstanceNo", "a") + + return stateBag +} diff --git a/builder/ncloud/step_stop_server_instance.go b/builder/ncloud/step_stop_server_instance.go new file mode 100644 index 000000000..1c9252ed2 --- /dev/null +++ b/builder/ncloud/step_stop_server_instance.go @@ -0,0 +1,64 @@ +package ncloud + +import ( + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepStopServerInstance struct { + Conn *ncloud.Conn + StopServerInstance func(serverInstanceNo string) error + Say func(message string) + Error func(e error) +} + +func NewStepStopServerInstance(conn *ncloud.Conn, ui packer.Ui) *StepStopServerInstance { + var step = &StepStopServerInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + } + + step.StopServerInstance = step.stopServerInstance + + return step +} + +func (s *StepStopServerInstance) stopServerInstance(serverInstanceNo string) error { + reqParams := new(ncloud.RequestStopServerInstances) + reqParams.ServerInstanceNoList = []string{serverInstanceNo} + + serverInstanceList, err := s.Conn.StopServerInstances(reqParams) + if err != nil { + return fmt.Errorf("error code: %d , error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + } + + s.Say(fmt.Sprintf("Server Instance is stopping. Server InstanceNo is %s", serverInstanceList.ServerInstanceList[0].ServerInstanceNo)) + log.Println("Server Instance information : ", serverInstanceList.ServerInstanceList[0]) + + if err := waiterServerInstanceStatus(s.Conn, serverInstanceNo, "NSTOP", 5*time.Minute); err != nil { + return err + } + + s.Say(fmt.Sprintf("Server Instance stopped. Server InstanceNo is %s", serverInstanceList.ServerInstanceList[0].ServerInstanceNo)) + + return nil +} + +func (s *StepStopServerInstance) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Stop Server Instance") + + var serverInstanceNo = state.Get("InstanceNo").(string) + + err := s.StopServerInstance(serverInstanceNo) + + return processStepResult(err, s.Error, state) +} + +func (*StepStopServerInstance) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_stop_server_instance_test.go b/builder/ncloud/step_stop_server_instance_test.go new file mode 100644 index 000000000..d90bc6953 --- /dev/null +++ b/builder/ncloud/step_stop_server_instance_test.go @@ -0,0 +1,55 @@ +package ncloud + +import ( + "fmt" + "testing" + + "github.com/mitchellh/multistep" +) + +func TestStepStopServerInstanceShouldFailIfOperationStopFails(t *testing.T) { + var testSubject = &StepStopServerInstance{ + StopServerInstance: func(serverInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepStopServerInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepStopServerInstanceShouldPassIfOperationStopPasses(t *testing.T) { + var testSubject = &StepStopServerInstance{ + StopServerInstance: func(serverInstanceNo string) error { return nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepStopServerInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepStopServerInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("InstanceNo", "a") + return stateBag +} diff --git a/builder/ncloud/step_terminate_server_instance.go b/builder/ncloud/step_terminate_server_instance.go new file mode 100644 index 000000000..5d60236f0 --- /dev/null +++ b/builder/ncloud/step_terminate_server_instance.go @@ -0,0 +1,81 @@ +package ncloud + +import ( + "errors" + "fmt" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" +) + +type StepTerminateServerInstance struct { + Conn *ncloud.Conn + TerminateServerInstance func(serverInstanceNo string) error + Say func(message string) + Error func(e error) +} + +func NewStepTerminateServerInstance(conn *ncloud.Conn, ui packer.Ui) *StepTerminateServerInstance { + var step = &StepTerminateServerInstance{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + } + + step.TerminateServerInstance = step.terminateServerInstance + + return step +} + +func (s *StepTerminateServerInstance) terminateServerInstance(serverInstanceNo string) error { + reqParams := new(ncloud.RequestTerminateServerInstances) + reqParams.ServerInstanceNoList = []string{serverInstanceNo} + + serverInstanceList, err := s.Conn.TerminateServerInstances(reqParams) + if err != nil { + return fmt.Errorf("error code: %d , error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + } + + c1 := make(chan error, 1) + + go func() { + reqParams := new(ncloud.RequestGetServerInstanceList) + reqParams.ServerInstanceNoList = []string{serverInstanceNo} + + for { + + serverInstanceList, err := s.Conn.GetServerInstanceList(reqParams) + if err != nil { + c1 <- fmt.Errorf("error code: %d , error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + return + } else if serverInstanceList.TotalRows == 0 { + c1 <- nil + return + } + + time.Sleep(time.Second * 3) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(time.Second * 60): + return errors.New("TIMEOUT : Can't terminate server instance") + } +} + +func (s *StepTerminateServerInstance) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Terminate Server Instance") + + var serverInstanceNo = state.Get("InstanceNo").(string) + + err := s.TerminateServerInstance(serverInstanceNo) + + return processStepResult(err, s.Error, state) +} + +func (*StepTerminateServerInstance) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_terminate_server_instance_test.go b/builder/ncloud/step_terminate_server_instance_test.go new file mode 100644 index 000000000..b5967fc65 --- /dev/null +++ b/builder/ncloud/step_terminate_server_instance_test.go @@ -0,0 +1,54 @@ +package ncloud + +import ( + "fmt" + "github.com/mitchellh/multistep" + "testing" +) + +func TestStepTerminateServerInstanceShouldFailIfOperationTerminationFails(t *testing.T) { + var testSubject = &StepTerminateServerInstance{ + TerminateServerInstance: func(serverInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepTerminateServerInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepTerminateServerInstanceShouldPassIfOperationTerminationPasses(t *testing.T) { + var testSubject = &StepTerminateServerInstance{ + TerminateServerInstance: func(serverInstanceNo string) error { return nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepTerminateServerInstance() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepTerminateServerInstance() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + stateBag.Put("InstanceNo", "a") + return stateBag +} diff --git a/builder/ncloud/step_validate_template.go b/builder/ncloud/step_validate_template.go new file mode 100644 index 000000000..0007bfa40 --- /dev/null +++ b/builder/ncloud/step_validate_template.go @@ -0,0 +1,263 @@ +package ncloud + +import ( + "bytes" + "errors" + "fmt" + "strings" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/packer" + "github.com/mitchellh/multistep" + "github.com/olekukonko/tablewriter" +) + +//StepValidateTemplate : struct for Validation a tempalte +type StepValidateTemplate struct { + Conn *ncloud.Conn + Validate func() error + Say func(message string) + Error func(e error) + Config *Config + zoneNo string + regionNo string +} + +// NewStepValidateTemplate : funciton for Validation a tempalte +func NewStepValidateTemplate(conn *ncloud.Conn, ui packer.Ui, config *Config) *StepValidateTemplate { + var step = &StepValidateTemplate{ + Conn: conn, + Say: func(message string) { ui.Say(message) }, + Error: func(e error) { ui.Error(e.Error()) }, + Config: config, + } + + step.Validate = step.validateTemplate + + return step +} + +// getZoneNo : get zoneNo +func (s *StepValidateTemplate) getZoneNo() error { + if s.Config.Region == "" { + return nil + } + + regionList, err := s.Conn.GetRegionList() + if err != nil { + return fmt.Errorf("error code: %d , error message: %s", regionList.ReturnCode, regionList.ReturnMessage) + } + + var regionNo string + for _, region := range regionList.RegionList { + if strings.EqualFold(region.RegionName, s.Config.Region) { + regionNo = region.RegionNo + } + } + + if regionNo == "" { + return fmt.Errorf("region %s is invalid", s.Config.Region) + } + + s.regionNo = regionNo + + // Get ZoneNo + ZoneList, err := s.Conn.GetZoneList(regionNo) + if err != nil { + return fmt.Errorf("error code: %d , error message: %s", ZoneList.ReturnCode, ZoneList.ReturnMessage) + } + + if len(ZoneList.Zone) > 0 { + s.zoneNo = ZoneList.Zone[0].ZoneNo + } + + return nil +} + +func (s *StepValidateTemplate) validateMemberServerImage() error { + var serverImageName = s.Config.ServerImageName + + reqParams := new(ncloud.RequestServerImageList) + reqParams.RegionNo = s.regionNo + + memberServerImageList, err := s.Conn.GetMemberServerImageList(reqParams) + if err != nil { + return err + } + + var isExistMemberServerImageNo = false + for _, image := range memberServerImageList.MemberServerImageList { + // Check duplicate server_image_name + if image.MemberServerImageName == serverImageName { + return fmt.Errorf("server_image_name %s is exists", serverImageName) + } + + if image.MemberServerImageNo == s.Config.MemberServerImageNo { + isExistMemberServerImageNo = true + if s.Config.ServerProductCode == "" { + s.Config.ServerProductCode = image.OriginalServerProductCode + s.Say("server_product_code for member server image '" + image.OriginalServerProductCode + "' is configured automatically") + } + s.Config.ServerImageProductCode = image.OriginalServerImageProductCode + } + } + + if s.Config.MemberServerImageNo != "" && !isExistMemberServerImageNo { + return fmt.Errorf("member_server_image_no %s does not exist", s.Config.MemberServerImageNo) + } + + return nil +} + +func (s *StepValidateTemplate) validateServerImageProduct() error { + var serverImageProductCode = s.Config.ServerImageProductCode + if serverImageProductCode == "" { + return nil + } + + reqParams := new(ncloud.RequestGetServerImageProductList) + reqParams.RegionNo = s.regionNo + + serverImageProductList, err := s.Conn.GetServerImageProductList(reqParams) + if err != nil { + return err + } + + var isExistServerImage = false + var buf bytes.Buffer + var productName string + table := tablewriter.NewWriter(&buf) + table.SetHeader([]string{"Name", "Code"}) + + for _, product := range serverImageProductList.Product { + // Check exist server image product code + if product.ProductCode == serverImageProductCode { + isExistServerImage = true + productName = product.ProductName + break + } + + table.Append([]string{product.ProductName, product.ProductCode}) + } + + if !isExistServerImage { + reqParams.BlockStorageSize = 100 + + serverImageProductList, err := s.Conn.GetServerImageProductList(reqParams) + if err != nil { + return err + } + + for _, product := range serverImageProductList.Product { + // Check exist server image product code + if product.ProductCode == serverImageProductCode { + isExistServerImage = true + productName = product.ProductName + break + } + + table.Append([]string{product.ProductName, product.ProductCode}) + } + } + + if !isExistServerImage { + table.Render() + s.Say(buf.String()) + + return fmt.Errorf("server_image_product_code %s does not exist", serverImageProductCode) + } + + if strings.Contains(productName, "mssql") { + s.Config.FeeSystemTypeCode = "FXSUM" + } + + return nil +} + +func (s *StepValidateTemplate) validateServerProductCode() error { + var serverImageProductCode = s.Config.ServerImageProductCode + var productCode = s.Config.ServerProductCode + + reqParams := new(ncloud.RequestGetServerProductList) + reqParams.ServerImageProductCode = serverImageProductCode + reqParams.RegionNo = s.regionNo + + productList, err := s.Conn.GetServerProductList(reqParams) + if err != nil { + return err + } + + var isExistProductCode = false + for _, product := range productList.Product { + // Check exist server image product code + if product.ProductCode == productCode { + isExistProductCode = true + if strings.Contains(product.ProductName, "mssql") { + s.Config.FeeSystemTypeCode = "FXSUM" + } + + if product.ProductType.Code == "VDS" { + return errors.New("You cannot create my server image for VDS servers") + } + + break + } else if productCode == "" && product.ProductType.Code == "STAND" { + isExistProductCode = true + s.Config.ServerProductCode = product.ProductCode + s.Say("server_product_code '" + product.ProductCode + "' is configured automatically") + break + } + } + + if !isExistProductCode { + var buf bytes.Buffer + table := tablewriter.NewWriter(&buf) + table.SetHeader([]string{"Name", "Code"}) + for _, product := range productList.Product { + table.Append([]string{product.ProductName, product.ProductCode}) + } + table.Render() + + s.Say(buf.String()) + + return fmt.Errorf("server_product_code %s does not exist", productCode) + } + + return nil +} + +// Check ImageName / Product Code / Server Image Product Code / Server Product Code... +func (s *StepValidateTemplate) validateTemplate() error { + // Get RegionNo, ZoneNo + if err := s.getZoneNo(); err != nil { + return err + } + + // Validate member_server_image_no and member_server_image_no + if err := s.validateMemberServerImage(); err != nil { + return err + } + + // Validate server_image_product_code + if err := s.validateServerImageProduct(); err != nil { + return err + } + + // Validate server_product_code + return s.validateServerProductCode() +} + +// Run : main funciton for validation a template +func (s *StepValidateTemplate) Run(state multistep.StateBag) multistep.StepAction { + s.Say("Validating deployment template ...") + + err := s.Validate() + + state.Put("ZoneNo", s.zoneNo) + + return processStepResult(err, s.Error, state) +} + +// Cleanup : cleanup on error +func (s *StepValidateTemplate) Cleanup(multistep.StateBag) { +} diff --git a/builder/ncloud/step_validate_template_test.go b/builder/ncloud/step_validate_template_test.go new file mode 100644 index 000000000..98f45b4a0 --- /dev/null +++ b/builder/ncloud/step_validate_template_test.go @@ -0,0 +1,54 @@ +package ncloud + +import ( + "fmt" + "testing" + + "github.com/mitchellh/multistep" +) + +func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) { + var testSubject = &StepValidateTemplate{ + Validate: func() error { return fmt.Errorf("!! Unit Test FAIL !!") }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepValidateTemplate() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionHalt { + t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == false { + t.Fatal("Expected the step to set stateBag['Error'], but it was not.") + } +} + +func TestStepValidateTemplateShouldPassIfValidatePasses(t *testing.T) { + var testSubject = &StepValidateTemplate{ + Validate: func() error { return nil }, + Say: func(message string) {}, + Error: func(e error) {}, + } + + stateBag := createTestStateBagStepValidateTemplate() + + var result = testSubject.Run(stateBag) + + if result != multistep.ActionContinue { + t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) + } + + if _, ok := stateBag.GetOk("Error"); ok == true { + t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") + } +} + +func createTestStateBagStepValidateTemplate() multistep.StateBag { + stateBag := new(multistep.BasicStateBag) + + return stateBag +} diff --git a/builder/ncloud/waiter_block_storage_instance.go b/builder/ncloud/waiter_block_storage_instance.go new file mode 100644 index 000000000..9cfa5562a --- /dev/null +++ b/builder/ncloud/waiter_block_storage_instance.go @@ -0,0 +1,80 @@ +package ncloud + +import ( + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" +) + +func waiterBlockStorageInstanceStatus(conn *ncloud.Conn, blockStorageInstanceNo string, status string, timeout time.Duration) error { + reqParams := new(ncloud.RequestBlockStorageInstanceList) + reqParams.BlockStorageInstanceNoList = []string{blockStorageInstanceNo} + + c1 := make(chan error, 1) + + go func() { + for { + blockStorageInstanceList, err := conn.GetBlockStorageInstance(reqParams) + if err != nil { + c1 <- err + return + } + + if status == "DETAC" && len(blockStorageInstanceList.BlockStorageInstance) == 0 { + c1 <- nil + return + } + + code := blockStorageInstanceList.BlockStorageInstance[0].BlockStorageInstanceStatus.Code + operationCode := blockStorageInstanceList.BlockStorageInstance[0].BlockStorageInstanceOperation.Code + + if code == status && operationCode == "NULL" { + c1 <- nil + return + } + + log.Println(blockStorageInstanceList.BlockStorageInstance[0]) + time.Sleep(time.Second * 5) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(timeout): + return fmt.Errorf("TIMEOUT : block storage instance status is not changed into status %s", status) + } +} + +func waiterDetachedBlockStorageInstance(conn *ncloud.Conn, serverInstanceNo string, timeout time.Duration) error { + reqParams := new(ncloud.RequestBlockStorageInstanceList) + reqParams.ServerInstanceNo = serverInstanceNo + + c1 := make(chan error, 1) + + go func() { + for { + blockStorageInstanceList, err := conn.GetBlockStorageInstance(reqParams) + if err != nil { + c1 <- err + return + } + + if blockStorageInstanceList.TotalRows == 1 { + c1 <- nil + return + } + + time.Sleep(time.Second * 5) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(timeout): + return fmt.Errorf("TIMEOUT : attached block storage instance is not detached") + } +} diff --git a/builder/ncloud/waiter_server_image_status.go b/builder/ncloud/waiter_server_image_status.go new file mode 100644 index 000000000..5ba640874 --- /dev/null +++ b/builder/ncloud/waiter_server_image_status.go @@ -0,0 +1,43 @@ +package ncloud + +import ( + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" +) + +func waiterMemberServerImageStatus(conn *ncloud.Conn, memberServerImageNo string, status string, timeout time.Duration) error { + reqParams := new(ncloud.RequestServerImageList) + reqParams.MemberServerImageNoList = []string{memberServerImageNo} + + c1 := make(chan error, 1) + + go func() { + for { + memberServerImageList, err := conn.GetMemberServerImageList(reqParams) + if err != nil { + c1 <- err + return + } + + code := memberServerImageList.MemberServerImageList[0].MemberServerImageStatus.Code + if code == status { + c1 <- nil + return + } + + log.Printf("Status of member server image [%s] is %s\n", memberServerImageNo, code) + log.Println(memberServerImageList.MemberServerImageList[0]) + time.Sleep(time.Second * 5) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(timeout): + return fmt.Errorf("TIMEOUT : member server image status is not changed into status %s", status) + } +} diff --git a/builder/ncloud/waiter_server_instance_status.go b/builder/ncloud/waiter_server_instance_status.go new file mode 100644 index 000000000..176cde701 --- /dev/null +++ b/builder/ncloud/waiter_server_instance_status.go @@ -0,0 +1,43 @@ +package ncloud + +import ( + "fmt" + "log" + "time" + + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" +) + +func waiterServerInstanceStatus(conn *ncloud.Conn, serverInstanceNo string, status string, timeout time.Duration) error { + reqParams := new(ncloud.RequestGetServerInstanceList) + reqParams.ServerInstanceNoList = []string{serverInstanceNo} + + c1 := make(chan error, 1) + + go func() { + for { + serverInstanceList, err := conn.GetServerInstanceList(reqParams) + if err != nil { + c1 <- err + return + } + + code := serverInstanceList.ServerInstanceList[0].ServerInstanceStatus.Code + if code == status { + c1 <- nil + return + } + + log.Printf("Status of serverInstanceNo [%s] is %s\n", serverInstanceNo, code) + log.Println(serverInstanceList.ServerInstanceList[0]) + time.Sleep(time.Second * 5) + } + }() + + select { + case res := <-c1: + return res + case <-time.After(timeout): + return fmt.Errorf("TIMEOUT : server instance status is not changed into status %s", status) + } +} diff --git a/command/plugin.go b/command/plugin.go index d9e7ea577..73a04a035 100644 --- a/command/plugin.go +++ b/command/plugin.go @@ -29,6 +29,7 @@ import ( hypervvmcxbuilder "github.com/hashicorp/packer/builder/hyperv/vmcx" lxcbuilder "github.com/hashicorp/packer/builder/lxc" lxdbuilder "github.com/hashicorp/packer/builder/lxd" + ncloudbuilder "github.com/hashicorp/packer/builder/ncloud" nullbuilder "github.com/hashicorp/packer/builder/null" oneandonebuilder "github.com/hashicorp/packer/builder/oneandone" openstackbuilder "github.com/hashicorp/packer/builder/openstack" @@ -96,6 +97,7 @@ var Builders = map[string]packer.Builder{ "hyperv-vmcx": new(hypervvmcxbuilder.Builder), "lxc": new(lxcbuilder.Builder), "lxd": new(lxdbuilder.Builder), + "ncloud": new(ncloudbuilder.Builder), "null": new(nullbuilder.Builder), "oneandone": new(oneandonebuilder.Builder), "openstack": new(openstackbuilder.Builder), From 4f9754a75c79b70bf795a2286766571440bfb1f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Thu, 11 Jan 2018 19:41:47 +0900 Subject: [PATCH 02/17] add ncloud-sdk-go dependency to vendor --- .../NaverCloudPlatform/ncloud-sdk-go/LICENSE | 7 + .../NaverCloudPlatform/ncloud-sdk-go/NOTICE | 26 ++ .../ncloud-sdk-go/common/commonResponse.go | 14 + .../ncloud-sdk-go/common/commoncode.go | 10 + .../common/parseErrorResponse.go | 20 + .../ncloud-sdk-go/common/region.go | 7 + .../ncloud-sdk-go/common/zone.go | 7 + .../ncloud-sdk-go/oauth/oauth.go | 370 ++++++++++++++++++ .../ncloud-sdk-go/request/request.go | 38 ++ .../ncloud-sdk-go/sdk/connection.go | 21 + .../sdk/createBlockStorageInstance.go | 87 ++++ .../ncloud-sdk-go/sdk/createLoginKey.go | 64 +++ .../sdk/createPublicIpInstance.go | 74 ++++ .../ncloud-sdk-go/sdk/createServerImage.go | 71 ++++ .../sdk/createServerInstances.go | 148 +++++++ .../sdk/deleteBlockStorageInstances.go | 60 +++ .../ncloud-sdk-go/sdk/deleteLoginKey.go | 59 +++ .../sdk/deletePublicIpInstances.go | 62 +++ .../disassociatePublicIpFromServerInstance.go | 54 +++ .../sdk/getAccessControlGroupList.go | 89 +++++ .../sdk/getAccessControlRuleList.go | 61 +++ .../sdk/getBlockStorageInstanceList.go | 144 +++++++ .../ncloud-sdk-go/sdk/getLoginKeyList.go | 77 ++++ .../sdk/getMemberServerImagesList.go | 87 ++++ .../sdk/getPublicIpInstanceList.go | 130 ++++++ .../ncloud-sdk-go/sdk/getRegionList.go | 40 ++ .../ncloud-sdk-go/sdk/getRootPassword.go | 67 ++++ .../sdk/getServerImageProductList.go | 88 +++++ .../sdk/getServerInstanceList.go | 133 +++++++ .../ncloud-sdk-go/sdk/getServerProductList.go | 79 ++++ .../ncloud-sdk-go/sdk/getZoneList.go | 44 +++ .../ncloud-sdk-go/sdk/model.go | 359 +++++++++++++++++ .../ncloud-sdk-go/sdk/stopServerInstances.go | 62 +++ .../sdk/terminateServerInstances.go | 62 +++ vendor/vendor.json | 24 ++ 35 files changed, 2745 insertions(+) create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/LICENSE create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/NOTICE create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commonResponse.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commoncode.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/parseErrorResponse.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/region.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/zone.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/oauth/oauth.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/request/request.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/connection.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createBlockStorageInstance.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createLoginKey.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createPublicIpInstance.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerImage.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerInstances.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteBlockStorageInstances.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteLoginKey.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deletePublicIpInstances.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/disassociatePublicIpFromServerInstance.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlGroupList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlRuleList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getBlockStorageInstanceList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getLoginKeyList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getMemberServerImagesList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getPublicIpInstanceList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRegionList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRootPassword.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerImageProductList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerInstanceList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerProductList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getZoneList.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/model.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/stopServerInstances.go create mode 100644 vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/terminateServerInstances.go diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/LICENSE b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/LICENSE new file mode 100644 index 000000000..4ae922683 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/LICENSE @@ -0,0 +1,7 @@ +Copyright 2017 NAVER BUSINESS PLATFORM Corp. + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/NOTICE b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/NOTICE new file mode 100644 index 000000000..f495434a4 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/NOTICE @@ -0,0 +1,26 @@ +ncp-sdk-go + +This project contains subcomponents with separate copyright notices and license terms. +Your use of the source code for these subcomponents is subject to the terms and conditions of the following licenses. + +======================================================================= +OAuth 1.0 Library for Go (https://github.com/mrjones/oauth/) +======================================================================= + +Copyright (C) 2013 Matthew R. Jones + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commonResponse.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commonResponse.go new file mode 100644 index 000000000..33f12f983 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commonResponse.go @@ -0,0 +1,14 @@ +package common + +import "encoding/xml" + +type CommonResponse struct { + RequestID string `xml:"requestId"` + ReturnCode int `xml:"returnCode"` + ReturnMessage string `xml:"returnMessage"` +} + +type ResponseError struct { + ResponseError xml.Name `xml:"responseError"` + CommonResponse +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commoncode.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commoncode.go new file mode 100644 index 000000000..aff8bcf98 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/commoncode.go @@ -0,0 +1,10 @@ +package common + +type CommonCode struct { + CodeKind string `xml:"codeKind"` + DetailCategorizeCode string `xml:"detailCategorizeCode"` + Code string `xml:"code"` + CodeName string `xml:"codeName"` + CodeOrder int `xml:"codeOrder"` + JavaConstantCode string `xml:"javaConstantCode"` +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/parseErrorResponse.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/parseErrorResponse.go new file mode 100644 index 000000000..10c76f58c --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/parseErrorResponse.go @@ -0,0 +1,20 @@ +package common + +import ( + "encoding/xml" + "strings" +) + +func ParseErrorResponse(bytes []byte) (*ResponseError, error) { + responseError := ResponseError{} + + if err := xml.Unmarshal([]byte(bytes), &responseError); err != nil { + return nil, err + } + + if responseError.ReturnMessage != "" { + responseError.ReturnMessage = strings.TrimSpace(responseError.ReturnMessage) + } + + return &responseError, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/region.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/region.go new file mode 100644 index 000000000..eaa055f6e --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/region.go @@ -0,0 +1,7 @@ +package common + +type Region struct { + RegionNo string `xml:"regionNo"` + RegionCode string `xml:"regionCode"` + RegionName string `xml:"regionName"` +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/zone.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/zone.go new file mode 100644 index 000000000..f2ec78381 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/common/zone.go @@ -0,0 +1,7 @@ +package common + +type Zone struct { + ZoneNo string `xml:"zoneNo"` + ZoneName string `xml:"zoneName"` + ZoneDescription string `xml:"zoneDescription"` +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/oauth/oauth.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/oauth/oauth.go new file mode 100644 index 000000000..c6b917b4c --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/oauth/oauth.go @@ -0,0 +1,370 @@ +package oauth + +import ( + "crypto" + "crypto/hmac" + _ "crypto/sha1" + "encoding/base64" + "fmt" + "math/rand" + "net/url" + "os" + "sort" + "strconv" + "sync" + "time" +) + +const ( + OAUTH_VERSION = "1.0" + SIGNATURE_METHOD_HMAC = "HMAC-" + + HTTP_AUTH_HEADER = "Authorization" + OAUTH_HEADER = "OAuth " + CONSUMER_KEY_PARAM = "oauth_consumer_key" + NONCE_PARAM = "oauth_nonce" + SIGNATURE_METHOD_PARAM = "oauth_signature_method" + SIGNATURE_PARAM = "oauth_signature" + TIMESTAMP_PARAM = "oauth_timestamp" + TOKEN_PARAM = "oauth_token" + TOKEN_SECRET_PARAM = "oauth_token_secret" + VERSION_PARAM = "oauth_version" +) + +var HASH_METHOD_MAP = map[crypto.Hash]string{ + crypto.SHA1: "SHA1", + crypto.SHA256: "SHA256", +} + +// Creates a new Consumer instance, with a HMAC-SHA1 signer +func NewConsumer(consumerKey string, consumerSecret string, requestMethod string, requestURL string) *Consumer { + clock := &defaultClock{} + consumer := &Consumer{ + consumerKey: consumerKey, + consumerSecret: consumerSecret, + requestMethod: requestMethod, + requestURL: requestURL, + clock: clock, + nonceGenerator: newLockedNonceGenerator(clock), + + AdditionalParams: make(map[string]string), + } + + consumer.signer = &HMACSigner{ + consumerSecret: consumerSecret, + hashFunc: crypto.SHA1, + } + + return consumer +} + +// lockedNonceGenerator wraps a non-reentrant random number generator with alock +type lockedNonceGenerator struct { + nonceGenerator nonceGenerator + lock sync.Mutex +} + +func newLockedNonceGenerator(c clock) *lockedNonceGenerator { + return &lockedNonceGenerator{ + nonceGenerator: rand.New(rand.NewSource(c.Nanos())), + } +} + +func (n *lockedNonceGenerator) Int63() int64 { + n.lock.Lock() + r := n.nonceGenerator.Int63() + n.lock.Unlock() + return r +} + +type clock interface { + Seconds() int64 + Nanos() int64 +} + +type nonceGenerator interface { + Int63() int64 +} + +type signer interface { + Sign(message string) (string, error) + Verify(message string, signature string) error + SignatureMethod() string + HashFunc() crypto.Hash + Debug(enabled bool) +} + +type defaultClock struct{} + +func (*defaultClock) Seconds() int64 { + return time.Now().Unix() +} + +func (*defaultClock) Nanos() int64 { + return time.Now().UnixNano() +} + +type Consumer struct { + AdditionalParams map[string]string + + // The rest of this class is configured via the NewConsumer function. + consumerKey string + + consumerSecret string + + requestMethod string + + requestURL string + + debug bool + + // Private seams for mocking dependencies when testing + clock clock + // Seeded generators are not reentrant + nonceGenerator nonceGenerator + signer signer +} + +type HMACSigner struct { + consumerSecret string + hashFunc crypto.Hash + debug bool +} + +func (s *HMACSigner) Debug(enabled bool) { + s.debug = enabled +} + +func (s *HMACSigner) Sign(message string) (string, error) { + key := escape(s.consumerSecret) + if s.debug { + fmt.Println("Signing:", message) + fmt.Println("Key:", key) + } + + h := hmac.New(s.HashFunc().New, []byte(key+"&")) + h.Write([]byte(message)) + rawSignature := h.Sum(nil) + + base64signature := base64.StdEncoding.EncodeToString(rawSignature) + if s.debug { + fmt.Println("Base64 signature:", base64signature) + } + return base64signature, nil +} + +func (s *HMACSigner) Verify(message string, signature string) error { + if s.debug { + fmt.Println("Verifying Base64 signature:", signature) + } + validSignature, err := s.Sign(message) + if err != nil { + return err + } + + if validSignature != signature { + decodedSigniture, _ := url.QueryUnescape(signature) + if validSignature != decodedSigniture { + return fmt.Errorf("signature did not match") + } + } + + return nil +} + +func (s *HMACSigner) SignatureMethod() string { + return SIGNATURE_METHOD_HMAC + HASH_METHOD_MAP[s.HashFunc()] +} + +func (s *HMACSigner) HashFunc() crypto.Hash { + return s.hashFunc +} + +func escape(s string) string { + t := make([]byte, 0, 3*len(s)) + for i := 0; i < len(s); i++ { + c := s[i] + if isEscapable(c) { + t = append(t, '%') + t = append(t, "0123456789ABCDEF"[c>>4]) + t = append(t, "0123456789ABCDEF"[c&15]) + } else { + t = append(t, s[i]) + } + } + return string(t) +} + +func isEscapable(b byte) bool { + return !('A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' || b == '-' || b == '.' || b == '_' || b == '~') +} + +func (c *Consumer) Debug(enabled bool) { + c.debug = enabled + c.signer.Debug(enabled) +} + +func (c *Consumer) GetRequestUrl() (loginUrl string, err error) { + if os.Getenv("GO_ENV") == "development" { + c.AdditionalParams["approachKey"] = c.consumerKey + c.AdditionalParams["secretKey"] = c.consumerSecret + } + c.AdditionalParams["responseFormatType"] = "xml" + + params := c.baseParams(c.consumerKey, c.AdditionalParams) + + if c.debug { + fmt.Println("params:", params) + } + + req := &request{ + method: c.requestMethod, + url: c.requestURL, + oauthParams: params, + } + + signature, err := c.signRequest(req) + if err != nil { + return "", err + } + + result := req.url + "?" + for pos, key := range req.oauthParams.Keys() { + for innerPos, value := range req.oauthParams.Get(key) { + if pos+innerPos != 0 { + result += "&" + } + result += fmt.Sprintf("%s=%s", key, value) + } + } + + result += fmt.Sprintf("&%s=%s", SIGNATURE_PARAM, escape(signature)) + + if c.debug { + fmt.Println("req: ", result) + } + + return result, nil +} + +func (c *Consumer) baseParams(consumerKey string, additionalParams map[string]string) *OrderedParams { + params := NewOrderedParams() + params.Add(VERSION_PARAM, OAUTH_VERSION) + params.Add(SIGNATURE_METHOD_PARAM, c.signer.SignatureMethod()) + params.Add(TIMESTAMP_PARAM, strconv.FormatInt(c.clock.Seconds(), 10)) + params.Add(NONCE_PARAM, strconv.FormatInt(c.nonceGenerator.Int63(), 10)) + params.Add(CONSUMER_KEY_PARAM, consumerKey) + + for key, value := range additionalParams { + params.Add(key, value) + } + + return params +} + +func (c *Consumer) signRequest(req *request) (string, error) { + baseString := c.requestString(req.method, req.url, req.oauthParams) + + if c.debug { + fmt.Println("baseString: ", baseString) + } + + signature, err := c.signer.Sign(baseString) + if err != nil { + return "", err + } + + return signature, nil +} + +func (c *Consumer) requestString(method string, url string, params *OrderedParams) string { + result := method + "&" + escape(url) + for pos, key := range params.Keys() { + for innerPos, value := range params.Get(key) { + if pos+innerPos == 0 { + result += "&" + } else { + result += escape("&") + } + result += escape(fmt.Sprintf("%s=%s", key, value)) + } + } + return result +} + +type request struct { + method string + url string + oauthParams *OrderedParams + userParams map[string]string +} + +// +// String Sorting helpers +// + +type ByValue []string + +func (a ByValue) Len() int { + return len(a) +} + +func (a ByValue) Swap(i, j int) { + a[i], a[j] = a[j], a[i] +} + +func (a ByValue) Less(i, j int) bool { + return a[i] < a[j] +} + +// +// ORDERED PARAMS +// + +type OrderedParams struct { + allParams map[string][]string + keyOrdering []string +} + +func NewOrderedParams() *OrderedParams { + return &OrderedParams{ + allParams: make(map[string][]string), + keyOrdering: make([]string, 0), + } +} + +func (o *OrderedParams) Get(key string) []string { + sort.Sort(ByValue(o.allParams[key])) + return o.allParams[key] +} + +func (o *OrderedParams) Keys() []string { + sort.Sort(o) + return o.keyOrdering +} + +func (o *OrderedParams) Add(key, value string) { + o.AddUnescaped(key, escape(value)) +} + +func (o *OrderedParams) AddUnescaped(key, value string) { + if _, exists := o.allParams[key]; !exists { + o.keyOrdering = append(o.keyOrdering, key) + o.allParams[key] = make([]string, 1) + o.allParams[key][0] = value + } else { + o.allParams[key] = append(o.allParams[key], value) + } +} + +func (o *OrderedParams) Len() int { + return len(o.keyOrdering) +} + +func (o *OrderedParams) Less(i int, j int) bool { + return o.keyOrdering[i] < o.keyOrdering[j] +} + +func (o *OrderedParams) Swap(i int, j int) { + o.keyOrdering[i], o.keyOrdering[j] = o.keyOrdering[j], o.keyOrdering[i] +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/request/request.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/request/request.go new file mode 100644 index 000000000..2f0d77d14 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/request/request.go @@ -0,0 +1,38 @@ +package request + +import ( + "io/ioutil" + "net/http" + + "github.com/NaverCloudPlatform/ncloud-sdk-go/oauth" +) + +// NewRequest is http request with oauth +func NewRequest(accessKey string, secretKey string, method string, url string, params map[string]string) ([]byte, *http.Response, error) { + c := oauth.NewConsumer(accessKey, secretKey, method, url) + + for k, v := range params { + c.AdditionalParams[k] = v + } + + reqURL, err := c.GetRequestUrl() + if err != nil { + return nil, nil, err + } + + req, err := http.NewRequest(method, reqURL, nil) + if err != nil { + return nil, nil, err + } + + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return nil, nil, err + } + defer resp.Body.Close() + + bytes, _ := ioutil.ReadAll(resp.Body) + + return bytes, resp, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/connection.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/connection.go new file mode 100644 index 000000000..27f8a6197 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/connection.go @@ -0,0 +1,21 @@ +package sdk + +import ( + "os" +) + +// NewConnection create connection for server api +func NewConnection(accessKey string, secretKey string) *Conn { + conn := &Conn{ + accessKey: accessKey, + secretKey: secretKey, + apiURL: "https://api.ncloud.com/", + } + + // for other phase(dev, test, beta ...) test + if os.Getenv("NCLOUD_API_GW") != "" { + conn.apiURL = os.Getenv("NCLOUD_API_GW") + } + + return conn +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createBlockStorageInstance.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createBlockStorageInstance.go new file mode 100644 index 000000000..3fd8e61b7 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createBlockStorageInstance.go @@ -0,0 +1,87 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processCreateBlockStorageInstanceParams(reqParams *RequestBlockStorageInstance) (map[string]string, error) { + params := make(map[string]string) + + if reqParams.BlockStorageName != "" { + if len := len(reqParams.BlockStorageName); len < 3 || len > 30 { + return nil, errors.New("Length of BlockStorageName should be min 3 or max 30") + } + params["blockStorageName"] = reqParams.BlockStorageName + } + + if reqParams.BlockStorageSize < 10 || reqParams.BlockStorageSize > 2000 { + return nil, errors.New("BlockStorageSize should be min 10 or max 2000") + } + + if reqParams.BlockStorageDescription != "" { + if len := len(reqParams.BlockStorageDescription); len > 1000 { + return nil, errors.New("Length of BlockStorageDescription should be max 1000") + } + params["blockStorageDescription"] = reqParams.BlockStorageDescription + } + + if int(reqParams.BlockStorageSize/10)*10 != reqParams.BlockStorageSize { + return nil, errors.New("BlockStorageSize must be a multiple of 10 GB") + } + + if reqParams.BlockStorageSize == 0 { + return nil, errors.New("BlockStorageSize field is required") + } + + params["blockStorageSize"] = strconv.Itoa(reqParams.BlockStorageSize) + + if reqParams.ServerInstanceNo == "" { + return nil, errors.New("ServerInstanceNo field is required") + } + + params["serverInstanceNo"] = reqParams.ServerInstanceNo + + return params, nil +} + +// CreateBlockStorageInstance create block storage instance +func (s *Conn) CreateBlockStorageInstance(reqParams *RequestBlockStorageInstance) (*BlockStorageInstanceList, error) { + + params, err := processCreateBlockStorageInstanceParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "createBlockStorageInstance" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := BlockStorageInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var blockStorageInstanceList = BlockStorageInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &blockStorageInstanceList); err != nil { + return nil, err + } + + return &blockStorageInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createLoginKey.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createLoginKey.go new file mode 100644 index 000000000..b2cd490dc --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createLoginKey.go @@ -0,0 +1,64 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strings" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processCreateLoginKeyParams(keyName string) error { + if keyName == "" { + return errors.New("KeyName is required field") + } + + if len := len(keyName); len < 3 || len > 30 { + return errors.New("Length of KeyName should be min 3 or max 30") + } + + return nil +} + +// CreateLoginKey create loginkey with keyName +func (s *Conn) CreateLoginKey(keyName string) (*PrivateKey, error) { + if err := processCreateLoginKeyParams(keyName); err != nil { + return nil, err + } + + params := make(map[string]string) + + params["keyName"] = keyName + params["action"] = "createLoginKey" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := PrivateKey{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + privateKey := PrivateKey{} + if err := xml.Unmarshal([]byte(bytes), &privateKey); err != nil { + return nil, err + } + + if privateKey.PrivateKey != "" { + privateKey.PrivateKey = strings.TrimSpace(privateKey.PrivateKey) + } + + return &privateKey, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createPublicIpInstance.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createPublicIpInstance.go new file mode 100644 index 000000000..6dc5aa0fe --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createPublicIpInstance.go @@ -0,0 +1,74 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processCreatePublicIPInstanceParams(reqParams *RequestCreatePublicIPInstance) (map[string]string, error) { + params := make(map[string]string) + + if reqParams.ServerInstanceNo != "" { + params["serverInstanceNo"] = reqParams.ServerInstanceNo + } + + if reqParams.PublicIPDescription != "" { + if len := len(reqParams.PublicIPDescription); len > 1000 { + return params, errors.New("Length of publicIpDescription should be max 1000") + } + params["publicIpDescription"] = reqParams.PublicIPDescription + } + + if reqParams.InternetLineTypeCode != "" { + if reqParams.InternetLineTypeCode != "PUBLC" && reqParams.InternetLineTypeCode != "GLBL" { + return params, errors.New("InternetLineTypeCode should be PUBLC or GLBL") + } + params["internetLineTypeCode"] = reqParams.InternetLineTypeCode + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + return params, nil +} + +// CreatePublicIPInstance create public ip instance and allocate it to server instance +func (s *Conn) CreatePublicIPInstance(reqParams *RequestCreatePublicIPInstance) (*PublicIPInstanceList, error) { + params, err := processCreatePublicIPInstanceParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "createPublicIpInstance" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := PublicIPInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var responseCreatePublicIPInstances = PublicIPInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &responseCreatePublicIPInstances); err != nil { + fmt.Println(err) + return nil, err + } + + return &responseCreatePublicIPInstances, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerImage.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerImage.go new file mode 100644 index 000000000..11fb9b308 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerImage.go @@ -0,0 +1,71 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processCreateMemberServerImageParams(reqParams *RequestCreateServerImage) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil || reqParams.ServerInstanceNo == "" { + return params, errors.New("ServerInstanceNo is required field") + } + + if reqParams.MemberServerImageName != "" { + if len := len(reqParams.MemberServerImageName); len < 3 || len > 30 { + return nil, errors.New("Length of MemberServerImageName should be min 3 or max 30") + } + params["memberServerImageName"] = reqParams.MemberServerImageName + } + + if reqParams.MemberServerImageDescription != "" { + if len := len(reqParams.MemberServerImageDescription); len > 1000 { + return nil, errors.New("Length of MemberServerImageDescription should be smaller than 1000") + } + params["memberServerImageDescription"] = reqParams.MemberServerImageDescription + } + + params["serverInstanceNo"] = reqParams.ServerInstanceNo + + return params, nil +} + +// CreateMemberServerImage create member server image and retrun member server image list +func (s *Conn) CreateMemberServerImage(reqParams *RequestCreateServerImage) (*MemberServerImageList, error) { + params, err := processCreateMemberServerImageParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "createMemberServerImage" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := MemberServerImageList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var serverImageListsResp = MemberServerImageList{} + if err := xml.Unmarshal([]byte(bytes), &serverImageListsResp); err != nil { + return nil, err + } + + return &serverImageListsResp, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerInstances.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerInstances.go new file mode 100644 index 000000000..a00da9145 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/createServerInstances.go @@ -0,0 +1,148 @@ +package sdk + +import ( + "encoding/base64" + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processCreateServerInstancesParams(reqParams *RequestCreateServerInstance) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if reqParams.ServerImageProductCode != "" { + if len := len(reqParams.ServerImageProductCode); len > 20 { + return nil, errors.New("Length of ServerImageProductCode should be min 1 or max 20") + } + params["serverImageProductCode"] = reqParams.ServerImageProductCode + } + + if reqParams.ServerProductCode != "" { + if len := len(reqParams.ServerProductCode); len > 20 { + return nil, errors.New("Length of ServerProductCode should be min 1 or max 20") + } + params["serverProductCode"] = reqParams.ServerProductCode + } + + if reqParams.MemberServerImageNo != "" { + params["memberServerImageNo"] = reqParams.MemberServerImageNo + } + + if reqParams.ServerName != "" { + if len := len(reqParams.ServerName); len < 3 || len > 30 { + return nil, errors.New("Length of ServerName should be min 3 or max 30") + } + params["serverName"] = reqParams.ServerName + } + + if reqParams.ServerDescription != "" { + if len := len(reqParams.ServerDescription); len > 1000 { + return nil, errors.New("Length of ServerDescription should be min 1 or max 1000") + } + params["serverDescription"] = reqParams.ServerDescription + } + + if reqParams.LoginKeyName != "" { + if len := len(reqParams.LoginKeyName); len < 3 || len > 30 { + return nil, errors.New("Length of LoginKeyName should be min 3 or max 30") + } + params["loginKeyName"] = reqParams.LoginKeyName + } + + if reqParams.IsProtectServerTermination == true { + params["isProtectServerTermination"] = "true" + } + + if reqParams.ServerCreateCount > 0 { + if reqParams.ServerCreateCount > 20 { + return nil, errors.New("ServerCreateCount should be min 1 or max 20") + + } + params["serverCreateCount"] = strconv.Itoa(reqParams.ServerCreateCount) + } + + if reqParams.ServerCreateStartNo > 0 { + if reqParams.ServerCreateCount+reqParams.ServerCreateStartNo > 1000 { + return nil, errors.New("Sum of ServerCreateCount and ServerCreateStartNo should be less than 1000") + + } + params["serverCreateStartNo"] = strconv.Itoa(reqParams.ServerCreateStartNo) + } + + if reqParams.InternetLineTypeCode != "" { + if reqParams.InternetLineTypeCode != "PUBLC" && reqParams.InternetLineTypeCode != "GLBL" { + return nil, errors.New("InternetLineTypeCode should be PUBLC or GLBL") + } + params["internetLineTypeCode"] = reqParams.InternetLineTypeCode + } + + if reqParams.FeeSystemTypeCode != "" { + if reqParams.FeeSystemTypeCode != "FXSUM" && reqParams.FeeSystemTypeCode != "MTRAT" { + return nil, errors.New("FeeSystemTypeCode should be FXSUM or MTRAT") + } + params["feeSystemTypeCode"] = reqParams.FeeSystemTypeCode + } + + if reqParams.UserData != "" { + if len := len(reqParams.UserData); len > 21847 { + return nil, errors.New("Length of UserData should be min 1 or max 21847") + } + params["userData"] = base64.StdEncoding.EncodeToString([]byte(reqParams.UserData)) + } + + if reqParams.ZoneNo != "" { + params["zoneNo"] = reqParams.ZoneNo + } + + if len(reqParams.AccessControlGroupConfigurationNoList) > 0 { + for k, v := range reqParams.AccessControlGroupConfigurationNoList { + params[fmt.Sprintf("accessControlGroupConfigurationNoList.%d", k+1)] = v + } + } + + return params, nil +} + +// CreateServerInstances create server instances +func (s *Conn) CreateServerInstances(reqParams *RequestCreateServerInstance) (*ServerInstanceList, error) { + params, err := processCreateServerInstancesParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "createServerInstances" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ServerInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var responseCreateServerInstances = ServerInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &responseCreateServerInstances); err != nil { + fmt.Println(err) + return nil, err + } + + return &responseCreateServerInstances, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteBlockStorageInstances.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteBlockStorageInstances.go new file mode 100644 index 000000000..c47f96bfb --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteBlockStorageInstances.go @@ -0,0 +1,60 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processDeleteBlockStorageInstancesParams(blockStorageInstanceNoList []string) (map[string]string, error) { + params := make(map[string]string) + + if len(blockStorageInstanceNoList) == 0 { + return params, errors.New("BlockStorageInstanceNoList field is Required") + } + + for k, v := range blockStorageInstanceNoList { + params[fmt.Sprintf("blockStorageInstanceNoList.%d", k+1)] = v + } + + return params, nil +} + +// DeleteBlockStorageInstances delete block storage instances +func (s *Conn) DeleteBlockStorageInstances(blockStorageInstanceNoList []string) (*BlockStorageInstanceList, error) { + params, err := processDeleteBlockStorageInstancesParams(blockStorageInstanceNoList) + if err != nil { + return nil, err + } + + params["action"] = "deleteBlockStorageInstances" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := BlockStorageInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var blockStorageInstanceList = BlockStorageInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &blockStorageInstanceList); err != nil { + fmt.Println(err) + return nil, err + } + + return &blockStorageInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteLoginKey.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteLoginKey.go new file mode 100644 index 000000000..7cc3cf257 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deleteLoginKey.go @@ -0,0 +1,59 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processDeleteLoginKeyParams(keyName string) error { + if keyName == "" { + return errors.New("KeyName is required field") + } + + if len := len(keyName); len < 3 || len > 30 { + return errors.New("Length of KeyName should be min 3 or max 30") + } + + return nil +} + +// DeleteLoginKey delete login key with keyName +func (s *Conn) DeleteLoginKey(keyName string) (*common.CommonResponse, error) { + if err := processDeleteLoginKeyParams(keyName); err != nil { + return nil, err + } + + params := make(map[string]string) + + params["keyName"] = keyName + params["action"] = "deleteLoginKey" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := common.CommonResponse{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var responseDeleteLoginKey = common.CommonResponse{} + if err := xml.Unmarshal([]byte(bytes), &responseDeleteLoginKey); err != nil { + return nil, err + } + + return &responseDeleteLoginKey, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deletePublicIpInstances.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deletePublicIpInstances.go new file mode 100644 index 000000000..5ea47602b --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/deletePublicIpInstances.go @@ -0,0 +1,62 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processDeletePublicIPInstancesParams(reqParams *RequestDeletePublicIPInstances) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil || len(reqParams.PublicIPInstanceNoList) == 0 { + return params, errors.New("Required field is not specified. location : publicIpInstanceNoList.N") + } + + if len(reqParams.PublicIPInstanceNoList) > 0 { + for k, v := range reqParams.PublicIPInstanceNoList { + params[fmt.Sprintf("publicIpInstanceNoList.%d", k+1)] = v + } + } + + return params, nil +} + +// DeletePublicIPInstances delete public ip instances +func (s *Conn) DeletePublicIPInstances(reqParams *RequestDeletePublicIPInstances) (*PublicIPInstanceList, error) { + params, err := processDeletePublicIPInstancesParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "deletePublicIpInstances" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := PublicIPInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var publicIPInstanceList = PublicIPInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &publicIPInstanceList); err != nil { + fmt.Println(err) + return nil, err + } + + return &publicIPInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/disassociatePublicIpFromServerInstance.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/disassociatePublicIpFromServerInstance.go new file mode 100644 index 000000000..6d1db9efc --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/disassociatePublicIpFromServerInstance.go @@ -0,0 +1,54 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processDisassociatePublicIPParams(PublicIPInstanceNo string) error { + if PublicIPInstanceNo == "" { + return errors.New("Required field is not specified. location : publicIpInstanceNo") + } + + return nil +} + +// DisassociatePublicIP diassociate public ip from server instance +func (s *Conn) DisassociatePublicIP(PublicIPInstanceNo string) (*PublicIPInstanceList, error) { + if err := processDisassociatePublicIPParams(PublicIPInstanceNo); err != nil { + return nil, err + } + + params := make(map[string]string) + params["publicIpInstanceNo"] = PublicIPInstanceNo + params["action"] = "disassociatePublicIpFromServerInstance" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := PublicIPInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var responseDisassociatePublicIPInstances = PublicIPInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &responseDisassociatePublicIPInstances); err != nil { + return nil, err + } + + return &responseDisassociatePublicIPInstances, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlGroupList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlGroupList.go new file mode 100644 index 000000000..937c877ce --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlGroupList.go @@ -0,0 +1,89 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetAccessControlGroupListParams(reqParams *RequestAccessControlGroupList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if len(reqParams.AccessControlGroupConfigurationNoList) > 0 { + for k, v := range reqParams.AccessControlGroupConfigurationNoList { + params[fmt.Sprintf("accessControlGroupConfigurationNoList.%d", k+1)] = v + } + } + + if reqParams.IsDefault { + params["isDefault"] = "true" + } + + if reqParams.AccessControlGroupName != "" { + if len(reqParams.AccessControlGroupName) < 3 || len(reqParams.AccessControlGroupName) > 30 { + return nil, errors.New("AccessControlGroupName must be between 3 and 30 characters in length") + } + params["accessControlGroupName"] = reqParams.AccessControlGroupName + } + + if reqParams.PageNo != 0 { + if reqParams.PageNo > 2147483647 { + return nil, errors.New("PageNo should be up to 2147483647") + } + + params["pageNo"] = strconv.Itoa(reqParams.PageNo) + } + + if reqParams.PageSize != 0 { + if reqParams.PageSize > 2147483647 { + return nil, errors.New("PageSize should be up to 2147483647") + } + + params["pageSize"] = strconv.Itoa(reqParams.PageSize) + } + + return params, nil +} + +// GetAccessControlGroupList get access control group list +func (s *Conn) GetAccessControlGroupList(reqParams *RequestAccessControlGroupList) (*AccessControlGroupList, error) { + params, err := processGetAccessControlGroupListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getAccessControlGroupList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := AccessControlGroupList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var AccessControlGroupList = AccessControlGroupList{} + if err := xml.Unmarshal([]byte(bytes), &AccessControlGroupList); err != nil { + return nil, err + } + + return &AccessControlGroupList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlRuleList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlRuleList.go new file mode 100644 index 000000000..c07f5985c --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getAccessControlRuleList.go @@ -0,0 +1,61 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func checkGetAccessControlRuleListParams(accessControlGroupConfigurationNo string) error { + if accessControlGroupConfigurationNo == "" { + return errors.New("accessControlGroupConfigurationNo is required") + } + + if no, err := strconv.Atoi(accessControlGroupConfigurationNo); err != nil { + return err + } else if no < 0 || no > 2147483647 { + return errors.New("accessControlGroupConfigurationNoeNo must be up to 2147483647") + } + + return nil +} + +// GetAccessControlRuleList get access control group list +func (s *Conn) GetAccessControlRuleList(accessControlGroupConfigurationNo string) (*AccessControlRuleList, error) { + if err := checkGetAccessControlRuleListParams(accessControlGroupConfigurationNo); err != nil { + return nil, err + } + + params := make(map[string]string) + params["accessControlGroupConfigurationNo"] = accessControlGroupConfigurationNo + params["action"] = "getAccessControlRuleList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := AccessControlRuleList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var AccessControlRuleList = AccessControlRuleList{} + if err := xml.Unmarshal([]byte(bytes), &AccessControlRuleList); err != nil { + return nil, err + } + + return &AccessControlRuleList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getBlockStorageInstanceList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getBlockStorageInstanceList.go new file mode 100644 index 000000000..48f1506f3 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getBlockStorageInstanceList.go @@ -0,0 +1,144 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + "strings" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetBlockStorageInstanceListParams(reqParams *RequestBlockStorageInstanceList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if reqParams.ServerInstanceNo != "" { + params["serverInstanceNo"] = reqParams.ServerInstanceNo + } + + if len(reqParams.BlockStorageInstanceNoList) > 0 { + for k, v := range reqParams.BlockStorageInstanceNoList { + params[fmt.Sprintf("blockStorageInstanceNoList.%d", k+1)] = v + } + } + + if reqParams.SearchFilterName != "" { + if reqParams.SearchFilterName != "blockStorageName" && reqParams.SearchFilterName != "attachmentInformation" { + return nil, errors.New("SearchFilterName should be blockStorageName or attachmentInformation") + } + params["searchFilterName"] = reqParams.SearchFilterName + } + + if reqParams.SearchFilterValue == "" { + params["searchFilterValue"] = reqParams.SearchFilterValue + } + + if len(reqParams.BlockStorageTypeCodeList) > 0 { + for k, v := range reqParams.BlockStorageTypeCodeList { + if v != "BASIC" && v != "SVRBS" { + return nil, errors.New("BlockStorageTypeCodeList value should be BASIC or SVRBS") + } + params[fmt.Sprintf("blockStorageTypeCodeList.%d", k+1)] = v + } + } + + if reqParams.PageNo != 0 { + if reqParams.PageNo > 2147483647 { + return nil, errors.New("PageNo should be up to 2147483647") + } + + params["pageNo"] = strconv.Itoa(reqParams.PageNo) + } + + if reqParams.PageSize != 0 { + if reqParams.PageSize > 2147483647 { + return nil, errors.New("PageSize should be up to 2147483647") + } + + params["pageSize"] = strconv.Itoa(reqParams.PageSize) + } + + if reqParams.BlockStorageInstanceStatusCode != "" { + if reqParams.BlockStorageInstanceStatusCode != "ATTAC" && reqParams.BlockStorageInstanceStatusCode != "CRAET" { + return nil, errors.New("BlockStorageInstanceStatusCode should be ATTAC or CRAET") + } + params["blockStorageInstanceStatusCode"] = reqParams.BlockStorageInstanceStatusCode + } + + if reqParams.DiskTypeCode != "" { + if reqParams.DiskTypeCode != "NET" && reqParams.DiskTypeCode != "LOCAL" { + return nil, errors.New("DiskTypeCode should be NET or LOCAL") + } + params["diskTypeCode"] = reqParams.DiskTypeCode + } + + if reqParams.DiskDetailTypeCode != "" { + if reqParams.DiskDetailTypeCode != "HDD" && reqParams.DiskDetailTypeCode != "SSD" { + return nil, errors.New("DiskDetailTypeCode should be HDD or SSD") + } + params["diskDetailTypeCode"] = reqParams.DiskDetailTypeCode + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + if reqParams.SortedBy != "" { + if strings.EqualFold(reqParams.SortedBy, "blockStorageName") || strings.EqualFold(reqParams.SortedBy, "blockStorageInstanceNo") { + params["sortedBy"] = reqParams.SortedBy + } else { + return nil, errors.New("SortedBy should be blockStorageName or blockStorageInstanceNo") + } + } + + if reqParams.SortingOrder != "" { + if strings.EqualFold(reqParams.SortingOrder, "ascending") || strings.EqualFold(reqParams.SortingOrder, "descending") { + params["sortingOrder"] = reqParams.SortingOrder + } else { + return nil, errors.New("SortingOrder should be ascending or descending") + } + } + + return params, nil +} + +// GetBlockStorageInstance Get block storage instance list +func (s *Conn) GetBlockStorageInstance(reqParams *RequestBlockStorageInstanceList) (*BlockStorageInstanceList, error) { + params, err := processGetBlockStorageInstanceListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getBlockStorageInstanceList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := BlockStorageInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var blockStorageInstanceList = BlockStorageInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &blockStorageInstanceList); err != nil { + return nil, err + } + + return &blockStorageInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getLoginKeyList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getLoginKeyList.go new file mode 100644 index 000000000..d6866ebaf --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getLoginKeyList.go @@ -0,0 +1,77 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetLoginKeyListParams(reqParams *RequestGetLoginKeyList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if reqParams.KeyName != "" { + if len := len(reqParams.KeyName); len < 3 || len > 20 { + return nil, errors.New("Length of KeyName should be min 3 or max 30") + } + params["keyName"] = reqParams.KeyName + } + + if reqParams.PageNo > 0 { + if reqParams.PageNo > 2147483647 { + return nil, errors.New("PageNo should be min 0 or max 2147483647") + } + params["pageNo"] = strconv.Itoa(reqParams.PageNo) + } + + if reqParams.PageSize > 0 { + if reqParams.PageSize > 2147483647 { + return nil, errors.New("PageSize should be min 0 or max 2147483647") + } + params["pageSize"] = strconv.Itoa(reqParams.PageSize) + } + + return params, nil +} + +// GetLoginKeyList get login key list +func (s *Conn) GetLoginKeyList(reqParams *RequestGetLoginKeyList) (*LoginKeyList, error) { + params, err := processGetLoginKeyListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getLoginKeyList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := LoginKeyList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + loginKeyList := LoginKeyList{} + if err := xml.Unmarshal([]byte(bytes), &loginKeyList); err != nil { + return nil, err + } + + return &loginKeyList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getMemberServerImagesList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getMemberServerImagesList.go new file mode 100644 index 000000000..f5fe9f8bf --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getMemberServerImagesList.go @@ -0,0 +1,87 @@ +package sdk + +import ( + "encoding/xml" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetMemberServerImageListParams(reqParams *RequestServerImageList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if len(reqParams.MemberServerImageNoList) > 0 { + for k, v := range reqParams.MemberServerImageNoList { + params[fmt.Sprintf("memberServerImageNoList.%d", k+1)] = v + } + } + + if len(reqParams.PlatformTypeCodeList) > 0 { + for k, v := range reqParams.PlatformTypeCodeList { + params[fmt.Sprintf("platformTypeCodeList.%d", k+1)] = v + } + } + + if reqParams.PageNo != 0 { + params["pageNo"] = strconv.Itoa(reqParams.PageNo) + } + + if reqParams.PageSize != 0 { + params["pageSize"] = strconv.Itoa(reqParams.PageSize) + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + if reqParams.SortedBy != "" { + params["sortedBy"] = reqParams.SortedBy + } + + if reqParams.SortingOrder != "" { + params["sortingOrder"] = reqParams.SortingOrder + } + + return params, nil +} + +// GetMemberServerImageList get member server image list +func (s *Conn) GetMemberServerImageList(reqParams *RequestServerImageList) (*MemberServerImageList, error) { + params, err := processGetMemberServerImageListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getMemberServerImageList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := MemberServerImageList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var serverImageListsResp = MemberServerImageList{} + if err := xml.Unmarshal([]byte(bytes), &serverImageListsResp); err != nil { + return nil, err + } + + return &serverImageListsResp, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getPublicIpInstanceList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getPublicIpInstanceList.go new file mode 100644 index 000000000..a781728c6 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getPublicIpInstanceList.go @@ -0,0 +1,130 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + "strings" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetPublicIPInstanceListParams(reqParams *RequestPublicIPInstanceList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if reqParams.IsAssociated { + params["isAssociated"] = "true" + } + + if len(reqParams.PublicIPInstanceNoList) > 0 { + for k, v := range reqParams.PublicIPInstanceNoList { + params[fmt.Sprintf("publicIpInstanceNoList.%d", k+1)] = v + } + } + + if len(reqParams.PublicIPList) > 0 { + for k, v := range reqParams.PublicIPList { + if len(reqParams.PublicIPList) < 5 || len(reqParams.PublicIPList) > 15 { + return nil, errors.New("PublicIPList must be between 5 and 15 characters in length") + } + params[fmt.Sprintf("publicIpList.%d", k+1)] = v + } + } + + if reqParams.SearchFilterName != "" { + if reqParams.SearchFilterName != "publicIp" && reqParams.SearchFilterName != "associatedServerName" { + return nil, errors.New("SearchFilterName must be publicIp or associatedServerName") + } + params["searchFilterName"] = reqParams.SearchFilterName + } + + if reqParams.SearchFilterValue != "" { + params["searchFilterValue"] = reqParams.SearchFilterValue + } + + if reqParams.InternetLineTypeCode != "" { + if reqParams.InternetLineTypeCode != "PUBLC" && reqParams.InternetLineTypeCode != "GLBL" { + return params, errors.New("InternetLineTypeCode must be PUBLC or GLBL") + } + params["internetLineTypeCode"] = reqParams.InternetLineTypeCode + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + if reqParams.PageNo != 0 { + if reqParams.PageNo > 2147483647 { + return nil, errors.New("PageNo must be up to 2147483647") + } + + params["pageNo"] = strconv.Itoa(reqParams.PageNo) + } + + if reqParams.PageSize != 0 { + if reqParams.PageSize > 2147483647 { + return nil, errors.New("PageSize must be up to 2147483647") + } + + params["pageSize"] = strconv.Itoa(reqParams.PageSize) + } + + if reqParams.SortedBy != "" { + if strings.EqualFold(reqParams.SortedBy, "publicIp") || strings.EqualFold(reqParams.SortedBy, "publicIpInstanceNo") { + params["sortedBy"] = reqParams.SortedBy + } else { + return nil, errors.New("SortedBy must be publicIp or publicIpInstanceNo") + } + } + + if reqParams.SortingOrder != "" { + if strings.EqualFold(reqParams.SortingOrder, "ascending") || strings.EqualFold(reqParams.SortingOrder, "descending") { + params["sortingOrder"] = reqParams.SortingOrder + } else { + return nil, errors.New("SortingOrder must be ascending or descending") + } + } + + return params, nil +} + +// GetPublicIPInstanceList get public ip instance list +func (s *Conn) GetPublicIPInstanceList(reqParams *RequestPublicIPInstanceList) (*PublicIPInstanceList, error) { + params, err := processGetPublicIPInstanceListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getPublicIpInstanceList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := PublicIPInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var publicIPInstanceList = PublicIPInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &publicIPInstanceList); err != nil { + return nil, err + } + + return &publicIPInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRegionList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRegionList.go new file mode 100644 index 000000000..0e1647684 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRegionList.go @@ -0,0 +1,40 @@ +package sdk + +import ( + "encoding/xml" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +// GetRegionList gets region list +func (s *Conn) GetRegionList() (*RegionList, error) { + params := make(map[string]string) + params["action"] = "getRegionList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := RegionList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + regionList := RegionList{} + if err := xml.Unmarshal([]byte(bytes), ®ionList); err != nil { + return nil, err + } + + return ®ionList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRootPassword.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRootPassword.go new file mode 100644 index 000000000..9ec595f49 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getRootPassword.go @@ -0,0 +1,67 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strings" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetRootPasswordParams(reqParams *RequestGetRootPassword) (map[string]string, error) { + params := make(map[string]string) + + if reqParams.ServerInstanceNo == "" { + return params, errors.New("Required field is not specified. location : serverInstanceNo") + } + + if reqParams.PrivateKey == "" { + return params, errors.New("Required field is not specified. location : privateKey") + } + + params["serverInstanceNo"] = reqParams.ServerInstanceNo + params["privateKey"] = reqParams.PrivateKey + + return params, nil +} + +// GetRootPassword get root password from server instance +func (s *Conn) GetRootPassword(reqParams *RequestGetRootPassword) (*RootPassword, error) { + params, err := processGetRootPasswordParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getRootPassword" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := RootPassword{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + responseGetRootPassword := RootPassword{} + if err := xml.Unmarshal([]byte(bytes), &responseGetRootPassword); err != nil { + return nil, err + } + + if responseGetRootPassword.RootPassword != "" { + responseGetRootPassword.RootPassword = strings.TrimSpace(responseGetRootPassword.RootPassword) + } + + return &responseGetRootPassword, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerImageProductList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerImageProductList.go new file mode 100644 index 000000000..645649097 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerImageProductList.go @@ -0,0 +1,88 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetServerImageProductListParams(reqParams *RequestGetServerImageProductList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if reqParams.ExclusionProductCode != "" { + if len(reqParams.ExclusionProductCode) > 20 { + return params, errors.New("Length of exclusionProductCode should be max 20") + } + params["exclusionProductCode"] = reqParams.ExclusionProductCode + } + + if reqParams.ProductCode != "" { + if len(reqParams.ProductCode) > 20 { + return params, errors.New("Length of productCode should be max 20") + } + params["productCode"] = reqParams.ProductCode + } + + if len(reqParams.PlatformTypeCodeList) > 0 { + for k, v := range reqParams.PlatformTypeCodeList { + params[fmt.Sprintf("platformTypeCodeList.%d", k+1)] = v + } + } + + if reqParams.BlockStorageSize > 0 { + if reqParams.BlockStorageSize != 50 && reqParams.BlockStorageSize != 100 { + return nil, errors.New("blockStorageSize should be null, 50 or 100") + } + params["blockStorageSize"] = strconv.Itoa(reqParams.BlockStorageSize) + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + return params, nil +} + +// GetServerImageProductList gets server image product list +func (s *Conn) GetServerImageProductList(reqParams *RequestGetServerImageProductList) (*ProductList, error) { + params, err := processGetServerImageProductListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getServerImageProductList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ProductList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var productList = ProductList{} + if err := xml.Unmarshal([]byte(bytes), &productList); err != nil { + fmt.Println(err) + return nil, err + } + + return &productList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerInstanceList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerInstanceList.go new file mode 100644 index 000000000..a4de2206e --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerInstanceList.go @@ -0,0 +1,133 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + "strconv" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetServerInstanceListParams(reqParams *RequestGetServerInstanceList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil { + return params, nil + } + + if len(reqParams.ServerInstanceNoList) > 0 { + for k, v := range reqParams.ServerInstanceNoList { + params[fmt.Sprintf("serverInstanceNoList.%d", k+1)] = v + } + } + + if reqParams.SearchFilterName != "" { + params["searchFilterName"] = reqParams.SearchFilterName + } + + if reqParams.SearchFilterValue != "" { + params["searchFilterValue"] = reqParams.SearchFilterValue + } + + if reqParams.PageNo > 0 { + if reqParams.PageNo > 2147483647 { + return nil, errors.New("PageNo should be less than 2147483647") + + } + params["pageNo"] = strconv.Itoa(reqParams.PageNo) + } + + if reqParams.PageSize > 0 { + if reqParams.PageSize > 2147483647 { + return nil, errors.New("PageSize should be less than 2147483647") + + } + params["pageSize"] = strconv.Itoa(reqParams.PageSize) + } + + if reqParams.ServerInstanceStatusCode != "" { + if reqParams.ServerInstanceStatusCode != "RUN" && reqParams.ServerInstanceStatusCode != "NSTOP" && reqParams.ServerInstanceStatusCode != "ING" { + return nil, errors.New("ServerInstanceStatusCode should be RUN, NSTOP or ING") + } + params["serverInstanceStatusCode"] = reqParams.ServerInstanceStatusCode + } + + if reqParams.InternetLineTypeCode != "" { + if reqParams.InternetLineTypeCode != "PUBLC" && reqParams.InternetLineTypeCode != "GLBL" { + return nil, errors.New("InternetLineTypeCode should be PUBLC or GLBL") + } + params["internetLineTypeCode"] = reqParams.InternetLineTypeCode + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + if reqParams.BaseBlockStorageDiskTypeCode != "" { + if reqParams.BaseBlockStorageDiskTypeCode != "NET" && reqParams.BaseBlockStorageDiskTypeCode != "LOCAL" { + return nil, errors.New("BaseBlockStorageDiskTypeCode should be NET or LOCAL") + } + params["baseBlockStorageDiskTypeCode"] = reqParams.BaseBlockStorageDiskTypeCode + } + + if reqParams.BaseBlockStorageDiskDetailTypeCode != "" { + if reqParams.BaseBlockStorageDiskDetailTypeCode != "HDD" && reqParams.BaseBlockStorageDiskDetailTypeCode != "SSD" { + return nil, errors.New("BaseBlockStorageDiskDetailTypeCode should be HDD or SSD") + } + params["baseBlockStorageDiskDetailTypeCode"] = reqParams.BaseBlockStorageDiskDetailTypeCode + } + + if reqParams.SortedBy != "" { + if reqParams.SortedBy != "serverName" && reqParams.SortedBy != "serverInstanceNo" { + return nil, errors.New("SortedBy should be serverName or serverInstanceNo") + } + params["sortedBy"] = reqParams.SortedBy + } + + if reqParams.SortingOrder != "" { + if reqParams.SortingOrder != "ascending" && reqParams.SortingOrder != "descending" { + return nil, errors.New("SortingOrder should be ascending or descending") + } + params["sortingOrder"] = reqParams.SortingOrder + } + + return params, nil +} + +// GetServerInstanceList get server instance list +func (s *Conn) GetServerInstanceList(reqParams *RequestGetServerInstanceList) (*ServerInstanceList, error) { + params, err := processGetServerInstanceListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getServerInstanceList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ServerInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var serverInstanceList = ServerInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &serverInstanceList); err != nil { + fmt.Println(err) + return nil, err + } + + return &serverInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerProductList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerProductList.go new file mode 100644 index 000000000..b932df876 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getServerProductList.go @@ -0,0 +1,79 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processGetServerProductListParams(reqParams *RequestGetServerProductList) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil || reqParams.ServerImageProductCode == "" { + return params, errors.New("ServerImageProductCode field is required") + } + + if len(reqParams.ServerImageProductCode) > 20 { + return params, errors.New("Length of serverImageProductCode should be max 20") + } + + params["serverImageProductCode"] = reqParams.ServerImageProductCode + + if reqParams.ExclusionProductCode != "" { + if len(reqParams.ExclusionProductCode) > 20 { + return params, errors.New("Length of exclusionProductCode should be max 20") + } + params["exclusionProductCode"] = reqParams.ExclusionProductCode + } + + if reqParams.ProductCode != "" { + if len(reqParams.ProductCode) > 20 { + return params, errors.New("Length of productCode should be max 20") + } + params["productCode"] = reqParams.ProductCode + } + + if reqParams.RegionNo != "" { + params["regionNo"] = reqParams.RegionNo + } + + return params, nil +} + +// GetServerProductList : Get Server product list with server image product code by default. +func (s *Conn) GetServerProductList(reqParams *RequestGetServerProductList) (*ProductList, error) { + params, err := processGetServerProductListParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "getServerProductList" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ProductList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var productListResp = ProductList{} + if err := xml.Unmarshal([]byte(bytes), &productListResp); err != nil { + return nil, err + } + + return &productListResp, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getZoneList.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getZoneList.go new file mode 100644 index 000000000..42354eec0 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/getZoneList.go @@ -0,0 +1,44 @@ +package sdk + +import ( + "encoding/xml" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +// GetZoneList get zone list +func (s *Conn) GetZoneList(regionNo string) (*ZoneList, error) { + params := make(map[string]string) + params["action"] = "getZoneList" + + if regionNo != "" { + params["regionNo"] = regionNo + } + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ZoneList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + ZoneList := ZoneList{} + if err := xml.Unmarshal([]byte(bytes), &ZoneList); err != nil { + return nil, err + } + + return &ZoneList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/model.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/model.go new file mode 100644 index 000000000..02cac088e --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/model.go @@ -0,0 +1,359 @@ +package sdk + +import ( + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" +) + +type Conn struct { + accessKey string + secretKey string + apiURL string +} + +// ServerImage structures +type ServerImage struct { + MemberServerImageNo string `xml:"memberServerImageNo"` + MemberServerImageName string `xml:"memberServerImageName"` + MemberServerImageDescription string `xml:"memberServerImageDescription"` + OriginalServerInstanceNo string `xml:"originalServerInstanceNo"` + OriginalServerProductCode string `xml:"originalServerProductCode"` + OriginalServerName string `xml:"originalServerName"` + OriginalBaseBlockStorageDiskType common.CommonCode `xml:"originalBaseBlockStorageDiskType"` + OriginalServerImageProductCode string `xml:"originalServerImageProductCode"` + OriginalOsInformation string `xml:"originalOsInformation"` + OriginalServerImageName string `xml:"originalServerImageName"` + MemberServerImageStatusName string `xml:"memberServerImageStatusName"` + MemberServerImageStatus common.CommonCode `xml:"memberServerImageStatus"` + MemberServerImageOperation common.CommonCode `xml:"memberServerImageOperation"` + MemberServerImagePlatformType common.CommonCode `xml:"memberServerImagePlatformType"` + CreateDate string `xml:"createDate"` + Zone common.Zone `xml:"zone"` + Region common.Region `xml:"region"` + MemberServerImageBlockStorageTotalRows int `xml:"memberServerImageBlockStorageTotalRows"` + MemberServerImageBlockStorageTotalSize int `xml:"memberServerImageBlockStorageTotalSize"` +} + +type MemberServerImageList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + MemberServerImageList []ServerImage `xml:"memberServerImageList>memberServerImage,omitempty"` +} + +type RequestServerImageList struct { + MemberServerImageNoList []string + PlatformTypeCodeList []string + PageNo int + PageSize int + RegionNo string + SortedBy string + SortingOrder string +} + +type RequestCreateServerImage struct { + MemberServerImageName string + MemberServerImageDescription string + ServerInstanceNo string +} + +type RequestGetServerImageProductList struct { + ExclusionProductCode string + ProductCode string + PlatformTypeCodeList []string + BlockStorageSize int + RegionNo string +} + +// ProductList : Response of server product list +type ProductList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + Product []Product `xml:"productList>product,omitempty"` +} + +// Product : Product information of Server +type Product struct { + ProductCode string `xml:"productCode"` + ProductName string `xml:"productName"` + ProductType common.CommonCode `xml:"productType"` + ProductDescription string `xml:"productDescription"` + InfraResourceType common.CommonCode `xml:"infraResourceType"` + CPUCount int `xml:"cpuCount"` + MemorySize int `xml:"memorySize"` + BaseBlockStorageSize int `xml:"baseBlockStorageSize"` + PlatformType common.CommonCode `xml:"platformType"` + OsInformation string `xml:"osInformation"` + AddBlockStroageSize int `xml:"addBlockStroageSize"` +} + +// RequestCreateServerInstance is Server Instances structures +type RequestCreateServerInstance struct { + ServerImageProductCode string + ServerProductCode string + MemberServerImageNo string + ServerName string + ServerDescription string + LoginKeyName string + IsProtectServerTermination bool + ServerCreateCount int + ServerCreateStartNo int + InternetLineTypeCode string + FeeSystemTypeCode string + UserData string + ZoneNo string + AccessControlGroupConfigurationNoList []string +} + +type ServerInstanceList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + ServerInstanceList []ServerInstance `xml:"serverInstanceList>serverInstance,omitempty"` +} + +type ServerInstance struct { + ServerInstanceNo string `xml:"serverInstanceNo"` + ServerName string `xml:"serverName"` + ServerDescription string `xml:"serverDescription"` + CPUCount int `xml:"cpuCount"` + MemorySize int `xml:"memorySize"` + BaseBlockStorageSize int `xml:"baseBlockStorageSize"` + PlatformType common.CommonCode `xml:"platformType"` + LoginKeyName string `xml:"loginKeyName"` + IsFeeChargingMonitoring bool `xml:"isFeeChargingMonitoring"` + PublicIP string `xml:"publicIp"` + PrivateIP string `xml:"privateIp"` + ServerImageName string `xml:"serverImageName"` + ServerInstanceStatus common.CommonCode `xml:"serverInstanceStatus"` + ServerInstanceOperation common.CommonCode `xml:"serverInstanceOperation"` + ServerInstanceStatusName string `xml:"serverInstanceStatusName"` + CreateDate string `xml:"createDate"` + Uptime string `xml:"uptime"` + ServerImageProductCode string `xml:"serverImageProductCode"` + ServerProductCode string `xml:"serverProductCode"` + IsProtectServerTermination bool `xml:"isProtectServerTermination"` + PortForwardingPublicIP string `xml:"portForwardingPublicIp"` + PortForwardingExternalPort int `xml:"portForwardingExternalPort"` + PortForwardingInternalPort int `xml:"portForwardingInternalPort"` + Zone common.Zone `xml:"zone"` + Region common.Region `xml:"region"` + BaseBlockStorageDiskType common.CommonCode `xml:"baseBlockStorageDiskType"` + BaseBlockStroageDiskDetailType common.CommonCode `xml:"baseBlockStroageDiskDetailType"` + InternetLineType common.CommonCode `xml:"internetLineType"` + UserData string `xml:"userData"` + AccessControlGroupList []AccessControlGroup `xml:"accessControlGroupList>accessControlGroup"` +} + +type AccessControlGroup struct { + AccessControlGroupConfigurationNo string `xml:"accessControlGroupConfigurationNo"` + AccessControlGroupName string `xml:"accessControlGroupName"` + AccessControlGroupDescription string `xml:"accessControlGroupDescription"` + IsDefault bool `xml:"isDefault"` + CreateDate string `xml:"createDate"` +} + +// RequestGetLoginKeyList is Login Key structures +type RequestGetLoginKeyList struct { + KeyName string + PageNo int + PageSize int +} + +type LoginKeyList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + LoginKeyList []LoginKey `xml:"loginKeyList>loginKey,omitempty"` +} + +type LoginKey struct { + Fingerprint string `xml:"fingerprint"` + KeyName string `xml:"keyName"` + CreateDate string `xml:"createDate"` +} + +type PrivateKey struct { + common.CommonResponse + PrivateKey string `xml:"privateKey"` +} +type RequestCreatePublicIPInstance struct { + ServerInstanceNo string + PublicIPDescription string + InternetLineTypeCode string + RegionNo string +} + +type RequestPublicIPInstanceList struct { + IsAssociated bool + PublicIPInstanceNoList []string + PublicIPList []string + SearchFilterName string + SearchFilterValue string + InternetLineTypeCode string + RegionNo string + PageNo int + PageSize int + SortedBy string + SortingOrder string +} + +type PublicIPInstanceList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + PublicIPInstanceList []PublicIPInstance `xml:"publicIpInstanceList>publicIpInstance,omitempty"` +} + +type PublicIPInstance struct { + PublicIPInstanceNo string `xml:"publicIpInstanceNo"` + PublicIP string `xml:"publicIp"` + PublicIPDescription string `xml:"publicIpDescription"` + CreateDate string `xml:"createDate"` + InternetLineType common.CommonCode `xml:"internetLineType"` + PublicIPInstanceStatusName string `xml:"publicIpInstanceStatusName"` + PublicIPInstanceStatus common.CommonCode `xml:"publicIpInstanceStatus"` + PublicIPInstanceOperation common.CommonCode `xml:"publicIpInstanceOperation"` + PublicIPKindType common.CommonCode `xml:"publicIpKindType"` + ServerInstance ServerInstance `xml:"serverInstanceAssociatedWithPublicIp"` +} + +type RequestDeletePublicIPInstances struct { + PublicIPInstanceNoList []string +} + +// RequestGetServerInstanceList : Get Server Instance List +type RequestGetServerInstanceList struct { + ServerInstanceNoList []string + SearchFilterName string + SearchFilterValue string + PageNo int + PageSize int + ServerInstanceStatusCode string + InternetLineTypeCode string + RegionNo string + BaseBlockStorageDiskTypeCode string + BaseBlockStorageDiskDetailTypeCode string + SortedBy string + SortingOrder string +} + +type RequestStopServerInstances struct { + ServerInstanceNoList []string +} + +type RequestTerminateServerInstances struct { + ServerInstanceNoList []string +} + +// RequestGetRootPassword : Request to get root password of the server +type RequestGetRootPassword struct { + ServerInstanceNo string + PrivateKey string +} + +// RootPassword : Response of getting root password of the server +type RootPassword struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + RootPassword string `xml:"rootPassword"` +} + +// RequestGetZoneList : Request to get zone list +type RequestGetZoneList struct { + regionNo string +} + +// ZoneList : Response of getting zone list +type ZoneList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + Zone []common.Zone `xml:"zoneList>zone"` +} + +// RegionList : Response of getting region list +type RegionList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + RegionList []common.Region `xml:"regionList>region,omitempty"` +} + +type RequestBlockStorageInstance struct { + BlockStorageName string + BlockStorageSize int + BlockStorageDescription string + ServerInstanceNo string +} + +type RequestBlockStorageInstanceList struct { + ServerInstanceNo string + BlockStorageInstanceNoList []string + SearchFilterName string + SearchFilterValue string + BlockStorageTypeCodeList []string + PageNo int + PageSize int + BlockStorageInstanceStatusCode string + DiskTypeCode string + DiskDetailTypeCode string + RegionNo string + SortedBy string + SortingOrder string +} + +type BlockStorageInstanceList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + BlockStorageInstance []BlockStorageInstance `xml:"blockStorageInstanceList>blockStorageInstance,omitempty"` +} + +type BlockStorageInstance struct { + BlockStorageInstanceNo string `xml:"blockStorageInstanceNo"` + ServerInstanceNo string `xml:"serverInstanceNo"` + ServerName string `xml:"serverName"` + BlockStorageType common.CommonCode `xml:"blockStorageType"` + BlockStorageName string `xml:"blockStorageName"` + BlockStorageSize int `xml:"blockStorageSize"` + DeviceName string `xml:"deviceName"` + BlockStorageProductCode string `xml:"blockStorageProductCode"` + BlockStorageInstanceStatus common.CommonCode `xml:"blockStorageInstanceStatus"` + BlockStorageInstanceOperation common.CommonCode `xml:"blockStorageInstanceOperation"` + BlockStorageInstanceStatusName string `xml:"blockStorageInstanceStatusName"` + CreateDate string `xml:"createDate"` + BlockStorageInstanceDescription string `xml:"blockStorageInstanceDescription"` + DiskType common.CommonCode `xml:"diskType"` + DiskDetailType common.CommonCode `xml:"diskDetailType"` +} + +// RequestGetServerProductList : Request to get server product list +type RequestGetServerProductList struct { + ExclusionProductCode string + ProductCode string + ServerImageProductCode string + RegionNo string +} + +type RequestAccessControlGroupList struct { + AccessControlGroupConfigurationNoList []string + IsDefault bool + AccessControlGroupName string + PageNo int + PageSize int +} + +type AccessControlGroupList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + AccessControlGroup []AccessControlGroup `xml:"accessControlGroupList>accessControlGroup,omitempty"` +} + +type AccessControlRuleList struct { + common.CommonResponse + TotalRows int `xml:"totalRows"` + AccessControlRuleList []AccessControlRule `xml:"accessControlRuleList>accessControlRule,omitempty"` +} + +type AccessControlRule struct { + AccessControlRuleConfigurationNo string `xml:"accessControlRuleConfigurationNo"` + AccessControlRuleDescription string `xml:"accessControlRuleDescription"` + SourceAccessControlRuleConfigurationNo string `xml:"sourceAccessControlRuleConfigurationNo"` + SourceAccessControlRuleName string `xml:"sourceAccessControlRuleName"` + ProtocolType common.CommonCode `xml:"protocolType"` + SourceIP string `xml:"sourceIp"` + DestinationPort string `xml:"destinationPort"` +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/stopServerInstances.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/stopServerInstances.go new file mode 100644 index 000000000..e3786e5fa --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/stopServerInstances.go @@ -0,0 +1,62 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processStopServerInstancesParams(reqParams *RequestStopServerInstances) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil || len(reqParams.ServerInstanceNoList) == 0 { + return params, errors.New("serverInstanceNoList is required") + } + + if len(reqParams.ServerInstanceNoList) > 0 { + for k, v := range reqParams.ServerInstanceNoList { + params[fmt.Sprintf("serverInstanceNoList.%d", k+1)] = v + } + } + + return params, nil +} + +// StopServerInstances stop server instances +func (s *Conn) StopServerInstances(reqParams *RequestStopServerInstances) (*ServerInstanceList, error) { + params, err := processStopServerInstancesParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "stopServerInstances" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ServerInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var serverInstanceList = ServerInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &serverInstanceList); err != nil { + fmt.Println(err) + return nil, err + } + + return &serverInstanceList, nil +} diff --git a/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/terminateServerInstances.go b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/terminateServerInstances.go new file mode 100644 index 000000000..598f8efa1 --- /dev/null +++ b/vendor/github.com/NaverCloudPlatform/ncloud-sdk-go/sdk/terminateServerInstances.go @@ -0,0 +1,62 @@ +package sdk + +import ( + "encoding/xml" + "errors" + "fmt" + + common "github.com/NaverCloudPlatform/ncloud-sdk-go/common" + request "github.com/NaverCloudPlatform/ncloud-sdk-go/request" +) + +func processTerminateServerInstancesParams(reqParams *RequestTerminateServerInstances) (map[string]string, error) { + params := make(map[string]string) + + if reqParams == nil || len(reqParams.ServerInstanceNoList) == 0 { + return params, errors.New("serverInstanceNoList is required") + } + + if len(reqParams.ServerInstanceNoList) > 0 { + for k, v := range reqParams.ServerInstanceNoList { + params[fmt.Sprintf("serverInstanceNoList.%d", k+1)] = v + } + } + + return params, nil +} + +// TerminateServerInstances terminate server instances +func (s *Conn) TerminateServerInstances(reqParams *RequestTerminateServerInstances) (*ServerInstanceList, error) { + params, err := processTerminateServerInstancesParams(reqParams) + if err != nil { + return nil, err + } + + params["action"] = "terminateServerInstances" + + bytes, resp, err := request.NewRequest(s.accessKey, s.secretKey, "GET", s.apiURL+"server/", params) + if err != nil { + return nil, err + } + + if resp.StatusCode != 200 { + responseError, err := common.ParseErrorResponse(bytes) + if err != nil { + return nil, err + } + + respError := ServerInstanceList{} + respError.ReturnCode = responseError.ReturnCode + respError.ReturnMessage = responseError.ReturnMessage + + return &respError, fmt.Errorf("%s %s - error code: %d , error message: %s", resp.Status, string(bytes), responseError.ReturnCode, responseError.ReturnMessage) + } + + var serverInstanceList = ServerInstanceList{} + if err := xml.Unmarshal([]byte(bytes), &serverInstanceList); err != nil { + fmt.Println(err) + return nil, err + } + + return &serverInstanceList, nil +} diff --git a/vendor/vendor.json b/vendor/vendor.json index 4438b367e..c5714b58f 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -209,6 +209,30 @@ "revision": "4fe03583929022c9c96829401ffabc755e69782e", "revisionTime": "2017-06-25T21:53:50Z" }, + { + "checksumSHA1": "N0jIjg2HeB8fM7dt8OED2BiRZz0=", + "path": "github.com/NaverCloudPlatform/ncloud-sdk-go/common", + "revision": "c2e73f942591b0f033a3c6df00f44badb2347c38", + "revisionTime": "2018-01-10T05:50:12Z" + }, + { + "checksumSHA1": "7lT5Xmeo2MhE6CJvIInZyLBu6S8=", + "path": "github.com/NaverCloudPlatform/ncloud-sdk-go/oauth", + "revision": "c2e73f942591b0f033a3c6df00f44badb2347c38", + "revisionTime": "2018-01-10T05:50:12Z" + }, + { + "checksumSHA1": "DpfU1gyyhIc1BuKZUZDRVDBkeSc=", + "path": "github.com/NaverCloudPlatform/ncloud-sdk-go/request", + "revision": "c2e73f942591b0f033a3c6df00f44badb2347c38", + "revisionTime": "2018-01-10T05:50:12Z" + }, + { + "checksumSHA1": "QnZ2RMlms/zYbD8jg+lyS8ncQOY=", + "path": "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk", + "revision": "c2e73f942591b0f033a3c6df00f44badb2347c38", + "revisionTime": "2018-01-10T05:50:12Z" + }, { "checksumSHA1": "HttiPj314X1a0i2Jen1p6lRH/vE=", "path": "github.com/aliyun/aliyun-oss-go-sdk/oss", From 26030d750cd47eba3713b4d85ab6313f8bfefb81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Fri, 12 Jan 2018 10:12:47 +0900 Subject: [PATCH 03/17] update err format --- builder/ncloud/step_create_block_storage_instance.go | 2 +- builder/ncloud/step_create_login_key.go | 2 +- builder/ncloud/step_create_public_ip_instance.go | 4 ++-- builder/ncloud/step_delete_block_storage_instance.go | 2 +- builder/ncloud/step_delete_login_key.go | 2 +- builder/ncloud/step_get_rootpassword.go | 2 +- builder/ncloud/step_stop_server_instance.go | 2 +- builder/ncloud/step_terminate_server_instance.go | 4 ++-- builder/ncloud/step_validate_template.go | 4 ++-- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/builder/ncloud/step_create_block_storage_instance.go b/builder/ncloud/step_create_block_storage_instance.go index ef7306264..7e4d4b54a 100644 --- a/builder/ncloud/step_create_block_storage_instance.go +++ b/builder/ncloud/step_create_block_storage_instance.go @@ -42,7 +42,7 @@ func (s *StepCreateBlockStorageInstance) createBlockStorageInstance(serverInstan blockStorageInstanceList, err := s.Conn.CreateBlockStorageInstance(reqParams) if err != nil { - return "", fmt.Errorf("error code: %d, error message: %s", blockStorageInstanceList.ReturnCode, blockStorageInstanceList.ReturnMessage) + return "", err } log.Println("Block Storage Instance information : ", blockStorageInstanceList.BlockStorageInstance[0]) diff --git a/builder/ncloud/step_create_login_key.go b/builder/ncloud/step_create_login_key.go index 7dddebd25..d200c3106 100644 --- a/builder/ncloud/step_create_login_key.go +++ b/builder/ncloud/step_create_login_key.go @@ -38,7 +38,7 @@ func (s *StepCreateLoginKey) createLoginKey() (*LoginKey, error) { privateKey, err := s.Conn.CreateLoginKey(KeyName) if err != nil { - return nil, fmt.Errorf("error code: %d , error message: %s", privateKey.ReturnCode, privateKey.ReturnMessage) + return nil, err } return &LoginKey{KeyName, privateKey.PrivateKey}, nil diff --git a/builder/ncloud/step_create_public_ip_instance.go b/builder/ncloud/step_create_public_ip_instance.go index 88d98eb6c..1ea1517c5 100644 --- a/builder/ncloud/step_create_public_ip_instance.go +++ b/builder/ncloud/step_create_public_ip_instance.go @@ -72,7 +72,7 @@ func (s *StepCreatePublicIPInstance) createPublicIPInstance(serverInstanceNo str publicIPInstanceList, err := s.Conn.CreatePublicIPInstance(reqParams) if err != nil { - return nil, fmt.Errorf("error code: %d, error message: %s", publicIPInstanceList.ReturnCode, publicIPInstanceList.ReturnMessage) + return nil, err } publicIPInstance := publicIPInstanceList.PublicIPInstanceList[0] @@ -143,7 +143,7 @@ func (s *StepCreatePublicIPInstance) waitPublicIPInstanceStatus(publicIPInstance for { resp, err := s.Conn.GetPublicIPInstanceList(reqParams) if err != nil { - log.Printf("error code: %d, error message: %s", resp.ReturnCode, resp.ReturnMessage) + log.Printf(err.Error()) c1 <- err return } diff --git a/builder/ncloud/step_delete_block_storage_instance.go b/builder/ncloud/step_delete_block_storage_instance.go index 3c6c44b82..a077d4880 100644 --- a/builder/ncloud/step_delete_block_storage_instance.go +++ b/builder/ncloud/step_delete_block_storage_instance.go @@ -65,7 +65,7 @@ func (s *StepDeleteBlockStorageInstance) deleteBlockStorageInstance(serverInstan result, err := s.Conn.DeleteBlockStorageInstances(blockStorageInstanceList) if err != nil { - return fmt.Errorf("error code: %d , error message: %s", result.ReturnCode, result.ReturnMessage) + return err } s.Say(fmt.Sprintf("Block Storage Instance is deleted. Block Storage InstanceNo is %s", blockStorageInstanceList)) diff --git a/builder/ncloud/step_delete_login_key.go b/builder/ncloud/step_delete_login_key.go index b0cfbf7a1..c53dc3d1c 100644 --- a/builder/ncloud/step_delete_login_key.go +++ b/builder/ncloud/step_delete_login_key.go @@ -30,7 +30,7 @@ func NewStepDeleteLoginKey(conn *ncloud.Conn, ui packer.Ui) *StepDeleteLoginKey func (s *StepDeleteLoginKey) deleteLoginKey(keyName string) error { resp, err := s.Conn.DeleteLoginKey(keyName) if err != nil { - return fmt.Errorf("error code: %d , error message: %s", resp.ReturnCode, resp.ReturnMessage) + return err } return nil diff --git a/builder/ncloud/step_get_rootpassword.go b/builder/ncloud/step_get_rootpassword.go index c5070d179..3766d86df 100644 --- a/builder/ncloud/step_get_rootpassword.go +++ b/builder/ncloud/step_get_rootpassword.go @@ -34,7 +34,7 @@ func (s *StepGetRootPassword) getRootPassword(serverInstanceNo string, privateKe rootPassword, err := s.Conn.GetRootPassword(reqParams) if err != nil { - return "", fmt.Errorf("error code: %d, error message: %s", rootPassword.ReturnCode, rootPassword.ReturnMessage) + return "", err } return rootPassword.RootPassword, nil diff --git a/builder/ncloud/step_stop_server_instance.go b/builder/ncloud/step_stop_server_instance.go index 1c9252ed2..f9cce7d9f 100644 --- a/builder/ncloud/step_stop_server_instance.go +++ b/builder/ncloud/step_stop_server_instance.go @@ -35,7 +35,7 @@ func (s *StepStopServerInstance) stopServerInstance(serverInstanceNo string) err serverInstanceList, err := s.Conn.StopServerInstances(reqParams) if err != nil { - return fmt.Errorf("error code: %d , error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + return err } s.Say(fmt.Sprintf("Server Instance is stopping. Server InstanceNo is %s", serverInstanceList.ServerInstanceList[0].ServerInstanceNo)) diff --git a/builder/ncloud/step_terminate_server_instance.go b/builder/ncloud/step_terminate_server_instance.go index 5d60236f0..208e6f1e6 100644 --- a/builder/ncloud/step_terminate_server_instance.go +++ b/builder/ncloud/step_terminate_server_instance.go @@ -35,7 +35,7 @@ func (s *StepTerminateServerInstance) terminateServerInstance(serverInstanceNo s serverInstanceList, err := s.Conn.TerminateServerInstances(reqParams) if err != nil { - return fmt.Errorf("error code: %d , error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + return err } c1 := make(chan error, 1) @@ -48,7 +48,7 @@ func (s *StepTerminateServerInstance) terminateServerInstance(serverInstanceNo s serverInstanceList, err := s.Conn.GetServerInstanceList(reqParams) if err != nil { - c1 <- fmt.Errorf("error code: %d , error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + c1 <- err return } else if serverInstanceList.TotalRows == 0 { c1 <- nil diff --git a/builder/ncloud/step_validate_template.go b/builder/ncloud/step_validate_template.go index 0007bfa40..d645111c4 100644 --- a/builder/ncloud/step_validate_template.go +++ b/builder/ncloud/step_validate_template.go @@ -45,7 +45,7 @@ func (s *StepValidateTemplate) getZoneNo() error { regionList, err := s.Conn.GetRegionList() if err != nil { - return fmt.Errorf("error code: %d , error message: %s", regionList.ReturnCode, regionList.ReturnMessage) + return err } var regionNo string @@ -64,7 +64,7 @@ func (s *StepValidateTemplate) getZoneNo() error { // Get ZoneNo ZoneList, err := s.Conn.GetZoneList(regionNo) if err != nil { - return fmt.Errorf("error code: %d , error message: %s", ZoneList.ReturnCode, ZoneList.ReturnMessage) + return err } if len(ZoneList.Zone) > 0 { From b909e9d4e672f7536afd0bdda25b3b5478463134 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Fri, 12 Jan 2018 10:15:40 +0900 Subject: [PATCH 04/17] remove not used variables --- builder/ncloud/step_create_server_image.go | 2 +- builder/ncloud/step_create_server_instance.go | 2 +- builder/ncloud/step_delete_block_storage_instance.go | 2 +- builder/ncloud/step_delete_login_key.go | 2 +- builder/ncloud/step_get_rootpassword.go | 2 -- builder/ncloud/step_terminate_server_instance.go | 3 +-- 6 files changed, 5 insertions(+), 8 deletions(-) diff --git a/builder/ncloud/step_create_server_image.go b/builder/ncloud/step_create_server_image.go index 4256664f4..ea0784058 100644 --- a/builder/ncloud/step_create_server_image.go +++ b/builder/ncloud/step_create_server_image.go @@ -44,7 +44,7 @@ func (s *StepCreateServerImage) createServerImage(serverInstanceNo string) (*ncl memberServerImageList, err := s.Conn.CreateMemberServerImage(reqParams) if err != nil { - return nil, fmt.Errorf("error code: %d , error message: %s", memberServerImageList.ReturnCode, memberServerImageList.ReturnMessage) + return nil, err } serverImage := memberServerImageList.MemberServerImageList[0] diff --git a/builder/ncloud/step_create_server_instance.go b/builder/ncloud/step_create_server_instance.go index 040e72eb1..d7decd4d8 100644 --- a/builder/ncloud/step_create_server_instance.go +++ b/builder/ncloud/step_create_server_instance.go @@ -55,7 +55,7 @@ func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zon serverInstanceList, err := s.Conn.CreateServerInstances(reqParams) if err != nil { - return "", fmt.Errorf("error code: %d, error message: %s", serverInstanceList.ReturnCode, serverInstanceList.ReturnMessage) + return "", err } s.serverInstanceNo = serverInstanceList.ServerInstanceList[0].ServerInstanceNo diff --git a/builder/ncloud/step_delete_block_storage_instance.go b/builder/ncloud/step_delete_block_storage_instance.go index a077d4880..61f8b7c3c 100644 --- a/builder/ncloud/step_delete_block_storage_instance.go +++ b/builder/ncloud/step_delete_block_storage_instance.go @@ -63,7 +63,7 @@ func (s *StepDeleteBlockStorageInstance) deleteBlockStorageInstance(serverInstan return nil } - result, err := s.Conn.DeleteBlockStorageInstances(blockStorageInstanceList) + _, err := s.Conn.DeleteBlockStorageInstances(blockStorageInstanceList) if err != nil { return err } diff --git a/builder/ncloud/step_delete_login_key.go b/builder/ncloud/step_delete_login_key.go index c53dc3d1c..18256c7d8 100644 --- a/builder/ncloud/step_delete_login_key.go +++ b/builder/ncloud/step_delete_login_key.go @@ -28,7 +28,7 @@ func NewStepDeleteLoginKey(conn *ncloud.Conn, ui packer.Ui) *StepDeleteLoginKey } func (s *StepDeleteLoginKey) deleteLoginKey(keyName string) error { - resp, err := s.Conn.DeleteLoginKey(keyName) + _, err := s.Conn.DeleteLoginKey(keyName) if err != nil { return err } diff --git a/builder/ncloud/step_get_rootpassword.go b/builder/ncloud/step_get_rootpassword.go index 3766d86df..b696e594d 100644 --- a/builder/ncloud/step_get_rootpassword.go +++ b/builder/ncloud/step_get_rootpassword.go @@ -1,8 +1,6 @@ package ncloud import ( - "fmt" - ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" diff --git a/builder/ncloud/step_terminate_server_instance.go b/builder/ncloud/step_terminate_server_instance.go index 208e6f1e6..aa154812b 100644 --- a/builder/ncloud/step_terminate_server_instance.go +++ b/builder/ncloud/step_terminate_server_instance.go @@ -2,7 +2,6 @@ package ncloud import ( "errors" - "fmt" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" @@ -33,7 +32,7 @@ func (s *StepTerminateServerInstance) terminateServerInstance(serverInstanceNo s reqParams := new(ncloud.RequestTerminateServerInstances) reqParams.ServerInstanceNoList = []string{serverInstanceNo} - serverInstanceList, err := s.Conn.TerminateServerInstances(reqParams) + _, err := s.Conn.TerminateServerInstances(reqParams) if err != nil { return err } From 9c728750762bcb83e028188496212a63b4234bea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Sun, 14 Jan 2018 16:08:06 +0900 Subject: [PATCH 05/17] Add tablewriter package --- vendor/github.com/mattn/go-runewidth/LICENSE | 21 + .../github.com/mattn/go-runewidth/README.mkd | 27 + .../mattn/go-runewidth/runewidth.go | 1224 +++++++++++++++++ .../mattn/go-runewidth/runewidth_js.go | 8 + .../mattn/go-runewidth/runewidth_posix.go | 77 ++ .../mattn/go-runewidth/runewidth_windows.go | 25 + .../olekukonko/tablewriter/LICENCE.md | 19 + .../olekukonko/tablewriter/README.md | 279 ++++ .../github.com/olekukonko/tablewriter/csv.go | 52 + .../olekukonko/tablewriter/table.go | 798 +++++++++++ .../tablewriter/table_with_color.go | 134 ++ .../olekukonko/tablewriter/test.csv | 4 + .../olekukonko/tablewriter/test_info.csv | 4 + .../github.com/olekukonko/tablewriter/util.go | 72 + .../github.com/olekukonko/tablewriter/wrap.go | 104 ++ vendor/vendor.json | 12 + 16 files changed, 2860 insertions(+) create mode 100644 vendor/github.com/mattn/go-runewidth/LICENSE create mode 100644 vendor/github.com/mattn/go-runewidth/README.mkd create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth.go create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_js.go create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_posix.go create mode 100644 vendor/github.com/mattn/go-runewidth/runewidth_windows.go create mode 100644 vendor/github.com/olekukonko/tablewriter/LICENCE.md create mode 100644 vendor/github.com/olekukonko/tablewriter/README.md create mode 100644 vendor/github.com/olekukonko/tablewriter/csv.go create mode 100644 vendor/github.com/olekukonko/tablewriter/table.go create mode 100644 vendor/github.com/olekukonko/tablewriter/table_with_color.go create mode 100644 vendor/github.com/olekukonko/tablewriter/test.csv create mode 100644 vendor/github.com/olekukonko/tablewriter/test_info.csv create mode 100644 vendor/github.com/olekukonko/tablewriter/util.go create mode 100644 vendor/github.com/olekukonko/tablewriter/wrap.go diff --git a/vendor/github.com/mattn/go-runewidth/LICENSE b/vendor/github.com/mattn/go-runewidth/LICENSE new file mode 100644 index 000000000..91b5cef30 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Yasuhiro Matsumoto + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/mattn/go-runewidth/README.mkd b/vendor/github.com/mattn/go-runewidth/README.mkd new file mode 100644 index 000000000..66663a94b --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/README.mkd @@ -0,0 +1,27 @@ +go-runewidth +============ + +[![Build Status](https://travis-ci.org/mattn/go-runewidth.png?branch=master)](https://travis-ci.org/mattn/go-runewidth) +[![Coverage Status](https://coveralls.io/repos/mattn/go-runewidth/badge.png?branch=HEAD)](https://coveralls.io/r/mattn/go-runewidth?branch=HEAD) +[![GoDoc](https://godoc.org/github.com/mattn/go-runewidth?status.svg)](http://godoc.org/github.com/mattn/go-runewidth) +[![Go Report Card](https://goreportcard.com/badge/github.com/mattn/go-runewidth)](https://goreportcard.com/report/github.com/mattn/go-runewidth) + +Provides functions to get fixed width of the character or string. + +Usage +----- + +```go +runewidth.StringWidth("つのだ☆HIRO") == 12 +``` + + +Author +------ + +Yasuhiro Matsumoto + +License +------- + +under the MIT License: http://mattn.mit-license.org/2013 diff --git a/vendor/github.com/mattn/go-runewidth/runewidth.go b/vendor/github.com/mattn/go-runewidth/runewidth.go new file mode 100644 index 000000000..a16f1af0e --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth.go @@ -0,0 +1,1224 @@ +package runewidth + +var ( + // EastAsianWidth will be set true if the current locale is CJK + EastAsianWidth = IsEastAsian() + + // DefaultCondition is a condition in current locale + DefaultCondition = &Condition{EastAsianWidth} +) + +type interval struct { + first rune + last rune +} + +type table []interval + +func inTables(r rune, ts ...table) bool { + for _, t := range ts { + if inTable(r, t) { + return true + } + } + return false +} + +func inTable(r rune, t table) bool { + // func (t table) IncludesRune(r rune) bool { + if r < t[0].first { + return false + } + + bot := 0 + top := len(t) - 1 + for top >= bot { + mid := (bot + top) / 2 + + switch { + case t[mid].last < r: + bot = mid + 1 + case t[mid].first > r: + top = mid - 1 + default: + return true + } + } + + return false +} + +var private = table{ + {0x00E000, 0x00F8FF}, {0x0F0000, 0x0FFFFD}, {0x100000, 0x10FFFD}, +} + +var nonprint = table{ + {0x0000, 0x001F}, {0x007F, 0x009F}, {0x00AD, 0x00AD}, + {0x070F, 0x070F}, {0x180B, 0x180E}, {0x200B, 0x200F}, + {0x2028, 0x2029}, + {0x202A, 0x202E}, {0x206A, 0x206F}, {0xD800, 0xDFFF}, + {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFE, 0xFFFF}, +} + +var combining = table{ + {0x0300, 0x036F}, {0x0483, 0x0489}, {0x0591, 0x05BD}, + {0x05BF, 0x05BF}, {0x05C1, 0x05C2}, {0x05C4, 0x05C5}, + {0x05C7, 0x05C7}, {0x0610, 0x061A}, {0x064B, 0x065F}, + {0x0670, 0x0670}, {0x06D6, 0x06DC}, {0x06DF, 0x06E4}, + {0x06E7, 0x06E8}, {0x06EA, 0x06ED}, {0x0711, 0x0711}, + {0x0730, 0x074A}, {0x07A6, 0x07B0}, {0x07EB, 0x07F3}, + {0x0816, 0x0819}, {0x081B, 0x0823}, {0x0825, 0x0827}, + {0x0829, 0x082D}, {0x0859, 0x085B}, {0x08D4, 0x08E1}, + {0x08E3, 0x0903}, {0x093A, 0x093C}, {0x093E, 0x094F}, + {0x0951, 0x0957}, {0x0962, 0x0963}, {0x0981, 0x0983}, + {0x09BC, 0x09BC}, {0x09BE, 0x09C4}, {0x09C7, 0x09C8}, + {0x09CB, 0x09CD}, {0x09D7, 0x09D7}, {0x09E2, 0x09E3}, + {0x0A01, 0x0A03}, {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A42}, + {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, + {0x0A70, 0x0A71}, {0x0A75, 0x0A75}, {0x0A81, 0x0A83}, + {0x0ABC, 0x0ABC}, {0x0ABE, 0x0AC5}, {0x0AC7, 0x0AC9}, + {0x0ACB, 0x0ACD}, {0x0AE2, 0x0AE3}, {0x0B01, 0x0B03}, + {0x0B3C, 0x0B3C}, {0x0B3E, 0x0B44}, {0x0B47, 0x0B48}, + {0x0B4B, 0x0B4D}, {0x0B56, 0x0B57}, {0x0B62, 0x0B63}, + {0x0B82, 0x0B82}, {0x0BBE, 0x0BC2}, {0x0BC6, 0x0BC8}, + {0x0BCA, 0x0BCD}, {0x0BD7, 0x0BD7}, {0x0C00, 0x0C03}, + {0x0C3E, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, + {0x0C55, 0x0C56}, {0x0C62, 0x0C63}, {0x0C81, 0x0C83}, + {0x0CBC, 0x0CBC}, {0x0CBE, 0x0CC4}, {0x0CC6, 0x0CC8}, + {0x0CCA, 0x0CCD}, {0x0CD5, 0x0CD6}, {0x0CE2, 0x0CE3}, + {0x0D01, 0x0D03}, {0x0D3E, 0x0D44}, {0x0D46, 0x0D48}, + {0x0D4A, 0x0D4D}, {0x0D57, 0x0D57}, {0x0D62, 0x0D63}, + {0x0D82, 0x0D83}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD4}, + {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, {0x0DF2, 0x0DF3}, + {0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E}, + {0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, + {0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35}, + {0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F3E, 0x0F3F}, + {0x0F71, 0x0F84}, {0x0F86, 0x0F87}, {0x0F8D, 0x0F97}, + {0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102B, 0x103E}, + {0x1056, 0x1059}, {0x105E, 0x1060}, {0x1062, 0x1064}, + {0x1067, 0x106D}, {0x1071, 0x1074}, {0x1082, 0x108D}, + {0x108F, 0x108F}, {0x109A, 0x109D}, {0x135D, 0x135F}, + {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753}, + {0x1772, 0x1773}, {0x17B4, 0x17D3}, {0x17DD, 0x17DD}, + {0x180B, 0x180D}, {0x1885, 0x1886}, {0x18A9, 0x18A9}, + {0x1920, 0x192B}, {0x1930, 0x193B}, {0x1A17, 0x1A1B}, + {0x1A55, 0x1A5E}, {0x1A60, 0x1A7C}, {0x1A7F, 0x1A7F}, + {0x1AB0, 0x1ABE}, {0x1B00, 0x1B04}, {0x1B34, 0x1B44}, + {0x1B6B, 0x1B73}, {0x1B80, 0x1B82}, {0x1BA1, 0x1BAD}, + {0x1BE6, 0x1BF3}, {0x1C24, 0x1C37}, {0x1CD0, 0x1CD2}, + {0x1CD4, 0x1CE8}, {0x1CED, 0x1CED}, {0x1CF2, 0x1CF4}, + {0x1CF8, 0x1CF9}, {0x1DC0, 0x1DF5}, {0x1DFB, 0x1DFF}, + {0x20D0, 0x20F0}, {0x2CEF, 0x2CF1}, {0x2D7F, 0x2D7F}, + {0x2DE0, 0x2DFF}, {0x302A, 0x302F}, {0x3099, 0x309A}, + {0xA66F, 0xA672}, {0xA674, 0xA67D}, {0xA69E, 0xA69F}, + {0xA6F0, 0xA6F1}, {0xA802, 0xA802}, {0xA806, 0xA806}, + {0xA80B, 0xA80B}, {0xA823, 0xA827}, {0xA880, 0xA881}, + {0xA8B4, 0xA8C5}, {0xA8E0, 0xA8F1}, {0xA926, 0xA92D}, + {0xA947, 0xA953}, {0xA980, 0xA983}, {0xA9B3, 0xA9C0}, + {0xA9E5, 0xA9E5}, {0xAA29, 0xAA36}, {0xAA43, 0xAA43}, + {0xAA4C, 0xAA4D}, {0xAA7B, 0xAA7D}, {0xAAB0, 0xAAB0}, + {0xAAB2, 0xAAB4}, {0xAAB7, 0xAAB8}, {0xAABE, 0xAABF}, + {0xAAC1, 0xAAC1}, {0xAAEB, 0xAAEF}, {0xAAF5, 0xAAF6}, + {0xABE3, 0xABEA}, {0xABEC, 0xABED}, {0xFB1E, 0xFB1E}, + {0xFE00, 0xFE0F}, {0xFE20, 0xFE2F}, {0x101FD, 0x101FD}, + {0x102E0, 0x102E0}, {0x10376, 0x1037A}, {0x10A01, 0x10A03}, + {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, {0x10A38, 0x10A3A}, + {0x10A3F, 0x10A3F}, {0x10AE5, 0x10AE6}, {0x11000, 0x11002}, + {0x11038, 0x11046}, {0x1107F, 0x11082}, {0x110B0, 0x110BA}, + {0x11100, 0x11102}, {0x11127, 0x11134}, {0x11173, 0x11173}, + {0x11180, 0x11182}, {0x111B3, 0x111C0}, {0x111CA, 0x111CC}, + {0x1122C, 0x11237}, {0x1123E, 0x1123E}, {0x112DF, 0x112EA}, + {0x11300, 0x11303}, {0x1133C, 0x1133C}, {0x1133E, 0x11344}, + {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11357, 0x11357}, + {0x11362, 0x11363}, {0x11366, 0x1136C}, {0x11370, 0x11374}, + {0x11435, 0x11446}, {0x114B0, 0x114C3}, {0x115AF, 0x115B5}, + {0x115B8, 0x115C0}, {0x115DC, 0x115DD}, {0x11630, 0x11640}, + {0x116AB, 0x116B7}, {0x1171D, 0x1172B}, {0x11C2F, 0x11C36}, + {0x11C38, 0x11C3F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CB6}, + {0x16AF0, 0x16AF4}, {0x16B30, 0x16B36}, {0x16F51, 0x16F7E}, + {0x16F8F, 0x16F92}, {0x1BC9D, 0x1BC9E}, {0x1D165, 0x1D169}, + {0x1D16D, 0x1D172}, {0x1D17B, 0x1D182}, {0x1D185, 0x1D18B}, + {0x1D1AA, 0x1D1AD}, {0x1D242, 0x1D244}, {0x1DA00, 0x1DA36}, + {0x1DA3B, 0x1DA6C}, {0x1DA75, 0x1DA75}, {0x1DA84, 0x1DA84}, + {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, {0x1E000, 0x1E006}, + {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, {0x1E023, 0x1E024}, + {0x1E026, 0x1E02A}, {0x1E8D0, 0x1E8D6}, {0x1E944, 0x1E94A}, + {0xE0100, 0xE01EF}, +} + +var doublewidth = table{ + {0x1100, 0x115F}, {0x231A, 0x231B}, {0x2329, 0x232A}, + {0x23E9, 0x23EC}, {0x23F0, 0x23F0}, {0x23F3, 0x23F3}, + {0x25FD, 0x25FE}, {0x2614, 0x2615}, {0x2648, 0x2653}, + {0x267F, 0x267F}, {0x2693, 0x2693}, {0x26A1, 0x26A1}, + {0x26AA, 0x26AB}, {0x26BD, 0x26BE}, {0x26C4, 0x26C5}, + {0x26CE, 0x26CE}, {0x26D4, 0x26D4}, {0x26EA, 0x26EA}, + {0x26F2, 0x26F3}, {0x26F5, 0x26F5}, {0x26FA, 0x26FA}, + {0x26FD, 0x26FD}, {0x2705, 0x2705}, {0x270A, 0x270B}, + {0x2728, 0x2728}, {0x274C, 0x274C}, {0x274E, 0x274E}, + {0x2753, 0x2755}, {0x2757, 0x2757}, {0x2795, 0x2797}, + {0x27B0, 0x27B0}, {0x27BF, 0x27BF}, {0x2B1B, 0x2B1C}, + {0x2B50, 0x2B50}, {0x2B55, 0x2B55}, {0x2E80, 0x2E99}, + {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, {0x2FF0, 0x2FFB}, + {0x3000, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF}, + {0x3105, 0x312D}, {0x3131, 0x318E}, {0x3190, 0x31BA}, + {0x31C0, 0x31E3}, {0x31F0, 0x321E}, {0x3220, 0x3247}, + {0x3250, 0x32FE}, {0x3300, 0x4DBF}, {0x4E00, 0xA48C}, + {0xA490, 0xA4C6}, {0xA960, 0xA97C}, {0xAC00, 0xD7A3}, + {0xF900, 0xFAFF}, {0xFE10, 0xFE19}, {0xFE30, 0xFE52}, + {0xFE54, 0xFE66}, {0xFE68, 0xFE6B}, {0xFF01, 0xFF60}, + {0xFFE0, 0xFFE6}, {0x16FE0, 0x16FE0}, {0x17000, 0x187EC}, + {0x18800, 0x18AF2}, {0x1B000, 0x1B001}, {0x1F004, 0x1F004}, + {0x1F0CF, 0x1F0CF}, {0x1F18E, 0x1F18E}, {0x1F191, 0x1F19A}, + {0x1F200, 0x1F202}, {0x1F210, 0x1F23B}, {0x1F240, 0x1F248}, + {0x1F250, 0x1F251}, {0x1F300, 0x1F320}, {0x1F32D, 0x1F335}, + {0x1F337, 0x1F37C}, {0x1F37E, 0x1F393}, {0x1F3A0, 0x1F3CA}, + {0x1F3CF, 0x1F3D3}, {0x1F3E0, 0x1F3F0}, {0x1F3F4, 0x1F3F4}, + {0x1F3F8, 0x1F43E}, {0x1F440, 0x1F440}, {0x1F442, 0x1F4FC}, + {0x1F4FF, 0x1F53D}, {0x1F54B, 0x1F54E}, {0x1F550, 0x1F567}, + {0x1F57A, 0x1F57A}, {0x1F595, 0x1F596}, {0x1F5A4, 0x1F5A4}, + {0x1F5FB, 0x1F64F}, {0x1F680, 0x1F6C5}, {0x1F6CC, 0x1F6CC}, + {0x1F6D0, 0x1F6D2}, {0x1F6EB, 0x1F6EC}, {0x1F6F4, 0x1F6F6}, + {0x1F910, 0x1F91E}, {0x1F920, 0x1F927}, {0x1F930, 0x1F930}, + {0x1F933, 0x1F93E}, {0x1F940, 0x1F94B}, {0x1F950, 0x1F95E}, + {0x1F980, 0x1F991}, {0x1F9C0, 0x1F9C0}, {0x20000, 0x2FFFD}, + {0x30000, 0x3FFFD}, +} + +var ambiguous = table{ + {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8}, + {0x00AA, 0x00AA}, {0x00AD, 0x00AE}, {0x00B0, 0x00B4}, + {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6}, + {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1}, + {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED}, + {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA}, + {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101}, + {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B}, + {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133}, + {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144}, + {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153}, + {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE}, + {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4}, + {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA}, + {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261}, + {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB}, + {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB}, + {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0300, 0x036F}, + {0x0391, 0x03A1}, {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, + {0x03C3, 0x03C9}, {0x0401, 0x0401}, {0x0410, 0x044F}, + {0x0451, 0x0451}, {0x2010, 0x2010}, {0x2013, 0x2016}, + {0x2018, 0x2019}, {0x201C, 0x201D}, {0x2020, 0x2022}, + {0x2024, 0x2027}, {0x2030, 0x2030}, {0x2032, 0x2033}, + {0x2035, 0x2035}, {0x203B, 0x203B}, {0x203E, 0x203E}, + {0x2074, 0x2074}, {0x207F, 0x207F}, {0x2081, 0x2084}, + {0x20AC, 0x20AC}, {0x2103, 0x2103}, {0x2105, 0x2105}, + {0x2109, 0x2109}, {0x2113, 0x2113}, {0x2116, 0x2116}, + {0x2121, 0x2122}, {0x2126, 0x2126}, {0x212B, 0x212B}, + {0x2153, 0x2154}, {0x215B, 0x215E}, {0x2160, 0x216B}, + {0x2170, 0x2179}, {0x2189, 0x2189}, {0x2190, 0x2199}, + {0x21B8, 0x21B9}, {0x21D2, 0x21D2}, {0x21D4, 0x21D4}, + {0x21E7, 0x21E7}, {0x2200, 0x2200}, {0x2202, 0x2203}, + {0x2207, 0x2208}, {0x220B, 0x220B}, {0x220F, 0x220F}, + {0x2211, 0x2211}, {0x2215, 0x2215}, {0x221A, 0x221A}, + {0x221D, 0x2220}, {0x2223, 0x2223}, {0x2225, 0x2225}, + {0x2227, 0x222C}, {0x222E, 0x222E}, {0x2234, 0x2237}, + {0x223C, 0x223D}, {0x2248, 0x2248}, {0x224C, 0x224C}, + {0x2252, 0x2252}, {0x2260, 0x2261}, {0x2264, 0x2267}, + {0x226A, 0x226B}, {0x226E, 0x226F}, {0x2282, 0x2283}, + {0x2286, 0x2287}, {0x2295, 0x2295}, {0x2299, 0x2299}, + {0x22A5, 0x22A5}, {0x22BF, 0x22BF}, {0x2312, 0x2312}, + {0x2460, 0x24E9}, {0x24EB, 0x254B}, {0x2550, 0x2573}, + {0x2580, 0x258F}, {0x2592, 0x2595}, {0x25A0, 0x25A1}, + {0x25A3, 0x25A9}, {0x25B2, 0x25B3}, {0x25B6, 0x25B7}, + {0x25BC, 0x25BD}, {0x25C0, 0x25C1}, {0x25C6, 0x25C8}, + {0x25CB, 0x25CB}, {0x25CE, 0x25D1}, {0x25E2, 0x25E5}, + {0x25EF, 0x25EF}, {0x2605, 0x2606}, {0x2609, 0x2609}, + {0x260E, 0x260F}, {0x261C, 0x261C}, {0x261E, 0x261E}, + {0x2640, 0x2640}, {0x2642, 0x2642}, {0x2660, 0x2661}, + {0x2663, 0x2665}, {0x2667, 0x266A}, {0x266C, 0x266D}, + {0x266F, 0x266F}, {0x269E, 0x269F}, {0x26BF, 0x26BF}, + {0x26C6, 0x26CD}, {0x26CF, 0x26D3}, {0x26D5, 0x26E1}, + {0x26E3, 0x26E3}, {0x26E8, 0x26E9}, {0x26EB, 0x26F1}, + {0x26F4, 0x26F4}, {0x26F6, 0x26F9}, {0x26FB, 0x26FC}, + {0x26FE, 0x26FF}, {0x273D, 0x273D}, {0x2776, 0x277F}, + {0x2B56, 0x2B59}, {0x3248, 0x324F}, {0xE000, 0xF8FF}, + {0xFE00, 0xFE0F}, {0xFFFD, 0xFFFD}, {0x1F100, 0x1F10A}, + {0x1F110, 0x1F12D}, {0x1F130, 0x1F169}, {0x1F170, 0x1F18D}, + {0x1F18F, 0x1F190}, {0x1F19B, 0x1F1AC}, {0xE0100, 0xE01EF}, + {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}, +} + +var emoji = table{ + {0x1F1E6, 0x1F1FF}, {0x1F321, 0x1F321}, {0x1F324, 0x1F32C}, + {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, {0x1F396, 0x1F397}, + {0x1F399, 0x1F39B}, {0x1F39E, 0x1F39F}, {0x1F3CB, 0x1F3CE}, + {0x1F3D4, 0x1F3DF}, {0x1F3F3, 0x1F3F5}, {0x1F3F7, 0x1F3F7}, + {0x1F43F, 0x1F43F}, {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FD}, + {0x1F549, 0x1F54A}, {0x1F56F, 0x1F570}, {0x1F573, 0x1F579}, + {0x1F587, 0x1F587}, {0x1F58A, 0x1F58D}, {0x1F590, 0x1F590}, + {0x1F5A5, 0x1F5A5}, {0x1F5A8, 0x1F5A8}, {0x1F5B1, 0x1F5B2}, + {0x1F5BC, 0x1F5BC}, {0x1F5C2, 0x1F5C4}, {0x1F5D1, 0x1F5D3}, + {0x1F5DC, 0x1F5DE}, {0x1F5E1, 0x1F5E1}, {0x1F5E3, 0x1F5E3}, + {0x1F5E8, 0x1F5E8}, {0x1F5EF, 0x1F5EF}, {0x1F5F3, 0x1F5F3}, + {0x1F5FA, 0x1F5FA}, {0x1F6CB, 0x1F6CF}, {0x1F6E0, 0x1F6E5}, + {0x1F6E9, 0x1F6E9}, {0x1F6F0, 0x1F6F0}, {0x1F6F3, 0x1F6F3}, +} + +var notassigned = table{ + {0x0378, 0x0379}, {0x0380, 0x0383}, {0x038B, 0x038B}, + {0x038D, 0x038D}, {0x03A2, 0x03A2}, {0x0530, 0x0530}, + {0x0557, 0x0558}, {0x0560, 0x0560}, {0x0588, 0x0588}, + {0x058B, 0x058C}, {0x0590, 0x0590}, {0x05C8, 0x05CF}, + {0x05EB, 0x05EF}, {0x05F5, 0x05FF}, {0x061D, 0x061D}, + {0x070E, 0x070E}, {0x074B, 0x074C}, {0x07B2, 0x07BF}, + {0x07FB, 0x07FF}, {0x082E, 0x082F}, {0x083F, 0x083F}, + {0x085C, 0x085D}, {0x085F, 0x089F}, {0x08B5, 0x08B5}, + {0x08BE, 0x08D3}, {0x0984, 0x0984}, {0x098D, 0x098E}, + {0x0991, 0x0992}, {0x09A9, 0x09A9}, {0x09B1, 0x09B1}, + {0x09B3, 0x09B5}, {0x09BA, 0x09BB}, {0x09C5, 0x09C6}, + {0x09C9, 0x09CA}, {0x09CF, 0x09D6}, {0x09D8, 0x09DB}, + {0x09DE, 0x09DE}, {0x09E4, 0x09E5}, {0x09FC, 0x0A00}, + {0x0A04, 0x0A04}, {0x0A0B, 0x0A0E}, {0x0A11, 0x0A12}, + {0x0A29, 0x0A29}, {0x0A31, 0x0A31}, {0x0A34, 0x0A34}, + {0x0A37, 0x0A37}, {0x0A3A, 0x0A3B}, {0x0A3D, 0x0A3D}, + {0x0A43, 0x0A46}, {0x0A49, 0x0A4A}, {0x0A4E, 0x0A50}, + {0x0A52, 0x0A58}, {0x0A5D, 0x0A5D}, {0x0A5F, 0x0A65}, + {0x0A76, 0x0A80}, {0x0A84, 0x0A84}, {0x0A8E, 0x0A8E}, + {0x0A92, 0x0A92}, {0x0AA9, 0x0AA9}, {0x0AB1, 0x0AB1}, + {0x0AB4, 0x0AB4}, {0x0ABA, 0x0ABB}, {0x0AC6, 0x0AC6}, + {0x0ACA, 0x0ACA}, {0x0ACE, 0x0ACF}, {0x0AD1, 0x0ADF}, + {0x0AE4, 0x0AE5}, {0x0AF2, 0x0AF8}, {0x0AFA, 0x0B00}, + {0x0B04, 0x0B04}, {0x0B0D, 0x0B0E}, {0x0B11, 0x0B12}, + {0x0B29, 0x0B29}, {0x0B31, 0x0B31}, {0x0B34, 0x0B34}, + {0x0B3A, 0x0B3B}, {0x0B45, 0x0B46}, {0x0B49, 0x0B4A}, + {0x0B4E, 0x0B55}, {0x0B58, 0x0B5B}, {0x0B5E, 0x0B5E}, + {0x0B64, 0x0B65}, {0x0B78, 0x0B81}, {0x0B84, 0x0B84}, + {0x0B8B, 0x0B8D}, {0x0B91, 0x0B91}, {0x0B96, 0x0B98}, + {0x0B9B, 0x0B9B}, {0x0B9D, 0x0B9D}, {0x0BA0, 0x0BA2}, + {0x0BA5, 0x0BA7}, {0x0BAB, 0x0BAD}, {0x0BBA, 0x0BBD}, + {0x0BC3, 0x0BC5}, {0x0BC9, 0x0BC9}, {0x0BCE, 0x0BCF}, + {0x0BD1, 0x0BD6}, {0x0BD8, 0x0BE5}, {0x0BFB, 0x0BFF}, + {0x0C04, 0x0C04}, {0x0C0D, 0x0C0D}, {0x0C11, 0x0C11}, + {0x0C29, 0x0C29}, {0x0C3A, 0x0C3C}, {0x0C45, 0x0C45}, + {0x0C49, 0x0C49}, {0x0C4E, 0x0C54}, {0x0C57, 0x0C57}, + {0x0C5B, 0x0C5F}, {0x0C64, 0x0C65}, {0x0C70, 0x0C77}, + {0x0C84, 0x0C84}, {0x0C8D, 0x0C8D}, {0x0C91, 0x0C91}, + {0x0CA9, 0x0CA9}, {0x0CB4, 0x0CB4}, {0x0CBA, 0x0CBB}, + {0x0CC5, 0x0CC5}, {0x0CC9, 0x0CC9}, {0x0CCE, 0x0CD4}, + {0x0CD7, 0x0CDD}, {0x0CDF, 0x0CDF}, {0x0CE4, 0x0CE5}, + {0x0CF0, 0x0CF0}, {0x0CF3, 0x0D00}, {0x0D04, 0x0D04}, + {0x0D0D, 0x0D0D}, {0x0D11, 0x0D11}, {0x0D3B, 0x0D3C}, + {0x0D45, 0x0D45}, {0x0D49, 0x0D49}, {0x0D50, 0x0D53}, + {0x0D64, 0x0D65}, {0x0D80, 0x0D81}, {0x0D84, 0x0D84}, + {0x0D97, 0x0D99}, {0x0DB2, 0x0DB2}, {0x0DBC, 0x0DBC}, + {0x0DBE, 0x0DBF}, {0x0DC7, 0x0DC9}, {0x0DCB, 0x0DCE}, + {0x0DD5, 0x0DD5}, {0x0DD7, 0x0DD7}, {0x0DE0, 0x0DE5}, + {0x0DF0, 0x0DF1}, {0x0DF5, 0x0E00}, {0x0E3B, 0x0E3E}, + {0x0E5C, 0x0E80}, {0x0E83, 0x0E83}, {0x0E85, 0x0E86}, + {0x0E89, 0x0E89}, {0x0E8B, 0x0E8C}, {0x0E8E, 0x0E93}, + {0x0E98, 0x0E98}, {0x0EA0, 0x0EA0}, {0x0EA4, 0x0EA4}, + {0x0EA6, 0x0EA6}, {0x0EA8, 0x0EA9}, {0x0EAC, 0x0EAC}, + {0x0EBA, 0x0EBA}, {0x0EBE, 0x0EBF}, {0x0EC5, 0x0EC5}, + {0x0EC7, 0x0EC7}, {0x0ECE, 0x0ECF}, {0x0EDA, 0x0EDB}, + {0x0EE0, 0x0EFF}, {0x0F48, 0x0F48}, {0x0F6D, 0x0F70}, + {0x0F98, 0x0F98}, {0x0FBD, 0x0FBD}, {0x0FCD, 0x0FCD}, + {0x0FDB, 0x0FFF}, {0x10C6, 0x10C6}, {0x10C8, 0x10CC}, + {0x10CE, 0x10CF}, {0x1249, 0x1249}, {0x124E, 0x124F}, + {0x1257, 0x1257}, {0x1259, 0x1259}, {0x125E, 0x125F}, + {0x1289, 0x1289}, {0x128E, 0x128F}, {0x12B1, 0x12B1}, + {0x12B6, 0x12B7}, {0x12BF, 0x12BF}, {0x12C1, 0x12C1}, + {0x12C6, 0x12C7}, {0x12D7, 0x12D7}, {0x1311, 0x1311}, + {0x1316, 0x1317}, {0x135B, 0x135C}, {0x137D, 0x137F}, + {0x139A, 0x139F}, {0x13F6, 0x13F7}, {0x13FE, 0x13FF}, + {0x169D, 0x169F}, {0x16F9, 0x16FF}, {0x170D, 0x170D}, + {0x1715, 0x171F}, {0x1737, 0x173F}, {0x1754, 0x175F}, + {0x176D, 0x176D}, {0x1771, 0x1771}, {0x1774, 0x177F}, + {0x17DE, 0x17DF}, {0x17EA, 0x17EF}, {0x17FA, 0x17FF}, + {0x180F, 0x180F}, {0x181A, 0x181F}, {0x1878, 0x187F}, + {0x18AB, 0x18AF}, {0x18F6, 0x18FF}, {0x191F, 0x191F}, + {0x192C, 0x192F}, {0x193C, 0x193F}, {0x1941, 0x1943}, + {0x196E, 0x196F}, {0x1975, 0x197F}, {0x19AC, 0x19AF}, + {0x19CA, 0x19CF}, {0x19DB, 0x19DD}, {0x1A1C, 0x1A1D}, + {0x1A5F, 0x1A5F}, {0x1A7D, 0x1A7E}, {0x1A8A, 0x1A8F}, + {0x1A9A, 0x1A9F}, {0x1AAE, 0x1AAF}, {0x1ABF, 0x1AFF}, + {0x1B4C, 0x1B4F}, {0x1B7D, 0x1B7F}, {0x1BF4, 0x1BFB}, + {0x1C38, 0x1C3A}, {0x1C4A, 0x1C4C}, {0x1C89, 0x1CBF}, + {0x1CC8, 0x1CCF}, {0x1CF7, 0x1CF7}, {0x1CFA, 0x1CFF}, + {0x1DF6, 0x1DFA}, {0x1F16, 0x1F17}, {0x1F1E, 0x1F1F}, + {0x1F46, 0x1F47}, {0x1F4E, 0x1F4F}, {0x1F58, 0x1F58}, + {0x1F5A, 0x1F5A}, {0x1F5C, 0x1F5C}, {0x1F5E, 0x1F5E}, + {0x1F7E, 0x1F7F}, {0x1FB5, 0x1FB5}, {0x1FC5, 0x1FC5}, + {0x1FD4, 0x1FD5}, {0x1FDC, 0x1FDC}, {0x1FF0, 0x1FF1}, + {0x1FF5, 0x1FF5}, {0x1FFF, 0x1FFF}, {0x2065, 0x2065}, + {0x2072, 0x2073}, {0x208F, 0x208F}, {0x209D, 0x209F}, + {0x20BF, 0x20CF}, {0x20F1, 0x20FF}, {0x218C, 0x218F}, + {0x23FF, 0x23FF}, {0x2427, 0x243F}, {0x244B, 0x245F}, + {0x2B74, 0x2B75}, {0x2B96, 0x2B97}, {0x2BBA, 0x2BBC}, + {0x2BC9, 0x2BC9}, {0x2BD2, 0x2BEB}, {0x2BF0, 0x2BFF}, + {0x2C2F, 0x2C2F}, {0x2C5F, 0x2C5F}, {0x2CF4, 0x2CF8}, + {0x2D26, 0x2D26}, {0x2D28, 0x2D2C}, {0x2D2E, 0x2D2F}, + {0x2D68, 0x2D6E}, {0x2D71, 0x2D7E}, {0x2D97, 0x2D9F}, + {0x2DA7, 0x2DA7}, {0x2DAF, 0x2DAF}, {0x2DB7, 0x2DB7}, + {0x2DBF, 0x2DBF}, {0x2DC7, 0x2DC7}, {0x2DCF, 0x2DCF}, + {0x2DD7, 0x2DD7}, {0x2DDF, 0x2DDF}, {0x2E45, 0x2E7F}, + {0x2E9A, 0x2E9A}, {0x2EF4, 0x2EFF}, {0x2FD6, 0x2FEF}, + {0x2FFC, 0x2FFF}, {0x3040, 0x3040}, {0x3097, 0x3098}, + {0x3100, 0x3104}, {0x312E, 0x3130}, {0x318F, 0x318F}, + {0x31BB, 0x31BF}, {0x31E4, 0x31EF}, {0x321F, 0x321F}, + {0x32FF, 0x32FF}, {0x4DB6, 0x4DBF}, {0x9FD6, 0x9FFF}, + {0xA48D, 0xA48F}, {0xA4C7, 0xA4CF}, {0xA62C, 0xA63F}, + {0xA6F8, 0xA6FF}, {0xA7AF, 0xA7AF}, {0xA7B8, 0xA7F6}, + {0xA82C, 0xA82F}, {0xA83A, 0xA83F}, {0xA878, 0xA87F}, + {0xA8C6, 0xA8CD}, {0xA8DA, 0xA8DF}, {0xA8FE, 0xA8FF}, + {0xA954, 0xA95E}, {0xA97D, 0xA97F}, {0xA9CE, 0xA9CE}, + {0xA9DA, 0xA9DD}, {0xA9FF, 0xA9FF}, {0xAA37, 0xAA3F}, + {0xAA4E, 0xAA4F}, {0xAA5A, 0xAA5B}, {0xAAC3, 0xAADA}, + {0xAAF7, 0xAB00}, {0xAB07, 0xAB08}, {0xAB0F, 0xAB10}, + {0xAB17, 0xAB1F}, {0xAB27, 0xAB27}, {0xAB2F, 0xAB2F}, + {0xAB66, 0xAB6F}, {0xABEE, 0xABEF}, {0xABFA, 0xABFF}, + {0xD7A4, 0xD7AF}, {0xD7C7, 0xD7CA}, {0xD7FC, 0xD7FF}, + {0xFA6E, 0xFA6F}, {0xFADA, 0xFAFF}, {0xFB07, 0xFB12}, + {0xFB18, 0xFB1C}, {0xFB37, 0xFB37}, {0xFB3D, 0xFB3D}, + {0xFB3F, 0xFB3F}, {0xFB42, 0xFB42}, {0xFB45, 0xFB45}, + {0xFBC2, 0xFBD2}, {0xFD40, 0xFD4F}, {0xFD90, 0xFD91}, + {0xFDC8, 0xFDEF}, {0xFDFE, 0xFDFF}, {0xFE1A, 0xFE1F}, + {0xFE53, 0xFE53}, {0xFE67, 0xFE67}, {0xFE6C, 0xFE6F}, + {0xFE75, 0xFE75}, {0xFEFD, 0xFEFE}, {0xFF00, 0xFF00}, + {0xFFBF, 0xFFC1}, {0xFFC8, 0xFFC9}, {0xFFD0, 0xFFD1}, + {0xFFD8, 0xFFD9}, {0xFFDD, 0xFFDF}, {0xFFE7, 0xFFE7}, + {0xFFEF, 0xFFF8}, {0xFFFE, 0xFFFF}, {0x1000C, 0x1000C}, + {0x10027, 0x10027}, {0x1003B, 0x1003B}, {0x1003E, 0x1003E}, + {0x1004E, 0x1004F}, {0x1005E, 0x1007F}, {0x100FB, 0x100FF}, + {0x10103, 0x10106}, {0x10134, 0x10136}, {0x1018F, 0x1018F}, + {0x1019C, 0x1019F}, {0x101A1, 0x101CF}, {0x101FE, 0x1027F}, + {0x1029D, 0x1029F}, {0x102D1, 0x102DF}, {0x102FC, 0x102FF}, + {0x10324, 0x1032F}, {0x1034B, 0x1034F}, {0x1037B, 0x1037F}, + {0x1039E, 0x1039E}, {0x103C4, 0x103C7}, {0x103D6, 0x103FF}, + {0x1049E, 0x1049F}, {0x104AA, 0x104AF}, {0x104D4, 0x104D7}, + {0x104FC, 0x104FF}, {0x10528, 0x1052F}, {0x10564, 0x1056E}, + {0x10570, 0x105FF}, {0x10737, 0x1073F}, {0x10756, 0x1075F}, + {0x10768, 0x107FF}, {0x10806, 0x10807}, {0x10809, 0x10809}, + {0x10836, 0x10836}, {0x10839, 0x1083B}, {0x1083D, 0x1083E}, + {0x10856, 0x10856}, {0x1089F, 0x108A6}, {0x108B0, 0x108DF}, + {0x108F3, 0x108F3}, {0x108F6, 0x108FA}, {0x1091C, 0x1091E}, + {0x1093A, 0x1093E}, {0x10940, 0x1097F}, {0x109B8, 0x109BB}, + {0x109D0, 0x109D1}, {0x10A04, 0x10A04}, {0x10A07, 0x10A0B}, + {0x10A14, 0x10A14}, {0x10A18, 0x10A18}, {0x10A34, 0x10A37}, + {0x10A3B, 0x10A3E}, {0x10A48, 0x10A4F}, {0x10A59, 0x10A5F}, + {0x10AA0, 0x10ABF}, {0x10AE7, 0x10AEA}, {0x10AF7, 0x10AFF}, + {0x10B36, 0x10B38}, {0x10B56, 0x10B57}, {0x10B73, 0x10B77}, + {0x10B92, 0x10B98}, {0x10B9D, 0x10BA8}, {0x10BB0, 0x10BFF}, + {0x10C49, 0x10C7F}, {0x10CB3, 0x10CBF}, {0x10CF3, 0x10CF9}, + {0x10D00, 0x10E5F}, {0x10E7F, 0x10FFF}, {0x1104E, 0x11051}, + {0x11070, 0x1107E}, {0x110C2, 0x110CF}, {0x110E9, 0x110EF}, + {0x110FA, 0x110FF}, {0x11135, 0x11135}, {0x11144, 0x1114F}, + {0x11177, 0x1117F}, {0x111CE, 0x111CF}, {0x111E0, 0x111E0}, + {0x111F5, 0x111FF}, {0x11212, 0x11212}, {0x1123F, 0x1127F}, + {0x11287, 0x11287}, {0x11289, 0x11289}, {0x1128E, 0x1128E}, + {0x1129E, 0x1129E}, {0x112AA, 0x112AF}, {0x112EB, 0x112EF}, + {0x112FA, 0x112FF}, {0x11304, 0x11304}, {0x1130D, 0x1130E}, + {0x11311, 0x11312}, {0x11329, 0x11329}, {0x11331, 0x11331}, + {0x11334, 0x11334}, {0x1133A, 0x1133B}, {0x11345, 0x11346}, + {0x11349, 0x1134A}, {0x1134E, 0x1134F}, {0x11351, 0x11356}, + {0x11358, 0x1135C}, {0x11364, 0x11365}, {0x1136D, 0x1136F}, + {0x11375, 0x113FF}, {0x1145A, 0x1145A}, {0x1145C, 0x1145C}, + {0x1145E, 0x1147F}, {0x114C8, 0x114CF}, {0x114DA, 0x1157F}, + {0x115B6, 0x115B7}, {0x115DE, 0x115FF}, {0x11645, 0x1164F}, + {0x1165A, 0x1165F}, {0x1166D, 0x1167F}, {0x116B8, 0x116BF}, + {0x116CA, 0x116FF}, {0x1171A, 0x1171C}, {0x1172C, 0x1172F}, + {0x11740, 0x1189F}, {0x118F3, 0x118FE}, {0x11900, 0x11ABF}, + {0x11AF9, 0x11BFF}, {0x11C09, 0x11C09}, {0x11C37, 0x11C37}, + {0x11C46, 0x11C4F}, {0x11C6D, 0x11C6F}, {0x11C90, 0x11C91}, + {0x11CA8, 0x11CA8}, {0x11CB7, 0x11FFF}, {0x1239A, 0x123FF}, + {0x1246F, 0x1246F}, {0x12475, 0x1247F}, {0x12544, 0x12FFF}, + {0x1342F, 0x143FF}, {0x14647, 0x167FF}, {0x16A39, 0x16A3F}, + {0x16A5F, 0x16A5F}, {0x16A6A, 0x16A6D}, {0x16A70, 0x16ACF}, + {0x16AEE, 0x16AEF}, {0x16AF6, 0x16AFF}, {0x16B46, 0x16B4F}, + {0x16B5A, 0x16B5A}, {0x16B62, 0x16B62}, {0x16B78, 0x16B7C}, + {0x16B90, 0x16EFF}, {0x16F45, 0x16F4F}, {0x16F7F, 0x16F8E}, + {0x16FA0, 0x16FDF}, {0x16FE1, 0x16FFF}, {0x187ED, 0x187FF}, + {0x18AF3, 0x1AFFF}, {0x1B002, 0x1BBFF}, {0x1BC6B, 0x1BC6F}, + {0x1BC7D, 0x1BC7F}, {0x1BC89, 0x1BC8F}, {0x1BC9A, 0x1BC9B}, + {0x1BCA4, 0x1CFFF}, {0x1D0F6, 0x1D0FF}, {0x1D127, 0x1D128}, + {0x1D1E9, 0x1D1FF}, {0x1D246, 0x1D2FF}, {0x1D357, 0x1D35F}, + {0x1D372, 0x1D3FF}, {0x1D455, 0x1D455}, {0x1D49D, 0x1D49D}, + {0x1D4A0, 0x1D4A1}, {0x1D4A3, 0x1D4A4}, {0x1D4A7, 0x1D4A8}, + {0x1D4AD, 0x1D4AD}, {0x1D4BA, 0x1D4BA}, {0x1D4BC, 0x1D4BC}, + {0x1D4C4, 0x1D4C4}, {0x1D506, 0x1D506}, {0x1D50B, 0x1D50C}, + {0x1D515, 0x1D515}, {0x1D51D, 0x1D51D}, {0x1D53A, 0x1D53A}, + {0x1D53F, 0x1D53F}, {0x1D545, 0x1D545}, {0x1D547, 0x1D549}, + {0x1D551, 0x1D551}, {0x1D6A6, 0x1D6A7}, {0x1D7CC, 0x1D7CD}, + {0x1DA8C, 0x1DA9A}, {0x1DAA0, 0x1DAA0}, {0x1DAB0, 0x1DFFF}, + {0x1E007, 0x1E007}, {0x1E019, 0x1E01A}, {0x1E022, 0x1E022}, + {0x1E025, 0x1E025}, {0x1E02B, 0x1E7FF}, {0x1E8C5, 0x1E8C6}, + {0x1E8D7, 0x1E8FF}, {0x1E94B, 0x1E94F}, {0x1E95A, 0x1E95D}, + {0x1E960, 0x1EDFF}, {0x1EE04, 0x1EE04}, {0x1EE20, 0x1EE20}, + {0x1EE23, 0x1EE23}, {0x1EE25, 0x1EE26}, {0x1EE28, 0x1EE28}, + {0x1EE33, 0x1EE33}, {0x1EE38, 0x1EE38}, {0x1EE3A, 0x1EE3A}, + {0x1EE3C, 0x1EE41}, {0x1EE43, 0x1EE46}, {0x1EE48, 0x1EE48}, + {0x1EE4A, 0x1EE4A}, {0x1EE4C, 0x1EE4C}, {0x1EE50, 0x1EE50}, + {0x1EE53, 0x1EE53}, {0x1EE55, 0x1EE56}, {0x1EE58, 0x1EE58}, + {0x1EE5A, 0x1EE5A}, {0x1EE5C, 0x1EE5C}, {0x1EE5E, 0x1EE5E}, + {0x1EE60, 0x1EE60}, {0x1EE63, 0x1EE63}, {0x1EE65, 0x1EE66}, + {0x1EE6B, 0x1EE6B}, {0x1EE73, 0x1EE73}, {0x1EE78, 0x1EE78}, + {0x1EE7D, 0x1EE7D}, {0x1EE7F, 0x1EE7F}, {0x1EE8A, 0x1EE8A}, + {0x1EE9C, 0x1EEA0}, {0x1EEA4, 0x1EEA4}, {0x1EEAA, 0x1EEAA}, + {0x1EEBC, 0x1EEEF}, {0x1EEF2, 0x1EFFF}, {0x1F02C, 0x1F02F}, + {0x1F094, 0x1F09F}, {0x1F0AF, 0x1F0B0}, {0x1F0C0, 0x1F0C0}, + {0x1F0D0, 0x1F0D0}, {0x1F0F6, 0x1F0FF}, {0x1F10D, 0x1F10F}, + {0x1F12F, 0x1F12F}, {0x1F16C, 0x1F16F}, {0x1F1AD, 0x1F1E5}, + {0x1F203, 0x1F20F}, {0x1F23C, 0x1F23F}, {0x1F249, 0x1F24F}, + {0x1F252, 0x1F2FF}, {0x1F6D3, 0x1F6DF}, {0x1F6ED, 0x1F6EF}, + {0x1F6F7, 0x1F6FF}, {0x1F774, 0x1F77F}, {0x1F7D5, 0x1F7FF}, + {0x1F80C, 0x1F80F}, {0x1F848, 0x1F84F}, {0x1F85A, 0x1F85F}, + {0x1F888, 0x1F88F}, {0x1F8AE, 0x1F90F}, {0x1F91F, 0x1F91F}, + {0x1F928, 0x1F92F}, {0x1F931, 0x1F932}, {0x1F93F, 0x1F93F}, + {0x1F94C, 0x1F94F}, {0x1F95F, 0x1F97F}, {0x1F992, 0x1F9BF}, + {0x1F9C1, 0x1FFFF}, {0x2A6D7, 0x2A6FF}, {0x2B735, 0x2B73F}, + {0x2B81E, 0x2B81F}, {0x2CEA2, 0x2F7FF}, {0x2FA1E, 0xE0000}, + {0xE0002, 0xE001F}, {0xE0080, 0xE00FF}, {0xE01F0, 0xEFFFF}, + {0xFFFFE, 0xFFFFF}, +} + +var neutral = table{ + {0x0000, 0x001F}, {0x007F, 0x007F}, {0x0080, 0x009F}, + {0x00A0, 0x00A0}, {0x00A9, 0x00A9}, {0x00AB, 0x00AB}, + {0x00B5, 0x00B5}, {0x00BB, 0x00BB}, {0x00C0, 0x00C5}, + {0x00C7, 0x00CF}, {0x00D1, 0x00D6}, {0x00D9, 0x00DD}, + {0x00E2, 0x00E5}, {0x00E7, 0x00E7}, {0x00EB, 0x00EB}, + {0x00EE, 0x00EF}, {0x00F1, 0x00F1}, {0x00F4, 0x00F6}, + {0x00FB, 0x00FB}, {0x00FD, 0x00FD}, {0x00FF, 0x00FF}, + {0x0100, 0x0100}, {0x0102, 0x0110}, {0x0112, 0x0112}, + {0x0114, 0x011A}, {0x011C, 0x0125}, {0x0128, 0x012A}, + {0x012C, 0x0130}, {0x0134, 0x0137}, {0x0139, 0x013E}, + {0x0143, 0x0143}, {0x0145, 0x0147}, {0x014C, 0x014C}, + {0x014E, 0x0151}, {0x0154, 0x0165}, {0x0168, 0x016A}, + {0x016C, 0x017F}, {0x0180, 0x01BA}, {0x01BB, 0x01BB}, + {0x01BC, 0x01BF}, {0x01C0, 0x01C3}, {0x01C4, 0x01CD}, + {0x01CF, 0x01CF}, {0x01D1, 0x01D1}, {0x01D3, 0x01D3}, + {0x01D5, 0x01D5}, {0x01D7, 0x01D7}, {0x01D9, 0x01D9}, + {0x01DB, 0x01DB}, {0x01DD, 0x024F}, {0x0250, 0x0250}, + {0x0252, 0x0260}, {0x0262, 0x0293}, {0x0294, 0x0294}, + {0x0295, 0x02AF}, {0x02B0, 0x02C1}, {0x02C2, 0x02C3}, + {0x02C5, 0x02C5}, {0x02C6, 0x02C6}, {0x02C8, 0x02C8}, + {0x02CC, 0x02CC}, {0x02CE, 0x02CF}, {0x02D1, 0x02D1}, + {0x02D2, 0x02D7}, {0x02DC, 0x02DC}, {0x02DE, 0x02DE}, + {0x02E0, 0x02E4}, {0x02E5, 0x02EB}, {0x02EC, 0x02EC}, + {0x02ED, 0x02ED}, {0x02EE, 0x02EE}, {0x02EF, 0x02FF}, + {0x0370, 0x0373}, {0x0374, 0x0374}, {0x0375, 0x0375}, + {0x0376, 0x0377}, {0x037A, 0x037A}, {0x037B, 0x037D}, + {0x037E, 0x037E}, {0x037F, 0x037F}, {0x0384, 0x0385}, + {0x0386, 0x0386}, {0x0387, 0x0387}, {0x0388, 0x038A}, + {0x038C, 0x038C}, {0x038E, 0x0390}, {0x03AA, 0x03B0}, + {0x03C2, 0x03C2}, {0x03CA, 0x03F5}, {0x03F6, 0x03F6}, + {0x03F7, 0x03FF}, {0x0400, 0x0400}, {0x0402, 0x040F}, + {0x0450, 0x0450}, {0x0452, 0x0481}, {0x0482, 0x0482}, + {0x0483, 0x0487}, {0x0488, 0x0489}, {0x048A, 0x04FF}, + {0x0500, 0x052F}, {0x0531, 0x0556}, {0x0559, 0x0559}, + {0x055A, 0x055F}, {0x0561, 0x0587}, {0x0589, 0x0589}, + {0x058A, 0x058A}, {0x058D, 0x058E}, {0x058F, 0x058F}, + {0x0591, 0x05BD}, {0x05BE, 0x05BE}, {0x05BF, 0x05BF}, + {0x05C0, 0x05C0}, {0x05C1, 0x05C2}, {0x05C3, 0x05C3}, + {0x05C4, 0x05C5}, {0x05C6, 0x05C6}, {0x05C7, 0x05C7}, + {0x05D0, 0x05EA}, {0x05F0, 0x05F2}, {0x05F3, 0x05F4}, + {0x0600, 0x0605}, {0x0606, 0x0608}, {0x0609, 0x060A}, + {0x060B, 0x060B}, {0x060C, 0x060D}, {0x060E, 0x060F}, + {0x0610, 0x061A}, {0x061B, 0x061B}, {0x061C, 0x061C}, + {0x061E, 0x061F}, {0x0620, 0x063F}, {0x0640, 0x0640}, + {0x0641, 0x064A}, {0x064B, 0x065F}, {0x0660, 0x0669}, + {0x066A, 0x066D}, {0x066E, 0x066F}, {0x0670, 0x0670}, + {0x0671, 0x06D3}, {0x06D4, 0x06D4}, {0x06D5, 0x06D5}, + {0x06D6, 0x06DC}, {0x06DD, 0x06DD}, {0x06DE, 0x06DE}, + {0x06DF, 0x06E4}, {0x06E5, 0x06E6}, {0x06E7, 0x06E8}, + {0x06E9, 0x06E9}, {0x06EA, 0x06ED}, {0x06EE, 0x06EF}, + {0x06F0, 0x06F9}, {0x06FA, 0x06FC}, {0x06FD, 0x06FE}, + {0x06FF, 0x06FF}, {0x0700, 0x070D}, {0x070F, 0x070F}, + {0x0710, 0x0710}, {0x0711, 0x0711}, {0x0712, 0x072F}, + {0x0730, 0x074A}, {0x074D, 0x074F}, {0x0750, 0x077F}, + {0x0780, 0x07A5}, {0x07A6, 0x07B0}, {0x07B1, 0x07B1}, + {0x07C0, 0x07C9}, {0x07CA, 0x07EA}, {0x07EB, 0x07F3}, + {0x07F4, 0x07F5}, {0x07F6, 0x07F6}, {0x07F7, 0x07F9}, + {0x07FA, 0x07FA}, {0x0800, 0x0815}, {0x0816, 0x0819}, + {0x081A, 0x081A}, {0x081B, 0x0823}, {0x0824, 0x0824}, + {0x0825, 0x0827}, {0x0828, 0x0828}, {0x0829, 0x082D}, + {0x0830, 0x083E}, {0x0840, 0x0858}, {0x0859, 0x085B}, + {0x085E, 0x085E}, {0x08A0, 0x08B4}, {0x08B6, 0x08BD}, + {0x08D4, 0x08E1}, {0x08E2, 0x08E2}, {0x08E3, 0x08FF}, + {0x0900, 0x0902}, {0x0903, 0x0903}, {0x0904, 0x0939}, + {0x093A, 0x093A}, {0x093B, 0x093B}, {0x093C, 0x093C}, + {0x093D, 0x093D}, {0x093E, 0x0940}, {0x0941, 0x0948}, + {0x0949, 0x094C}, {0x094D, 0x094D}, {0x094E, 0x094F}, + {0x0950, 0x0950}, {0x0951, 0x0957}, {0x0958, 0x0961}, + {0x0962, 0x0963}, {0x0964, 0x0965}, {0x0966, 0x096F}, + {0x0970, 0x0970}, {0x0971, 0x0971}, {0x0972, 0x097F}, + {0x0980, 0x0980}, {0x0981, 0x0981}, {0x0982, 0x0983}, + {0x0985, 0x098C}, {0x098F, 0x0990}, {0x0993, 0x09A8}, + {0x09AA, 0x09B0}, {0x09B2, 0x09B2}, {0x09B6, 0x09B9}, + {0x09BC, 0x09BC}, {0x09BD, 0x09BD}, {0x09BE, 0x09C0}, + {0x09C1, 0x09C4}, {0x09C7, 0x09C8}, {0x09CB, 0x09CC}, + {0x09CD, 0x09CD}, {0x09CE, 0x09CE}, {0x09D7, 0x09D7}, + {0x09DC, 0x09DD}, {0x09DF, 0x09E1}, {0x09E2, 0x09E3}, + {0x09E6, 0x09EF}, {0x09F0, 0x09F1}, {0x09F2, 0x09F3}, + {0x09F4, 0x09F9}, {0x09FA, 0x09FA}, {0x09FB, 0x09FB}, + {0x0A01, 0x0A02}, {0x0A03, 0x0A03}, {0x0A05, 0x0A0A}, + {0x0A0F, 0x0A10}, {0x0A13, 0x0A28}, {0x0A2A, 0x0A30}, + {0x0A32, 0x0A33}, {0x0A35, 0x0A36}, {0x0A38, 0x0A39}, + {0x0A3C, 0x0A3C}, {0x0A3E, 0x0A40}, {0x0A41, 0x0A42}, + {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D}, {0x0A51, 0x0A51}, + {0x0A59, 0x0A5C}, {0x0A5E, 0x0A5E}, {0x0A66, 0x0A6F}, + {0x0A70, 0x0A71}, {0x0A72, 0x0A74}, {0x0A75, 0x0A75}, + {0x0A81, 0x0A82}, {0x0A83, 0x0A83}, {0x0A85, 0x0A8D}, + {0x0A8F, 0x0A91}, {0x0A93, 0x0AA8}, {0x0AAA, 0x0AB0}, + {0x0AB2, 0x0AB3}, {0x0AB5, 0x0AB9}, {0x0ABC, 0x0ABC}, + {0x0ABD, 0x0ABD}, {0x0ABE, 0x0AC0}, {0x0AC1, 0x0AC5}, + {0x0AC7, 0x0AC8}, {0x0AC9, 0x0AC9}, {0x0ACB, 0x0ACC}, + {0x0ACD, 0x0ACD}, {0x0AD0, 0x0AD0}, {0x0AE0, 0x0AE1}, + {0x0AE2, 0x0AE3}, {0x0AE6, 0x0AEF}, {0x0AF0, 0x0AF0}, + {0x0AF1, 0x0AF1}, {0x0AF9, 0x0AF9}, {0x0B01, 0x0B01}, + {0x0B02, 0x0B03}, {0x0B05, 0x0B0C}, {0x0B0F, 0x0B10}, + {0x0B13, 0x0B28}, {0x0B2A, 0x0B30}, {0x0B32, 0x0B33}, + {0x0B35, 0x0B39}, {0x0B3C, 0x0B3C}, {0x0B3D, 0x0B3D}, + {0x0B3E, 0x0B3E}, {0x0B3F, 0x0B3F}, {0x0B40, 0x0B40}, + {0x0B41, 0x0B44}, {0x0B47, 0x0B48}, {0x0B4B, 0x0B4C}, + {0x0B4D, 0x0B4D}, {0x0B56, 0x0B56}, {0x0B57, 0x0B57}, + {0x0B5C, 0x0B5D}, {0x0B5F, 0x0B61}, {0x0B62, 0x0B63}, + {0x0B66, 0x0B6F}, {0x0B70, 0x0B70}, {0x0B71, 0x0B71}, + {0x0B72, 0x0B77}, {0x0B82, 0x0B82}, {0x0B83, 0x0B83}, + {0x0B85, 0x0B8A}, {0x0B8E, 0x0B90}, {0x0B92, 0x0B95}, + {0x0B99, 0x0B9A}, {0x0B9C, 0x0B9C}, {0x0B9E, 0x0B9F}, + {0x0BA3, 0x0BA4}, {0x0BA8, 0x0BAA}, {0x0BAE, 0x0BB9}, + {0x0BBE, 0x0BBF}, {0x0BC0, 0x0BC0}, {0x0BC1, 0x0BC2}, + {0x0BC6, 0x0BC8}, {0x0BCA, 0x0BCC}, {0x0BCD, 0x0BCD}, + {0x0BD0, 0x0BD0}, {0x0BD7, 0x0BD7}, {0x0BE6, 0x0BEF}, + {0x0BF0, 0x0BF2}, {0x0BF3, 0x0BF8}, {0x0BF9, 0x0BF9}, + {0x0BFA, 0x0BFA}, {0x0C00, 0x0C00}, {0x0C01, 0x0C03}, + {0x0C05, 0x0C0C}, {0x0C0E, 0x0C10}, {0x0C12, 0x0C28}, + {0x0C2A, 0x0C39}, {0x0C3D, 0x0C3D}, {0x0C3E, 0x0C40}, + {0x0C41, 0x0C44}, {0x0C46, 0x0C48}, {0x0C4A, 0x0C4D}, + {0x0C55, 0x0C56}, {0x0C58, 0x0C5A}, {0x0C60, 0x0C61}, + {0x0C62, 0x0C63}, {0x0C66, 0x0C6F}, {0x0C78, 0x0C7E}, + {0x0C7F, 0x0C7F}, {0x0C80, 0x0C80}, {0x0C81, 0x0C81}, + {0x0C82, 0x0C83}, {0x0C85, 0x0C8C}, {0x0C8E, 0x0C90}, + {0x0C92, 0x0CA8}, {0x0CAA, 0x0CB3}, {0x0CB5, 0x0CB9}, + {0x0CBC, 0x0CBC}, {0x0CBD, 0x0CBD}, {0x0CBE, 0x0CBE}, + {0x0CBF, 0x0CBF}, {0x0CC0, 0x0CC4}, {0x0CC6, 0x0CC6}, + {0x0CC7, 0x0CC8}, {0x0CCA, 0x0CCB}, {0x0CCC, 0x0CCD}, + {0x0CD5, 0x0CD6}, {0x0CDE, 0x0CDE}, {0x0CE0, 0x0CE1}, + {0x0CE2, 0x0CE3}, {0x0CE6, 0x0CEF}, {0x0CF1, 0x0CF2}, + {0x0D01, 0x0D01}, {0x0D02, 0x0D03}, {0x0D05, 0x0D0C}, + {0x0D0E, 0x0D10}, {0x0D12, 0x0D3A}, {0x0D3D, 0x0D3D}, + {0x0D3E, 0x0D40}, {0x0D41, 0x0D44}, {0x0D46, 0x0D48}, + {0x0D4A, 0x0D4C}, {0x0D4D, 0x0D4D}, {0x0D4E, 0x0D4E}, + {0x0D4F, 0x0D4F}, {0x0D54, 0x0D56}, {0x0D57, 0x0D57}, + {0x0D58, 0x0D5E}, {0x0D5F, 0x0D61}, {0x0D62, 0x0D63}, + {0x0D66, 0x0D6F}, {0x0D70, 0x0D78}, {0x0D79, 0x0D79}, + {0x0D7A, 0x0D7F}, {0x0D82, 0x0D83}, {0x0D85, 0x0D96}, + {0x0D9A, 0x0DB1}, {0x0DB3, 0x0DBB}, {0x0DBD, 0x0DBD}, + {0x0DC0, 0x0DC6}, {0x0DCA, 0x0DCA}, {0x0DCF, 0x0DD1}, + {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6}, {0x0DD8, 0x0DDF}, + {0x0DE6, 0x0DEF}, {0x0DF2, 0x0DF3}, {0x0DF4, 0x0DF4}, + {0x0E01, 0x0E30}, {0x0E31, 0x0E31}, {0x0E32, 0x0E33}, + {0x0E34, 0x0E3A}, {0x0E3F, 0x0E3F}, {0x0E40, 0x0E45}, + {0x0E46, 0x0E46}, {0x0E47, 0x0E4E}, {0x0E4F, 0x0E4F}, + {0x0E50, 0x0E59}, {0x0E5A, 0x0E5B}, {0x0E81, 0x0E82}, + {0x0E84, 0x0E84}, {0x0E87, 0x0E88}, {0x0E8A, 0x0E8A}, + {0x0E8D, 0x0E8D}, {0x0E94, 0x0E97}, {0x0E99, 0x0E9F}, + {0x0EA1, 0x0EA3}, {0x0EA5, 0x0EA5}, {0x0EA7, 0x0EA7}, + {0x0EAA, 0x0EAB}, {0x0EAD, 0x0EB0}, {0x0EB1, 0x0EB1}, + {0x0EB2, 0x0EB3}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC}, + {0x0EBD, 0x0EBD}, {0x0EC0, 0x0EC4}, {0x0EC6, 0x0EC6}, + {0x0EC8, 0x0ECD}, {0x0ED0, 0x0ED9}, {0x0EDC, 0x0EDF}, + {0x0F00, 0x0F00}, {0x0F01, 0x0F03}, {0x0F04, 0x0F12}, + {0x0F13, 0x0F13}, {0x0F14, 0x0F14}, {0x0F15, 0x0F17}, + {0x0F18, 0x0F19}, {0x0F1A, 0x0F1F}, {0x0F20, 0x0F29}, + {0x0F2A, 0x0F33}, {0x0F34, 0x0F34}, {0x0F35, 0x0F35}, + {0x0F36, 0x0F36}, {0x0F37, 0x0F37}, {0x0F38, 0x0F38}, + {0x0F39, 0x0F39}, {0x0F3A, 0x0F3A}, {0x0F3B, 0x0F3B}, + {0x0F3C, 0x0F3C}, {0x0F3D, 0x0F3D}, {0x0F3E, 0x0F3F}, + {0x0F40, 0x0F47}, {0x0F49, 0x0F6C}, {0x0F71, 0x0F7E}, + {0x0F7F, 0x0F7F}, {0x0F80, 0x0F84}, {0x0F85, 0x0F85}, + {0x0F86, 0x0F87}, {0x0F88, 0x0F8C}, {0x0F8D, 0x0F97}, + {0x0F99, 0x0FBC}, {0x0FBE, 0x0FC5}, {0x0FC6, 0x0FC6}, + {0x0FC7, 0x0FCC}, {0x0FCE, 0x0FCF}, {0x0FD0, 0x0FD4}, + {0x0FD5, 0x0FD8}, {0x0FD9, 0x0FDA}, {0x1000, 0x102A}, + {0x102B, 0x102C}, {0x102D, 0x1030}, {0x1031, 0x1031}, + {0x1032, 0x1037}, {0x1038, 0x1038}, {0x1039, 0x103A}, + {0x103B, 0x103C}, {0x103D, 0x103E}, {0x103F, 0x103F}, + {0x1040, 0x1049}, {0x104A, 0x104F}, {0x1050, 0x1055}, + {0x1056, 0x1057}, {0x1058, 0x1059}, {0x105A, 0x105D}, + {0x105E, 0x1060}, {0x1061, 0x1061}, {0x1062, 0x1064}, + {0x1065, 0x1066}, {0x1067, 0x106D}, {0x106E, 0x1070}, + {0x1071, 0x1074}, {0x1075, 0x1081}, {0x1082, 0x1082}, + {0x1083, 0x1084}, {0x1085, 0x1086}, {0x1087, 0x108C}, + {0x108D, 0x108D}, {0x108E, 0x108E}, {0x108F, 0x108F}, + {0x1090, 0x1099}, {0x109A, 0x109C}, {0x109D, 0x109D}, + {0x109E, 0x109F}, {0x10A0, 0x10C5}, {0x10C7, 0x10C7}, + {0x10CD, 0x10CD}, {0x10D0, 0x10FA}, {0x10FB, 0x10FB}, + {0x10FC, 0x10FC}, {0x10FD, 0x10FF}, {0x1160, 0x11FF}, + {0x1200, 0x1248}, {0x124A, 0x124D}, {0x1250, 0x1256}, + {0x1258, 0x1258}, {0x125A, 0x125D}, {0x1260, 0x1288}, + {0x128A, 0x128D}, {0x1290, 0x12B0}, {0x12B2, 0x12B5}, + {0x12B8, 0x12BE}, {0x12C0, 0x12C0}, {0x12C2, 0x12C5}, + {0x12C8, 0x12D6}, {0x12D8, 0x1310}, {0x1312, 0x1315}, + {0x1318, 0x135A}, {0x135D, 0x135F}, {0x1360, 0x1368}, + {0x1369, 0x137C}, {0x1380, 0x138F}, {0x1390, 0x1399}, + {0x13A0, 0x13F5}, {0x13F8, 0x13FD}, {0x1400, 0x1400}, + {0x1401, 0x166C}, {0x166D, 0x166E}, {0x166F, 0x167F}, + {0x1680, 0x1680}, {0x1681, 0x169A}, {0x169B, 0x169B}, + {0x169C, 0x169C}, {0x16A0, 0x16EA}, {0x16EB, 0x16ED}, + {0x16EE, 0x16F0}, {0x16F1, 0x16F8}, {0x1700, 0x170C}, + {0x170E, 0x1711}, {0x1712, 0x1714}, {0x1720, 0x1731}, + {0x1732, 0x1734}, {0x1735, 0x1736}, {0x1740, 0x1751}, + {0x1752, 0x1753}, {0x1760, 0x176C}, {0x176E, 0x1770}, + {0x1772, 0x1773}, {0x1780, 0x17B3}, {0x17B4, 0x17B5}, + {0x17B6, 0x17B6}, {0x17B7, 0x17BD}, {0x17BE, 0x17C5}, + {0x17C6, 0x17C6}, {0x17C7, 0x17C8}, {0x17C9, 0x17D3}, + {0x17D4, 0x17D6}, {0x17D7, 0x17D7}, {0x17D8, 0x17DA}, + {0x17DB, 0x17DB}, {0x17DC, 0x17DC}, {0x17DD, 0x17DD}, + {0x17E0, 0x17E9}, {0x17F0, 0x17F9}, {0x1800, 0x1805}, + {0x1806, 0x1806}, {0x1807, 0x180A}, {0x180B, 0x180D}, + {0x180E, 0x180E}, {0x1810, 0x1819}, {0x1820, 0x1842}, + {0x1843, 0x1843}, {0x1844, 0x1877}, {0x1880, 0x1884}, + {0x1885, 0x1886}, {0x1887, 0x18A8}, {0x18A9, 0x18A9}, + {0x18AA, 0x18AA}, {0x18B0, 0x18F5}, {0x1900, 0x191E}, + {0x1920, 0x1922}, {0x1923, 0x1926}, {0x1927, 0x1928}, + {0x1929, 0x192B}, {0x1930, 0x1931}, {0x1932, 0x1932}, + {0x1933, 0x1938}, {0x1939, 0x193B}, {0x1940, 0x1940}, + {0x1944, 0x1945}, {0x1946, 0x194F}, {0x1950, 0x196D}, + {0x1970, 0x1974}, {0x1980, 0x19AB}, {0x19B0, 0x19C9}, + {0x19D0, 0x19D9}, {0x19DA, 0x19DA}, {0x19DE, 0x19DF}, + {0x19E0, 0x19FF}, {0x1A00, 0x1A16}, {0x1A17, 0x1A18}, + {0x1A19, 0x1A1A}, {0x1A1B, 0x1A1B}, {0x1A1E, 0x1A1F}, + {0x1A20, 0x1A54}, {0x1A55, 0x1A55}, {0x1A56, 0x1A56}, + {0x1A57, 0x1A57}, {0x1A58, 0x1A5E}, {0x1A60, 0x1A60}, + {0x1A61, 0x1A61}, {0x1A62, 0x1A62}, {0x1A63, 0x1A64}, + {0x1A65, 0x1A6C}, {0x1A6D, 0x1A72}, {0x1A73, 0x1A7C}, + {0x1A7F, 0x1A7F}, {0x1A80, 0x1A89}, {0x1A90, 0x1A99}, + {0x1AA0, 0x1AA6}, {0x1AA7, 0x1AA7}, {0x1AA8, 0x1AAD}, + {0x1AB0, 0x1ABD}, {0x1ABE, 0x1ABE}, {0x1B00, 0x1B03}, + {0x1B04, 0x1B04}, {0x1B05, 0x1B33}, {0x1B34, 0x1B34}, + {0x1B35, 0x1B35}, {0x1B36, 0x1B3A}, {0x1B3B, 0x1B3B}, + {0x1B3C, 0x1B3C}, {0x1B3D, 0x1B41}, {0x1B42, 0x1B42}, + {0x1B43, 0x1B44}, {0x1B45, 0x1B4B}, {0x1B50, 0x1B59}, + {0x1B5A, 0x1B60}, {0x1B61, 0x1B6A}, {0x1B6B, 0x1B73}, + {0x1B74, 0x1B7C}, {0x1B80, 0x1B81}, {0x1B82, 0x1B82}, + {0x1B83, 0x1BA0}, {0x1BA1, 0x1BA1}, {0x1BA2, 0x1BA5}, + {0x1BA6, 0x1BA7}, {0x1BA8, 0x1BA9}, {0x1BAA, 0x1BAA}, + {0x1BAB, 0x1BAD}, {0x1BAE, 0x1BAF}, {0x1BB0, 0x1BB9}, + {0x1BBA, 0x1BBF}, {0x1BC0, 0x1BE5}, {0x1BE6, 0x1BE6}, + {0x1BE7, 0x1BE7}, {0x1BE8, 0x1BE9}, {0x1BEA, 0x1BEC}, + {0x1BED, 0x1BED}, {0x1BEE, 0x1BEE}, {0x1BEF, 0x1BF1}, + {0x1BF2, 0x1BF3}, {0x1BFC, 0x1BFF}, {0x1C00, 0x1C23}, + {0x1C24, 0x1C2B}, {0x1C2C, 0x1C33}, {0x1C34, 0x1C35}, + {0x1C36, 0x1C37}, {0x1C3B, 0x1C3F}, {0x1C40, 0x1C49}, + {0x1C4D, 0x1C4F}, {0x1C50, 0x1C59}, {0x1C5A, 0x1C77}, + {0x1C78, 0x1C7D}, {0x1C7E, 0x1C7F}, {0x1C80, 0x1C88}, + {0x1CC0, 0x1CC7}, {0x1CD0, 0x1CD2}, {0x1CD3, 0x1CD3}, + {0x1CD4, 0x1CE0}, {0x1CE1, 0x1CE1}, {0x1CE2, 0x1CE8}, + {0x1CE9, 0x1CEC}, {0x1CED, 0x1CED}, {0x1CEE, 0x1CF1}, + {0x1CF2, 0x1CF3}, {0x1CF4, 0x1CF4}, {0x1CF5, 0x1CF6}, + {0x1CF8, 0x1CF9}, {0x1D00, 0x1D2B}, {0x1D2C, 0x1D6A}, + {0x1D6B, 0x1D77}, {0x1D78, 0x1D78}, {0x1D79, 0x1D7F}, + {0x1D80, 0x1D9A}, {0x1D9B, 0x1DBF}, {0x1DC0, 0x1DF5}, + {0x1DFB, 0x1DFF}, {0x1E00, 0x1EFF}, {0x1F00, 0x1F15}, + {0x1F18, 0x1F1D}, {0x1F20, 0x1F45}, {0x1F48, 0x1F4D}, + {0x1F50, 0x1F57}, {0x1F59, 0x1F59}, {0x1F5B, 0x1F5B}, + {0x1F5D, 0x1F5D}, {0x1F5F, 0x1F7D}, {0x1F80, 0x1FB4}, + {0x1FB6, 0x1FBC}, {0x1FBD, 0x1FBD}, {0x1FBE, 0x1FBE}, + {0x1FBF, 0x1FC1}, {0x1FC2, 0x1FC4}, {0x1FC6, 0x1FCC}, + {0x1FCD, 0x1FCF}, {0x1FD0, 0x1FD3}, {0x1FD6, 0x1FDB}, + {0x1FDD, 0x1FDF}, {0x1FE0, 0x1FEC}, {0x1FED, 0x1FEF}, + {0x1FF2, 0x1FF4}, {0x1FF6, 0x1FFC}, {0x1FFD, 0x1FFE}, + {0x2000, 0x200A}, {0x200B, 0x200F}, {0x2011, 0x2012}, + {0x2017, 0x2017}, {0x201A, 0x201A}, {0x201B, 0x201B}, + {0x201E, 0x201E}, {0x201F, 0x201F}, {0x2023, 0x2023}, + {0x2028, 0x2028}, {0x2029, 0x2029}, {0x202A, 0x202E}, + {0x202F, 0x202F}, {0x2031, 0x2031}, {0x2034, 0x2034}, + {0x2036, 0x2038}, {0x2039, 0x2039}, {0x203A, 0x203A}, + {0x203C, 0x203D}, {0x203F, 0x2040}, {0x2041, 0x2043}, + {0x2044, 0x2044}, {0x2045, 0x2045}, {0x2046, 0x2046}, + {0x2047, 0x2051}, {0x2052, 0x2052}, {0x2053, 0x2053}, + {0x2054, 0x2054}, {0x2055, 0x205E}, {0x205F, 0x205F}, + {0x2060, 0x2064}, {0x2066, 0x206F}, {0x2070, 0x2070}, + {0x2071, 0x2071}, {0x2075, 0x2079}, {0x207A, 0x207C}, + {0x207D, 0x207D}, {0x207E, 0x207E}, {0x2080, 0x2080}, + {0x2085, 0x2089}, {0x208A, 0x208C}, {0x208D, 0x208D}, + {0x208E, 0x208E}, {0x2090, 0x209C}, {0x20A0, 0x20A8}, + {0x20AA, 0x20AB}, {0x20AD, 0x20BE}, {0x20D0, 0x20DC}, + {0x20DD, 0x20E0}, {0x20E1, 0x20E1}, {0x20E2, 0x20E4}, + {0x20E5, 0x20F0}, {0x2100, 0x2101}, {0x2102, 0x2102}, + {0x2104, 0x2104}, {0x2106, 0x2106}, {0x2107, 0x2107}, + {0x2108, 0x2108}, {0x210A, 0x2112}, {0x2114, 0x2114}, + {0x2115, 0x2115}, {0x2117, 0x2117}, {0x2118, 0x2118}, + {0x2119, 0x211D}, {0x211E, 0x2120}, {0x2123, 0x2123}, + {0x2124, 0x2124}, {0x2125, 0x2125}, {0x2127, 0x2127}, + {0x2128, 0x2128}, {0x2129, 0x2129}, {0x212A, 0x212A}, + {0x212C, 0x212D}, {0x212E, 0x212E}, {0x212F, 0x2134}, + {0x2135, 0x2138}, {0x2139, 0x2139}, {0x213A, 0x213B}, + {0x213C, 0x213F}, {0x2140, 0x2144}, {0x2145, 0x2149}, + {0x214A, 0x214A}, {0x214B, 0x214B}, {0x214C, 0x214D}, + {0x214E, 0x214E}, {0x214F, 0x214F}, {0x2150, 0x2152}, + {0x2155, 0x215A}, {0x215F, 0x215F}, {0x216C, 0x216F}, + {0x217A, 0x2182}, {0x2183, 0x2184}, {0x2185, 0x2188}, + {0x218A, 0x218B}, {0x219A, 0x219B}, {0x219C, 0x219F}, + {0x21A0, 0x21A0}, {0x21A1, 0x21A2}, {0x21A3, 0x21A3}, + {0x21A4, 0x21A5}, {0x21A6, 0x21A6}, {0x21A7, 0x21AD}, + {0x21AE, 0x21AE}, {0x21AF, 0x21B7}, {0x21BA, 0x21CD}, + {0x21CE, 0x21CF}, {0x21D0, 0x21D1}, {0x21D3, 0x21D3}, + {0x21D5, 0x21E6}, {0x21E8, 0x21F3}, {0x21F4, 0x21FF}, + {0x2201, 0x2201}, {0x2204, 0x2206}, {0x2209, 0x220A}, + {0x220C, 0x220E}, {0x2210, 0x2210}, {0x2212, 0x2214}, + {0x2216, 0x2219}, {0x221B, 0x221C}, {0x2221, 0x2222}, + {0x2224, 0x2224}, {0x2226, 0x2226}, {0x222D, 0x222D}, + {0x222F, 0x2233}, {0x2238, 0x223B}, {0x223E, 0x2247}, + {0x2249, 0x224B}, {0x224D, 0x2251}, {0x2253, 0x225F}, + {0x2262, 0x2263}, {0x2268, 0x2269}, {0x226C, 0x226D}, + {0x2270, 0x2281}, {0x2284, 0x2285}, {0x2288, 0x2294}, + {0x2296, 0x2298}, {0x229A, 0x22A4}, {0x22A6, 0x22BE}, + {0x22C0, 0x22FF}, {0x2300, 0x2307}, {0x2308, 0x2308}, + {0x2309, 0x2309}, {0x230A, 0x230A}, {0x230B, 0x230B}, + {0x230C, 0x2311}, {0x2313, 0x2319}, {0x231C, 0x231F}, + {0x2320, 0x2321}, {0x2322, 0x2328}, {0x232B, 0x237B}, + {0x237C, 0x237C}, {0x237D, 0x239A}, {0x239B, 0x23B3}, + {0x23B4, 0x23DB}, {0x23DC, 0x23E1}, {0x23E2, 0x23E8}, + {0x23ED, 0x23EF}, {0x23F1, 0x23F2}, {0x23F4, 0x23FE}, + {0x2400, 0x2426}, {0x2440, 0x244A}, {0x24EA, 0x24EA}, + {0x254C, 0x254F}, {0x2574, 0x257F}, {0x2590, 0x2591}, + {0x2596, 0x259F}, {0x25A2, 0x25A2}, {0x25AA, 0x25B1}, + {0x25B4, 0x25B5}, {0x25B8, 0x25BB}, {0x25BE, 0x25BF}, + {0x25C2, 0x25C5}, {0x25C9, 0x25CA}, {0x25CC, 0x25CD}, + {0x25D2, 0x25E1}, {0x25E6, 0x25EE}, {0x25F0, 0x25F7}, + {0x25F8, 0x25FC}, {0x25FF, 0x25FF}, {0x2600, 0x2604}, + {0x2607, 0x2608}, {0x260A, 0x260D}, {0x2610, 0x2613}, + {0x2616, 0x261B}, {0x261D, 0x261D}, {0x261F, 0x263F}, + {0x2641, 0x2641}, {0x2643, 0x2647}, {0x2654, 0x265F}, + {0x2662, 0x2662}, {0x2666, 0x2666}, {0x266B, 0x266B}, + {0x266E, 0x266E}, {0x2670, 0x267E}, {0x2680, 0x2692}, + {0x2694, 0x269D}, {0x26A0, 0x26A0}, {0x26A2, 0x26A9}, + {0x26AC, 0x26BC}, {0x26C0, 0x26C3}, {0x26E2, 0x26E2}, + {0x26E4, 0x26E7}, {0x2700, 0x2704}, {0x2706, 0x2709}, + {0x270C, 0x2727}, {0x2729, 0x273C}, {0x273E, 0x274B}, + {0x274D, 0x274D}, {0x274F, 0x2752}, {0x2756, 0x2756}, + {0x2758, 0x2767}, {0x2768, 0x2768}, {0x2769, 0x2769}, + {0x276A, 0x276A}, {0x276B, 0x276B}, {0x276C, 0x276C}, + {0x276D, 0x276D}, {0x276E, 0x276E}, {0x276F, 0x276F}, + {0x2770, 0x2770}, {0x2771, 0x2771}, {0x2772, 0x2772}, + {0x2773, 0x2773}, {0x2774, 0x2774}, {0x2775, 0x2775}, + {0x2780, 0x2793}, {0x2794, 0x2794}, {0x2798, 0x27AF}, + {0x27B1, 0x27BE}, {0x27C0, 0x27C4}, {0x27C5, 0x27C5}, + {0x27C6, 0x27C6}, {0x27C7, 0x27E5}, {0x27EE, 0x27EE}, + {0x27EF, 0x27EF}, {0x27F0, 0x27FF}, {0x2800, 0x28FF}, + {0x2900, 0x297F}, {0x2980, 0x2982}, {0x2983, 0x2983}, + {0x2984, 0x2984}, {0x2987, 0x2987}, {0x2988, 0x2988}, + {0x2989, 0x2989}, {0x298A, 0x298A}, {0x298B, 0x298B}, + {0x298C, 0x298C}, {0x298D, 0x298D}, {0x298E, 0x298E}, + {0x298F, 0x298F}, {0x2990, 0x2990}, {0x2991, 0x2991}, + {0x2992, 0x2992}, {0x2993, 0x2993}, {0x2994, 0x2994}, + {0x2995, 0x2995}, {0x2996, 0x2996}, {0x2997, 0x2997}, + {0x2998, 0x2998}, {0x2999, 0x29D7}, {0x29D8, 0x29D8}, + {0x29D9, 0x29D9}, {0x29DA, 0x29DA}, {0x29DB, 0x29DB}, + {0x29DC, 0x29FB}, {0x29FC, 0x29FC}, {0x29FD, 0x29FD}, + {0x29FE, 0x29FF}, {0x2A00, 0x2AFF}, {0x2B00, 0x2B1A}, + {0x2B1D, 0x2B2F}, {0x2B30, 0x2B44}, {0x2B45, 0x2B46}, + {0x2B47, 0x2B4C}, {0x2B4D, 0x2B4F}, {0x2B51, 0x2B54}, + {0x2B5A, 0x2B73}, {0x2B76, 0x2B95}, {0x2B98, 0x2BB9}, + {0x2BBD, 0x2BC8}, {0x2BCA, 0x2BD1}, {0x2BEC, 0x2BEF}, + {0x2C00, 0x2C2E}, {0x2C30, 0x2C5E}, {0x2C60, 0x2C7B}, + {0x2C7C, 0x2C7D}, {0x2C7E, 0x2C7F}, {0x2C80, 0x2CE4}, + {0x2CE5, 0x2CEA}, {0x2CEB, 0x2CEE}, {0x2CEF, 0x2CF1}, + {0x2CF2, 0x2CF3}, {0x2CF9, 0x2CFC}, {0x2CFD, 0x2CFD}, + {0x2CFE, 0x2CFF}, {0x2D00, 0x2D25}, {0x2D27, 0x2D27}, + {0x2D2D, 0x2D2D}, {0x2D30, 0x2D67}, {0x2D6F, 0x2D6F}, + {0x2D70, 0x2D70}, {0x2D7F, 0x2D7F}, {0x2D80, 0x2D96}, + {0x2DA0, 0x2DA6}, {0x2DA8, 0x2DAE}, {0x2DB0, 0x2DB6}, + {0x2DB8, 0x2DBE}, {0x2DC0, 0x2DC6}, {0x2DC8, 0x2DCE}, + {0x2DD0, 0x2DD6}, {0x2DD8, 0x2DDE}, {0x2DE0, 0x2DFF}, + {0x2E00, 0x2E01}, {0x2E02, 0x2E02}, {0x2E03, 0x2E03}, + {0x2E04, 0x2E04}, {0x2E05, 0x2E05}, {0x2E06, 0x2E08}, + {0x2E09, 0x2E09}, {0x2E0A, 0x2E0A}, {0x2E0B, 0x2E0B}, + {0x2E0C, 0x2E0C}, {0x2E0D, 0x2E0D}, {0x2E0E, 0x2E16}, + {0x2E17, 0x2E17}, {0x2E18, 0x2E19}, {0x2E1A, 0x2E1A}, + {0x2E1B, 0x2E1B}, {0x2E1C, 0x2E1C}, {0x2E1D, 0x2E1D}, + {0x2E1E, 0x2E1F}, {0x2E20, 0x2E20}, {0x2E21, 0x2E21}, + {0x2E22, 0x2E22}, {0x2E23, 0x2E23}, {0x2E24, 0x2E24}, + {0x2E25, 0x2E25}, {0x2E26, 0x2E26}, {0x2E27, 0x2E27}, + {0x2E28, 0x2E28}, {0x2E29, 0x2E29}, {0x2E2A, 0x2E2E}, + {0x2E2F, 0x2E2F}, {0x2E30, 0x2E39}, {0x2E3A, 0x2E3B}, + {0x2E3C, 0x2E3F}, {0x2E40, 0x2E40}, {0x2E41, 0x2E41}, + {0x2E42, 0x2E42}, {0x2E43, 0x2E44}, {0x303F, 0x303F}, + {0x4DC0, 0x4DFF}, {0xA4D0, 0xA4F7}, {0xA4F8, 0xA4FD}, + {0xA4FE, 0xA4FF}, {0xA500, 0xA60B}, {0xA60C, 0xA60C}, + {0xA60D, 0xA60F}, {0xA610, 0xA61F}, {0xA620, 0xA629}, + {0xA62A, 0xA62B}, {0xA640, 0xA66D}, {0xA66E, 0xA66E}, + {0xA66F, 0xA66F}, {0xA670, 0xA672}, {0xA673, 0xA673}, + {0xA674, 0xA67D}, {0xA67E, 0xA67E}, {0xA67F, 0xA67F}, + {0xA680, 0xA69B}, {0xA69C, 0xA69D}, {0xA69E, 0xA69F}, + {0xA6A0, 0xA6E5}, {0xA6E6, 0xA6EF}, {0xA6F0, 0xA6F1}, + {0xA6F2, 0xA6F7}, {0xA700, 0xA716}, {0xA717, 0xA71F}, + {0xA720, 0xA721}, {0xA722, 0xA76F}, {0xA770, 0xA770}, + {0xA771, 0xA787}, {0xA788, 0xA788}, {0xA789, 0xA78A}, + {0xA78B, 0xA78E}, {0xA78F, 0xA78F}, {0xA790, 0xA7AE}, + {0xA7B0, 0xA7B7}, {0xA7F7, 0xA7F7}, {0xA7F8, 0xA7F9}, + {0xA7FA, 0xA7FA}, {0xA7FB, 0xA7FF}, {0xA800, 0xA801}, + {0xA802, 0xA802}, {0xA803, 0xA805}, {0xA806, 0xA806}, + {0xA807, 0xA80A}, {0xA80B, 0xA80B}, {0xA80C, 0xA822}, + {0xA823, 0xA824}, {0xA825, 0xA826}, {0xA827, 0xA827}, + {0xA828, 0xA82B}, {0xA830, 0xA835}, {0xA836, 0xA837}, + {0xA838, 0xA838}, {0xA839, 0xA839}, {0xA840, 0xA873}, + {0xA874, 0xA877}, {0xA880, 0xA881}, {0xA882, 0xA8B3}, + {0xA8B4, 0xA8C3}, {0xA8C4, 0xA8C5}, {0xA8CE, 0xA8CF}, + {0xA8D0, 0xA8D9}, {0xA8E0, 0xA8F1}, {0xA8F2, 0xA8F7}, + {0xA8F8, 0xA8FA}, {0xA8FB, 0xA8FB}, {0xA8FC, 0xA8FC}, + {0xA8FD, 0xA8FD}, {0xA900, 0xA909}, {0xA90A, 0xA925}, + {0xA926, 0xA92D}, {0xA92E, 0xA92F}, {0xA930, 0xA946}, + {0xA947, 0xA951}, {0xA952, 0xA953}, {0xA95F, 0xA95F}, + {0xA980, 0xA982}, {0xA983, 0xA983}, {0xA984, 0xA9B2}, + {0xA9B3, 0xA9B3}, {0xA9B4, 0xA9B5}, {0xA9B6, 0xA9B9}, + {0xA9BA, 0xA9BB}, {0xA9BC, 0xA9BC}, {0xA9BD, 0xA9C0}, + {0xA9C1, 0xA9CD}, {0xA9CF, 0xA9CF}, {0xA9D0, 0xA9D9}, + {0xA9DE, 0xA9DF}, {0xA9E0, 0xA9E4}, {0xA9E5, 0xA9E5}, + {0xA9E6, 0xA9E6}, {0xA9E7, 0xA9EF}, {0xA9F0, 0xA9F9}, + {0xA9FA, 0xA9FE}, {0xAA00, 0xAA28}, {0xAA29, 0xAA2E}, + {0xAA2F, 0xAA30}, {0xAA31, 0xAA32}, {0xAA33, 0xAA34}, + {0xAA35, 0xAA36}, {0xAA40, 0xAA42}, {0xAA43, 0xAA43}, + {0xAA44, 0xAA4B}, {0xAA4C, 0xAA4C}, {0xAA4D, 0xAA4D}, + {0xAA50, 0xAA59}, {0xAA5C, 0xAA5F}, {0xAA60, 0xAA6F}, + {0xAA70, 0xAA70}, {0xAA71, 0xAA76}, {0xAA77, 0xAA79}, + {0xAA7A, 0xAA7A}, {0xAA7B, 0xAA7B}, {0xAA7C, 0xAA7C}, + {0xAA7D, 0xAA7D}, {0xAA7E, 0xAA7F}, {0xAA80, 0xAAAF}, + {0xAAB0, 0xAAB0}, {0xAAB1, 0xAAB1}, {0xAAB2, 0xAAB4}, + {0xAAB5, 0xAAB6}, {0xAAB7, 0xAAB8}, {0xAAB9, 0xAABD}, + {0xAABE, 0xAABF}, {0xAAC0, 0xAAC0}, {0xAAC1, 0xAAC1}, + {0xAAC2, 0xAAC2}, {0xAADB, 0xAADC}, {0xAADD, 0xAADD}, + {0xAADE, 0xAADF}, {0xAAE0, 0xAAEA}, {0xAAEB, 0xAAEB}, + {0xAAEC, 0xAAED}, {0xAAEE, 0xAAEF}, {0xAAF0, 0xAAF1}, + {0xAAF2, 0xAAF2}, {0xAAF3, 0xAAF4}, {0xAAF5, 0xAAF5}, + {0xAAF6, 0xAAF6}, {0xAB01, 0xAB06}, {0xAB09, 0xAB0E}, + {0xAB11, 0xAB16}, {0xAB20, 0xAB26}, {0xAB28, 0xAB2E}, + {0xAB30, 0xAB5A}, {0xAB5B, 0xAB5B}, {0xAB5C, 0xAB5F}, + {0xAB60, 0xAB65}, {0xAB70, 0xABBF}, {0xABC0, 0xABE2}, + {0xABE3, 0xABE4}, {0xABE5, 0xABE5}, {0xABE6, 0xABE7}, + {0xABE8, 0xABE8}, {0xABE9, 0xABEA}, {0xABEB, 0xABEB}, + {0xABEC, 0xABEC}, {0xABED, 0xABED}, {0xABF0, 0xABF9}, + {0xD7B0, 0xD7C6}, {0xD7CB, 0xD7FB}, {0xD800, 0xDB7F}, + {0xDB80, 0xDBFF}, {0xDC00, 0xDFFF}, {0xFB00, 0xFB06}, + {0xFB13, 0xFB17}, {0xFB1D, 0xFB1D}, {0xFB1E, 0xFB1E}, + {0xFB1F, 0xFB28}, {0xFB29, 0xFB29}, {0xFB2A, 0xFB36}, + {0xFB38, 0xFB3C}, {0xFB3E, 0xFB3E}, {0xFB40, 0xFB41}, + {0xFB43, 0xFB44}, {0xFB46, 0xFB4F}, {0xFB50, 0xFBB1}, + {0xFBB2, 0xFBC1}, {0xFBD3, 0xFD3D}, {0xFD3E, 0xFD3E}, + {0xFD3F, 0xFD3F}, {0xFD50, 0xFD8F}, {0xFD92, 0xFDC7}, + {0xFDF0, 0xFDFB}, {0xFDFC, 0xFDFC}, {0xFDFD, 0xFDFD}, + {0xFE20, 0xFE2F}, {0xFE70, 0xFE74}, {0xFE76, 0xFEFC}, + {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB}, {0xFFFC, 0xFFFC}, + {0x10000, 0x1000B}, {0x1000D, 0x10026}, {0x10028, 0x1003A}, + {0x1003C, 0x1003D}, {0x1003F, 0x1004D}, {0x10050, 0x1005D}, + {0x10080, 0x100FA}, {0x10100, 0x10102}, {0x10107, 0x10133}, + {0x10137, 0x1013F}, {0x10140, 0x10174}, {0x10175, 0x10178}, + {0x10179, 0x10189}, {0x1018A, 0x1018B}, {0x1018C, 0x1018E}, + {0x10190, 0x1019B}, {0x101A0, 0x101A0}, {0x101D0, 0x101FC}, + {0x101FD, 0x101FD}, {0x10280, 0x1029C}, {0x102A0, 0x102D0}, + {0x102E0, 0x102E0}, {0x102E1, 0x102FB}, {0x10300, 0x1031F}, + {0x10320, 0x10323}, {0x10330, 0x10340}, {0x10341, 0x10341}, + {0x10342, 0x10349}, {0x1034A, 0x1034A}, {0x10350, 0x10375}, + {0x10376, 0x1037A}, {0x10380, 0x1039D}, {0x1039F, 0x1039F}, + {0x103A0, 0x103C3}, {0x103C8, 0x103CF}, {0x103D0, 0x103D0}, + {0x103D1, 0x103D5}, {0x10400, 0x1044F}, {0x10450, 0x1047F}, + {0x10480, 0x1049D}, {0x104A0, 0x104A9}, {0x104B0, 0x104D3}, + {0x104D8, 0x104FB}, {0x10500, 0x10527}, {0x10530, 0x10563}, + {0x1056F, 0x1056F}, {0x10600, 0x10736}, {0x10740, 0x10755}, + {0x10760, 0x10767}, {0x10800, 0x10805}, {0x10808, 0x10808}, + {0x1080A, 0x10835}, {0x10837, 0x10838}, {0x1083C, 0x1083C}, + {0x1083F, 0x1083F}, {0x10840, 0x10855}, {0x10857, 0x10857}, + {0x10858, 0x1085F}, {0x10860, 0x10876}, {0x10877, 0x10878}, + {0x10879, 0x1087F}, {0x10880, 0x1089E}, {0x108A7, 0x108AF}, + {0x108E0, 0x108F2}, {0x108F4, 0x108F5}, {0x108FB, 0x108FF}, + {0x10900, 0x10915}, {0x10916, 0x1091B}, {0x1091F, 0x1091F}, + {0x10920, 0x10939}, {0x1093F, 0x1093F}, {0x10980, 0x1099F}, + {0x109A0, 0x109B7}, {0x109BC, 0x109BD}, {0x109BE, 0x109BF}, + {0x109C0, 0x109CF}, {0x109D2, 0x109FF}, {0x10A00, 0x10A00}, + {0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F}, + {0x10A10, 0x10A13}, {0x10A15, 0x10A17}, {0x10A19, 0x10A33}, + {0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x10A40, 0x10A47}, + {0x10A50, 0x10A58}, {0x10A60, 0x10A7C}, {0x10A7D, 0x10A7E}, + {0x10A7F, 0x10A7F}, {0x10A80, 0x10A9C}, {0x10A9D, 0x10A9F}, + {0x10AC0, 0x10AC7}, {0x10AC8, 0x10AC8}, {0x10AC9, 0x10AE4}, + {0x10AE5, 0x10AE6}, {0x10AEB, 0x10AEF}, {0x10AF0, 0x10AF6}, + {0x10B00, 0x10B35}, {0x10B39, 0x10B3F}, {0x10B40, 0x10B55}, + {0x10B58, 0x10B5F}, {0x10B60, 0x10B72}, {0x10B78, 0x10B7F}, + {0x10B80, 0x10B91}, {0x10B99, 0x10B9C}, {0x10BA9, 0x10BAF}, + {0x10C00, 0x10C48}, {0x10C80, 0x10CB2}, {0x10CC0, 0x10CF2}, + {0x10CFA, 0x10CFF}, {0x10E60, 0x10E7E}, {0x11000, 0x11000}, + {0x11001, 0x11001}, {0x11002, 0x11002}, {0x11003, 0x11037}, + {0x11038, 0x11046}, {0x11047, 0x1104D}, {0x11052, 0x11065}, + {0x11066, 0x1106F}, {0x1107F, 0x1107F}, {0x11080, 0x11081}, + {0x11082, 0x11082}, {0x11083, 0x110AF}, {0x110B0, 0x110B2}, + {0x110B3, 0x110B6}, {0x110B7, 0x110B8}, {0x110B9, 0x110BA}, + {0x110BB, 0x110BC}, {0x110BD, 0x110BD}, {0x110BE, 0x110C1}, + {0x110D0, 0x110E8}, {0x110F0, 0x110F9}, {0x11100, 0x11102}, + {0x11103, 0x11126}, {0x11127, 0x1112B}, {0x1112C, 0x1112C}, + {0x1112D, 0x11134}, {0x11136, 0x1113F}, {0x11140, 0x11143}, + {0x11150, 0x11172}, {0x11173, 0x11173}, {0x11174, 0x11175}, + {0x11176, 0x11176}, {0x11180, 0x11181}, {0x11182, 0x11182}, + {0x11183, 0x111B2}, {0x111B3, 0x111B5}, {0x111B6, 0x111BE}, + {0x111BF, 0x111C0}, {0x111C1, 0x111C4}, {0x111C5, 0x111C9}, + {0x111CA, 0x111CC}, {0x111CD, 0x111CD}, {0x111D0, 0x111D9}, + {0x111DA, 0x111DA}, {0x111DB, 0x111DB}, {0x111DC, 0x111DC}, + {0x111DD, 0x111DF}, {0x111E1, 0x111F4}, {0x11200, 0x11211}, + {0x11213, 0x1122B}, {0x1122C, 0x1122E}, {0x1122F, 0x11231}, + {0x11232, 0x11233}, {0x11234, 0x11234}, {0x11235, 0x11235}, + {0x11236, 0x11237}, {0x11238, 0x1123D}, {0x1123E, 0x1123E}, + {0x11280, 0x11286}, {0x11288, 0x11288}, {0x1128A, 0x1128D}, + {0x1128F, 0x1129D}, {0x1129F, 0x112A8}, {0x112A9, 0x112A9}, + {0x112B0, 0x112DE}, {0x112DF, 0x112DF}, {0x112E0, 0x112E2}, + {0x112E3, 0x112EA}, {0x112F0, 0x112F9}, {0x11300, 0x11301}, + {0x11302, 0x11303}, {0x11305, 0x1130C}, {0x1130F, 0x11310}, + {0x11313, 0x11328}, {0x1132A, 0x11330}, {0x11332, 0x11333}, + {0x11335, 0x11339}, {0x1133C, 0x1133C}, {0x1133D, 0x1133D}, + {0x1133E, 0x1133F}, {0x11340, 0x11340}, {0x11341, 0x11344}, + {0x11347, 0x11348}, {0x1134B, 0x1134D}, {0x11350, 0x11350}, + {0x11357, 0x11357}, {0x1135D, 0x11361}, {0x11362, 0x11363}, + {0x11366, 0x1136C}, {0x11370, 0x11374}, {0x11400, 0x11434}, + {0x11435, 0x11437}, {0x11438, 0x1143F}, {0x11440, 0x11441}, + {0x11442, 0x11444}, {0x11445, 0x11445}, {0x11446, 0x11446}, + {0x11447, 0x1144A}, {0x1144B, 0x1144F}, {0x11450, 0x11459}, + {0x1145B, 0x1145B}, {0x1145D, 0x1145D}, {0x11480, 0x114AF}, + {0x114B0, 0x114B2}, {0x114B3, 0x114B8}, {0x114B9, 0x114B9}, + {0x114BA, 0x114BA}, {0x114BB, 0x114BE}, {0x114BF, 0x114C0}, + {0x114C1, 0x114C1}, {0x114C2, 0x114C3}, {0x114C4, 0x114C5}, + {0x114C6, 0x114C6}, {0x114C7, 0x114C7}, {0x114D0, 0x114D9}, + {0x11580, 0x115AE}, {0x115AF, 0x115B1}, {0x115B2, 0x115B5}, + {0x115B8, 0x115BB}, {0x115BC, 0x115BD}, {0x115BE, 0x115BE}, + {0x115BF, 0x115C0}, {0x115C1, 0x115D7}, {0x115D8, 0x115DB}, + {0x115DC, 0x115DD}, {0x11600, 0x1162F}, {0x11630, 0x11632}, + {0x11633, 0x1163A}, {0x1163B, 0x1163C}, {0x1163D, 0x1163D}, + {0x1163E, 0x1163E}, {0x1163F, 0x11640}, {0x11641, 0x11643}, + {0x11644, 0x11644}, {0x11650, 0x11659}, {0x11660, 0x1166C}, + {0x11680, 0x116AA}, {0x116AB, 0x116AB}, {0x116AC, 0x116AC}, + {0x116AD, 0x116AD}, {0x116AE, 0x116AF}, {0x116B0, 0x116B5}, + {0x116B6, 0x116B6}, {0x116B7, 0x116B7}, {0x116C0, 0x116C9}, + {0x11700, 0x11719}, {0x1171D, 0x1171F}, {0x11720, 0x11721}, + {0x11722, 0x11725}, {0x11726, 0x11726}, {0x11727, 0x1172B}, + {0x11730, 0x11739}, {0x1173A, 0x1173B}, {0x1173C, 0x1173E}, + {0x1173F, 0x1173F}, {0x118A0, 0x118DF}, {0x118E0, 0x118E9}, + {0x118EA, 0x118F2}, {0x118FF, 0x118FF}, {0x11AC0, 0x11AF8}, + {0x11C00, 0x11C08}, {0x11C0A, 0x11C2E}, {0x11C2F, 0x11C2F}, + {0x11C30, 0x11C36}, {0x11C38, 0x11C3D}, {0x11C3E, 0x11C3E}, + {0x11C3F, 0x11C3F}, {0x11C40, 0x11C40}, {0x11C41, 0x11C45}, + {0x11C50, 0x11C59}, {0x11C5A, 0x11C6C}, {0x11C70, 0x11C71}, + {0x11C72, 0x11C8F}, {0x11C92, 0x11CA7}, {0x11CA9, 0x11CA9}, + {0x11CAA, 0x11CB0}, {0x11CB1, 0x11CB1}, {0x11CB2, 0x11CB3}, + {0x11CB4, 0x11CB4}, {0x11CB5, 0x11CB6}, {0x12000, 0x12399}, + {0x12400, 0x1246E}, {0x12470, 0x12474}, {0x12480, 0x12543}, + {0x13000, 0x1342E}, {0x14400, 0x14646}, {0x16800, 0x16A38}, + {0x16A40, 0x16A5E}, {0x16A60, 0x16A69}, {0x16A6E, 0x16A6F}, + {0x16AD0, 0x16AED}, {0x16AF0, 0x16AF4}, {0x16AF5, 0x16AF5}, + {0x16B00, 0x16B2F}, {0x16B30, 0x16B36}, {0x16B37, 0x16B3B}, + {0x16B3C, 0x16B3F}, {0x16B40, 0x16B43}, {0x16B44, 0x16B44}, + {0x16B45, 0x16B45}, {0x16B50, 0x16B59}, {0x16B5B, 0x16B61}, + {0x16B63, 0x16B77}, {0x16B7D, 0x16B8F}, {0x16F00, 0x16F44}, + {0x16F50, 0x16F50}, {0x16F51, 0x16F7E}, {0x16F8F, 0x16F92}, + {0x16F93, 0x16F9F}, {0x1BC00, 0x1BC6A}, {0x1BC70, 0x1BC7C}, + {0x1BC80, 0x1BC88}, {0x1BC90, 0x1BC99}, {0x1BC9C, 0x1BC9C}, + {0x1BC9D, 0x1BC9E}, {0x1BC9F, 0x1BC9F}, {0x1BCA0, 0x1BCA3}, + {0x1D000, 0x1D0F5}, {0x1D100, 0x1D126}, {0x1D129, 0x1D164}, + {0x1D165, 0x1D166}, {0x1D167, 0x1D169}, {0x1D16A, 0x1D16C}, + {0x1D16D, 0x1D172}, {0x1D173, 0x1D17A}, {0x1D17B, 0x1D182}, + {0x1D183, 0x1D184}, {0x1D185, 0x1D18B}, {0x1D18C, 0x1D1A9}, + {0x1D1AA, 0x1D1AD}, {0x1D1AE, 0x1D1E8}, {0x1D200, 0x1D241}, + {0x1D242, 0x1D244}, {0x1D245, 0x1D245}, {0x1D300, 0x1D356}, + {0x1D360, 0x1D371}, {0x1D400, 0x1D454}, {0x1D456, 0x1D49C}, + {0x1D49E, 0x1D49F}, {0x1D4A2, 0x1D4A2}, {0x1D4A5, 0x1D4A6}, + {0x1D4A9, 0x1D4AC}, {0x1D4AE, 0x1D4B9}, {0x1D4BB, 0x1D4BB}, + {0x1D4BD, 0x1D4C3}, {0x1D4C5, 0x1D505}, {0x1D507, 0x1D50A}, + {0x1D50D, 0x1D514}, {0x1D516, 0x1D51C}, {0x1D51E, 0x1D539}, + {0x1D53B, 0x1D53E}, {0x1D540, 0x1D544}, {0x1D546, 0x1D546}, + {0x1D54A, 0x1D550}, {0x1D552, 0x1D6A5}, {0x1D6A8, 0x1D6C0}, + {0x1D6C1, 0x1D6C1}, {0x1D6C2, 0x1D6DA}, {0x1D6DB, 0x1D6DB}, + {0x1D6DC, 0x1D6FA}, {0x1D6FB, 0x1D6FB}, {0x1D6FC, 0x1D714}, + {0x1D715, 0x1D715}, {0x1D716, 0x1D734}, {0x1D735, 0x1D735}, + {0x1D736, 0x1D74E}, {0x1D74F, 0x1D74F}, {0x1D750, 0x1D76E}, + {0x1D76F, 0x1D76F}, {0x1D770, 0x1D788}, {0x1D789, 0x1D789}, + {0x1D78A, 0x1D7A8}, {0x1D7A9, 0x1D7A9}, {0x1D7AA, 0x1D7C2}, + {0x1D7C3, 0x1D7C3}, {0x1D7C4, 0x1D7CB}, {0x1D7CE, 0x1D7FF}, + {0x1D800, 0x1D9FF}, {0x1DA00, 0x1DA36}, {0x1DA37, 0x1DA3A}, + {0x1DA3B, 0x1DA6C}, {0x1DA6D, 0x1DA74}, {0x1DA75, 0x1DA75}, + {0x1DA76, 0x1DA83}, {0x1DA84, 0x1DA84}, {0x1DA85, 0x1DA86}, + {0x1DA87, 0x1DA8B}, {0x1DA9B, 0x1DA9F}, {0x1DAA1, 0x1DAAF}, + {0x1E000, 0x1E006}, {0x1E008, 0x1E018}, {0x1E01B, 0x1E021}, + {0x1E023, 0x1E024}, {0x1E026, 0x1E02A}, {0x1E800, 0x1E8C4}, + {0x1E8C7, 0x1E8CF}, {0x1E8D0, 0x1E8D6}, {0x1E900, 0x1E943}, + {0x1E944, 0x1E94A}, {0x1E950, 0x1E959}, {0x1E95E, 0x1E95F}, + {0x1EE00, 0x1EE03}, {0x1EE05, 0x1EE1F}, {0x1EE21, 0x1EE22}, + {0x1EE24, 0x1EE24}, {0x1EE27, 0x1EE27}, {0x1EE29, 0x1EE32}, + {0x1EE34, 0x1EE37}, {0x1EE39, 0x1EE39}, {0x1EE3B, 0x1EE3B}, + {0x1EE42, 0x1EE42}, {0x1EE47, 0x1EE47}, {0x1EE49, 0x1EE49}, + {0x1EE4B, 0x1EE4B}, {0x1EE4D, 0x1EE4F}, {0x1EE51, 0x1EE52}, + {0x1EE54, 0x1EE54}, {0x1EE57, 0x1EE57}, {0x1EE59, 0x1EE59}, + {0x1EE5B, 0x1EE5B}, {0x1EE5D, 0x1EE5D}, {0x1EE5F, 0x1EE5F}, + {0x1EE61, 0x1EE62}, {0x1EE64, 0x1EE64}, {0x1EE67, 0x1EE6A}, + {0x1EE6C, 0x1EE72}, {0x1EE74, 0x1EE77}, {0x1EE79, 0x1EE7C}, + {0x1EE7E, 0x1EE7E}, {0x1EE80, 0x1EE89}, {0x1EE8B, 0x1EE9B}, + {0x1EEA1, 0x1EEA3}, {0x1EEA5, 0x1EEA9}, {0x1EEAB, 0x1EEBB}, + {0x1EEF0, 0x1EEF1}, {0x1F000, 0x1F003}, {0x1F005, 0x1F02B}, + {0x1F030, 0x1F093}, {0x1F0A0, 0x1F0AE}, {0x1F0B1, 0x1F0BF}, + {0x1F0C1, 0x1F0CE}, {0x1F0D1, 0x1F0F5}, {0x1F10B, 0x1F10C}, + {0x1F12E, 0x1F12E}, {0x1F16A, 0x1F16B}, {0x1F1E6, 0x1F1FF}, + {0x1F321, 0x1F32C}, {0x1F336, 0x1F336}, {0x1F37D, 0x1F37D}, + {0x1F394, 0x1F39F}, {0x1F3CB, 0x1F3CE}, {0x1F3D4, 0x1F3DF}, + {0x1F3F1, 0x1F3F3}, {0x1F3F5, 0x1F3F7}, {0x1F43F, 0x1F43F}, + {0x1F441, 0x1F441}, {0x1F4FD, 0x1F4FE}, {0x1F53E, 0x1F54A}, + {0x1F54F, 0x1F54F}, {0x1F568, 0x1F579}, {0x1F57B, 0x1F594}, + {0x1F597, 0x1F5A3}, {0x1F5A5, 0x1F5FA}, {0x1F650, 0x1F67F}, + {0x1F6C6, 0x1F6CB}, {0x1F6CD, 0x1F6CF}, {0x1F6E0, 0x1F6EA}, + {0x1F6F0, 0x1F6F3}, {0x1F700, 0x1F773}, {0x1F780, 0x1F7D4}, + {0x1F800, 0x1F80B}, {0x1F810, 0x1F847}, {0x1F850, 0x1F859}, + {0x1F860, 0x1F887}, {0x1F890, 0x1F8AD}, {0xE0001, 0xE0001}, + {0xE0020, 0xE007F}, +} + +// Condition have flag EastAsianWidth whether the current locale is CJK or not. +type Condition struct { + EastAsianWidth bool +} + +// NewCondition return new instance of Condition which is current locale. +func NewCondition() *Condition { + return &Condition{EastAsianWidth} +} + +// RuneWidth returns the number of cells in r. +// See http://www.unicode.org/reports/tr11/ +func (c *Condition) RuneWidth(r rune) int { + switch { + case r < 0 || r > 0x10FFFF || + inTables(r, nonprint, combining, notassigned): + return 0 + case (c.EastAsianWidth && IsAmbiguousWidth(r)) || + inTables(r, doublewidth, emoji): + return 2 + default: + return 1 + } +} + +// StringWidth return width as you can see +func (c *Condition) StringWidth(s string) (width int) { + for _, r := range []rune(s) { + width += c.RuneWidth(r) + } + return width +} + +// Truncate return string truncated with w cells +func (c *Condition) Truncate(s string, w int, tail string) string { + if c.StringWidth(s) <= w { + return s + } + r := []rune(s) + tw := c.StringWidth(tail) + w -= tw + width := 0 + i := 0 + for ; i < len(r); i++ { + cw := c.RuneWidth(r[i]) + if width+cw > w { + break + } + width += cw + } + return string(r[0:i]) + tail +} + +// Wrap return string wrapped with w cells +func (c *Condition) Wrap(s string, w int) string { + width := 0 + out := "" + for _, r := range []rune(s) { + cw := RuneWidth(r) + if r == '\n' { + out += string(r) + width = 0 + continue + } else if width+cw > w { + out += "\n" + width = 0 + out += string(r) + width += cw + continue + } + out += string(r) + width += cw + } + return out +} + +// FillLeft return string filled in left by spaces in w cells +func (c *Condition) FillLeft(s string, w int) string { + width := c.StringWidth(s) + count := w - width + if count > 0 { + b := make([]byte, count) + for i := range b { + b[i] = ' ' + } + return string(b) + s + } + return s +} + +// FillRight return string filled in left by spaces in w cells +func (c *Condition) FillRight(s string, w int) string { + width := c.StringWidth(s) + count := w - width + if count > 0 { + b := make([]byte, count) + for i := range b { + b[i] = ' ' + } + return s + string(b) + } + return s +} + +// RuneWidth returns the number of cells in r. +// See http://www.unicode.org/reports/tr11/ +func RuneWidth(r rune) int { + return DefaultCondition.RuneWidth(r) +} + +// IsAmbiguousWidth returns whether is ambiguous width or not. +func IsAmbiguousWidth(r rune) bool { + return inTables(r, private, ambiguous) +} + +// IsNeutralWidth returns whether is neutral width or not. +func IsNeutralWidth(r rune) bool { + return inTable(r, neutral) +} + +// StringWidth return width as you can see +func StringWidth(s string) (width int) { + return DefaultCondition.StringWidth(s) +} + +// Truncate return string truncated with w cells +func Truncate(s string, w int, tail string) string { + return DefaultCondition.Truncate(s, w, tail) +} + +// Wrap return string wrapped with w cells +func Wrap(s string, w int) string { + return DefaultCondition.Wrap(s, w) +} + +// FillLeft return string filled in left by spaces in w cells +func FillLeft(s string, w int) string { + return DefaultCondition.FillLeft(s, w) +} + +// FillRight return string filled in left by spaces in w cells +func FillRight(s string, w int) string { + return DefaultCondition.FillRight(s, w) +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_js.go b/vendor/github.com/mattn/go-runewidth/runewidth_js.go new file mode 100644 index 000000000..0ce32c5e7 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth_js.go @@ -0,0 +1,8 @@ +// +build js + +package runewidth + +func IsEastAsian() bool { + // TODO: Implement this for the web. Detect east asian in a compatible way, and return true. + return false +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_posix.go b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go new file mode 100644 index 000000000..c579e9a31 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth_posix.go @@ -0,0 +1,77 @@ +// +build !windows,!js + +package runewidth + +import ( + "os" + "regexp" + "strings" +) + +var reLoc = regexp.MustCompile(`^[a-z][a-z][a-z]?(?:_[A-Z][A-Z])?\.(.+)`) + +var mblenTable = map[string]int{ + "utf-8": 6, + "utf8": 6, + "jis": 8, + "eucjp": 3, + "euckr": 2, + "euccn": 2, + "sjis": 2, + "cp932": 2, + "cp51932": 2, + "cp936": 2, + "cp949": 2, + "cp950": 2, + "big5": 2, + "gbk": 2, + "gb2312": 2, +} + +func isEastAsian(locale string) bool { + charset := strings.ToLower(locale) + r := reLoc.FindStringSubmatch(locale) + if len(r) == 2 { + charset = strings.ToLower(r[1]) + } + + if strings.HasSuffix(charset, "@cjk_narrow") { + return false + } + + for pos, b := range []byte(charset) { + if b == '@' { + charset = charset[:pos] + break + } + } + max := 1 + if m, ok := mblenTable[charset]; ok { + max = m + } + if max > 1 && (charset[0] != 'u' || + strings.HasPrefix(locale, "ja") || + strings.HasPrefix(locale, "ko") || + strings.HasPrefix(locale, "zh")) { + return true + } + return false +} + +// IsEastAsian return true if the current locale is CJK +func IsEastAsian() bool { + locale := os.Getenv("LC_CTYPE") + if locale == "" { + locale = os.Getenv("LANG") + } + + // ignore C locale + if locale == "POSIX" || locale == "C" { + return false + } + if len(locale) > 1 && locale[0] == 'C' && (locale[1] == '.' || locale[1] == '-') { + return false + } + + return isEastAsian(locale) +} diff --git a/vendor/github.com/mattn/go-runewidth/runewidth_windows.go b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go new file mode 100644 index 000000000..0258876b9 --- /dev/null +++ b/vendor/github.com/mattn/go-runewidth/runewidth_windows.go @@ -0,0 +1,25 @@ +package runewidth + +import ( + "syscall" +) + +var ( + kernel32 = syscall.NewLazyDLL("kernel32") + procGetConsoleOutputCP = kernel32.NewProc("GetConsoleOutputCP") +) + +// IsEastAsian return true if the current locale is CJK +func IsEastAsian() bool { + r1, _, _ := procGetConsoleOutputCP.Call() + if r1 == 0 { + return false + } + + switch int(r1) { + case 932, 51932, 936, 949, 950: + return true + } + + return false +} diff --git a/vendor/github.com/olekukonko/tablewriter/LICENCE.md b/vendor/github.com/olekukonko/tablewriter/LICENCE.md new file mode 100644 index 000000000..1fd848425 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/LICENCE.md @@ -0,0 +1,19 @@ +Copyright (C) 2014 by Oleku Konko + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/vendor/github.com/olekukonko/tablewriter/README.md b/vendor/github.com/olekukonko/tablewriter/README.md new file mode 100644 index 000000000..ae12208be --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/README.md @@ -0,0 +1,279 @@ +ASCII Table Writer +========= + +[![Build Status](https://travis-ci.org/olekukonko/tablewriter.png?branch=master)](https://travis-ci.org/olekukonko/tablewriter) +[![Total views](https://img.shields.io/sourcegraph/rrc/github.com/olekukonko/tablewriter.svg)](https://sourcegraph.com/github.com/olekukonko/tablewriter) +[![Godoc](https://godoc.org/github.com/olekukonko/tablewriter?status.svg)](https://godoc.org/github.com/olekukonko/tablewriter) + +Generate ASCII table on the fly ... Installation is simple as + + go get github.com/olekukonko/tablewriter + + +#### Features +- Automatic Padding +- Support Multiple Lines +- Supports Alignment +- Support Custom Separators +- Automatic Alignment of numbers & percentage +- Write directly to http , file etc via `io.Writer` +- Read directly from CSV file +- Optional row line via `SetRowLine` +- Normalise table header +- Make CSV Headers optional +- Enable or disable table border +- Set custom footer support +- Optional identical cells merging +- Set custom caption + + +#### Example 1 - Basic +```go +data := [][]string{ + []string{"A", "The Good", "500"}, + []string{"B", "The Very very Bad Man", "288"}, + []string{"C", "The Ugly", "120"}, + []string{"D", "The Gopher", "800"}, +} + +table := tablewriter.NewWriter(os.Stdout) +table.SetHeader([]string{"Name", "Sign", "Rating"}) + +for _, v := range data { + table.Append(v) +} +table.Render() // Send output +``` + +##### Output 1 +``` ++------+-----------------------+--------+ +| NAME | SIGN | RATING | ++------+-----------------------+--------+ +| A | The Good | 500 | +| B | The Very very Bad Man | 288 | +| C | The Ugly | 120 | +| D | The Gopher | 800 | ++------+-----------------------+--------+ +``` + +#### Example 2 - Without Border / Footer / Bulk Append +```go +data := [][]string{ + []string{"1/1/2014", "Domain name", "2233", "$10.98"}, + []string{"1/1/2014", "January Hosting", "2233", "$54.95"}, + []string{"1/4/2014", "February Hosting", "2233", "$51.00"}, + []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, +} + +table := tablewriter.NewWriter(os.Stdout) +table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) +table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer +table.SetBorder(false) // Set Border to false +table.AppendBulk(data) // Add Bulk Data +table.Render() +``` + +##### Output 2 +``` + + DATE | DESCRIPTION | CV2 | AMOUNT ++----------+--------------------------+-------+---------+ + 1/1/2014 | Domain name | 2233 | $10.98 + 1/1/2014 | January Hosting | 2233 | $54.95 + 1/4/2014 | February Hosting | 2233 | $51.00 + 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 ++----------+--------------------------+-------+---------+ + TOTAL | $146 93 + +-------+---------+ + +``` + + +#### Example 3 - CSV +```go +table, _ := tablewriter.NewCSV(os.Stdout, "test_info.csv", true) +table.SetAlignment(tablewriter.ALIGN_LEFT) // Set Alignment +table.Render() +``` + +##### Output 3 +``` ++----------+--------------+------+-----+---------+----------------+ +| FIELD | TYPE | NULL | KEY | DEFAULT | EXTRA | ++----------+--------------+------+-----+---------+----------------+ +| user_id | smallint(5) | NO | PRI | NULL | auto_increment | +| username | varchar(10) | NO | | NULL | | +| password | varchar(100) | NO | | NULL | | ++----------+--------------+------+-----+---------+----------------+ +``` + +#### Example 4 - Custom Separator +```go +table, _ := tablewriter.NewCSV(os.Stdout, "test.csv", true) +table.SetRowLine(true) // Enable row line + +// Change table lines +table.SetCenterSeparator("*") +table.SetColumnSeparator("‡") +table.SetRowSeparator("-") + +table.SetAlignment(tablewriter.ALIGN_LEFT) +table.Render() +``` + +##### Output 4 +``` +*------------*-----------*---------* +╪ FIRST NAME ╪ LAST NAME ╪ SSN ╪ +*------------*-----------*---------* +╪ John ╪ Barry ╪ 123456 ╪ +*------------*-----------*---------* +╪ Kathy ╪ Smith ╪ 687987 ╪ +*------------*-----------*---------* +╪ Bob ╪ McCornick ╪ 3979870 ╪ +*------------*-----------*---------* +``` + +#### Example 5 - Markdown Format +```go +data := [][]string{ + []string{"1/1/2014", "Domain name", "2233", "$10.98"}, + []string{"1/1/2014", "January Hosting", "2233", "$54.95"}, + []string{"1/4/2014", "February Hosting", "2233", "$51.00"}, + []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, +} + +table := tablewriter.NewWriter(os.Stdout) +table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) +table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) +table.SetCenterSeparator("|") +table.AppendBulk(data) // Add Bulk Data +table.Render() +``` + +##### Output 5 +``` +| DATE | DESCRIPTION | CV2 | AMOUNT | +|----------|--------------------------|------|--------| +| 1/1/2014 | Domain name | 2233 | $10.98 | +| 1/1/2014 | January Hosting | 2233 | $54.95 | +| 1/4/2014 | February Hosting | 2233 | $51.00 | +| 1/4/2014 | February Extra Bandwidth | 2233 | $30.00 | +``` + +#### Example 6 - Identical cells merging +```go +data := [][]string{ + []string{"1/1/2014", "Domain name", "1234", "$10.98"}, + []string{"1/1/2014", "January Hosting", "2345", "$54.95"}, + []string{"1/4/2014", "February Hosting", "3456", "$51.00"}, + []string{"1/4/2014", "February Extra Bandwidth", "4567", "$30.00"}, +} + +table := tablewriter.NewWriter(os.Stdout) +table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) +table.SetFooter([]string{"", "", "Total", "$146.93"}) +table.SetAutoMergeCells(true) +table.SetRowLine(true) +table.AppendBulk(data) +table.Render() +``` + +##### Output 6 +``` ++----------+--------------------------+-------+---------+ +| DATE | DESCRIPTION | CV2 | AMOUNT | ++----------+--------------------------+-------+---------+ +| 1/1/2014 | Domain name | 1234 | $10.98 | ++ +--------------------------+-------+---------+ +| | January Hosting | 2345 | $54.95 | ++----------+--------------------------+-------+---------+ +| 1/4/2014 | February Hosting | 3456 | $51.00 | ++ +--------------------------+-------+---------+ +| | February Extra Bandwidth | 4567 | $30.00 | ++----------+--------------------------+-------+---------+ +| TOTAL | $146 93 | ++----------+--------------------------+-------+---------+ +``` + + +#### Table with color +```go +data := [][]string{ + []string{"1/1/2014", "Domain name", "2233", "$10.98"}, + []string{"1/1/2014", "January Hosting", "2233", "$54.95"}, + []string{"1/4/2014", "February Hosting", "2233", "$51.00"}, + []string{"1/4/2014", "February Extra Bandwidth", "2233", "$30.00"}, +} + +table := tablewriter.NewWriter(os.Stdout) +table.SetHeader([]string{"Date", "Description", "CV2", "Amount"}) +table.SetFooter([]string{"", "", "Total", "$146.93"}) // Add Footer +table.SetBorder(false) // Set Border to false + +table.SetHeaderColor(tablewriter.Colors{tablewriter.Bold, tablewriter.BgGreenColor}, + tablewriter.Colors{tablewriter.FgHiRedColor, tablewriter.Bold, tablewriter.BgBlackColor}, + tablewriter.Colors{tablewriter.BgRedColor, tablewriter.FgWhiteColor}, + tablewriter.Colors{tablewriter.BgCyanColor, tablewriter.FgWhiteColor}) + +table.SetColumnColor(tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor}, + tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiRedColor}, + tablewriter.Colors{tablewriter.Bold, tablewriter.FgHiBlackColor}, + tablewriter.Colors{tablewriter.Bold, tablewriter.FgBlackColor}) + +table.SetFooterColor(tablewriter.Colors{}, tablewriter.Colors{}, + tablewriter.Colors{tablewriter.Bold}, + tablewriter.Colors{tablewriter.FgHiRedColor}) + +table.AppendBulk(data) +table.Render() +``` + +#### Table with color Output +![Table with Color](https://cloud.githubusercontent.com/assets/6460392/21101956/bbc7b356-c0a1-11e6-9f36-dba694746efc.png) + +#### Example 6 - Set table caption +```go +data := [][]string{ + []string{"A", "The Good", "500"}, + []string{"B", "The Very very Bad Man", "288"}, + []string{"C", "The Ugly", "120"}, + []string{"D", "The Gopher", "800"}, +} + +table := tablewriter.NewWriter(os.Stdout) +table.SetHeader([]string{"Name", "Sign", "Rating"}) +table.SetCaption(true, "Movie ratings.") + +for _, v := range data { + table.Append(v) +} +table.Render() // Send output +``` + +Note: Caption text will wrap with total width of rendered table. + +##### Output 6 +``` ++------+-----------------------+--------+ +| NAME | SIGN | RATING | ++------+-----------------------+--------+ +| A | The Good | 500 | +| B | The Very very Bad Man | 288 | +| C | The Ugly | 120 | +| D | The Gopher | 800 | ++------+-----------------------+--------+ +Movie ratings. +``` + +#### TODO +- ~~Import Directly from CSV~~ - `done` +- ~~Support for `SetFooter`~~ - `done` +- ~~Support for `SetBorder`~~ - `done` +- ~~Support table with uneven rows~~ - `done` +- Support custom alignment +- General Improvement & Optimisation +- `NewHTML` Parse table from HTML + + diff --git a/vendor/github.com/olekukonko/tablewriter/csv.go b/vendor/github.com/olekukonko/tablewriter/csv.go new file mode 100644 index 000000000..98878303b --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/csv.go @@ -0,0 +1,52 @@ +// Copyright 2014 Oleku Konko All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +// This module is a Table Writer API for the Go Programming Language. +// The protocols were written in pure Go and works on windows and unix systems + +package tablewriter + +import ( + "encoding/csv" + "io" + "os" +) + +// Start A new table by importing from a CSV file +// Takes io.Writer and csv File name +func NewCSV(writer io.Writer, fileName string, hasHeader bool) (*Table, error) { + file, err := os.Open(fileName) + if err != nil { + return &Table{}, err + } + defer file.Close() + csvReader := csv.NewReader(file) + t, err := NewCSVReader(writer, csvReader, hasHeader) + return t, err +} + +// Start a New Table Writer with csv.Reader +// This enables customisation such as reader.Comma = ';' +// See http://golang.org/src/pkg/encoding/csv/reader.go?s=3213:3671#L94 +func NewCSVReader(writer io.Writer, csvReader *csv.Reader, hasHeader bool) (*Table, error) { + t := NewWriter(writer) + if hasHeader { + // Read the first row + headers, err := csvReader.Read() + if err != nil { + return &Table{}, err + } + t.SetHeader(headers) + } + for { + record, err := csvReader.Read() + if err == io.EOF { + break + } else if err != nil { + return &Table{}, err + } + t.Append(record) + } + return t, nil +} diff --git a/vendor/github.com/olekukonko/tablewriter/table.go b/vendor/github.com/olekukonko/tablewriter/table.go new file mode 100644 index 000000000..8b62c628c --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/table.go @@ -0,0 +1,798 @@ +// Copyright 2014 Oleku Konko All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +// This module is a Table Writer API for the Go Programming Language. +// The protocols were written in pure Go and works on windows and unix systems + +// Create & Generate text based table +package tablewriter + +import ( + "bytes" + "fmt" + "io" + "regexp" + "strings" +) + +const ( + MAX_ROW_WIDTH = 30 +) + +const ( + CENTER = "+" + ROW = "-" + COLUMN = "|" + SPACE = " " + NEWLINE = "\n" +) + +const ( + ALIGN_DEFAULT = iota + ALIGN_CENTER + ALIGN_RIGHT + ALIGN_LEFT +) + +var ( + decimal = regexp.MustCompile(`^-*\d*\.?\d*$`) + percent = regexp.MustCompile(`^-*\d*\.?\d*$%$`) +) + +type Border struct { + Left bool + Right bool + Top bool + Bottom bool +} + +type Table struct { + out io.Writer + rows [][]string + lines [][][]string + cs map[int]int + rs map[int]int + headers []string + footers []string + caption bool + captionText string + autoFmt bool + autoWrap bool + mW int + pCenter string + pRow string + pColumn string + tColumn int + tRow int + hAlign int + fAlign int + align int + newLine string + rowLine bool + autoMergeCells bool + hdrLine bool + borders Border + colSize int + headerParams []string + columnsParams []string + footerParams []string + columnsAlign []int +} + +// Start New Table +// Take io.Writer Directly +func NewWriter(writer io.Writer) *Table { + t := &Table{ + out: writer, + rows: [][]string{}, + lines: [][][]string{}, + cs: make(map[int]int), + rs: make(map[int]int), + headers: []string{}, + footers: []string{}, + caption: false, + captionText: "Table caption.", + autoFmt: true, + autoWrap: true, + mW: MAX_ROW_WIDTH, + pCenter: CENTER, + pRow: ROW, + pColumn: COLUMN, + tColumn: -1, + tRow: -1, + hAlign: ALIGN_DEFAULT, + fAlign: ALIGN_DEFAULT, + align: ALIGN_DEFAULT, + newLine: NEWLINE, + rowLine: false, + hdrLine: true, + borders: Border{Left: true, Right: true, Bottom: true, Top: true}, + colSize: -1, + headerParams: []string{}, + columnsParams: []string{}, + footerParams: []string{}, + columnsAlign: []int{}} + return t +} + +// Render table output +func (t *Table) Render() { + if t.borders.Top { + t.printLine(true) + } + t.printHeading() + if t.autoMergeCells { + t.printRowsMergeCells() + } else { + t.printRows() + } + if !t.rowLine && t.borders.Bottom { + t.printLine(true) + } + t.printFooter() + + if t.caption { + t.printCaption() + } +} + +// Set table header +func (t *Table) SetHeader(keys []string) { + t.colSize = len(keys) + for i, v := range keys { + t.parseDimension(v, i, -1) + t.headers = append(t.headers, v) + } +} + +// Set table Footer +func (t *Table) SetFooter(keys []string) { + //t.colSize = len(keys) + for i, v := range keys { + t.parseDimension(v, i, -1) + t.footers = append(t.footers, v) + } +} + +// Set table Caption +func (t *Table) SetCaption(caption bool, captionText ...string) { + t.caption = caption + if len(captionText) == 1 { + t.captionText = captionText[0] + } +} + +// Turn header autoformatting on/off. Default is on (true). +func (t *Table) SetAutoFormatHeaders(auto bool) { + t.autoFmt = auto +} + +// Turn automatic multiline text adjustment on/off. Default is on (true). +func (t *Table) SetAutoWrapText(auto bool) { + t.autoWrap = auto +} + +// Set the Default column width +func (t *Table) SetColWidth(width int) { + t.mW = width +} + +// Set the minimal width for a column +func (t *Table) SetColMinWidth(column int, width int) { + t.cs[column] = width +} + +// Set the Column Separator +func (t *Table) SetColumnSeparator(sep string) { + t.pColumn = sep +} + +// Set the Row Separator +func (t *Table) SetRowSeparator(sep string) { + t.pRow = sep +} + +// Set the center Separator +func (t *Table) SetCenterSeparator(sep string) { + t.pCenter = sep +} + +// Set Header Alignment +func (t *Table) SetHeaderAlignment(hAlign int) { + t.hAlign = hAlign +} + +// Set Footer Alignment +func (t *Table) SetFooterAlignment(fAlign int) { + t.fAlign = fAlign +} + +// Set Table Alignment +func (t *Table) SetAlignment(align int) { + t.align = align +} + +func (t *Table) SetColumnAlignment(keys []int) { + for _, v := range keys { + switch v { + case ALIGN_CENTER: + break + case ALIGN_LEFT: + break + case ALIGN_RIGHT: + break + default: + v = ALIGN_DEFAULT + } + t.columnsAlign = append(t.columnsAlign, v) + } +} + +// Set New Line +func (t *Table) SetNewLine(nl string) { + t.newLine = nl +} + +// Set Header Line +// This would enable / disable a line after the header +func (t *Table) SetHeaderLine(line bool) { + t.hdrLine = line +} + +// Set Row Line +// This would enable / disable a line on each row of the table +func (t *Table) SetRowLine(line bool) { + t.rowLine = line +} + +// Set Auto Merge Cells +// This would enable / disable the merge of cells with identical values +func (t *Table) SetAutoMergeCells(auto bool) { + t.autoMergeCells = auto +} + +// Set Table Border +// This would enable / disable line around the table +func (t *Table) SetBorder(border bool) { + t.SetBorders(Border{border, border, border, border}) +} + +func (t *Table) SetBorders(border Border) { + t.borders = border +} + +// Append row to table +func (t *Table) Append(row []string) { + rowSize := len(t.headers) + if rowSize > t.colSize { + t.colSize = rowSize + } + + n := len(t.lines) + line := [][]string{} + for i, v := range row { + + // Detect string width + // Detect String height + // Break strings into words + out := t.parseDimension(v, i, n) + + // Append broken words + line = append(line, out) + } + t.lines = append(t.lines, line) +} + +// Allow Support for Bulk Append +// Eliminates repeated for loops +func (t *Table) AppendBulk(rows [][]string) { + for _, row := range rows { + t.Append(row) + } +} + +// NumLines to get the number of lines +func (t *Table) NumLines() int { + return len(t.lines) +} + +// Clear rows +func (t *Table) ClearRows() { + t.lines = [][][]string{} +} + +// Clear footer +func (t *Table) ClearFooter() { + t.footers = []string{} +} + +// Print line based on row width +func (t *Table) printLine(nl bool) { + fmt.Fprint(t.out, t.pCenter) + for i := 0; i < len(t.cs); i++ { + v := t.cs[i] + fmt.Fprintf(t.out, "%s%s%s%s", + t.pRow, + strings.Repeat(string(t.pRow), v), + t.pRow, + t.pCenter) + } + if nl { + fmt.Fprint(t.out, t.newLine) + } +} + +// Print line based on row width with our without cell separator +func (t *Table) printLineOptionalCellSeparators(nl bool, displayCellSeparator []bool) { + fmt.Fprint(t.out, t.pCenter) + for i := 0; i < len(t.cs); i++ { + v := t.cs[i] + if i > len(displayCellSeparator) || displayCellSeparator[i] { + // Display the cell separator + fmt.Fprintf(t.out, "%s%s%s%s", + t.pRow, + strings.Repeat(string(t.pRow), v), + t.pRow, + t.pCenter) + } else { + // Don't display the cell separator for this cell + fmt.Fprintf(t.out, "%s%s", + strings.Repeat(" ", v+2), + t.pCenter) + } + } + if nl { + fmt.Fprint(t.out, t.newLine) + } +} + +// Return the PadRight function if align is left, PadLeft if align is right, +// and Pad by default +func pad(align int) func(string, string, int) string { + padFunc := Pad + switch align { + case ALIGN_LEFT: + padFunc = PadRight + case ALIGN_RIGHT: + padFunc = PadLeft + } + return padFunc +} + +// Print heading information +func (t *Table) printHeading() { + // Check if headers is available + if len(t.headers) < 1 { + return + } + + // Check if border is set + // Replace with space if not set + fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE)) + + // Identify last column + end := len(t.cs) - 1 + + // Get pad function + padFunc := pad(t.hAlign) + + // Checking for ANSI escape sequences for header + is_esc_seq := false + if len(t.headerParams) > 0 { + is_esc_seq = true + } + + // Print Heading column + for i := 0; i <= end; i++ { + v := t.cs[i] + h := "" + if i < len(t.headers) { + h = t.headers[i] + } + if t.autoFmt { + h = Title(h) + } + pad := ConditionString((i == end && !t.borders.Left), SPACE, t.pColumn) + + if is_esc_seq { + fmt.Fprintf(t.out, " %s %s", + format(padFunc(h, SPACE, v), + t.headerParams[i]), pad) + } else { + fmt.Fprintf(t.out, " %s %s", + padFunc(h, SPACE, v), + pad) + } + + } + // Next line + fmt.Fprint(t.out, t.newLine) + if t.hdrLine { + t.printLine(true) + } +} + +// Print heading information +func (t *Table) printFooter() { + // Check if headers is available + if len(t.footers) < 1 { + return + } + + // Only print line if border is not set + if !t.borders.Bottom { + t.printLine(true) + } + // Check if border is set + // Replace with space if not set + fmt.Fprint(t.out, ConditionString(t.borders.Bottom, t.pColumn, SPACE)) + + // Identify last column + end := len(t.cs) - 1 + + // Get pad function + padFunc := pad(t.fAlign) + + // Checking for ANSI escape sequences for header + is_esc_seq := false + if len(t.footerParams) > 0 { + is_esc_seq = true + } + + // Print Heading column + for i := 0; i <= end; i++ { + v := t.cs[i] + f := t.footers[i] + if t.autoFmt { + f = Title(f) + } + pad := ConditionString((i == end && !t.borders.Top), SPACE, t.pColumn) + + if len(t.footers[i]) == 0 { + pad = SPACE + } + + if is_esc_seq { + fmt.Fprintf(t.out, " %s %s", + format(padFunc(f, SPACE, v), + t.footerParams[i]), pad) + } else { + fmt.Fprintf(t.out, " %s %s", + padFunc(f, SPACE, v), + pad) + } + + //fmt.Fprintf(t.out, " %s %s", + // padFunc(f, SPACE, v), + // pad) + } + // Next line + fmt.Fprint(t.out, t.newLine) + //t.printLine(true) + + hasPrinted := false + + for i := 0; i <= end; i++ { + v := t.cs[i] + pad := t.pRow + center := t.pCenter + length := len(t.footers[i]) + + if length > 0 { + hasPrinted = true + } + + // Set center to be space if length is 0 + if length == 0 && !t.borders.Right { + center = SPACE + } + + // Print first junction + if i == 0 { + fmt.Fprint(t.out, center) + } + + // Pad With space of length is 0 + if length == 0 { + pad = SPACE + } + // Ignore left space of it has printed before + if hasPrinted || t.borders.Left { + pad = t.pRow + center = t.pCenter + } + + // Change Center start position + if center == SPACE { + if i < end && len(t.footers[i+1]) != 0 { + center = t.pCenter + } + } + + // Print the footer + fmt.Fprintf(t.out, "%s%s%s%s", + pad, + strings.Repeat(string(pad), v), + pad, + center) + + } + + fmt.Fprint(t.out, t.newLine) +} + +// Print caption text +func (t Table) printCaption() { + width := t.getTableWidth() + paragraph, _ := WrapString(t.captionText, width) + for linecount := 0; linecount < len(paragraph); linecount++ { + fmt.Fprintln(t.out, paragraph[linecount]) + } +} + +// Calculate the total number of characters in a row +func (t Table) getTableWidth() int { + var chars int + for _, v := range t.cs { + chars += v + } + + // Add chars, spaces, seperators to calculate the total width of the table. + // ncols := t.colSize + // spaces := ncols * 2 + // seps := ncols + 1 + + return (chars + (3 * t.colSize) + 2) +} + +func (t Table) printRows() { + for i, lines := range t.lines { + t.printRow(lines, i) + } +} + +func (t *Table) fillAlignment(num int) { + if len(t.columnsAlign) < num { + t.columnsAlign = make([]int, num) + for i := range t.columnsAlign { + t.columnsAlign[i] = t.align + } + } +} + +// Print Row Information +// Adjust column alignment based on type + +func (t *Table) printRow(columns [][]string, colKey int) { + // Get Maximum Height + max := t.rs[colKey] + total := len(columns) + + // TODO Fix uneven col size + // if total < t.colSize { + // for n := t.colSize - total; n < t.colSize ; n++ { + // columns = append(columns, []string{SPACE}) + // t.cs[n] = t.mW + // } + //} + + // Pad Each Height + // pads := []int{} + pads := []int{} + + // Checking for ANSI escape sequences for columns + is_esc_seq := false + if len(t.columnsParams) > 0 { + is_esc_seq = true + } + t.fillAlignment(total) + + for i, line := range columns { + length := len(line) + pad := max - length + pads = append(pads, pad) + for n := 0; n < pad; n++ { + columns[i] = append(columns[i], " ") + } + } + //fmt.Println(max, "\n") + for x := 0; x < max; x++ { + for y := 0; y < total; y++ { + + // Check if border is set + fmt.Fprint(t.out, ConditionString((!t.borders.Left && y == 0), SPACE, t.pColumn)) + + fmt.Fprintf(t.out, SPACE) + str := columns[y][x] + + // Embedding escape sequence with column value + if is_esc_seq { + str = format(str, t.columnsParams[y]) + } + + // This would print alignment + // Default alignment would use multiple configuration + switch t.columnsAlign[y] { + case ALIGN_CENTER: // + fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y])) + case ALIGN_RIGHT: + fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y])) + case ALIGN_LEFT: + fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y])) + default: + if decimal.MatchString(strings.TrimSpace(str)) || percent.MatchString(strings.TrimSpace(str)) { + fmt.Fprintf(t.out, "%s", PadLeft(str, SPACE, t.cs[y])) + } else { + fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y])) + + // TODO Custom alignment per column + //if max == 1 || pads[y] > 0 { + // fmt.Fprintf(t.out, "%s", Pad(str, SPACE, t.cs[y])) + //} else { + // fmt.Fprintf(t.out, "%s", PadRight(str, SPACE, t.cs[y])) + //} + + } + } + fmt.Fprintf(t.out, SPACE) + } + // Check if border is set + // Replace with space if not set + fmt.Fprint(t.out, ConditionString(t.borders.Left, t.pColumn, SPACE)) + fmt.Fprint(t.out, t.newLine) + } + + if t.rowLine { + t.printLine(true) + } +} + +// Print the rows of the table and merge the cells that are identical +func (t *Table) printRowsMergeCells() { + var previousLine []string + var displayCellBorder []bool + var tmpWriter bytes.Buffer + for i, lines := range t.lines { + // We store the display of the current line in a tmp writer, as we need to know which border needs to be print above + previousLine, displayCellBorder = t.printRowMergeCells(&tmpWriter, lines, i, previousLine) + if i > 0 { //We don't need to print borders above first line + if t.rowLine { + t.printLineOptionalCellSeparators(true, displayCellBorder) + } + } + tmpWriter.WriteTo(t.out) + } + //Print the end of the table + if t.rowLine { + t.printLine(true) + } +} + +// Print Row Information to a writer and merge identical cells. +// Adjust column alignment based on type + +func (t *Table) printRowMergeCells(writer io.Writer, columns [][]string, colKey int, previousLine []string) ([]string, []bool) { + // Get Maximum Height + max := t.rs[colKey] + total := len(columns) + + // Pad Each Height + pads := []int{} + + for i, line := range columns { + length := len(line) + pad := max - length + pads = append(pads, pad) + for n := 0; n < pad; n++ { + columns[i] = append(columns[i], " ") + } + } + + var displayCellBorder []bool + t.fillAlignment(total) + for x := 0; x < max; x++ { + for y := 0; y < total; y++ { + + // Check if border is set + fmt.Fprint(writer, ConditionString((!t.borders.Left && y == 0), SPACE, t.pColumn)) + + fmt.Fprintf(writer, SPACE) + + str := columns[y][x] + + if t.autoMergeCells { + //Store the full line to merge mutli-lines cells + fullLine := strings.Join(columns[y], " ") + if len(previousLine) > y && fullLine == previousLine[y] && fullLine != "" { + // If this cell is identical to the one above but not empty, we don't display the border and keep the cell empty. + displayCellBorder = append(displayCellBorder, false) + str = "" + } else { + // First line or different content, keep the content and print the cell border + displayCellBorder = append(displayCellBorder, true) + } + } + + // This would print alignment + // Default alignment would use multiple configuration + switch t.columnsAlign[y] { + case ALIGN_CENTER: // + fmt.Fprintf(writer, "%s", Pad(str, SPACE, t.cs[y])) + case ALIGN_RIGHT: + fmt.Fprintf(writer, "%s", PadLeft(str, SPACE, t.cs[y])) + case ALIGN_LEFT: + fmt.Fprintf(writer, "%s", PadRight(str, SPACE, t.cs[y])) + default: + if decimal.MatchString(strings.TrimSpace(str)) || percent.MatchString(strings.TrimSpace(str)) { + fmt.Fprintf(writer, "%s", PadLeft(str, SPACE, t.cs[y])) + } else { + fmt.Fprintf(writer, "%s", PadRight(str, SPACE, t.cs[y])) + } + } + fmt.Fprintf(writer, SPACE) + } + // Check if border is set + // Replace with space if not set + fmt.Fprint(writer, ConditionString(t.borders.Left, t.pColumn, SPACE)) + fmt.Fprint(writer, t.newLine) + } + + //The new previous line is the current one + previousLine = make([]string, total) + for y := 0; y < total; y++ { + previousLine[y] = strings.Join(columns[y], " ") //Store the full line for multi-lines cells + } + //Returns the newly added line and wether or not a border should be displayed above. + return previousLine, displayCellBorder +} + +func (t *Table) parseDimension(str string, colKey, rowKey int) []string { + var ( + raw []string + max int + ) + w := DisplayWidth(str) + // Calculate Width + // Check if with is grater than maximum width + if w > t.mW { + w = t.mW + } + + // Check if width exists + v, ok := t.cs[colKey] + if !ok || v < w || v == 0 { + t.cs[colKey] = w + } + + if rowKey == -1 { + return raw + } + // Calculate Height + if t.autoWrap { + raw, _ = WrapString(str, t.cs[colKey]) + } else { + raw = getLines(str) + } + + for _, line := range raw { + if w := DisplayWidth(line); w > max { + max = w + } + } + + // Make sure the with is the same length as maximum word + // Important for cases where the width is smaller than maxu word + if max > t.cs[colKey] { + t.cs[colKey] = max + } + + h := len(raw) + v, ok = t.rs[rowKey] + + if !ok || v < h || v == 0 { + t.rs[rowKey] = h + } + //fmt.Printf("Raw %+v %d\n", raw, len(raw)) + return raw +} diff --git a/vendor/github.com/olekukonko/tablewriter/table_with_color.go b/vendor/github.com/olekukonko/tablewriter/table_with_color.go new file mode 100644 index 000000000..5a4a53ec2 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/table_with_color.go @@ -0,0 +1,134 @@ +package tablewriter + +import ( + "fmt" + "strconv" + "strings" +) + +const ESC = "\033" +const SEP = ";" + +const ( + BgBlackColor int = iota + 40 + BgRedColor + BgGreenColor + BgYellowColor + BgBlueColor + BgMagentaColor + BgCyanColor + BgWhiteColor +) + +const ( + FgBlackColor int = iota + 30 + FgRedColor + FgGreenColor + FgYellowColor + FgBlueColor + FgMagentaColor + FgCyanColor + FgWhiteColor +) + +const ( + BgHiBlackColor int = iota + 100 + BgHiRedColor + BgHiGreenColor + BgHiYellowColor + BgHiBlueColor + BgHiMagentaColor + BgHiCyanColor + BgHiWhiteColor +) + +const ( + FgHiBlackColor int = iota + 90 + FgHiRedColor + FgHiGreenColor + FgHiYellowColor + FgHiBlueColor + FgHiMagentaColor + FgHiCyanColor + FgHiWhiteColor +) + +const ( + Normal = 0 + Bold = 1 + UnderlineSingle = 4 + Italic +) + +type Colors []int + +func startFormat(seq string) string { + return fmt.Sprintf("%s[%sm", ESC, seq) +} + +func stopFormat() string { + return fmt.Sprintf("%s[%dm", ESC, Normal) +} + +// Making the SGR (Select Graphic Rendition) sequence. +func makeSequence(codes []int) string { + codesInString := []string{} + for _, code := range codes { + codesInString = append(codesInString, strconv.Itoa(code)) + } + return strings.Join(codesInString, SEP) +} + +// Adding ANSI escape sequences before and after string +func format(s string, codes interface{}) string { + var seq string + + switch v := codes.(type) { + + case string: + seq = v + case []int: + seq = makeSequence(v) + default: + return s + } + + if len(seq) == 0 { + return s + } + return startFormat(seq) + s + stopFormat() +} + +// Adding header colors (ANSI codes) +func (t *Table) SetHeaderColor(colors ...Colors) { + if t.colSize != len(colors) { + panic("Number of header colors must be equal to number of headers.") + } + for i := 0; i < len(colors); i++ { + t.headerParams = append(t.headerParams, makeSequence(colors[i])) + } +} + +// Adding column colors (ANSI codes) +func (t *Table) SetColumnColor(colors ...Colors) { + if t.colSize != len(colors) { + panic("Number of column colors must be equal to number of headers.") + } + for i := 0; i < len(colors); i++ { + t.columnsParams = append(t.columnsParams, makeSequence(colors[i])) + } +} + +// Adding column colors (ANSI codes) +func (t *Table) SetFooterColor(colors ...Colors) { + if len(t.footers) != len(colors) { + panic("Number of footer colors must be equal to number of footer.") + } + for i := 0; i < len(colors); i++ { + t.footerParams = append(t.footerParams, makeSequence(colors[i])) + } +} + +func Color(colors ...int) []int { + return colors +} diff --git a/vendor/github.com/olekukonko/tablewriter/test.csv b/vendor/github.com/olekukonko/tablewriter/test.csv new file mode 100644 index 000000000..1609327e9 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/test.csv @@ -0,0 +1,4 @@ +first_name,last_name,ssn +John,Barry,123456 +Kathy,Smith,687987 +Bob,McCornick,3979870 \ No newline at end of file diff --git a/vendor/github.com/olekukonko/tablewriter/test_info.csv b/vendor/github.com/olekukonko/tablewriter/test_info.csv new file mode 100644 index 000000000..e4c40e983 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/test_info.csv @@ -0,0 +1,4 @@ +Field,Type,Null,Key,Default,Extra +user_id,smallint(5),NO,PRI,NULL,auto_increment +username,varchar(10),NO,,NULL, +password,varchar(100),NO,,NULL, \ No newline at end of file diff --git a/vendor/github.com/olekukonko/tablewriter/util.go b/vendor/github.com/olekukonko/tablewriter/util.go new file mode 100644 index 000000000..2deefbc52 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/util.go @@ -0,0 +1,72 @@ +// Copyright 2014 Oleku Konko All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +// This module is a Table Writer API for the Go Programming Language. +// The protocols were written in pure Go and works on windows and unix systems + +package tablewriter + +import ( + "math" + "regexp" + "strings" + + "github.com/mattn/go-runewidth" +) + +var ansi = regexp.MustCompile("\033\\[(?:[0-9]{1,3}(?:;[0-9]{1,3})*)?[m|K]") + +func DisplayWidth(str string) int { + return runewidth.StringWidth(ansi.ReplaceAllLiteralString(str, "")) +} + +// Simple Condition for string +// Returns value based on condition +func ConditionString(cond bool, valid, inValid string) string { + if cond { + return valid + } + return inValid +} + +// Format Table Header +// Replace _ , . and spaces +func Title(name string) string { + name = strings.Replace(name, "_", " ", -1) + name = strings.Replace(name, ".", " ", -1) + name = strings.TrimSpace(name) + return strings.ToUpper(name) +} + +// Pad String +// Attempts to play string in the center +func Pad(s, pad string, width int) string { + gap := width - DisplayWidth(s) + if gap > 0 { + gapLeft := int(math.Ceil(float64(gap / 2))) + gapRight := gap - gapLeft + return strings.Repeat(string(pad), gapLeft) + s + strings.Repeat(string(pad), gapRight) + } + return s +} + +// Pad String Right position +// This would pace string at the left side fo the screen +func PadRight(s, pad string, width int) string { + gap := width - DisplayWidth(s) + if gap > 0 { + return s + strings.Repeat(string(pad), gap) + } + return s +} + +// Pad String Left position +// This would pace string at the right side fo the screen +func PadLeft(s, pad string, width int) string { + gap := width - DisplayWidth(s) + if gap > 0 { + return strings.Repeat(string(pad), gap) + s + } + return s +} diff --git a/vendor/github.com/olekukonko/tablewriter/wrap.go b/vendor/github.com/olekukonko/tablewriter/wrap.go new file mode 100644 index 000000000..9ef69e904 --- /dev/null +++ b/vendor/github.com/olekukonko/tablewriter/wrap.go @@ -0,0 +1,104 @@ +// Copyright 2014 Oleku Konko All rights reserved. +// Use of this source code is governed by a MIT +// license that can be found in the LICENSE file. + +// This module is a Table Writer API for the Go Programming Language. +// The protocols were written in pure Go and works on windows and unix systems + +package tablewriter + +import ( + "math" + "strings" + + "github.com/mattn/go-runewidth" +) + +var ( + nl = "\n" + sp = " " +) + +const defaultPenalty = 1e5 + +// Wrap wraps s into a paragraph of lines of length lim, with minimal +// raggedness. +func WrapString(s string, lim int) ([]string, int) { + words := strings.Split(strings.Replace(s, nl, sp, -1), sp) + var lines []string + max := 0 + for _, v := range words { + max = runewidth.StringWidth(v) + if max > lim { + lim = max + } + } + for _, line := range WrapWords(words, 1, lim, defaultPenalty) { + lines = append(lines, strings.Join(line, sp)) + } + return lines, lim +} + +// WrapWords is the low-level line-breaking algorithm, useful if you need more +// control over the details of the text wrapping process. For most uses, +// WrapString will be sufficient and more convenient. +// +// WrapWords splits a list of words into lines with minimal "raggedness", +// treating each rune as one unit, accounting for spc units between adjacent +// words on each line, and attempting to limit lines to lim units. Raggedness +// is the total error over all lines, where error is the square of the +// difference of the length of the line and lim. Too-long lines (which only +// happen when a single word is longer than lim units) have pen penalty units +// added to the error. +func WrapWords(words []string, spc, lim, pen int) [][]string { + n := len(words) + + length := make([][]int, n) + for i := 0; i < n; i++ { + length[i] = make([]int, n) + length[i][i] = runewidth.StringWidth(words[i]) + for j := i + 1; j < n; j++ { + length[i][j] = length[i][j-1] + spc + runewidth.StringWidth(words[j]) + } + } + nbrk := make([]int, n) + cost := make([]int, n) + for i := range cost { + cost[i] = math.MaxInt32 + } + for i := n - 1; i >= 0; i-- { + if length[i][n-1] <= lim { + cost[i] = 0 + nbrk[i] = n + } else { + for j := i + 1; j < n; j++ { + d := lim - length[i][j-1] + c := d*d + cost[j] + if length[i][j-1] > lim { + c += pen // too-long lines get a worse penalty + } + if c < cost[i] { + cost[i] = c + nbrk[i] = j + } + } + } + } + var lines [][]string + i := 0 + for i < n { + lines = append(lines, words[i:nbrk[i]]) + i = nbrk[i] + } + return lines +} + +// getLines decomposes a multiline string into a slice of strings. +func getLines(s string) []string { + var lines []string + + for _, line := range strings.Split(s, nl) { + lines = append(lines, line) + } + return lines +} diff --git a/vendor/vendor.json b/vendor/vendor.json index c5714b58f..5ce94fe2c 100644 --- a/vendor/vendor.json +++ b/vendor/vendor.json @@ -941,6 +941,12 @@ "path": "github.com/mattn/go-isatty", "revision": "56b76bdf51f7708750eac80fa38b952bb9f32639" }, + { + "checksumSHA1": "cJE7dphDlam/i7PhnsyosNWtbd4=", + "path": "github.com/mattn/go-runewidth", + "revision": "97311d9f7767e3d6f422ea06661bc2c7a19e8a5d", + "revisionTime": "2017-05-10T07:48:58Z" + }, { "checksumSHA1": "UP+pXl+ic9y6qrpZA5MqDIAuGfw=", "path": "github.com/mitchellh/cli", @@ -1006,6 +1012,12 @@ "path": "github.com/nu7hatch/gouuid", "revision": "179d4d0c4d8d407a32af483c2354df1d2c91e6c3" }, + { + "checksumSHA1": "WY8p2ZNGyl69P1tcVc5HFal/Ng0=", + "path": "github.com/olekukonko/tablewriter", + "revision": "96aac992fc8b1a4c83841a6c3e7178d20d989625", + "revisionTime": "2018-01-05T11:11:33Z" + }, { "checksumSHA1": "/NoE6t3UkW4/iKAtbf59GGv6tF8=", "path": "github.com/packer-community/winrmcp/winrmcp", From 32e9ff84c5efd937036a4fccb35931e214bc5b2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 17:16:28 +0900 Subject: [PATCH 06/17] Add ncloud doc html --- website/source/docs/builders/ncloud.html.md | 88 +++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 website/source/docs/builders/ncloud.html.md diff --git a/website/source/docs/builders/ncloud.html.md b/website/source/docs/builders/ncloud.html.md new file mode 100644 index 000000000..ce38a9c71 --- /dev/null +++ b/website/source/docs/builders/ncloud.html.md @@ -0,0 +1,88 @@ +--- +description: | + As Packer allows users to develop a custom builder as a plugin, NAVER CLOUD PLATFORM provides its own Packer builder for your convenience. +You can use NAVER CLOUD PLATFORM's Packer builder to easily create your server images. +layout: docs +page_title: 'Naver Cloud Platform - Builders' +sidebar_current: 'docs-builders-ncloud' +--- + +# NAVER CLOUD PLATFORM Builder + +As Packer allows users to develop a custom builder as a plugin, NAVER CLOUD PLATFORM provides its own Packer builder for your convenience. +You can use NAVER CLOUD PLATFORM's Packer builder to easily create your server images. + +#### Sample code of template.json + +``` +{ + "variables": { + "ncloud_access_key": "FRxhOQRNjKVMqIz3sRLY", + "ncloud_secret_key": "xd6kTO5iNcLookBx0D8TDKmpLj2ikxqEhc06MQD2" + }, + "builders": [ + { + "type": "ncloud", + "access_key": "{{user `ncloud_access_key`}}", + "secret_key": "{{user `ncloud_secret_key`}}", + + "server_image_product_code": "SPSW0WINNT000016", + "server_product_code": "SPSVRSSD00000011", + "member_server_image_no": "4223", + "server_image_name": "packer-test {{timestamp}}", + "server_description": "server description", + "user_data": "CreateObject(\"WScript.Shell\").run(\"cmd.exe /c powershell Set-ExecutionPolicy RemoteSigned & winrm quickconfig -q & sc config WinRM start= auto & winrm set winrm/config/service/auth @{Basic=\"\"true\"\"} & winrm set winrm/config/service @{AllowUnencrypted=\"\"true\"\"} & winrm get winrm/config/service\")", + "region": "US-West" + } + ] +} +``` + +#### Description + +* type(required): "ncloud" +* ncloud_access_key (required): User's access key. Go to [[Account Management > Authentication Key]](https://www.ncloud.com/mypage/manage/authkey) to create and view your authentication key. +* ncloud_secret_key (required): User's secret key paired with the access key. Go to [[Account Management > Authentication Key]](https://www.ncloud.com/mypage/manage/authkey) to create and view your authentication key. +* server_image_product_code: Product code of an image to create. (member_server_image_no is required if not specified) +* server_product_code (required): Product (spec) code to create. +* member_server_image_no: Previous image code. If there is an image previously created, it can be used to create a new image. (server_image_product_code is required if not specified) +* server_image_name (option): Name of an image to create. +* server_image_description (option): Description of an image to create. +* block_storage_size (option): You can add block storage ranging from 10 GB to 2000 GB, in increments of 10 GB. +* access_control_group_configuration_no: This is used to allow winrm access when you create a Windows server. An ACG that specifies an access source ("0.0.0.0/0") and allowed port (5985) must be created in advance. +* user_data (option): Init script to run when an instance is created. + * For Linux servers, Python, Perl, and Shell scripts can be used. The path of the script to run should be included at the beginning of the script, like #!/usr/bin/env python, #!/bin/perl, or #!/bin/bash. + * For Windows servers, only Visual Basic scripts can be used. + * All scripts must be written in English. +* region (option): Name of the region where you want to create an image. (default: Korea) + * values: Korea / US-West / HongKong / Singapore / Japan / Germany + +### Requirements for creating Windows images + +You should include the following code in the packer configuration file for provision when creating a Windows server. + +``` + "builders": [ + { + "type": "ncloud", + ... + "user_data": + "CreateObject(\"WScript.Shell\").run(\"cmd.exe /c powershell Set-ExecutionPolicy RemoteSigned & winrm set winrm/config/service/auth @{Basic=\"\"true\"\"} & winrm set winrm/config/service @{AllowUnencrypted=\"\"true\"\"} & winrm quickconfig -q & sc config WinRM start= auto & winrm get winrm/config/service\")", + "communicator": "winrm", + "winrm_username": "Administrator" + } + ], + "provisioners": [ + { + "type": "powershell", + "inline": [ + "$Env:SystemRoot\\System32\\Sysprep\\Sysprep.exe /oobe /generalize /shutdown /quiet \"/unattend:C:\\Program Files (x86)\\NBP\\nserver64.xml\" " + ] + } + ] +``` + +### Note + +* You can only create as many public IP addresses as the number of server instances you own. Before running Packer, please make sure that the number of public IP addresses previously created is not larger than the number of server instances (including those to be used to create server images). +* When you forcibly terminate the packer process or close the terminal (command) window where the process is running, the resources may not be cleaned up as the packer process no longer runs. In this case, you should manually clean up the resources associated with the process. From da78ebbf837db0aa37a77e8989d91693feebddcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 17:29:26 +0900 Subject: [PATCH 07/17] - Remove plugin version - remove `os_type`. use `communicator` instead of this. --- builder/ncloud/builder.go | 10 +++------- builder/ncloud/config.go | 10 +++------- builder/ncloud/config_test.go | 3 --- builder/ncloud/step_create_public_ip_instance.go | 6 +++--- builder/ncloud/step_create_public_ip_instance_test.go | 6 +++++- 5 files changed, 14 insertions(+), 21 deletions(-) diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index 580514d53..24ec670d3 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -8,8 +8,6 @@ import ( "github.com/mitchellh/multistep" ) -const version = "1.0.0" - // Builder assume this implements packer.Builder type Builder struct { config *Config @@ -30,8 +28,6 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { } func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packer.Artifact, error) { - ui.Say("Running builder for Naver Cloud Platform (version: " + version + ") ...") - ui.Message("Creating Naver Cloud Platform Connection ...") conn := ncloud.NewConnection(b.config.AccessKey, b.config.SecretKey) @@ -42,7 +38,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe steps = []multistep.Step{} - if b.config.OSType == "Linux" { + if b.config.Comm.Type == "ssh" { steps = []multistep.Step{ NewStepValidateTemplate(conn, ui, b.config), NewStepCreateLoginKey(conn, ui), @@ -63,7 +59,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe NewStepDeleteLoginKey(conn, ui), NewStepDeletePublicIPInstance(conn, ui), } - } else if b.config.OSType == "Windows" { + } else if b.config.Comm.Type == "Windows" { steps = []multistep.Step{ NewStepValidateTemplate(conn, ui, b.config), NewStepCreateLoginKey(conn, ui), @@ -94,7 +90,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe } // Run! - b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) + b.runner = common.NewRunnerWithPauseFn(steps, b.config.PackerConfig, ui, b.stateBag) b.runner.Run(b.stateBag) // If there was an error, return that diff --git a/builder/ncloud/config.go b/builder/ncloud/config.go index e18ab822d..abaca35c3 100644 --- a/builder/ncloud/config.go +++ b/builder/ncloud/config.go @@ -16,13 +16,13 @@ type Config struct { AccessKey string `mapstructure:"access_key"` SecretKey string `mapstructure:"secret_key"` - OSType string `mapstructure:"os_type"` ServerImageProductCode string `mapstructure:"server_image_product_code"` ServerProductCode string `mapstructure:"server_product_code"` MemberServerImageNo string `mapstructure:"member_server_image_no"` ServerImageName string `mapstructure:"server_image_name"` ServerImageDescription string `mapstructure:"server_image_description"` UserData string `mapstructure:"user_data"` + UserDataFile string `mapstructure:"user_data_file"` BlockStorageSize int `mapstructure:"block_storage_size"` Region string `mapstructure:"region"` AccessControlGroupConfigurationNo string `mapstructure:"access_control_group_configuration_no"` @@ -60,10 +60,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend(errs, errors.New("secret_key is required")) } - if c.OSType != "Linux" && c.OSType != "Windows" { - errs = packer.MultiErrorAppend(errs, errors.New("os_type is required. ('Linux' or 'Windows')")) - } - if c.MemberServerImageNo == "" && c.ServerImageProductCode == "" { errs = packer.MultiErrorAppend(errs, errors.New("server_image_product_code or member_server_image_no is required")) } @@ -100,8 +96,8 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend(errs, errors.New("If user_data field is set, length of UserData should be max 21847")) } - if c.OSType == "Windows" && c.AccessControlGroupConfigurationNo == "" { - errs = packer.MultiErrorAppend(errs, errors.New("If os_type is Windows, access_control_group_configuration_no is required")) + if c.Comm.Type == "wrinrm" && c.AccessControlGroupConfigurationNo == "" { + errs = packer.MultiErrorAppend(errs, errors.New("If Communicator is winrm, access_control_group_configuration_no is required")) } c.FeeSystemTypeCode = "MTRAT" diff --git a/builder/ncloud/config_test.go b/builder/ncloud/config_test.go index 7907c7ee1..7e2591594 100644 --- a/builder/ncloud/config_test.go +++ b/builder/ncloud/config_test.go @@ -9,7 +9,6 @@ func testConfig() map[string]interface{} { return map[string]interface{}{ "access_key": "access_key", "secret_key": "secret_key", - "os_type": "Windows", "server_image_product_code": "SPSW0WINNT000016", "server_product_code": "SPSVRSSD00000011", "server_image_name": "packer-test {{timestamp}}", @@ -27,7 +26,6 @@ func testConfigForMemberServerImage() map[string]interface{} { return map[string]interface{}{ "access_key": "access_key", "secret_key": "secret_key", - "os_type": "Windows", "server_product_code": "SPSVRSSD00000011", "member_server_image_no": "2440", "server_image_name": "packer-test {{timestamp}}", @@ -135,7 +133,6 @@ func TestExistsBothServerImageProductCodeAndMemberServerImageNoConfig(t *testing raw := map[string]interface{}{ "access_key": "access_key", "secret_key": "secret_key", - "os_type": "Windows", "server_image_product_code": "SPSW0WINNT000016", "server_product_code": "SPSVRSSD00000011", "member_server_image_no": "2440", diff --git a/builder/ncloud/step_create_public_ip_instance.go b/builder/ncloud/step_create_public_ip_instance.go index 1ea1517c5..897ff1504 100644 --- a/builder/ncloud/step_create_public_ip_instance.go +++ b/builder/ncloud/step_create_public_ip_instance.go @@ -91,10 +91,10 @@ func (s *StepCreatePublicIPInstance) Run(state multistep.StateBag) multistep.Ste publicIPInstance, err := s.CreatePublicIPInstance(serverInstanceNo) if err == nil { - switch s.Config.OSType { - case "Linux": + switch s.Config.Comm.Type { + case "ssh": state.Put("SSHHost", publicIPInstance.PublicIP) - case "Windows": + case "winrm": state.Put("WinRMHost", publicIPInstance.PublicIP) } diff --git a/builder/ncloud/step_create_public_ip_instance_test.go b/builder/ncloud/step_create_public_ip_instance_test.go index 30eaca017..0f44f4a33 100644 --- a/builder/ncloud/step_create_public_ip_instance_test.go +++ b/builder/ncloud/step_create_public_ip_instance_test.go @@ -31,13 +31,17 @@ func TestStepCreatePublicIPInstanceShouldFailIfOperationCreatePublicIPInstanceFa } func TestStepCreatePublicIPInstanceShouldPassIfOperationCreatePublicIPInstancePasses(t *testing.T) { + c := new(Config) + c.Comm.Prepare(nil) + c.Comm.Type = "ssh" + var testSubject = &StepCreatePublicIPInstance{ CreatePublicIPInstance: func(serverInstanceNo string) (*ncloud.PublicIPInstance, error) { return &ncloud.PublicIPInstance{PublicIPInstanceNo: "a", PublicIP: "b"}, nil }, Say: func(message string) {}, Error: func(e error) {}, - Config: &Config{OSType: "Windows"}, + Config: c, } stateBag := createTestStateBagStepCreatePublicIPInstance() From 2152ad76093bbd29f16075598e97fb473257be8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 18:09:14 +0900 Subject: [PATCH 08/17] Add UserDataFile --- builder/ncloud/config.go | 10 +++++++++- builder/ncloud/step_create_server_instance.go | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/builder/ncloud/config.go b/builder/ncloud/config.go index abaca35c3..5e713d44d 100644 --- a/builder/ncloud/config.go +++ b/builder/ncloud/config.go @@ -22,7 +22,7 @@ type Config struct { ServerImageName string `mapstructure:"server_image_name"` ServerImageDescription string `mapstructure:"server_image_description"` UserData string `mapstructure:"user_data"` - UserDataFile string `mapstructure:"user_data_file"` + UserDataFile string `mapstructure:"user_data_file"` BlockStorageSize int `mapstructure:"block_storage_size"` Region string `mapstructure:"region"` AccessControlGroupConfigurationNo string `mapstructure:"access_control_group_configuration_no"` @@ -92,6 +92,14 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { } } + if c.UserData != "" && c.UserDataFile != "" { + errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) + } else if c.UserDataFile != "" { + if _, err := os.Stat(c.UserDataFile); err != nil { + errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) + } + } + if c.UserData != "" && len(c.UserData) > 21847 { errs = packer.MultiErrorAppend(errs, errors.New("If user_data field is set, length of UserData should be max 21847")) } diff --git a/builder/ncloud/step_create_server_instance.go b/builder/ncloud/step_create_server_instance.go index d7decd4d8..3a842f899 100644 --- a/builder/ncloud/step_create_server_instance.go +++ b/builder/ncloud/step_create_server_instance.go @@ -3,6 +3,7 @@ package ncloud import ( "errors" "fmt" + "io/ioutil" "log" "time" @@ -49,6 +50,15 @@ func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zon reqParams.UserData = s.Config.UserData } + if s.Config.UserDataFile != "" { + contents, err := ioutil.ReadFile(s.Config.UserDataFile) + if err != nil { + return "", fmt.Errorf("Problem reading user data file: %s", err) + } + + reqParams.UserData = string(contents) + } + if s.Config.AccessControlGroupConfigurationNo != "" { reqParams.AccessControlGroupConfigurationNoList = []string{s.Config.AccessControlGroupConfigurationNo} } From 3820f97a0b4b6b93e091d9ec78ecb0cc1da4bc27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 18:35:43 +0900 Subject: [PATCH 09/17] use state storage to save `feeSystemTypeCode` --- builder/ncloud/config.go | 9 ++++---- builder/ncloud/step_create_server_instance.go | 13 +++++++---- .../step_create_server_instance_test.go | 4 ++-- builder/ncloud/step_validate_template.go | 23 +++++++++++-------- 4 files changed, 29 insertions(+), 20 deletions(-) diff --git a/builder/ncloud/config.go b/builder/ncloud/config.go index 5e713d44d..c8c1374bb 100644 --- a/builder/ncloud/config.go +++ b/builder/ncloud/config.go @@ -2,6 +2,8 @@ package ncloud import ( "errors" + "fmt" + "os" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" @@ -26,7 +28,6 @@ type Config struct { BlockStorageSize int `mapstructure:"block_storage_size"` Region string `mapstructure:"region"` AccessControlGroupConfigurationNo string `mapstructure:"access_control_group_configuration_no"` - FeeSystemTypeCode string `mapstructure:"-"` Comm communicator.Config `mapstructure:",squash"` ctx *interpolate.Context @@ -93,10 +94,10 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { } if c.UserData != "" && c.UserDataFile != "" { - errs = append(errs, fmt.Errorf("Only one of user_data or user_data_file can be specified.")) + errs = packer.MultiErrorAppend(errs, errors.New("Only one of user_data or user_data_file can be specified.")) } else if c.UserDataFile != "" { if _, err := os.Stat(c.UserDataFile); err != nil { - errs = append(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) + errs = packer.MultiErrorAppend(errs, fmt.Errorf("user_data_file not found: %s", c.UserDataFile)) } } @@ -108,8 +109,6 @@ func NewConfig(raws ...interface{}) (*Config, []string, error) { errs = packer.MultiErrorAppend(errs, errors.New("If Communicator is winrm, access_control_group_configuration_no is required")) } - c.FeeSystemTypeCode = "MTRAT" - if errs != nil && len(errs.Errors) > 0 { return nil, warnings, errs } diff --git a/builder/ncloud/step_create_server_instance.go b/builder/ncloud/step_create_server_instance.go index 3a842f899..346ce3a1c 100644 --- a/builder/ncloud/step_create_server_instance.go +++ b/builder/ncloud/step_create_server_instance.go @@ -14,7 +14,7 @@ import ( type StepCreateServerInstance struct { Conn *ncloud.Conn - CreateServerInstance func(loginKeyName string, zoneNo string) (string, error) + CreateServerInstance func(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) CheckServerInstanceStatusIsRunning func(serverInstanceNo string) error Say func(message string) Error func(e error) @@ -35,7 +35,7 @@ func NewStepCreateServerInstance(conn *ncloud.Conn, ui packer.Ui, config *Config return step } -func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zoneNo string) (string, error) { +func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) { reqParams := new(ncloud.RequestCreateServerInstance) reqParams.ServerProductCode = s.Config.ServerProductCode reqParams.MemberServerImageNo = s.Config.MemberServerImageNo @@ -44,7 +44,7 @@ func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zon } reqParams.LoginKeyName = loginKeyName reqParams.ZoneNo = zoneNo - reqParams.FeeSystemTypeCode = s.Config.FeeSystemTypeCode + reqParams.FeeSystemTypeCode = feeSystemTypeCode if s.Config.UserData != "" { reqParams.UserData = s.Config.UserData @@ -87,7 +87,12 @@ func (s *StepCreateServerInstance) Run(state multistep.StateBag) multistep.StepA var loginKey = state.Get("LoginKey").(*LoginKey) var zoneNo = state.Get("ZoneNo").(string) - serverInstanceNo, err := s.CreateServerInstance(loginKey.KeyName, zoneNo) + feeSystemTypeCode := "MTRAT" + if _, ok := state.GetOk("FeeSystemTypeCode"); ok { + feeSystemTypeCode = state.Get("FeeSystemTypeCode").(string) + } + + serverInstanceNo, err := s.CreateServerInstance(loginKey.KeyName, zoneNo, feeSystemTypeCode) if err == nil { state.Put("InstanceNo", serverInstanceNo) } diff --git a/builder/ncloud/step_create_server_instance_test.go b/builder/ncloud/step_create_server_instance_test.go index 327228b75..ddaa34157 100644 --- a/builder/ncloud/step_create_server_instance_test.go +++ b/builder/ncloud/step_create_server_instance_test.go @@ -8,7 +8,7 @@ import ( func TestStepCreateServerInstanceShouldFailIfOperationCreateFails(t *testing.T) { var testSubject = &StepCreateServerInstance{ - CreateServerInstance: func(loginKeyName string, zoneNo string) (string, error) { + CreateServerInstance: func(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) { return "", fmt.Errorf("!! Unit Test FAIL !!") }, Say: func(message string) {}, @@ -30,7 +30,7 @@ func TestStepCreateServerInstanceShouldFailIfOperationCreateFails(t *testing.T) func TestStepCreateServerInstanceShouldPassIfOperationCreatePasses(t *testing.T) { var testSubject = &StepCreateServerInstance{ - CreateServerInstance: func(loginKeyName string, zoneNo string) (string, error) { return "", nil }, + CreateServerInstance: func(loginKeyName string, zoneNo string, feeSystemTypeCode string) (string, error) { return "", nil }, Say: func(message string) {}, Error: func(e error) {}, } diff --git a/builder/ncloud/step_validate_template.go b/builder/ncloud/step_validate_template.go index d645111c4..d4c576946 100644 --- a/builder/ncloud/step_validate_template.go +++ b/builder/ncloud/step_validate_template.go @@ -14,13 +14,14 @@ import ( //StepValidateTemplate : struct for Validation a tempalte type StepValidateTemplate struct { - Conn *ncloud.Conn - Validate func() error - Say func(message string) - Error func(e error) - Config *Config - zoneNo string - regionNo string + Conn *ncloud.Conn + Validate func() error + Say func(message string) + Error func(e error) + Config *Config + zoneNo string + regionNo string + FeeSystemTypeCode string } // NewStepValidateTemplate : funciton for Validation a tempalte @@ -168,7 +169,7 @@ func (s *StepValidateTemplate) validateServerImageProduct() error { } if strings.Contains(productName, "mssql") { - s.Config.FeeSystemTypeCode = "FXSUM" + s.FeeSystemTypeCode = "FXSUM" } return nil @@ -193,7 +194,7 @@ func (s *StepValidateTemplate) validateServerProductCode() error { if product.ProductCode == productCode { isExistProductCode = true if strings.Contains(product.ProductName, "mssql") { - s.Config.FeeSystemTypeCode = "FXSUM" + s.FeeSystemTypeCode = "FXSUM" } if product.ProductType.Code == "VDS" { @@ -255,6 +256,10 @@ func (s *StepValidateTemplate) Run(state multistep.StateBag) multistep.StepActio state.Put("ZoneNo", s.zoneNo) + if s.FeeSystemTypeCode != "" { + state.Put("FeeSystemTypeCode", s.FeeSystemTypeCode) + } + return processStepResult(err, s.Error, state) } From 30f8fee40259c2daa0e4d872683d31ee212fbc6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 19:08:53 +0900 Subject: [PATCH 10/17] use comment with english --- builder/ncloud/step_create_server_image.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/ncloud/step_create_server_image.go b/builder/ncloud/step_create_server_image.go index ea0784058..8bec7f11f 100644 --- a/builder/ncloud/step_create_server_image.go +++ b/builder/ncloud/step_create_server_image.go @@ -32,7 +32,7 @@ func NewStepCreateServerImage(conn *ncloud.Conn, ui packer.Ui, config *Config) * } func (s *StepCreateServerImage) createServerImage(serverInstanceNo string) (*ncloud.ServerImage, error) { - // 서버 인스턴스 상태가 정지 중일 경우에는 서버 이미지 생성할 수 없음. + // Can't create server image when status of server instance is stopping (not stopped) if err := waiterServerInstanceStatus(s.Conn, serverInstanceNo, "NSTOP", 1*time.Minute); err != nil { return nil, err } From 2a3a35334a9237d521f3e644e204c454ae1f595a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 20:42:22 +0900 Subject: [PATCH 11/17] Logging root password --- builder/ncloud/step_get_rootpassword.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/builder/ncloud/step_get_rootpassword.go b/builder/ncloud/step_get_rootpassword.go index b696e594d..9ec0feae2 100644 --- a/builder/ncloud/step_get_rootpassword.go +++ b/builder/ncloud/step_get_rootpassword.go @@ -35,6 +35,8 @@ func (s *StepGetRootPassword) getRootPassword(serverInstanceNo string, privateKe return "", err } + s.Say(fmt.Sprintf("Root password is %s", rootPassword.RootPassword)) + return rootPassword.RootPassword, nil } From e57a8161e06d7fd24904b23e474c40b063a78b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 21:47:58 +0900 Subject: [PATCH 12/17] remove delete step of `login key` and `public ip instance`. --- builder/ncloud/builder.go | 4 - builder/ncloud/step_create_login_key.go | 7 -- .../ncloud/step_create_public_ip_instance.go | 12 ++- builder/ncloud/step_delete_login_key.go | 51 ------------ builder/ncloud/step_delete_login_key_test.go | 55 ------------- .../ncloud/step_delete_public_ip_instance.go | 78 ------------------- .../step_delete_public_ip_instance_test.go | 57 -------------- builder/ncloud/step_get_rootpassword.go | 2 + 8 files changed, 7 insertions(+), 259 deletions(-) delete mode 100644 builder/ncloud/step_delete_login_key.go delete mode 100644 builder/ncloud/step_delete_login_key_test.go delete mode 100644 builder/ncloud/step_delete_public_ip_instance.go delete mode 100644 builder/ncloud/step_delete_public_ip_instance_test.go diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index 24ec670d3..21435e6d0 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -56,8 +56,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe NewStepCreateServerImage(conn, ui, b.config), NewStepDeleteBlockStorageInstance(conn, ui, b.config), NewStepTerminateServerInstance(conn, ui), - NewStepDeleteLoginKey(conn, ui), - NewStepDeletePublicIPInstance(conn, ui), } } else if b.config.Comm.Type == "Windows" { steps = []multistep.Step{ @@ -84,8 +82,6 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe NewStepCreateServerImage(conn, ui, b.config), NewStepDeleteBlockStorageInstance(conn, ui, b.config), NewStepTerminateServerInstance(conn, ui), - NewStepDeleteLoginKey(conn, ui), - NewStepDeletePublicIPInstance(conn, ui), } } diff --git a/builder/ncloud/step_create_login_key.go b/builder/ncloud/step_create_login_key.go index d200c3106..f79c4decf 100644 --- a/builder/ncloud/step_create_login_key.go +++ b/builder/ncloud/step_create_login_key.go @@ -57,13 +57,6 @@ func (s *StepCreateLoginKey) Run(state multistep.StateBag) multistep.StepAction } func (s *StepCreateLoginKey) Cleanup(state multistep.StateBag) { - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - - if !cancelled && !halted { - return - } - if loginKey, ok := state.GetOk("LoginKey"); ok { s.Say("Clean up login key") s.Conn.DeleteLoginKey(loginKey.(*LoginKey).KeyName) diff --git a/builder/ncloud/step_create_public_ip_instance.go b/builder/ncloud/step_create_public_ip_instance.go index 897ff1504..d15fd9f54 100644 --- a/builder/ncloud/step_create_public_ip_instance.go +++ b/builder/ncloud/step_create_public_ip_instance.go @@ -105,13 +105,6 @@ func (s *StepCreatePublicIPInstance) Run(state multistep.StateBag) multistep.Ste } func (s *StepCreatePublicIPInstance) Cleanup(state multistep.StateBag) { - _, cancelled := state.GetOk(multistep.StateCancelled) - _, halted := state.GetOk(multistep.StateHalted) - - if !cancelled && !halted { - return - } - publicIPInstance, ok := state.GetOk("PublicIPInstance") if !ok { return @@ -148,6 +141,11 @@ func (s *StepCreatePublicIPInstance) waitPublicIPInstanceStatus(publicIPInstance return } + if resp.TotalRows == 0 { + c1 <- nil + return + } + instance := resp.PublicIPInstanceList[0] if instance.PublicIPInstanceStatus.Code == status && instance.PublicIPInstanceOperation.Code == "NULL" { c1 <- nil diff --git a/builder/ncloud/step_delete_login_key.go b/builder/ncloud/step_delete_login_key.go deleted file mode 100644 index 18256c7d8..000000000 --- a/builder/ncloud/step_delete_login_key.go +++ /dev/null @@ -1,51 +0,0 @@ -package ncloud - -import ( - "fmt" - - ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" - "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" -) - -type StepDeleteLoginKey struct { - Conn *ncloud.Conn - DeleteLoginKey func(keyName string) error - Say func(message string) - Error func(e error) -} - -func NewStepDeleteLoginKey(conn *ncloud.Conn, ui packer.Ui) *StepDeleteLoginKey { - var step = &StepDeleteLoginKey{ - Conn: conn, - Say: func(message string) { ui.Say(message) }, - Error: func(e error) { ui.Error(e.Error()) }, - } - - step.DeleteLoginKey = step.deleteLoginKey - - return step -} - -func (s *StepDeleteLoginKey) deleteLoginKey(keyName string) error { - _, err := s.Conn.DeleteLoginKey(keyName) - if err != nil { - return err - } - - return nil -} - -func (s *StepDeleteLoginKey) Run(state multistep.StateBag) multistep.StepAction { - var loginKey = state.Get("LoginKey").(*LoginKey) - - err := s.DeleteLoginKey(loginKey.KeyName) - if err == nil { - s.Say(fmt.Sprintf("Login Key[%s] is deleted", loginKey.KeyName)) - } - - return processStepResult(err, s.Error, state) -} - -func (*StepDeleteLoginKey) Cleanup(multistep.StateBag) { -} diff --git a/builder/ncloud/step_delete_login_key_test.go b/builder/ncloud/step_delete_login_key_test.go deleted file mode 100644 index 38ce1e22c..000000000 --- a/builder/ncloud/step_delete_login_key_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package ncloud - -import ( - "fmt" - "github.com/mitchellh/multistep" - "testing" -) - -func TestStepDeleteLoginKeyShouldFailIfOperationDeleteLoginKeyFails(t *testing.T) { - var testSubject = &StepDeleteLoginKey{ - DeleteLoginKey: func(keyName string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, - Say: func(message string) {}, - Error: func(e error) {}, - } - - stateBag := DeleteTestStateBagStepDeleteLoginKey() - - var result = testSubject.Run(stateBag) - - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk("Error"); ok == false { - t.Fatal("Expected the step to set stateBag['Error'], but it was not.") - } -} - -func TestStepDeleteLoginKeyShouldPassIfOperationDeleteLoginKeyPasses(t *testing.T) { - var testSubject = &StepDeleteLoginKey{ - DeleteLoginKey: func(keyName string) error { return nil }, - Say: func(message string) {}, - Error: func(e error) {}, - } - - stateBag := DeleteTestStateBagStepDeleteLoginKey() - - var result = testSubject.Run(stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk("Error"); ok == true { - t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") - } -} - -func DeleteTestStateBagStepDeleteLoginKey() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put("LoginKey", &LoginKey{"a", "b"}) - - return stateBag -} diff --git a/builder/ncloud/step_delete_public_ip_instance.go b/builder/ncloud/step_delete_public_ip_instance.go deleted file mode 100644 index 4a1401984..000000000 --- a/builder/ncloud/step_delete_public_ip_instance.go +++ /dev/null @@ -1,78 +0,0 @@ -package ncloud - -import ( - "errors" - "fmt" - "log" - "time" - - ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" - "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" -) - -type StepDeletePublicIPInstance struct { - Conn *ncloud.Conn - DeletePublicIPInstance func(publicIPInstanceNo string) error - Say func(message string) - Error func(e error) -} - -func NewStepDeletePublicIPInstance(conn *ncloud.Conn, ui packer.Ui) *StepDeletePublicIPInstance { - var step = &StepDeletePublicIPInstance{ - Conn: conn, - Say: func(message string) { ui.Say(message) }, - Error: func(e error) { ui.Error(e.Error()) }, - } - - step.DeletePublicIPInstance = step.deletePublicIPInstance - - return step -} - -func (s *StepDeletePublicIPInstance) deletePublicIPInstance(publicIPInstanceNo string) error { - reqParams := new(ncloud.RequestDeletePublicIPInstances) - reqParams.PublicIPInstanceNoList = []string{publicIPInstanceNo} - - c1 := make(chan error, 1) - - go func() { - for { - resp, err := s.Conn.DeletePublicIPInstances(reqParams) - if err != nil && (resp.ReturnCode == 24073 || resp.ReturnCode == 25032) { - // error code : 24073 : Unable to destroy the server since a public IP is associated with the server. First, please disassociate a public IP from the server. - // error code : 25032 : You may not delete sk since (other) user is changing the target official IP settings. - log.Println(resp.ReturnCode, resp.ReturnMessage) - } else if err != nil { - c1 <- fmt.Errorf("error code: %d, error message: %s", resp.ReturnCode, resp.ReturnMessage) - return - } else if err == nil { - s.Say(fmt.Sprintf("Public IP Instance [%s] is deleted.", publicIPInstanceNo)) - c1 <- nil - return - } - - time.Sleep(time.Second * 5) - } - }() - - select { - case res := <-c1: - return res - case <-time.After(time.Second * 60): - return errors.New("TIMEOUT : Can't delete server instance") - } -} - -func (s *StepDeletePublicIPInstance) Run(state multistep.StateBag) multistep.StepAction { - s.Say("Delete Public IP Instance") - - publicIPInstance := state.Get("PublicIPInstance").(*ncloud.PublicIPInstance) - - err := s.DeletePublicIPInstance(publicIPInstance.PublicIPInstanceNo) - - return processStepResult(err, s.Error, state) -} - -func (*StepDeletePublicIPInstance) Cleanup(multistep.StateBag) { -} diff --git a/builder/ncloud/step_delete_public_ip_instance_test.go b/builder/ncloud/step_delete_public_ip_instance_test.go deleted file mode 100644 index b9fa04ec8..000000000 --- a/builder/ncloud/step_delete_public_ip_instance_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package ncloud - -import ( - "fmt" - ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" - "testing" - - "github.com/mitchellh/multistep" -) - -func TestStepDeletePublicIPInstanceShouldFailIfOperationDeletePublicIPInstanceFails(t *testing.T) { - var testSubject = &StepDeletePublicIPInstance{ - DeletePublicIPInstance: func(publicIPInstanceNo string) error { return fmt.Errorf("!! Unit Test FAIL !!") }, - Say: func(message string) {}, - Error: func(e error) {}, - } - - stateBag := createTestStateBagStepDeletePublicIPInstance() - - var result = testSubject.Run(stateBag) - - if result != multistep.ActionHalt { - t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk("Error"); ok == false { - t.Fatal("Expected the step to set stateBag['Error'], but it was not.") - } -} - -func TestStepDeletePublicIPInstanceShouldPassIfOperationDeletePublicIPInstancePasses(t *testing.T) { - var testSubject = &StepDeletePublicIPInstance{ - DeletePublicIPInstance: func(publicIPInstanceNo string) error { return nil }, - Say: func(message string) {}, - Error: func(e error) {}, - } - - stateBag := createTestStateBagStepDeletePublicIPInstance() - - var result = testSubject.Run(stateBag) - - if result != multistep.ActionContinue { - t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) - } - - if _, ok := stateBag.GetOk("Error"); ok == true { - t.Fatalf("Expected the step to not set stateBag['Error'], but it was.") - } -} - -func createTestStateBagStepDeletePublicIPInstance() multistep.StateBag { - stateBag := new(multistep.BasicStateBag) - - stateBag.Put("PublicIPInstance", &ncloud.PublicIPInstance{PublicIPInstanceNo: "22"}) - - return stateBag -} diff --git a/builder/ncloud/step_get_rootpassword.go b/builder/ncloud/step_get_rootpassword.go index 9ec0feae2..d9eda578a 100644 --- a/builder/ncloud/step_get_rootpassword.go +++ b/builder/ncloud/step_get_rootpassword.go @@ -1,6 +1,8 @@ package ncloud import ( + "fmt" + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" "github.com/hashicorp/packer/packer" "github.com/mitchellh/multistep" From 6b40c726e0f742c73964f3150e9aec9f91c6f3ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 22:07:32 +0900 Subject: [PATCH 13/17] Use `PublicIp` for communicator --- builder/ncloud/builder.go | 8 +++++--- builder/ncloud/ssh.go | 5 ----- builder/ncloud/step_create_public_ip_instance.go | 8 +------- 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index 21435e6d0..e493661be 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -47,8 +47,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe NewStepGetRootPassword(conn, ui), NewStepCreatePublicIPInstance(conn, ui, b.config), &communicator.StepConnectSSH{ - Config: &b.config.Comm, - Host: SSHHost, + Config: &b.config.Comm, + Host: func(stateBag multistep.StateBag) (string, error) { + return stateBag.Get("PublicIP").(string), nil + }, SSHConfig: SSHConfig(b.config.Comm.SSHUsername), }, &common.StepProvision{}, @@ -68,7 +70,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe &communicator.StepConnectWinRM{ Config: &b.config.Comm, Host: func(stateBag multistep.StateBag) (string, error) { - return stateBag.Get("WinRMHost").(string), nil + return stateBag.Get("PublicIP").(string), nil }, WinRMConfig: func(state multistep.StateBag) (*communicator.WinRMConfig, error) { return &communicator.WinRMConfig{ diff --git a/builder/ncloud/ssh.go b/builder/ncloud/ssh.go index ee7d99226..5e7d31748 100644 --- a/builder/ncloud/ssh.go +++ b/builder/ncloud/ssh.go @@ -6,11 +6,6 @@ import ( "golang.org/x/crypto/ssh" ) -func SSHHost(state multistep.StateBag) (string, error) { - host := state.Get("SSHHost").(string) - return host, nil -} - // SSHConfig returns a function that can be used for the SSH communicator // config for connecting to the specified host via SSH func SSHConfig(username string) func(multistep.StateBag) (*ssh.ClientConfig, error) { diff --git a/builder/ncloud/step_create_public_ip_instance.go b/builder/ncloud/step_create_public_ip_instance.go index d15fd9f54..e9c4a8e37 100644 --- a/builder/ncloud/step_create_public_ip_instance.go +++ b/builder/ncloud/step_create_public_ip_instance.go @@ -91,13 +91,7 @@ func (s *StepCreatePublicIPInstance) Run(state multistep.StateBag) multistep.Ste publicIPInstance, err := s.CreatePublicIPInstance(serverInstanceNo) if err == nil { - switch s.Config.Comm.Type { - case "ssh": - state.Put("SSHHost", publicIPInstance.PublicIP) - case "winrm": - state.Put("WinRMHost", publicIPInstance.PublicIP) - } - + state.Put("PublicIP", publicIPInstance.PublicIP) state.Put("PublicIPInstance", publicIPInstance) } From 175dd2730f3465c12f0a7a95440df35643384eb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 22:41:22 +0900 Subject: [PATCH 14/17] Use 'github.com/hashicorp/packer/helper/multistep' --- builder/ncloud/builder.go | 2 +- builder/ncloud/ssh.go | 2 +- builder/ncloud/step.go | 2 +- builder/ncloud/step_create_block_storage_instance.go | 5 +++-- builder/ncloud/step_create_block_storage_instance_test.go | 3 ++- builder/ncloud/step_create_login_key.go | 5 +++-- builder/ncloud/step_create_login_key_test.go | 3 ++- builder/ncloud/step_create_public_ip_instance.go | 5 +++-- builder/ncloud/step_create_public_ip_instance_test.go | 5 +++-- builder/ncloud/step_create_server_image.go | 5 +++-- builder/ncloud/step_create_server_image_test.go | 5 +++-- builder/ncloud/step_create_server_instance.go | 5 +++-- builder/ncloud/step_create_server_instance_test.go | 3 ++- builder/ncloud/step_delete_block_storage_instance.go | 5 +++-- builder/ncloud/step_delete_block_storage_instance_test.go | 3 ++- builder/ncloud/step_get_rootpassword.go | 5 +++-- builder/ncloud/step_get_rootpassword_test.go | 3 ++- builder/ncloud/step_stop_server_instance.go | 5 +++-- builder/ncloud/step_stop_server_instance_test.go | 2 +- builder/ncloud/step_terminate_server_instance.go | 5 +++-- builder/ncloud/step_terminate_server_instance_test.go | 3 ++- builder/ncloud/step_validate_template.go | 5 +++-- builder/ncloud/step_validate_template_test.go | 2 +- 23 files changed, 53 insertions(+), 35 deletions(-) diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index e493661be..18f45b53c 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -5,7 +5,7 @@ import ( "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" + "github.com/hashicorp/packer/helper/multistep" ) // Builder assume this implements packer.Builder diff --git a/builder/ncloud/ssh.go b/builder/ncloud/ssh.go index 5e7d31748..08764aee6 100644 --- a/builder/ncloud/ssh.go +++ b/builder/ncloud/ssh.go @@ -2,7 +2,7 @@ package ncloud import ( packerssh "github.com/hashicorp/packer/communicator/ssh" - "github.com/mitchellh/multistep" + "github.com/hashicorp/packer/helper/multistep" "golang.org/x/crypto/ssh" ) diff --git a/builder/ncloud/step.go b/builder/ncloud/step.go index ba71efbee..8b312fae7 100644 --- a/builder/ncloud/step.go +++ b/builder/ncloud/step.go @@ -1,7 +1,7 @@ package ncloud import ( - "github.com/mitchellh/multistep" + "github.com/hashicorp/packer/helper/multistep" ) func processStepResult(err error, sayError func(error), state multistep.StateBag) multistep.StepAction { diff --git a/builder/ncloud/step_create_block_storage_instance.go b/builder/ncloud/step_create_block_storage_instance.go index 7e4d4b54a..b135a15e7 100644 --- a/builder/ncloud/step_create_block_storage_instance.go +++ b/builder/ncloud/step_create_block_storage_instance.go @@ -1,14 +1,15 @@ package ncloud import ( + "context" "errors" "fmt" "log" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) // StepCreateBlockStorageInstance struct is for making extra block storage @@ -54,7 +55,7 @@ func (s *StepCreateBlockStorageInstance) createBlockStorageInstance(serverInstan return blockStorageInstanceList.BlockStorageInstance[0].BlockStorageInstanceNo, nil } -func (s *StepCreateBlockStorageInstance) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepCreateBlockStorageInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { if s.Config.BlockStorageSize == 0 { return processStepResult(nil, s.Error, state) } diff --git a/builder/ncloud/step_create_block_storage_instance_test.go b/builder/ncloud/step_create_block_storage_instance_test.go index 101e94658..feae195d1 100644 --- a/builder/ncloud/step_create_block_storage_instance_test.go +++ b/builder/ncloud/step_create_block_storage_instance_test.go @@ -2,8 +2,9 @@ package ncloud import ( "fmt" - "github.com/mitchellh/multistep" "testing" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepCreateBlockStorageInstanceShouldFailIfOperationCreateBlockStorageInstanceFails(t *testing.T) { diff --git a/builder/ncloud/step_create_login_key.go b/builder/ncloud/step_create_login_key.go index f79c4decf..05ef97739 100644 --- a/builder/ncloud/step_create_login_key.go +++ b/builder/ncloud/step_create_login_key.go @@ -1,12 +1,13 @@ package ncloud import ( + "context" "fmt" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type LoginKey struct { @@ -44,7 +45,7 @@ func (s *StepCreateLoginKey) createLoginKey() (*LoginKey, error) { return &LoginKey{KeyName, privateKey.PrivateKey}, nil } -func (s *StepCreateLoginKey) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepCreateLoginKey) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Create Login Key") loginKey, err := s.CreateLoginKey() diff --git a/builder/ncloud/step_create_login_key_test.go b/builder/ncloud/step_create_login_key_test.go index 374d10330..6f0d7af8f 100644 --- a/builder/ncloud/step_create_login_key_test.go +++ b/builder/ncloud/step_create_login_key_test.go @@ -2,8 +2,9 @@ package ncloud import ( "fmt" - "github.com/mitchellh/multistep" "testing" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepCreateLoginKeyShouldFailIfOperationCreateLoginKeyFails(t *testing.T) { diff --git a/builder/ncloud/step_create_public_ip_instance.go b/builder/ncloud/step_create_public_ip_instance.go index e9c4a8e37..d4cd72b6d 100644 --- a/builder/ncloud/step_create_public_ip_instance.go +++ b/builder/ncloud/step_create_public_ip_instance.go @@ -1,13 +1,14 @@ package ncloud import ( + "context" "fmt" "log" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepCreatePublicIPInstance struct { @@ -84,7 +85,7 @@ func (s *StepCreatePublicIPInstance) createPublicIPInstance(serverInstanceNo str return &publicIPInstance, nil } -func (s *StepCreatePublicIPInstance) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepCreatePublicIPInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Create Public IP Instance") serverInstanceNo := state.Get("InstanceNo").(string) diff --git a/builder/ncloud/step_create_public_ip_instance_test.go b/builder/ncloud/step_create_public_ip_instance_test.go index 0f44f4a33..7269e3af5 100644 --- a/builder/ncloud/step_create_public_ip_instance_test.go +++ b/builder/ncloud/step_create_public_ip_instance_test.go @@ -2,10 +2,11 @@ package ncloud import ( "fmt" - ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" "testing" - "github.com/mitchellh/multistep" + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepCreatePublicIPInstanceShouldFailIfOperationCreatePublicIPInstanceFails(t *testing.T) { diff --git a/builder/ncloud/step_create_server_image.go b/builder/ncloud/step_create_server_image.go index 8bec7f11f..447485641 100644 --- a/builder/ncloud/step_create_server_image.go +++ b/builder/ncloud/step_create_server_image.go @@ -1,13 +1,14 @@ package ncloud import ( + "context" "errors" "fmt" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepCreateServerImage struct { @@ -60,7 +61,7 @@ func (s *StepCreateServerImage) createServerImage(serverInstanceNo string) (*ncl return &serverImage, nil } -func (s *StepCreateServerImage) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepCreateServerImage) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Create Server Image") serverInstanceNo := state.Get("InstanceNo").(string) diff --git a/builder/ncloud/step_create_server_image_test.go b/builder/ncloud/step_create_server_image_test.go index 41a40971a..fa7745135 100644 --- a/builder/ncloud/step_create_server_image_test.go +++ b/builder/ncloud/step_create_server_image_test.go @@ -2,10 +2,11 @@ package ncloud import ( "fmt" - ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" "testing" - "github.com/mitchellh/multistep" + ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepCreateServerImageShouldFailIfOperationCreateServerImageFails(t *testing.T) { diff --git a/builder/ncloud/step_create_server_instance.go b/builder/ncloud/step_create_server_instance.go index 346ce3a1c..a8a72586d 100644 --- a/builder/ncloud/step_create_server_instance.go +++ b/builder/ncloud/step_create_server_instance.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "errors" "fmt" "io/ioutil" @@ -8,8 +9,8 @@ import ( "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepCreateServerInstance struct { @@ -81,7 +82,7 @@ func (s *StepCreateServerInstance) createServerInstance(loginKeyName string, zon return s.serverInstanceNo, nil } -func (s *StepCreateServerInstance) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepCreateServerInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Create Server Instance") var loginKey = state.Get("LoginKey").(*LoginKey) diff --git a/builder/ncloud/step_create_server_instance_test.go b/builder/ncloud/step_create_server_instance_test.go index ddaa34157..db337c41b 100644 --- a/builder/ncloud/step_create_server_instance_test.go +++ b/builder/ncloud/step_create_server_instance_test.go @@ -2,8 +2,9 @@ package ncloud import ( "fmt" - "github.com/mitchellh/multistep" "testing" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepCreateServerInstanceShouldFailIfOperationCreateFails(t *testing.T) { diff --git a/builder/ncloud/step_delete_block_storage_instance.go b/builder/ncloud/step_delete_block_storage_instance.go index 61f8b7c3c..d43edf1c9 100644 --- a/builder/ncloud/step_delete_block_storage_instance.go +++ b/builder/ncloud/step_delete_block_storage_instance.go @@ -1,14 +1,15 @@ package ncloud import ( + "context" "errors" "fmt" "log" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepDeleteBlockStorageInstance struct { @@ -77,7 +78,7 @@ func (s *StepDeleteBlockStorageInstance) deleteBlockStorageInstance(serverInstan return nil } -func (s *StepDeleteBlockStorageInstance) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepDeleteBlockStorageInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { if s.Config.BlockStorageSize == 0 { return processStepResult(nil, s.Error, state) } diff --git a/builder/ncloud/step_delete_block_storage_instance_test.go b/builder/ncloud/step_delete_block_storage_instance_test.go index ce0f0cb09..c5fc4566e 100644 --- a/builder/ncloud/step_delete_block_storage_instance_test.go +++ b/builder/ncloud/step_delete_block_storage_instance_test.go @@ -2,8 +2,9 @@ package ncloud import ( "fmt" - "github.com/mitchellh/multistep" "testing" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepDeleteBlockStorageInstanceShouldFailIfOperationDeleteBlockStorageInstanceFails(t *testing.T) { diff --git a/builder/ncloud/step_get_rootpassword.go b/builder/ncloud/step_get_rootpassword.go index d9eda578a..051eb386b 100644 --- a/builder/ncloud/step_get_rootpassword.go +++ b/builder/ncloud/step_get_rootpassword.go @@ -1,11 +1,12 @@ package ncloud import ( + "context" "fmt" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepGetRootPassword struct { @@ -42,7 +43,7 @@ func (s *StepGetRootPassword) getRootPassword(serverInstanceNo string, privateKe return rootPassword.RootPassword, nil } -func (s *StepGetRootPassword) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepGetRootPassword) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Get Root Password") serverInstanceNo := state.Get("InstanceNo").(string) diff --git a/builder/ncloud/step_get_rootpassword_test.go b/builder/ncloud/step_get_rootpassword_test.go index b9ed6aa56..1717b5753 100644 --- a/builder/ncloud/step_get_rootpassword_test.go +++ b/builder/ncloud/step_get_rootpassword_test.go @@ -2,8 +2,9 @@ package ncloud import ( "fmt" - "github.com/mitchellh/multistep" "testing" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepGetRootPasswordShouldFailIfOperationGetRootPasswordFails(t *testing.T) { diff --git a/builder/ncloud/step_stop_server_instance.go b/builder/ncloud/step_stop_server_instance.go index f9cce7d9f..293c8e55d 100644 --- a/builder/ncloud/step_stop_server_instance.go +++ b/builder/ncloud/step_stop_server_instance.go @@ -1,13 +1,14 @@ package ncloud import ( + "context" "fmt" "log" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepStopServerInstance struct { @@ -50,7 +51,7 @@ func (s *StepStopServerInstance) stopServerInstance(serverInstanceNo string) err return nil } -func (s *StepStopServerInstance) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepStopServerInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Stop Server Instance") var serverInstanceNo = state.Get("InstanceNo").(string) diff --git a/builder/ncloud/step_stop_server_instance_test.go b/builder/ncloud/step_stop_server_instance_test.go index d90bc6953..04c39d313 100644 --- a/builder/ncloud/step_stop_server_instance_test.go +++ b/builder/ncloud/step_stop_server_instance_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/mitchellh/multistep" + "github.com/hashicorp/packer/helper/multistep" ) func TestStepStopServerInstanceShouldFailIfOperationStopFails(t *testing.T) { diff --git a/builder/ncloud/step_terminate_server_instance.go b/builder/ncloud/step_terminate_server_instance.go index aa154812b..f6c8d281a 100644 --- a/builder/ncloud/step_terminate_server_instance.go +++ b/builder/ncloud/step_terminate_server_instance.go @@ -1,12 +1,13 @@ package ncloud import ( + "context" "errors" "time" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" ) type StepTerminateServerInstance struct { @@ -66,7 +67,7 @@ func (s *StepTerminateServerInstance) terminateServerInstance(serverInstanceNo s } } -func (s *StepTerminateServerInstance) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepTerminateServerInstance) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Terminate Server Instance") var serverInstanceNo = state.Get("InstanceNo").(string) diff --git a/builder/ncloud/step_terminate_server_instance_test.go b/builder/ncloud/step_terminate_server_instance_test.go index b5967fc65..9256b85b9 100644 --- a/builder/ncloud/step_terminate_server_instance_test.go +++ b/builder/ncloud/step_terminate_server_instance_test.go @@ -2,8 +2,9 @@ package ncloud import ( "fmt" - "github.com/mitchellh/multistep" "testing" + + "github.com/hashicorp/packer/helper/multistep" ) func TestStepTerminateServerInstanceShouldFailIfOperationTerminationFails(t *testing.T) { diff --git a/builder/ncloud/step_validate_template.go b/builder/ncloud/step_validate_template.go index d4c576946..c63c5f04b 100644 --- a/builder/ncloud/step_validate_template.go +++ b/builder/ncloud/step_validate_template.go @@ -2,13 +2,14 @@ package ncloud import ( "bytes" + "context" "errors" "fmt" "strings" ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" + "github.com/hashicorp/packer/helper/multistep" "github.com/hashicorp/packer/packer" - "github.com/mitchellh/multistep" "github.com/olekukonko/tablewriter" ) @@ -249,7 +250,7 @@ func (s *StepValidateTemplate) validateTemplate() error { } // Run : main funciton for validation a template -func (s *StepValidateTemplate) Run(state multistep.StateBag) multistep.StepAction { +func (s *StepValidateTemplate) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { s.Say("Validating deployment template ...") err := s.Validate() diff --git a/builder/ncloud/step_validate_template_test.go b/builder/ncloud/step_validate_template_test.go index 98f45b4a0..6836f8446 100644 --- a/builder/ncloud/step_validate_template_test.go +++ b/builder/ncloud/step_validate_template_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - "github.com/mitchellh/multistep" + "github.com/hashicorp/packer/helper/multistep" ) func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) { From e68a742bca2b91488eadcc3c3cf0ad336912e059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Mon, 29 Jan 2018 22:44:24 +0900 Subject: [PATCH 15/17] make fmt --- builder/ncloud/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index 18f45b53c..b1aaef790 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -4,8 +4,8 @@ import ( ncloud "github.com/NaverCloudPlatform/ncloud-sdk-go/sdk" "github.com/hashicorp/packer/common" "github.com/hashicorp/packer/helper/communicator" - "github.com/hashicorp/packer/packer" "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" ) // Builder assume this implements packer.Builder From f39c3458f71b98101903e932720a9a0e2c9d24b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Tue, 30 Jan 2018 10:20:02 +0900 Subject: [PATCH 16/17] fix Run method arguments for testing --- builder/ncloud/step_create_block_storage_instance_test.go | 5 +++-- builder/ncloud/step_create_login_key_test.go | 5 +++-- builder/ncloud/step_create_public_ip_instance_test.go | 5 +++-- builder/ncloud/step_create_server_image_test.go | 5 +++-- builder/ncloud/step_create_server_instance_test.go | 5 +++-- builder/ncloud/step_delete_block_storage_instance_test.go | 5 +++-- builder/ncloud/step_get_rootpassword_test.go | 5 +++-- builder/ncloud/step_stop_server_instance_test.go | 5 +++-- builder/ncloud/step_terminate_server_instance_test.go | 5 +++-- builder/ncloud/step_validate_template_test.go | 5 +++-- 10 files changed, 30 insertions(+), 20 deletions(-) diff --git a/builder/ncloud/step_create_block_storage_instance_test.go b/builder/ncloud/step_create_block_storage_instance_test.go index feae195d1..6f4a9e4e2 100644 --- a/builder/ncloud/step_create_block_storage_instance_test.go +++ b/builder/ncloud/step_create_block_storage_instance_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -20,7 +21,7 @@ func TestStepCreateBlockStorageInstanceShouldFailIfOperationCreateBlockStorageIn stateBag := createTestStateBagStepCreateBlockStorageInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -43,7 +44,7 @@ func TestStepCreateBlockStorageInstanceShouldPassIfOperationCreateBlockStorageIn stateBag := createTestStateBagStepCreateBlockStorageInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_create_login_key_test.go b/builder/ncloud/step_create_login_key_test.go index 6f0d7af8f..3583f47a5 100644 --- a/builder/ncloud/step_create_login_key_test.go +++ b/builder/ncloud/step_create_login_key_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -16,7 +17,7 @@ func TestStepCreateLoginKeyShouldFailIfOperationCreateLoginKeyFails(t *testing.T stateBag := createTestStateBagStepCreateLoginKey() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -36,7 +37,7 @@ func TestStepCreateLoginKeyShouldPassIfOperationCreateLoginKeyPasses(t *testing. stateBag := createTestStateBagStepCreateLoginKey() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_create_public_ip_instance_test.go b/builder/ncloud/step_create_public_ip_instance_test.go index 7269e3af5..e28a19d48 100644 --- a/builder/ncloud/step_create_public_ip_instance_test.go +++ b/builder/ncloud/step_create_public_ip_instance_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -20,7 +21,7 @@ func TestStepCreatePublicIPInstanceShouldFailIfOperationCreatePublicIPInstanceFa stateBag := createTestStateBagStepCreateServerImage() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -47,7 +48,7 @@ func TestStepCreatePublicIPInstanceShouldPassIfOperationCreatePublicIPInstancePa stateBag := createTestStateBagStepCreatePublicIPInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_create_server_image_test.go b/builder/ncloud/step_create_server_image_test.go index fa7745135..49915ced2 100644 --- a/builder/ncloud/step_create_server_image_test.go +++ b/builder/ncloud/step_create_server_image_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -20,7 +21,7 @@ func TestStepCreateServerImageShouldFailIfOperationCreateServerImageFails(t *tes stateBag := createTestStateBagStepCreateServerImage() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -39,7 +40,7 @@ func TestStepCreateServerImageShouldPassIfOperationCreateServerImagePasses(t *te stateBag := createTestStateBagStepCreateServerImage() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_create_server_instance_test.go b/builder/ncloud/step_create_server_instance_test.go index db337c41b..676c3fa3f 100644 --- a/builder/ncloud/step_create_server_instance_test.go +++ b/builder/ncloud/step_create_server_instance_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -18,7 +19,7 @@ func TestStepCreateServerInstanceShouldFailIfOperationCreateFails(t *testing.T) stateBag := createTestStateBagStepCreateServerInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -38,7 +39,7 @@ func TestStepCreateServerInstanceShouldPassIfOperationCreatePasses(t *testing.T) stateBag := createTestStateBagStepCreateServerInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_delete_block_storage_instance_test.go b/builder/ncloud/step_delete_block_storage_instance_test.go index c5fc4566e..024ed332e 100644 --- a/builder/ncloud/step_delete_block_storage_instance_test.go +++ b/builder/ncloud/step_delete_block_storage_instance_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -17,7 +18,7 @@ func TestStepDeleteBlockStorageInstanceShouldFailIfOperationDeleteBlockStorageIn stateBag := createTestStateBagStepDeleteBlockStorageInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -38,7 +39,7 @@ func TestStepDeleteBlockStorageInstanceShouldPassIfOperationDeleteBlockStorageIn stateBag := createTestStateBagStepDeleteBlockStorageInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_get_rootpassword_test.go b/builder/ncloud/step_get_rootpassword_test.go index 1717b5753..0c93229bd 100644 --- a/builder/ncloud/step_get_rootpassword_test.go +++ b/builder/ncloud/step_get_rootpassword_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -16,7 +17,7 @@ func TestStepGetRootPasswordShouldFailIfOperationGetRootPasswordFails(t *testing stateBag := DeleteTestStateBagStepGetRootPassword() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -36,7 +37,7 @@ func TestStepGetRootPasswordShouldPassIfOperationGetRootPasswordPasses(t *testin stateBag := DeleteTestStateBagStepGetRootPassword() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_stop_server_instance_test.go b/builder/ncloud/step_stop_server_instance_test.go index 04c39d313..4b5afe605 100644 --- a/builder/ncloud/step_stop_server_instance_test.go +++ b/builder/ncloud/step_stop_server_instance_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -16,7 +17,7 @@ func TestStepStopServerInstanceShouldFailIfOperationStopFails(t *testing.T) { stateBag := createTestStateBagStepStopServerInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -36,7 +37,7 @@ func TestStepStopServerInstanceShouldPassIfOperationStopPasses(t *testing.T) { stateBag := createTestStateBagStepStopServerInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_terminate_server_instance_test.go b/builder/ncloud/step_terminate_server_instance_test.go index 9256b85b9..54a00748a 100644 --- a/builder/ncloud/step_terminate_server_instance_test.go +++ b/builder/ncloud/step_terminate_server_instance_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -16,7 +17,7 @@ func TestStepTerminateServerInstanceShouldFailIfOperationTerminationFails(t *tes stateBag := createTestStateBagStepTerminateServerInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -36,7 +37,7 @@ func TestStepTerminateServerInstanceShouldPassIfOperationTerminationPasses(t *te stateBag := createTestStateBagStepTerminateServerInstance() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) diff --git a/builder/ncloud/step_validate_template_test.go b/builder/ncloud/step_validate_template_test.go index 6836f8446..7e9212c7f 100644 --- a/builder/ncloud/step_validate_template_test.go +++ b/builder/ncloud/step_validate_template_test.go @@ -1,6 +1,7 @@ package ncloud import ( + "context" "fmt" "testing" @@ -16,7 +17,7 @@ func TestStepValidateTemplateShouldFailIfValidateFails(t *testing.T) { stateBag := createTestStateBagStepValidateTemplate() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionHalt { t.Fatalf("Expected the step to return 'ActionHalt', but got '%d'.", result) @@ -36,7 +37,7 @@ func TestStepValidateTemplateShouldPassIfValidatePasses(t *testing.T) { stateBag := createTestStateBagStepValidateTemplate() - var result = testSubject.Run(stateBag) + var result = testSubject.Run(context.Background(), stateBag) if result != multistep.ActionContinue { t.Fatalf("Expected the step to return 'ActionContinue', but got '%d'.", result) From 0ebdad293447c2b82c59a7ae7320d63af40db5ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=8B=E1=85=B2=E1=84=89=E1=85=A5=E1=86=BC=E1=84=83?= =?UTF-8?q?=E1=85=A5=E1=86=A8?= Date: Wed, 7 Feb 2018 10:29:56 +0900 Subject: [PATCH 17/17] fix communicator type : Windows -> winrm --- builder/ncloud/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/ncloud/builder.go b/builder/ncloud/builder.go index b1aaef790..d5d546024 100644 --- a/builder/ncloud/builder.go +++ b/builder/ncloud/builder.go @@ -59,7 +59,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe NewStepDeleteBlockStorageInstance(conn, ui, b.config), NewStepTerminateServerInstance(conn, ui), } - } else if b.config.Comm.Type == "Windows" { + } else if b.config.Comm.Type == "winrm" { steps = []multistep.Step{ NewStepValidateTemplate(conn, ui, b.config), NewStepCreateLoginKey(conn, ui),