From 6f667af18fc81378e0c90806090914ca116c8c58 Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Fri, 28 Jan 2022 21:28:10 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=E3=82=A2=E3=83=97=E3=83=AA=E3=82=B1?= =?UTF-8?q?=E3=83=BC=E3=82=B7=E3=83=A7=E3=83=B3=E3=82=92src=E4=BB=A5?= =?UTF-8?q?=E4=B8=8B=E3=81=AB=E7=A7=BB=E5=8B=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 2 +- {config => src/config}/config.go | 0 go.mod => src/go.mod | 0 main.go => src/main.go | 0 4 files changed, 1 insertion(+), 1 deletion(-) rename {config => src/config}/config.go (100%) rename go.mod => src/go.mod (100%) rename main.go => src/main.go (100%) diff --git a/docker-compose.yml b/docker-compose.yml index 2a68818..79dfb2e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,6 @@ services: AWS_DEFAULT_REGION: ap-northeast-1 AWS_DEFAULT_OUTPUT: json volumes: - - ./:/src/hansel + - ./src:/src/hansel working_dir: /src/hansel command: "go run main.go" diff --git a/config/config.go b/src/config/config.go similarity index 100% rename from config/config.go rename to src/config/config.go diff --git a/go.mod b/src/go.mod similarity index 100% rename from go.mod rename to src/go.mod diff --git a/main.go b/src/main.go similarity index 100% rename from main.go rename to src/main.go From c473961e016dd0b7e91455c185127090043f02e4 Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Sat, 29 Jan 2022 12:56:08 +0900 Subject: [PATCH 2/7] =?UTF-8?q?main=E3=82=92discord=E3=83=91=E3=83=83?= =?UTF-8?q?=E3=82=B1=E3=83=BC=E3=82=B8=E3=81=AB=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/discord/bot-receive.go | 212 +++++++++++++++++++++++++++++++++ src/discord/bot.go | 40 +++++++ src/main.go | 234 ++----------------------------------- 3 files changed, 260 insertions(+), 226 deletions(-) create mode 100644 src/discord/bot-receive.go create mode 100644 src/discord/bot.go diff --git a/src/discord/bot-receive.go b/src/discord/bot-receive.go new file mode 100644 index 0000000..d1960ce --- /dev/null +++ b/src/discord/bot-receive.go @@ -0,0 +1,212 @@ +package discord + +import ( + "encoding/json" + "hansel/config" + "log" + "os" + "os/exec" + "time" + + "github.com/bwmarrin/discordgo" +) + +// ServerStatusResponse EC2起動後のステータス確認レスポンス +type ServerStatusResponse struct { + PublicIP string `json:"publicip"` +} + +// StartResponse EC2起動指示時のレスポンス +type StartResponse struct { + StartingInstances []InstanceStatus `json:"StartingInstances"` +} + +// StopResponse EC2停止指示時のレスポンス +type StopResponse struct { + StoppingInstances []InstanceStatus `json:"StoppingInstances"` +} + +// InstanceStatus EC2指示時の共通レスポンス +type InstanceStatus struct { + InstanceID string `json:"InstanceId"` + CurrentState struct { + Code int `json:"Code"` + Name string `json:"Name"` + } `json:"CurrentState"` + PreviousState struct { + Code int `json:"Code"` + Name string `json:"Name"` + } `json:"PreviousState"` +} + +// TargetChannel Botがメッセージを投稿するDiscordチャンネル +type TargetChannel struct { + s *discordgo.Session + event *discordgo.MessageCreate +} + +func (tc *TargetChannel) messageSend(message string) error { + // コマンドが投稿されたチャンネル + targetChannel, err := tc.s.State.Channel(tc.event.ChannelID) + if err != nil { + log.Println("チャンネルの取得に失敗 :", err) + return err + } + + // Botからメッセージ投稿 + if _, err := tc.s.ChannelMessageSend(targetChannel.ID, message); err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return err + } + return nil +} + +// getIPAddress インスタンスのIPアドレス取得 +func getIPAddress() (string, error) { + statusOutputJSON, err := exec.Command("aws", "ec2", "describe-instances", "--instance-ids", os.Getenv("INSTANCE_ID"), "--query", "Reservations[].Instances[].{publicip:PublicIpAddress}").Output() + if err != nil { + log.Println("IPアドレス取得時、コマンド実行に失敗 : ", err) + return "", err + } + + ssResponse := []ServerStatusResponse{} + if err := json.Unmarshal(statusOutputJSON, &ssResponse); err != nil { + log.Println("IPアドレス取得時のレスポンスに異常 :", err) + return "", err + } + + ipaddress := ssResponse[0].PublicIP + if ipaddress != "" { + log.Println("IPアドレス : ", ipaddress) + } + + return ipaddress, nil +} + +func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { + targetChannel := TargetChannel{ + s: s, + event: event, + } + + messages, err := config.GetConfig() + if err != nil { + log.Fatalln(err) + } + + if event.Content == messages.StartTriggerMessage { + // 起動時 + log.Println("開始 : インスタンス起動...") + targetChannel.messageSend("インスタンスの起動コマンドを検知") + + outputJSON, err := exec.Command("aws", "ec2", "start-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() + if err != nil { + log.Println("起動に失敗した :", err) + targetChannel.messageSend("インスタンスの起動に失敗") + return + } + + startResponse := StartResponse{} + if err := json.Unmarshal(outputJSON, &startResponse); err != nil { + log.Println("起動時のレスポンスに異常 :", err) + targetChannel.messageSend("インスタンスの起動に失敗") + return + } + currentState := startResponse.StartingInstances[0].CurrentState.Name + if currentState == "running" { + log.Println("既に起動している") + targetChannel.messageSend("インスタンスは起動済み") + return + } + + previousState := startResponse.StartingInstances[0].PreviousState.Name + if currentState == "pending" && previousState == "pending" { + log.Println("起動処理実行中") + targetChannel.messageSend("インスタンスは既に起動準備中") + return + } + + // 開始待ち + if _, err := exec.Command("aws", "ec2", "wait", "instance-running", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { + log.Println("起動待ちに失敗した :", err) + targetChannel.messageSend("インスタンスの起動状態不明 再度のコマンド入力を要求") + return + } + + log.Println("正常終了 : インスタンス起動") + targetChannel.messageSend("インスタンスの起動に成功") + + // IPアドレス通知 + log.Println("IPアドレス取得待機中...") + time.Sleep(time.Second) + + ipaddress, err := getIPAddress() + if err != nil { + targetChannel.messageSend("IPアドレスの取得に失敗") + return + } + + targetChannel.messageSend("今回のIPアドレス : " + ipaddress) + + } else if event.Content == messages.HibernateTriggerMessage { + // 停止時 + log.Println("開始 : インスタンス停止...") + targetChannel.messageSend("インスタンスの停止コマンドを検知") + + outputJSON, err := exec.Command("aws", "ec2", "stop-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() + if err != nil { + log.Println("停止に失敗した :", err) + targetChannel.messageSend("インスタンスの停止に失敗") + return + } + + stopResponse := StopResponse{} + if err := json.Unmarshal(outputJSON, &stopResponse); err != nil { + log.Println("停止時のレスポンスに異常 :", err) + targetChannel.messageSend("インスタンスの停止に失敗") + return + } + + currentState := stopResponse.StoppingInstances[0].CurrentState.Name + if currentState == "stopped" { + log.Println("既に停止している") + targetChannel.messageSend("インスタンスは停止済み") + return + } + + previousState := stopResponse.StoppingInstances[0].PreviousState.Name + if currentState == "stopping" && previousState == "stopping" { + log.Println("停止処理実行中") + targetChannel.messageSend("インスタンスは既に停止準備中") + return + } + + // 停止待ち + if _, err := exec.Command("aws", "ec2", "wait", "instance-stopped", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { + log.Println("停止待ちに失敗した :", err) + targetChannel.messageSend("インスタンスの停止状態不明 再度のコマンド入力を要求") + return + } + + log.Println("正常終了 : インスタンス停止") + targetChannel.messageSend("インスタンスの停止に成功") + + } else if event.Content == messages.GetStatusTriggerMessage { + // 起動状態の確認(IPアドレスの取得) + log.Println("開始 : インスタンスステータス確認") + targetChannel.messageSend("インスタンスの確認コマンドを検知") + + ipaddress, err := getIPAddress() + if err != nil { + targetChannel.messageSend("インスタンスの確認に失敗") + return + } + + if ipaddress != "" { + targetChannel.messageSend("インスタンスは起動済み :" + ipaddress) + } else { + targetChannel.messageSend("インスタンスは未起動") + } + + } +} diff --git a/src/discord/bot.go b/src/discord/bot.go new file mode 100644 index 0000000..99896b7 --- /dev/null +++ b/src/discord/bot.go @@ -0,0 +1,40 @@ +package discord + +import ( + "log" + "os" + + "github.com/bwmarrin/discordgo" +) + +type Bot struct { + session *discordgo.Session +} + +func NewBot() (*Bot, error) { + session, err := discordgo.New("Bot " + os.Getenv("BOT_ID")) + if err != nil { + return &Bot{}, nil + } + + return &Bot{ + session: session, + }, nil +} + +func (b *Bot) Start() error { + b.session.AddHandler(b.receive) + + err := b.session.Open() + if err != nil { + log.Println("Failed : Start Bot") + return err + } + + log.Println("Succeeded : Start Bot") + return nil +} + +func (b *Bot) Stop() error { + return b.session.Close() +} diff --git a/src/main.go b/src/main.go index 9aba360..9fbd5a1 100644 --- a/src/main.go +++ b/src/main.go @@ -1,245 +1,27 @@ package main import ( - "encoding/json" - "hansel/config" + "hansel/discord" "log" "os" - "os/exec" "os/signal" "syscall" - "time" - - "github.com/bwmarrin/discordgo" ) -// ServerStatusResponse EC2起動後のステータス確認レスポンス -type ServerStatusResponse struct { - PublicIP string `json:"publicip"` -} - -// StartResponse EC2起動指示時のレスポンス -type StartResponse struct { - StartingInstances []InstanceStatus `json:"StartingInstances"` -} - -// StopResponse EC2停止指示時のレスポンス -type StopResponse struct { - StoppingInstances []InstanceStatus `json:"StoppingInstances"` -} - -// InstanceStatus EC2指示時の共通レスポンス -type InstanceStatus struct { - InstanceID string `json:"InstanceId"` - CurrentState struct { - Code int `json:"Code"` - Name string `json:"Name"` - } `json:"CurrentState"` - PreviousState struct { - Code int `json:"Code"` - Name string `json:"Name"` - } `json:"PreviousState"` -} - -// TargetChannel Botがメッセージを投稿するDiscordチャンネル -type TargetChannel struct { - s *discordgo.Session - event *discordgo.MessageCreate -} - -func (tc *TargetChannel) messageSend(message string) error { - // コマンドが投稿されたチャンネル - targetChannel, err := tc.s.State.Channel(tc.event.ChannelID) - if err != nil { - log.Println("チャンネルの取得に失敗 :", err) - return err - } - - // Botからメッセージ投稿 - if _, err := tc.s.ChannelMessageSend(targetChannel.ID, message); err != nil { - log.Println("チャンネルメッセージの送信に失敗 :", err) - return err - } - return nil -} - -// getIPAddress インスタンスのIPアドレス取得 -func getIPAddress() (string, error) { - statusOutputJSON, err := exec.Command("aws", "ec2", "describe-instances", "--instance-ids", os.Getenv("INSTANCE_ID"), "--query", "Reservations[].Instances[].{publicip:PublicIpAddress}").Output() - if err != nil { - log.Println("IPアドレス取得時、コマンド実行に失敗 : ", err) - return "", err - } - - ssResponse := []ServerStatusResponse{} - if err := json.Unmarshal(statusOutputJSON, &ssResponse); err != nil { - log.Println("IPアドレス取得時のレスポンスに異常 :", err) - return "", err - } - - ipaddress := ssResponse[0].PublicIP - if ipaddress != "" { - log.Println("IPアドレス : ", ipaddress) - } - - return ipaddress, nil -} - -func receive(s *discordgo.Session, event *discordgo.MessageCreate) { - targetChannel := TargetChannel{ - s: s, - event: event, - } - - messages, err := config.GetConfig() - if err != nil { - log.Fatalln(err) - } - - if event.Content == messages.StartTriggerMessage { - // 起動時 - log.Println("開始 : インスタンス起動...") - targetChannel.messageSend("インスタンスの起動コマンドを検知") - - outputJSON, err := exec.Command("aws", "ec2", "start-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() - if err != nil { - log.Println("起動に失敗した :", err) - targetChannel.messageSend("インスタンスの起動に失敗") - return - } - - startResponse := StartResponse{} - if err := json.Unmarshal(outputJSON, &startResponse); err != nil { - log.Println("起動時のレスポンスに異常 :", err) - targetChannel.messageSend("インスタンスの起動に失敗") - return - } - currentState := startResponse.StartingInstances[0].CurrentState.Name - if currentState == "running" { - log.Println("既に起動している") - targetChannel.messageSend("インスタンスは起動済み") - return - } - - previousState := startResponse.StartingInstances[0].PreviousState.Name - if currentState == "pending" && previousState == "pending" { - log.Println("起動処理実行中") - targetChannel.messageSend("インスタンスは既に起動準備中") - return - } - - // 開始待ち - if _, err := exec.Command("aws", "ec2", "wait", "instance-running", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { - log.Println("起動待ちに失敗した :", err) - targetChannel.messageSend("インスタンスの起動状態不明 再度のコマンド入力を要求") - return - } - - log.Println("正常終了 : インスタンス起動") - targetChannel.messageSend("インスタンスの起動に成功") - - // IPアドレス通知 - log.Println("IPアドレス取得待機中...") - time.Sleep(time.Second) - - ipaddress, err := getIPAddress() - if err != nil { - targetChannel.messageSend("IPアドレスの取得に失敗") - return - } - - targetChannel.messageSend("今回のIPアドレス : " + ipaddress) - - } else if event.Content == messages.HibernateTriggerMessage { - // 停止時 - log.Println("開始 : インスタンス停止...") - targetChannel.messageSend("インスタンスの停止コマンドを検知") - - outputJSON, err := exec.Command("aws", "ec2", "stop-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() - if err != nil { - log.Println("停止に失敗した :", err) - targetChannel.messageSend("インスタンスの停止に失敗") - return - } - - stopResponse := StopResponse{} - if err := json.Unmarshal(outputJSON, &stopResponse); err != nil { - log.Println("停止時のレスポンスに異常 :", err) - targetChannel.messageSend("インスタンスの停止に失敗") - return - } - - currentState := stopResponse.StoppingInstances[0].CurrentState.Name - if currentState == "stopped" { - log.Println("既に停止している") - targetChannel.messageSend("インスタンスは停止済み") - return - } - - previousState := stopResponse.StoppingInstances[0].PreviousState.Name - if currentState == "stopping" && previousState == "stopping" { - log.Println("停止処理実行中") - targetChannel.messageSend("インスタンスは既に停止準備中") - return - } - - // 停止待ち - if _, err := exec.Command("aws", "ec2", "wait", "instance-stopped", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { - log.Println("停止待ちに失敗した :", err) - targetChannel.messageSend("インスタンスの停止状態不明 再度のコマンド入力を要求") - return - } - - log.Println("正常終了 : インスタンス停止") - targetChannel.messageSend("インスタンスの停止に成功") - - } else if event.Content == messages.GetStatusTriggerMessage { - // 起動状態の確認(IPアドレスの取得) - log.Println("開始 : インスタンスステータス確認") - targetChannel.messageSend("インスタンスの確認コマンドを検知") - - ipaddress, err := getIPAddress() - if err != nil { - targetChannel.messageSend("インスタンスの確認に失敗") - return - } - - if ipaddress != "" { - targetChannel.messageSend("インスタンスは起動済み :" + ipaddress) - } else { - targetChannel.messageSend("インスタンスは未起動") - } - - } -} - -func runDiscordBot(session *discordgo.Session) error { - session.Token = "Bot " + os.Getenv("BOT_ID") - - session.AddHandler(receive) - err := session.Open() - if err != nil { - log.Println("Failed : Start Bot") - return err - } - log.Println("Succeeded : Start Bot") - - return nil -} - func main() { - session, err := discordgo.New() + bot, err := discord.NewBot() if err != nil { - panic(err) + log.Fatalln(err) + return } - err = runDiscordBot(session) + err = bot.Start() if err != nil { - panic(err) + log.Fatalln(err) + return } - //goland:noinspection GoUnhandledErrorResult - defer session.Close() + defer bot.Stop() // 終了を待機 signalChan := make(chan os.Signal, 1) From 72dba89ffe2bd083d3ab4168cbeed426d8f1fadf Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:55:27 +0900 Subject: [PATCH 3/7] =?UTF-8?q?aws=E3=82=B3=E3=83=9E=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=82=92aws=E3=83=91=E3=83=83=E3=82=B1=E3=83=BC=E3=82=B8?= =?UTF-8?q?=E3=81=AB=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aws/client.go | 114 ++++++++++++++++++++++ src/aws/error.go | 32 ++++++ src/discord/bot-receive.go | 193 ++++++++++++++----------------------- 3 files changed, 217 insertions(+), 122 deletions(-) create mode 100644 src/aws/client.go create mode 100644 src/aws/error.go diff --git a/src/aws/client.go b/src/aws/client.go new file mode 100644 index 0000000..7de6a26 --- /dev/null +++ b/src/aws/client.go @@ -0,0 +1,114 @@ +package aws + +import ( + "encoding/json" + "log" + "os" + "os/exec" +) + +// ServerStatusResponse EC2起動後のステータス確認レスポンス +type ServerStatusResponse struct { + PublicIP string `json:"publicip"` +} + +// StartResponse EC2起動指示時のレスポンス +type StartResponse struct { + StartingInstances []InstanceStatus `json:"StartingInstances"` +} + +// StopResponse EC2停止指示時のレスポンス +type StopResponse struct { + StoppingInstances []InstanceStatus `json:"StoppingInstances"` +} + +// InstanceStatus EC2指示時の共通レスポンス +type InstanceStatus struct { + InstanceID string `json:"InstanceId"` + CurrentState struct { + Code int `json:"Code"` + Name string `json:"Name"` + } `json:"CurrentState"` + PreviousState struct { + Code int `json:"Code"` + Name string `json:"Name"` + } `json:"PreviousState"` +} + +// GetIPAddress インスタンスのIPアドレス取得 +func GetIPAddress() (string, StatusError) { + statusOutputJSON, err := exec.Command("aws", "ec2", "describe-instances", "--instance-ids", os.Getenv("INSTANCE_ID"), "--query", "Reservations[].Instances[].{publicip:PublicIpAddress}").Output() + if err != nil { + return "", NewStatusError(ERR_FAILED_GET_IP_ADDRESS, err) + } + + ssResponse := []ServerStatusResponse{} + if err := json.Unmarshal(statusOutputJSON, &ssResponse); err != nil { + return "", NewStatusError(ERR_INVALID_RESPONSE_GET_IP_ADDRESS, err) + } + + ipaddress := ssResponse[0].PublicIP + if ipaddress != "" { + log.Println("IPアドレス : ", ipaddress) + } + + return ipaddress, StatusError{} +} + +func StartInstance() StatusError { + outputJSON, err := exec.Command("aws", "ec2", "start-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() + if err != nil { + return NewStatusError(ERR_FAILED_START_INSTANCE, err) + } + + startResponse := StartResponse{} + if err := json.Unmarshal(outputJSON, &startResponse); err != nil { + return NewStatusError(ERR_INVALID_RESPONSE_START_INSTANCE, err) + } + + currentState := startResponse.StartingInstances[0].CurrentState.Name + if currentState == "running" { + return NewStatusError(ERR_INSTANCE_ALREADY_STARTED, nil) + } + + previousState := startResponse.StartingInstances[0].PreviousState.Name + if currentState == "pending" && previousState == "pending" { + return NewStatusError(ERR_STARTING_INSTANCE, nil) + } + + // 開始待ち + if _, err := exec.Command("aws", "ec2", "wait", "instance-running", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { + return NewStatusError(ERR_FAILED_WAIT_START_INSTANCE, err) + } + + return StatusError{} +} + +func StopInstance() StatusError { + outputJSON, err := exec.Command("aws", "ec2", "stop-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() + if err != nil { + return NewStatusError(ERR_FAILED_STOP_INSTANCE, err) + } + + stopResponse := StopResponse{} + if err := json.Unmarshal(outputJSON, &stopResponse); err != nil { + return NewStatusError(ERR_INVALID_RESPONSE_STOP_INSTANCE, err) + } + + currentState := stopResponse.StoppingInstances[0].CurrentState.Name + if currentState == "stopped" { + return NewStatusError(ERR_INSTANCE_ALREADY_STOPPED, nil) + } + + previousState := stopResponse.StoppingInstances[0].PreviousState.Name + if currentState == "stopping" && previousState == "stopping" { + return NewStatusError(ERR_STOPPING_INSTANCE, nil) + } + + // 停止待ち + if _, err := exec.Command("aws", "ec2", "wait", "instance-stopped", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { + return NewStatusError(ERR_FAILED_WAIT_STOP_INSTANCE, err) + } + + return StatusError{} +} diff --git a/src/aws/error.go b/src/aws/error.go new file mode 100644 index 0000000..9945245 --- /dev/null +++ b/src/aws/error.go @@ -0,0 +1,32 @@ +package aws + +const ( + ERR_FAILED_START_INSTANCE = iota + ERR_INVALID_RESPONSE_START_INSTANCE + ERR_INSTANCE_ALREADY_STARTED + ERR_STARTING_INSTANCE + ERR_FAILED_WAIT_START_INSTANCE + ERR_FAILED_GET_IP_ADDRESS + ERR_INVALID_RESPONSE_GET_IP_ADDRESS + ERR_FAILED_STOP_INSTANCE + ERR_INVALID_RESPONSE_STOP_INSTANCE + ERR_INSTANCE_ALREADY_STOPPED + ERR_STOPPING_INSTANCE + ERR_FAILED_WAIT_STOP_INSTANCE +) + +type StatusError struct { + Code int // ERR_で始まる定数のみ + Err error +} + +func NewStatusError(code int, err error) StatusError { + return StatusError{ + Code: code, + Err: err, + } +} + +func (e StatusError) IsEmpty() bool { + return e == StatusError{} +} diff --git a/src/discord/bot-receive.go b/src/discord/bot-receive.go index d1960ce..ee39177 100644 --- a/src/discord/bot-receive.go +++ b/src/discord/bot-receive.go @@ -1,44 +1,14 @@ package discord import ( - "encoding/json" + "hansel/aws" "hansel/config" "log" - "os" - "os/exec" "time" "github.com/bwmarrin/discordgo" ) -// ServerStatusResponse EC2起動後のステータス確認レスポンス -type ServerStatusResponse struct { - PublicIP string `json:"publicip"` -} - -// StartResponse EC2起動指示時のレスポンス -type StartResponse struct { - StartingInstances []InstanceStatus `json:"StartingInstances"` -} - -// StopResponse EC2停止指示時のレスポンス -type StopResponse struct { - StoppingInstances []InstanceStatus `json:"StoppingInstances"` -} - -// InstanceStatus EC2指示時の共通レスポンス -type InstanceStatus struct { - InstanceID string `json:"InstanceId"` - CurrentState struct { - Code int `json:"Code"` - Name string `json:"Name"` - } `json:"CurrentState"` - PreviousState struct { - Code int `json:"Code"` - Name string `json:"Name"` - } `json:"PreviousState"` -} - // TargetChannel Botがメッセージを投稿するDiscordチャンネル type TargetChannel struct { s *discordgo.Session @@ -61,28 +31,6 @@ func (tc *TargetChannel) messageSend(message string) error { return nil } -// getIPAddress インスタンスのIPアドレス取得 -func getIPAddress() (string, error) { - statusOutputJSON, err := exec.Command("aws", "ec2", "describe-instances", "--instance-ids", os.Getenv("INSTANCE_ID"), "--query", "Reservations[].Instances[].{publicip:PublicIpAddress}").Output() - if err != nil { - log.Println("IPアドレス取得時、コマンド実行に失敗 : ", err) - return "", err - } - - ssResponse := []ServerStatusResponse{} - if err := json.Unmarshal(statusOutputJSON, &ssResponse); err != nil { - log.Println("IPアドレス取得時のレスポンスに異常 :", err) - return "", err - } - - ipaddress := ssResponse[0].PublicIP - if ipaddress != "" { - log.Println("IPアドレス : ", ipaddress) - } - - return ipaddress, nil -} - func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { targetChannel := TargetChannel{ s: s, @@ -99,37 +47,29 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { log.Println("開始 : インスタンス起動...") targetChannel.messageSend("インスタンスの起動コマンドを検知") - outputJSON, err := exec.Command("aws", "ec2", "start-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() - if err != nil { - log.Println("起動に失敗した :", err) - targetChannel.messageSend("インスタンスの起動に失敗") - return - } - - startResponse := StartResponse{} - if err := json.Unmarshal(outputJSON, &startResponse); err != nil { - log.Println("起動時のレスポンスに異常 :", err) - targetChannel.messageSend("インスタンスの起動に失敗") - return - } - currentState := startResponse.StartingInstances[0].CurrentState.Name - if currentState == "running" { - log.Println("既に起動している") - targetChannel.messageSend("インスタンスは起動済み") - return - } - - previousState := startResponse.StartingInstances[0].PreviousState.Name - if currentState == "pending" && previousState == "pending" { - log.Println("起動処理実行中") - targetChannel.messageSend("インスタンスは既に起動準備中") - return - } - - // 開始待ち - if _, err := exec.Command("aws", "ec2", "wait", "instance-running", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { - log.Println("起動待ちに失敗した :", err) - targetChannel.messageSend("インスタンスの起動状態不明 再度のコマンド入力を要求") + statusErr := aws.StartInstance() + if !statusErr.IsEmpty() { + errLogMsg := "" + errDiscordMsg := "" + switch statusErr.Code { + case aws.ERR_FAILED_START_INSTANCE: + errLogMsg = "起動に失敗した :" + errDiscordMsg = "インスタンスの起動に失敗" + case aws.ERR_INVALID_RESPONSE_START_INSTANCE: + errLogMsg = "起動時のレスポンスに異常 :" + errDiscordMsg = "インスタンスの起動に失敗" + case aws.ERR_INSTANCE_ALREADY_STARTED: + errLogMsg = "既に起動している" + errDiscordMsg = "インスタンスは起動済み" + case aws.ERR_STARTING_INSTANCE: + errLogMsg = "起動処理実行中" + errDiscordMsg = "インスタンスは既に起動準備中" + case aws.ERR_FAILED_WAIT_START_INSTANCE: + errLogMsg = "起動待ちに失敗した" + errDiscordMsg = "インスタンスの起動状態不明 再度のコマンド入力を要求" + } + log.Println(errLogMsg, statusErr.Err) + targetChannel.messageSend(errDiscordMsg) return } @@ -140,9 +80,18 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { log.Println("IPアドレス取得待機中...") time.Sleep(time.Second) - ipaddress, err := getIPAddress() - if err != nil { - targetChannel.messageSend("IPアドレスの取得に失敗") + ipaddress, statusErr := aws.GetIPAddress() + if !statusErr.IsEmpty() { + errLogMsg := "" + errDiscordMsg := "IPアドレスの取得に失敗" + switch statusErr.Code { + case aws.ERR_FAILED_GET_IP_ADDRESS: + errLogMsg = "IPアドレス取得時、コマンド実行に失敗 : " + case aws.ERR_INVALID_RESPONSE_GET_IP_ADDRESS: + errLogMsg = "IPアドレス取得時のレスポンスに異常 :" + } + log.Println(errLogMsg, err) + targetChannel.messageSend(errDiscordMsg) return } @@ -153,38 +102,29 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { log.Println("開始 : インスタンス停止...") targetChannel.messageSend("インスタンスの停止コマンドを検知") - outputJSON, err := exec.Command("aws", "ec2", "stop-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() - if err != nil { - log.Println("停止に失敗した :", err) - targetChannel.messageSend("インスタンスの停止に失敗") - return - } - - stopResponse := StopResponse{} - if err := json.Unmarshal(outputJSON, &stopResponse); err != nil { - log.Println("停止時のレスポンスに異常 :", err) - targetChannel.messageSend("インスタンスの停止に失敗") - return - } - - currentState := stopResponse.StoppingInstances[0].CurrentState.Name - if currentState == "stopped" { - log.Println("既に停止している") - targetChannel.messageSend("インスタンスは停止済み") - return - } - - previousState := stopResponse.StoppingInstances[0].PreviousState.Name - if currentState == "stopping" && previousState == "stopping" { - log.Println("停止処理実行中") - targetChannel.messageSend("インスタンスは既に停止準備中") - return - } - - // 停止待ち - if _, err := exec.Command("aws", "ec2", "wait", "instance-stopped", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { - log.Println("停止待ちに失敗した :", err) - targetChannel.messageSend("インスタンスの停止状態不明 再度のコマンド入力を要求") + statusErr := aws.StopInstance() + if !statusErr.IsEmpty() { + errLogMsg := "" + errDiscordMsg := "" + switch statusErr.Code { + case aws.ERR_FAILED_STOP_INSTANCE: + errLogMsg = "停止に失敗した :" + errDiscordMsg = "インスタンスの停止に失敗" + case aws.ERR_INVALID_RESPONSE_STOP_INSTANCE: + errLogMsg = "停止時のレスポンスに異常 :" + errDiscordMsg = "インスタンスの停止に失敗" + case aws.ERR_INSTANCE_ALREADY_STOPPED: + errLogMsg = "既に停止している" + errDiscordMsg = "インスタンスは停止済み" + case aws.ERR_STOPPING_INSTANCE: + errLogMsg = "停止処理実行中" + errDiscordMsg = "インスタンスは既に停止準備中" + case aws.ERR_FAILED_WAIT_STOP_INSTANCE: + errLogMsg = "停止待ちに失敗した :" + errDiscordMsg = "インスタンスの停止状態不明 再度のコマンド入力を要求" + } + log.Println(errLogMsg, err) + targetChannel.messageSend(errDiscordMsg) return } @@ -196,9 +136,18 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { log.Println("開始 : インスタンスステータス確認") targetChannel.messageSend("インスタンスの確認コマンドを検知") - ipaddress, err := getIPAddress() - if err != nil { - targetChannel.messageSend("インスタンスの確認に失敗") + ipaddress, statusErr := aws.GetIPAddress() + if !statusErr.IsEmpty() { + errLogMsg := "" + errDiscordMsg := "インスタンスの確認に失敗" + switch statusErr.Code { + case aws.ERR_FAILED_GET_IP_ADDRESS: + errLogMsg = "IPアドレス取得時、コマンド実行に失敗 : " + case aws.ERR_INVALID_RESPONSE_GET_IP_ADDRESS: + errLogMsg = "IPアドレス取得時のレスポンスに異常 :" + } + log.Println(errLogMsg, err) + targetChannel.messageSend(errDiscordMsg) return } From f4d6086856c59e2a86a83a8482bfe3e23ad25737 Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Sat, 29 Jan 2022 21:56:43 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=E4=B8=8D=E8=A6=81=E3=81=AA=E5=87=A6?= =?UTF-8?q?=E7=90=86=E3=81=A7=E3=81=82=E3=81=A3=E3=81=9F=E3=81=9F=E3=82=81?= =?UTF-8?q?messageSend=E3=82=92=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/discord/bot-receive.go | 100 ++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/src/discord/bot-receive.go b/src/discord/bot-receive.go index ee39177..1f094d0 100644 --- a/src/discord/bot-receive.go +++ b/src/discord/bot-receive.go @@ -9,34 +9,7 @@ import ( "github.com/bwmarrin/discordgo" ) -// TargetChannel Botがメッセージを投稿するDiscordチャンネル -type TargetChannel struct { - s *discordgo.Session - event *discordgo.MessageCreate -} - -func (tc *TargetChannel) messageSend(message string) error { - // コマンドが投稿されたチャンネル - targetChannel, err := tc.s.State.Channel(tc.event.ChannelID) - if err != nil { - log.Println("チャンネルの取得に失敗 :", err) - return err - } - - // Botからメッセージ投稿 - if _, err := tc.s.ChannelMessageSend(targetChannel.ID, message); err != nil { - log.Println("チャンネルメッセージの送信に失敗 :", err) - return err - } - return nil -} - func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { - targetChannel := TargetChannel{ - s: s, - event: event, - } - messages, err := config.GetConfig() if err != nil { log.Fatalln(err) @@ -45,7 +18,11 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { if event.Content == messages.StartTriggerMessage { // 起動時 log.Println("開始 : インスタンス起動...") - targetChannel.messageSend("インスタンスの起動コマンドを検知") + _, err := s.ChannelMessageSend(event.ChannelID, "インスタンスの起動コマンドを検知") + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } statusErr := aws.StartInstance() if !statusErr.IsEmpty() { @@ -69,12 +46,20 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { errDiscordMsg = "インスタンスの起動状態不明 再度のコマンド入力を要求" } log.Println(errLogMsg, statusErr.Err) - targetChannel.messageSend(errDiscordMsg) + _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } return } log.Println("正常終了 : インスタンス起動") - targetChannel.messageSend("インスタンスの起動に成功") + _, err = s.ChannelMessageSend(event.ChannelID, "インスタンスの起動に成功") + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } // IPアドレス通知 log.Println("IPアドレス取得待機中...") @@ -91,16 +76,28 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { errLogMsg = "IPアドレス取得時のレスポンスに異常 :" } log.Println(errLogMsg, err) - targetChannel.messageSend(errDiscordMsg) + _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } return } - targetChannel.messageSend("今回のIPアドレス : " + ipaddress) + _, err = s.ChannelMessageSend(event.ChannelID, "今回のIPアドレス : "+ipaddress) + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } } else if event.Content == messages.HibernateTriggerMessage { // 停止時 log.Println("開始 : インスタンス停止...") - targetChannel.messageSend("インスタンスの停止コマンドを検知") + _, err := s.ChannelMessageSend(event.ChannelID, "インスタンスの停止コマンドを検知") + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } statusErr := aws.StopInstance() if !statusErr.IsEmpty() { @@ -124,17 +121,29 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { errDiscordMsg = "インスタンスの停止状態不明 再度のコマンド入力を要求" } log.Println(errLogMsg, err) - targetChannel.messageSend(errDiscordMsg) + _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } return } log.Println("正常終了 : インスタンス停止") - targetChannel.messageSend("インスタンスの停止に成功") + _, err = s.ChannelMessageSend(event.ChannelID, "インスタンスの停止に成功") + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } } else if event.Content == messages.GetStatusTriggerMessage { // 起動状態の確認(IPアドレスの取得) log.Println("開始 : インスタンスステータス確認") - targetChannel.messageSend("インスタンスの確認コマンドを検知") + _, err := s.ChannelMessageSend(event.ChannelID, "インスタンスの確認コマンドを検知") + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } ipaddress, statusErr := aws.GetIPAddress() if !statusErr.IsEmpty() { @@ -147,15 +156,26 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { errLogMsg = "IPアドレス取得時のレスポンスに異常 :" } log.Println(errLogMsg, err) - targetChannel.messageSend(errDiscordMsg) + _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } return } if ipaddress != "" { - targetChannel.messageSend("インスタンスは起動済み :" + ipaddress) + _, err := s.ChannelMessageSend(event.ChannelID, "インスタンスは起動済み :"+ipaddress) + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } } else { - targetChannel.messageSend("インスタンスは未起動") + _, err := s.ChannelMessageSend(event.ChannelID, "インスタンスは未起動") + if err != nil { + log.Println("チャンネルメッセージの送信に失敗 :", err) + return + } } - } } From ec0ddc2f92299b1b706739e38378263139479601 Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Sun, 30 Jan 2022 09:06:04 +0900 Subject: [PATCH 5/7] =?UTF-8?q?CI=E3=81=AE=E3=83=AF=E3=83=BC=E3=82=AD?= =?UTF-8?q?=E3=83=B3=E3=82=B0=E3=83=87=E3=82=A3=E3=83=AC=E3=82=AF=E3=83=88?= =?UTF-8?q?=E3=83=AA=E3=82=92src=E3=81=AB=E5=A4=89=E6=9B=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/go.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 229dd00..af779d7 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -22,9 +22,12 @@ jobs: - name: Run go vet run: go vet ./... + working-directory: ./src - name: Run go build run: go build . + working-directory: ./src - name: Run go test run: go test -v ./... + working-directory: ./src From e0a6b36c59befeb0dbcc44ef4b46dd8aca049d80 Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Sun, 30 Jan 2022 23:24:41 +0900 Subject: [PATCH 6/7] =?UTF-8?q?errors=E3=82=92=E5=88=A9=E7=94=A8=E3=81=97?= =?UTF-8?q?=E3=81=9F=E3=82=A8=E3=83=A9=E3=83=BC=E3=83=8F=E3=83=B3=E3=83=89?= =?UTF-8?q?=E3=83=AA=E3=83=B3=E3=82=B0=E3=81=AB=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aws/client.go | 36 ++++++++--------- src/aws/error.go | 51 ++++++++++++++---------- src/discord/bot-receive.go | 79 ++++++++++++++------------------------ 3 files changed, 77 insertions(+), 89 deletions(-) diff --git a/src/aws/client.go b/src/aws/client.go index 7de6a26..e2ef8bc 100644 --- a/src/aws/client.go +++ b/src/aws/client.go @@ -36,15 +36,15 @@ type InstanceStatus struct { } // GetIPAddress インスタンスのIPアドレス取得 -func GetIPAddress() (string, StatusError) { +func GetIPAddress() (string, error) { statusOutputJSON, err := exec.Command("aws", "ec2", "describe-instances", "--instance-ids", os.Getenv("INSTANCE_ID"), "--query", "Reservations[].Instances[].{publicip:PublicIpAddress}").Output() if err != nil { - return "", NewStatusError(ERR_FAILED_GET_IP_ADDRESS, err) + return "", WrapError(err, ErrFailedGetIpAddress) } ssResponse := []ServerStatusResponse{} if err := json.Unmarshal(statusOutputJSON, &ssResponse); err != nil { - return "", NewStatusError(ERR_INVALID_RESPONSE_GET_IP_ADDRESS, err) + return "", WrapError(err, ErrInvalidResponseGetIpAddress) } ipaddress := ssResponse[0].PublicIP @@ -52,63 +52,63 @@ func GetIPAddress() (string, StatusError) { log.Println("IPアドレス : ", ipaddress) } - return ipaddress, StatusError{} + return ipaddress, nil } -func StartInstance() StatusError { +func StartInstance() error { outputJSON, err := exec.Command("aws", "ec2", "start-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() if err != nil { - return NewStatusError(ERR_FAILED_START_INSTANCE, err) + return WrapError(err, ErrFailedStartInstance) } startResponse := StartResponse{} if err := json.Unmarshal(outputJSON, &startResponse); err != nil { - return NewStatusError(ERR_INVALID_RESPONSE_START_INSTANCE, err) + return WrapError(err, ErrInvalidResponseStartInstance) } currentState := startResponse.StartingInstances[0].CurrentState.Name if currentState == "running" { - return NewStatusError(ERR_INSTANCE_ALREADY_STARTED, nil) + return WrapError(nil, ErrInstanceAlreadyStarted) } previousState := startResponse.StartingInstances[0].PreviousState.Name if currentState == "pending" && previousState == "pending" { - return NewStatusError(ERR_STARTING_INSTANCE, nil) + return WrapError(nil, ErrStartingInstance) } // 開始待ち if _, err := exec.Command("aws", "ec2", "wait", "instance-running", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { - return NewStatusError(ERR_FAILED_WAIT_START_INSTANCE, err) + return WrapError(err, ErrFailedWaitStartInstance) } - return StatusError{} + return nil } -func StopInstance() StatusError { +func StopInstance() error { outputJSON, err := exec.Command("aws", "ec2", "stop-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() if err != nil { - return NewStatusError(ERR_FAILED_STOP_INSTANCE, err) + return WrapError(err, ErrFailedStopInstance) } stopResponse := StopResponse{} if err := json.Unmarshal(outputJSON, &stopResponse); err != nil { - return NewStatusError(ERR_INVALID_RESPONSE_STOP_INSTANCE, err) + return WrapError(err, ErrInvalidResponseStopInstance) } currentState := stopResponse.StoppingInstances[0].CurrentState.Name if currentState == "stopped" { - return NewStatusError(ERR_INSTANCE_ALREADY_STOPPED, nil) + return WrapError(nil, ErrInstanceAlreadyStopped) } previousState := stopResponse.StoppingInstances[0].PreviousState.Name if currentState == "stopping" && previousState == "stopping" { - return NewStatusError(ERR_STOPPING_INSTANCE, nil) + return WrapError(nil, ErrStoppingInstance) } // 停止待ち if _, err := exec.Command("aws", "ec2", "wait", "instance-stopped", "--instance-ids", os.Getenv("INSTANCE_ID")).Output(); err != nil { - return NewStatusError(ERR_FAILED_WAIT_STOP_INSTANCE, err) + return WrapError(err, ErrFailedWaitStopInstance) } - return StatusError{} + return nil } diff --git a/src/aws/error.go b/src/aws/error.go index 9945245..7ba867e 100644 --- a/src/aws/error.go +++ b/src/aws/error.go @@ -1,32 +1,41 @@ package aws -const ( - ERR_FAILED_START_INSTANCE = iota - ERR_INVALID_RESPONSE_START_INSTANCE - ERR_INSTANCE_ALREADY_STARTED - ERR_STARTING_INSTANCE - ERR_FAILED_WAIT_START_INSTANCE - ERR_FAILED_GET_IP_ADDRESS - ERR_INVALID_RESPONSE_GET_IP_ADDRESS - ERR_FAILED_STOP_INSTANCE - ERR_INVALID_RESPONSE_STOP_INSTANCE - ERR_INSTANCE_ALREADY_STOPPED - ERR_STOPPING_INSTANCE - ERR_FAILED_WAIT_STOP_INSTANCE +import "fmt" + +var ( + ErrFailedGetIpAddress error = &StatusError{message: "IPアドレス取得時、コマンド実行に失敗 :"} + ErrFailedStartInstance error = &StatusError{message: "起動に失敗した :"} + ErrFailedStopInstance error = &StatusError{message: "停止に失敗した :"} + ErrFailedWaitStartInstance error = &StatusError{message: "起動待ちに失敗した"} + ErrFailedWaitStopInstance error = &StatusError{message: "停止待ちに失敗した :"} + ErrInstanceAlreadyStarted error = &StatusError{message: "既に起動している"} + ErrInstanceAlreadyStopped error = &StatusError{message: "既に停止している"} + ErrInvalidResponseGetIpAddress error = &StatusError{message: "IPアドレス取得時のレスポンスに異常 :"} + ErrInvalidResponseStartInstance error = &StatusError{message: "起動時のレスポンスに異常 :"} + ErrInvalidResponseStopInstance error = &StatusError{message: "停止時のレスポンスに異常 :"} + ErrStartingInstance error = &StatusError{message: "起動処理実行中"} + ErrStoppingInstance error = &StatusError{message: "停止処理実行中"} ) type StatusError struct { - Code int // ERR_で始まる定数のみ - Err error + base error + message string } -func NewStatusError(code int, err error) StatusError { - return StatusError{ - Code: code, - Err: err, +func (e *StatusError) Error() string { + baseMessage := "" + if e.base != nil { + baseMessage = e.base.Error() } + return fmt.Sprintf("%s %s", e.message, baseMessage) +} + +func (e *StatusError) Unwrap() error { + return e.base } -func (e StatusError) IsEmpty() bool { - return e == StatusError{} +func WrapError(err error, statusError error) error { + e := statusError.(*StatusError) + e.base = err + return e } diff --git a/src/discord/bot-receive.go b/src/discord/bot-receive.go index 1f094d0..c5d5bc5 100644 --- a/src/discord/bot-receive.go +++ b/src/discord/bot-receive.go @@ -1,6 +1,7 @@ package discord import ( + "errors" "hansel/aws" "hansel/config" "log" @@ -24,28 +25,23 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { return } - statusErr := aws.StartInstance() - if !statusErr.IsEmpty() { - errLogMsg := "" + err = aws.StartInstance() + if err != nil { + log.Println(err) + errDiscordMsg := "" - switch statusErr.Code { - case aws.ERR_FAILED_START_INSTANCE: - errLogMsg = "起動に失敗した :" + if errors.Is(err, aws.ErrFailedStartInstance) { errDiscordMsg = "インスタンスの起動に失敗" - case aws.ERR_INVALID_RESPONSE_START_INSTANCE: - errLogMsg = "起動時のレスポンスに異常 :" + } else if errors.Is(err, aws.ErrInvalidResponseStartInstance) { errDiscordMsg = "インスタンスの起動に失敗" - case aws.ERR_INSTANCE_ALREADY_STARTED: - errLogMsg = "既に起動している" + } else if errors.Is(err, aws.ErrInstanceAlreadyStarted) { errDiscordMsg = "インスタンスは起動済み" - case aws.ERR_STARTING_INSTANCE: - errLogMsg = "起動処理実行中" + } else if errors.Is(err, aws.ErrStartingInstance) { errDiscordMsg = "インスタンスは既に起動準備中" - case aws.ERR_FAILED_WAIT_START_INSTANCE: - errLogMsg = "起動待ちに失敗した" + } else if errors.Is(err, aws.ErrFailedWaitStartInstance) { errDiscordMsg = "インスタンスの起動状態不明 再度のコマンド入力を要求" } - log.Println(errLogMsg, statusErr.Err) + _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) if err != nil { log.Println("チャンネルメッセージの送信に失敗 :", err) @@ -65,17 +61,11 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { log.Println("IPアドレス取得待機中...") time.Sleep(time.Second) - ipaddress, statusErr := aws.GetIPAddress() - if !statusErr.IsEmpty() { - errLogMsg := "" + ipaddress, err := aws.GetIPAddress() + if err != nil { + log.Println(err) + errDiscordMsg := "IPアドレスの取得に失敗" - switch statusErr.Code { - case aws.ERR_FAILED_GET_IP_ADDRESS: - errLogMsg = "IPアドレス取得時、コマンド実行に失敗 : " - case aws.ERR_INVALID_RESPONSE_GET_IP_ADDRESS: - errLogMsg = "IPアドレス取得時のレスポンスに異常 :" - } - log.Println(errLogMsg, err) _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) if err != nil { log.Println("チャンネルメッセージの送信に失敗 :", err) @@ -99,28 +89,23 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { return } - statusErr := aws.StopInstance() - if !statusErr.IsEmpty() { - errLogMsg := "" + err = aws.StopInstance() + if err != nil { + log.Println(err) + errDiscordMsg := "" - switch statusErr.Code { - case aws.ERR_FAILED_STOP_INSTANCE: - errLogMsg = "停止に失敗した :" + if errors.Is(err, aws.ErrFailedStopInstance) { errDiscordMsg = "インスタンスの停止に失敗" - case aws.ERR_INVALID_RESPONSE_STOP_INSTANCE: - errLogMsg = "停止時のレスポンスに異常 :" + } else if errors.Is(err, aws.ErrInvalidResponseStopInstance) { errDiscordMsg = "インスタンスの停止に失敗" - case aws.ERR_INSTANCE_ALREADY_STOPPED: - errLogMsg = "既に停止している" + } else if errors.Is(err, aws.ErrInstanceAlreadyStopped) { errDiscordMsg = "インスタンスは停止済み" - case aws.ERR_STOPPING_INSTANCE: - errLogMsg = "停止処理実行中" + } else if errors.Is(err, aws.ErrStoppingInstance) { errDiscordMsg = "インスタンスは既に停止準備中" - case aws.ERR_FAILED_WAIT_STOP_INSTANCE: - errLogMsg = "停止待ちに失敗した :" + } else if errors.Is(err, aws.ErrFailedWaitStopInstance) { errDiscordMsg = "インスタンスの停止状態不明 再度のコマンド入力を要求" } - log.Println(errLogMsg, err) + _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) if err != nil { log.Println("チャンネルメッセージの送信に失敗 :", err) @@ -145,17 +130,11 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { return } - ipaddress, statusErr := aws.GetIPAddress() - if !statusErr.IsEmpty() { - errLogMsg := "" + ipaddress, err := aws.GetIPAddress() + if err != nil { + log.Println(err) + errDiscordMsg := "インスタンスの確認に失敗" - switch statusErr.Code { - case aws.ERR_FAILED_GET_IP_ADDRESS: - errLogMsg = "IPアドレス取得時、コマンド実行に失敗 : " - case aws.ERR_INVALID_RESPONSE_GET_IP_ADDRESS: - errLogMsg = "IPアドレス取得時のレスポンスに異常 :" - } - log.Println(errLogMsg, err) _, err := s.ChannelMessageSend(event.ChannelID, errDiscordMsg) if err != nil { log.Println("チャンネルメッセージの送信に失敗 :", err) From a85196b866e42abfb03c850f6d7c29dac88482d3 Mon Sep 17 00:00:00 2001 From: shokkunrf <19404989+shokkunrf@users.noreply.github.com> Date: Sun, 30 Jan 2022 23:41:26 +0900 Subject: [PATCH 7/7] =?UTF-8?q?EC2=E3=82=92=E6=93=8D=E4=BD=9C=E3=81=99?= =?UTF-8?q?=E3=82=8B=E3=81=9F=E3=82=81=E3=81=AEinterface=E3=82=92=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/aws/client.go | 18 +++++++++++++++--- src/discord/bot-receive.go | 8 ++++---- src/discord/bot.go | 7 +++++-- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/src/aws/client.go b/src/aws/client.go index e2ef8bc..96f9e4c 100644 --- a/src/aws/client.go +++ b/src/aws/client.go @@ -35,8 +35,20 @@ type InstanceStatus struct { } `json:"PreviousState"` } +type Client interface { + GetIPAddress() (string, error) + StartInstance() error + StopInstance() error +} + +type EC2Client struct{} + +func NewEC2Client() Client { + return EC2Client{} +} + // GetIPAddress インスタンスのIPアドレス取得 -func GetIPAddress() (string, error) { +func (c EC2Client) GetIPAddress() (string, error) { statusOutputJSON, err := exec.Command("aws", "ec2", "describe-instances", "--instance-ids", os.Getenv("INSTANCE_ID"), "--query", "Reservations[].Instances[].{publicip:PublicIpAddress}").Output() if err != nil { return "", WrapError(err, ErrFailedGetIpAddress) @@ -55,7 +67,7 @@ func GetIPAddress() (string, error) { return ipaddress, nil } -func StartInstance() error { +func (c EC2Client) StartInstance() error { outputJSON, err := exec.Command("aws", "ec2", "start-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() if err != nil { return WrapError(err, ErrFailedStartInstance) @@ -84,7 +96,7 @@ func StartInstance() error { return nil } -func StopInstance() error { +func (c EC2Client) StopInstance() error { outputJSON, err := exec.Command("aws", "ec2", "stop-instances", "--instance-ids", os.Getenv("INSTANCE_ID")).Output() if err != nil { return WrapError(err, ErrFailedStopInstance) diff --git a/src/discord/bot-receive.go b/src/discord/bot-receive.go index c5d5bc5..0c06d26 100644 --- a/src/discord/bot-receive.go +++ b/src/discord/bot-receive.go @@ -25,7 +25,7 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { return } - err = aws.StartInstance() + err = b.awsClient.StartInstance() if err != nil { log.Println(err) @@ -61,7 +61,7 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { log.Println("IPアドレス取得待機中...") time.Sleep(time.Second) - ipaddress, err := aws.GetIPAddress() + ipaddress, err := b.awsClient.GetIPAddress() if err != nil { log.Println(err) @@ -89,7 +89,7 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { return } - err = aws.StopInstance() + err = b.awsClient.StopInstance() if err != nil { log.Println(err) @@ -130,7 +130,7 @@ func (b *Bot) receive(s *discordgo.Session, event *discordgo.MessageCreate) { return } - ipaddress, err := aws.GetIPAddress() + ipaddress, err := b.awsClient.GetIPAddress() if err != nil { log.Println(err) diff --git a/src/discord/bot.go b/src/discord/bot.go index 99896b7..c7967ec 100644 --- a/src/discord/bot.go +++ b/src/discord/bot.go @@ -1,6 +1,7 @@ package discord import ( + "hansel/aws" "log" "os" @@ -8,7 +9,8 @@ import ( ) type Bot struct { - session *discordgo.Session + session *discordgo.Session + awsClient aws.Client } func NewBot() (*Bot, error) { @@ -18,7 +20,8 @@ func NewBot() (*Bot, error) { } return &Bot{ - session: session, + session: session, + awsClient: aws.NewEC2Client(), }, nil }