update dns update ip job to update technitium via api
This commit is contained in:
parent
8f7ece5dac
commit
543fca5dbb
5 changed files with 222 additions and 33 deletions
48
cli/main.go
48
cli/main.go
|
|
@ -195,30 +195,32 @@ func run() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Send notification as glue records can't be modified programatically for godaddy :/
|
// Send notification as glue records can't be modified programatically for godaddy :/
|
||||||
err = notifyForIPChange(publicDNSIp, dynamicDNSIp)
|
defer notifyForIPChange(publicDNSIp, dynamicDNSIp)
|
||||||
if err != nil {
|
|
||||||
return errors.Wrapf(err, "failed to notify for ip change. this must succeed otherwise the glue records won't be updated")
|
|
||||||
}
|
|
||||||
// setup git repo
|
// setup git repo
|
||||||
gitFs, err := NewGitFS(repository)
|
// Old, code-as-infra based approach
|
||||||
if err != nil {
|
// gitFs, err := NewGitFS(repository)
|
||||||
return errors.Wrapf(err, "failed to initialize git fs")
|
// if err != nil {
|
||||||
}
|
// return errors.Wrapf(err, "failed to initialize git fs")
|
||||||
worktree, err := gitFs.repo.Worktree()
|
// }
|
||||||
if err != nil {
|
// worktree, err := gitFs.repo.Worktree()
|
||||||
return errors.Wrapf(err, "failed to get worktree")
|
// if err != nil {
|
||||||
}
|
// return errors.Wrapf(err, "failed to get worktree")
|
||||||
err = updatePublicIP(gitFs, publicDNSIp, dynamicDNSIp)
|
// }
|
||||||
if err != nil {
|
// err = updatePublicIP(gitFs, publicDNSIp, dynamicDNSIp)
|
||||||
return fmt.Errorf("failed to update public ip: %w", err)
|
// if err != nil {
|
||||||
}
|
// return fmt.Errorf("failed to update public ip: %w", err)
|
||||||
// // commit changes
|
// }
|
||||||
if _, err = worktree.Commit("Update public ip and ns records", &git.CommitOptions{All: true, Author: &object.Signature{Name: "Webhook Handler Bot"}}); err != nil {
|
// // // commit changes
|
||||||
return errors.Wrapf(err, "failed to commit")
|
// if _, err = worktree.Commit("Update public ip and ns records", &git.CommitOptions{All: true, Author: &object.Signature{Name: "Webhook Handler Bot"}}); err != nil {
|
||||||
}
|
// return errors.Wrapf(err, "failed to commit")
|
||||||
if err = gitFs.Push(); err != nil {
|
// }
|
||||||
return errors.Wrapf(err, "failed to push changes")
|
// if err = gitFs.Push(); err != nil {
|
||||||
}
|
// return errors.Wrapf(err, "failed to push changes")
|
||||||
|
// }
|
||||||
|
username := os.Getenv("TECHNITIUM_USERNAME")
|
||||||
|
password := os.Getenv("TECHNITIUM_PASSWORD")
|
||||||
|
// dynamicDNSIp = net.ParseIP("6.9.6.9")
|
||||||
|
return UpdatePublicIPViaTechnitiumAPI(dynamicDNSIp, username, password)
|
||||||
default:
|
default:
|
||||||
err = errors.New(fmt.Sprintf("unsupported use case: %s", *useCase))
|
err = errors.New(fmt.Sprintf("unsupported use case: %s", *useCase))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
167
cli/update_viktorbarzin_me_technitium.go
Normal file
167
cli/update_viktorbarzin_me_technitium.go
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CreateTokenResponse struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
TokenName string `json:"tokenName"`
|
||||||
|
Token string `json:"token"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
ErrorMessage string `json:"errorMessage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetRecordsResponse struct {
|
||||||
|
Response struct {
|
||||||
|
Zone struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Internal bool `json:"internal"`
|
||||||
|
DnssecStatus string `json:"dnssecStatus"`
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
} `json:"zone"`
|
||||||
|
Records []struct {
|
||||||
|
Disabled bool `json:"disabled"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Ttl int64 `json:"ttl"`
|
||||||
|
RData struct {
|
||||||
|
IpAddress string `json:"ipAddress"`
|
||||||
|
// there's more fields that we don't use atm
|
||||||
|
} `json:"rData"`
|
||||||
|
// RData interface{} `json:"rData"`
|
||||||
|
DnsSecStatus string `json:"dnsSecStatus"`
|
||||||
|
} `json:"records"`
|
||||||
|
} `json:"response"`
|
||||||
|
}
|
||||||
|
type UpdateRecordResponse struct {
|
||||||
|
Status string `json:"status"`
|
||||||
|
ErrorMessage string `json:"errorMessage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// const TECHNITIUM_HOST = "technitium-web.technitium"
|
||||||
|
|
||||||
|
const TECHNITIUM_HOST = "localhost"
|
||||||
|
|
||||||
|
func UpdatePublicIPViaTechnitiumAPI(newIp net.IP, username string, password string) error {
|
||||||
|
token, err := createTechnitiumToken(username, password)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to get technitium token")
|
||||||
|
}
|
||||||
|
for _, ns := range []string{"ns1", "ns2"} {
|
||||||
|
nsRecordName := ns + ".viktorbarzin.me"
|
||||||
|
currIpStr, err := getRecordValue(token, nsRecordName, "A")
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to get A record for ns server")
|
||||||
|
}
|
||||||
|
currIp := net.ParseIP(currIpStr)
|
||||||
|
fmt.Printf("updating record %s to %s\n", nsRecordName, newIp.String())
|
||||||
|
err = UpdateTechnitiumNSARecord(token, nsRecordName, currIp, newIp)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to update NS A record")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateTechnitiumNSARecord(token, domain string, currIp, newIp net.IP) error {
|
||||||
|
baseURL := fmt.Sprintf("http://%s:5380/api/zones/records/update", TECHNITIUM_HOST)
|
||||||
|
params := map[string]string{
|
||||||
|
"token": token,
|
||||||
|
"domain": domain,
|
||||||
|
"type": "A",
|
||||||
|
"newIpAddress": newIp.String(),
|
||||||
|
"ipAddress": currIp.String(),
|
||||||
|
}
|
||||||
|
resp, err := sendTechnitiumAPIRequest(baseURL, params)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to update record")
|
||||||
|
}
|
||||||
|
var parsedResponse UpdateRecordResponse
|
||||||
|
err = json.NewDecoder(strings.NewReader(resp)).Decode(&parsedResponse)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "failed to decode json response when updating record")
|
||||||
|
}
|
||||||
|
if parsedResponse.Status == "error" {
|
||||||
|
return fmt.Errorf("received error status when updating record: %s", parsedResponse.ErrorMessage)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createTechnitiumToken(username string, password string) (string, error) {
|
||||||
|
baseURL := fmt.Sprintf("http://%s:5380/api/user/createToken", TECHNITIUM_HOST)
|
||||||
|
params := map[string]string{
|
||||||
|
"user": username,
|
||||||
|
"pass": password,
|
||||||
|
"tokenName": "infra-cli-token",
|
||||||
|
}
|
||||||
|
resp, err := sendTechnitiumAPIRequest(baseURL, params)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to fetch token")
|
||||||
|
}
|
||||||
|
var tokenResponse CreateTokenResponse
|
||||||
|
// println(resp)
|
||||||
|
err = json.NewDecoder(strings.NewReader(resp)).Decode(&tokenResponse)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to decode json response")
|
||||||
|
}
|
||||||
|
if tokenResponse.Status != "ok" {
|
||||||
|
return "", fmt.Errorf("received error status when fetching token: %s, error: %s", tokenResponse.Status, tokenResponse.ErrorMessage)
|
||||||
|
}
|
||||||
|
return tokenResponse.Token, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRecordValue(token, domain, recordType string) (string, error) {
|
||||||
|
baseURL := fmt.Sprintf("http://%s:5380/api/zones/records/get", TECHNITIUM_HOST)
|
||||||
|
params := map[string]string{
|
||||||
|
"token": token,
|
||||||
|
"domain": domain,
|
||||||
|
}
|
||||||
|
resp, err := sendTechnitiumAPIRequest(baseURL, params)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "failed to fetch record values for domain %s", domain)
|
||||||
|
}
|
||||||
|
|
||||||
|
var response GetRecordsResponse
|
||||||
|
err = json.NewDecoder(strings.NewReader(resp)).Decode(&response)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to decode json response when getting all zone records")
|
||||||
|
}
|
||||||
|
for _, record := range response.Response.Records {
|
||||||
|
if record.Type == recordType {
|
||||||
|
return record.RData.IpAddress, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", fmt.Errorf("failed to find record for name %s and type %s", domain, recordType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sendTechnitiumAPIRequest(baseURL string, params map[string]string) (string, error) {
|
||||||
|
url, err := url.Parse(baseURL)
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrapf(err, "failed to create base url")
|
||||||
|
}
|
||||||
|
// Encode the URL parameters
|
||||||
|
query := url.Query()
|
||||||
|
for key, value := range params {
|
||||||
|
query.Add(key, value)
|
||||||
|
}
|
||||||
|
url.RawQuery = query.Encode()
|
||||||
|
|
||||||
|
resp, err := http.Get(url.String())
|
||||||
|
if err != nil {
|
||||||
|
return "", errors.Wrap(err, "failed to create token")
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return string(body), err
|
||||||
|
}
|
||||||
6
main.tf
6
main.tf
|
|
@ -44,6 +44,8 @@ variable "webhook_handler_fb_verify_token" {}
|
||||||
variable "webhook_handler_fb_page_token" {}
|
variable "webhook_handler_fb_page_token" {}
|
||||||
variable "webhook_handler_fb_app_secret" {}
|
variable "webhook_handler_fb_app_secret" {}
|
||||||
variable "webhook_handler_git_user" {}
|
variable "webhook_handler_git_user" {}
|
||||||
|
variable "technitium_username" {}
|
||||||
|
variable "technitium_password" {}
|
||||||
variable "webhook_handler_git_token" {}
|
variable "webhook_handler_git_token" {}
|
||||||
variable "webhook_handler_ssh_key" {}
|
variable "webhook_handler_ssh_key" {}
|
||||||
variable "monitoring_idrac_username" {}
|
variable "monitoring_idrac_username" {}
|
||||||
|
|
@ -344,6 +346,10 @@ module "kubernetes_cluster" {
|
||||||
resume_database_url = var.resume_database_url
|
resume_database_url = var.resume_database_url
|
||||||
|
|
||||||
frigate_valchedrym_camera_credentials = var.frigate_valchedrym_camera_credentials
|
frigate_valchedrym_camera_credentials = var.frigate_valchedrym_camera_credentials
|
||||||
|
|
||||||
|
// updating technitium records
|
||||||
|
technitium_username = var.technitium_username
|
||||||
|
technitium_password = var.technitium_password
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# Module to run some infra-specific things like updating the public ip
|
# Module to run some infra-specific things like updating the public ip
|
||||||
variable git_user {}
|
variable "git_user" {}
|
||||||
variable git_token {}
|
variable "git_token" {}
|
||||||
|
variable "technitium_username" {}
|
||||||
|
variable "technitium_password" {}
|
||||||
|
|
||||||
|
|
||||||
resource "kubernetes_cron_job_v1" "update-public-ip" {
|
resource "kubernetes_cron_job_v1" "update-public-ip" {
|
||||||
|
|
@ -23,21 +25,29 @@ resource "kubernetes_cron_job_v1" "update-public-ip" {
|
||||||
spec {
|
spec {
|
||||||
priority_class_name = "system-cluster-critical"
|
priority_class_name = "system-cluster-critical"
|
||||||
container {
|
container {
|
||||||
name = "update-public-ip"
|
name = "update-public-ip"
|
||||||
image = "viktorbarzin/infra"
|
image = "viktorbarzin/infra"
|
||||||
command = ["./infra_cli"]
|
command = ["./infra_cli"]
|
||||||
args = ["-use-case", "update-public-ip"]
|
args = ["-use-case", "update-public-ip"]
|
||||||
|
|
||||||
env {
|
env {
|
||||||
name = "GIT_USER"
|
name = "GIT_USER"
|
||||||
value = var.git_user
|
value = var.git_user
|
||||||
}
|
}
|
||||||
env {
|
env {
|
||||||
name = "GIT_TOKEN"
|
name = "GIT_TOKEN"
|
||||||
value = var.git_token
|
value = var.git_token
|
||||||
}
|
}
|
||||||
|
env {
|
||||||
|
name = "TECHNITIUM_USERNAME"
|
||||||
|
value = var.technitium_username
|
||||||
|
}
|
||||||
|
env {
|
||||||
|
name = "TECHNITIUM_PASSWORD"
|
||||||
|
value = var.technitium_password
|
||||||
|
}
|
||||||
}
|
}
|
||||||
restart_policy = "Never"
|
restart_policy = "Never"
|
||||||
# service_account_name = "descheduler-sa"
|
# service_account_name = "descheduler-sa"
|
||||||
# volume {
|
# volume {
|
||||||
# name = "policy-volume"
|
# name = "policy-volume"
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ variable "webhook_handler_fb_app_secret" {}
|
||||||
variable "webhook_handler_git_user" {}
|
variable "webhook_handler_git_user" {}
|
||||||
variable "webhook_handler_git_token" {}
|
variable "webhook_handler_git_token" {}
|
||||||
variable "webhook_handler_ssh_key" {}
|
variable "webhook_handler_ssh_key" {}
|
||||||
|
variable "technitium_username" {}
|
||||||
|
variable "technitium_password" {}
|
||||||
variable "idrac_username" {}
|
variable "idrac_username" {}
|
||||||
variable "idrac_password" {}
|
variable "idrac_password" {}
|
||||||
variable "alertmanager_slack_api_url" {}
|
variable "alertmanager_slack_api_url" {}
|
||||||
|
|
@ -285,9 +287,11 @@ module "excalidraw" {
|
||||||
}
|
}
|
||||||
|
|
||||||
module "infra-maintenance" {
|
module "infra-maintenance" {
|
||||||
source = "./infra-maintenance"
|
source = "./infra-maintenance"
|
||||||
git_user = var.webhook_handler_git_user
|
git_user = var.webhook_handler_git_user
|
||||||
git_token = var.webhook_handler_git_token
|
git_token = var.webhook_handler_git_token
|
||||||
|
technitium_username = var.technitium_username
|
||||||
|
technitium_password = var.technitium_password
|
||||||
}
|
}
|
||||||
|
|
||||||
module "travel_blog" {
|
module "travel_blog" {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue