INT 21h

Hi, I am Vladimir Smagin, SysAdmin and Kaptain. Telegram Email / GIT / Thingiverse / RSS / GPG

Golang: marshal and unmarshal iota (yaml, json, toml)

№ 11025 В разделе "Programming" от June 16th, 2020,
В подшивках:

Tried to unmarshal enum value from app config file and failed?

DB:
  masterDB: "ips.sdb"
  clean: Full

Use strings instead of iota.

const (
	CleanRecreate  = "Recreate" // completely remove DB file and create again
	CleanFull      = "Full" // delete all and vacuum
	CleanLastDay   = "LastDay" // remove all before last day
	CleanLastWeek  = "LastWeek"
	CleanLastMonth = "LastMonth"
	CleanNever     = "Never" // do nothing
)

type CleanType string

type AppConfig struct {
	DB    struct {
		MasterDB string    `yaml:"masterDB"`        // master sqlite database
		Clean    CleanType `yaml:"clean,omitempty"` // cleanup at startup
	} `yaml:"DB"`
}

Now load config file:

func main() {
	flag.Parse()
	if *configFilename == "" {
		log.Fatalln("Set configuration filename")
	}

	// read settings from file
	log.Println("Loading config file", *configFilename)
	appConfig := AppConfig{}

	yamlFile, err := ioutil.ReadFile(*configFilename)
	if err != nil {
		log.Fatalf("Config read error: %v\n", err)
	}
	err = yaml.Unmarshal(yamlFile, &appConfig)
	if err != nil {
		log.Fatalf("Config format error: %v\n", err)
	}

	switch appConfig.DB.Clean {
	case CleanRecreate:
		log.Println("Recreate cleanup option set")
		os.Remove(appConfig.DB.MasterDB)
	case CleanFull:
		log.Println("Full cleanup option set")
	case CleanLastDay:
		log.Println("Save only last day cleanup option set")
	case CleanLastWeek:
		log.Println("Save only last week option set")
	case CleanLastMonth:
		log.Println("Save only last month option set")
	}
	dbHandler := dbLoadFile(appConfig.DB.MasterDB)
	defer dbHandler.Close()
}

Here is another solution https://gist.github.com/lummie/7f5c237a17853c031a57277371528e87#file-enum-go

Нет комментариев »

Прекрасный Hashicorp Packer

№ 11013 В разделе "Sysadmin" от May 30th, 2020,
В подшивках:

Допустим, у вас где-то в облачном сервисе хостится большое количество однотипных серверов, какая-то ферма из wordpress или кластер kubernetes и вы хотите сделать регулировку количества нод в зависимости от нагрузки для снижения стоимости эксплуатации. Нодами можно управлять руками или с помощью terraform и деплоить туда софт через ansible, но такой метод все равно плохо подходит когда это нужно делать быстро. Есть выход из ситуации в виде создания образа ноды из уже поднятой рабочей ноды, а потом в зависимости от нагрузки поднимать из этого образа новые ноды, но такой способ довольно затратен по времени и может легко вылиться в часы работы. Одна хитрая фирма, занимающаяся автоматизацией процессов создала штуку под названием Packer. И нет, это не накладной хуец, как мог бы подумать гугол.

Packer предназначен для быстрого создания образов для последующего развертывания. Конфигурационный файл описывает состояние будущей виртуальной машины и Packer старается привести образ к этому состоянию. Для примера можно взять Hetzner и какой-то php проект, для которого развернем nginx, php-fpm, модули баз данных, сами базы данных и пара административных утилит. Поскольку это всего-лишь пример работы, я здесь не упоминаю многих функций и рекомендую изучить полное руководство.

Все необходимые файлы лежат в этом git репозитории. Откройте hetzner.json и внимательно его изучите. В билдере как раз описывается требуемое состояние образа. Кстати, никто не запрещает иметь два билдера, или три, для прода, стейджинга или даже в другом облаке. В текущем примере билдер всего один для хецнера. Метки и имена очень полезны для последующей работы с образами, не пренебрегайте ими. Есть 2 пути доставки команд в образ, через user_data и через provisioners и между ними есть существенное отличие, которое рекомендую тщательно изучить, этот пример использует оба пути. Также провижионерами можно, например, копировать файлы или запустить ansible плейбук.

{
  "variables": {
    "hcloud_token": "my_hetzner_token"
  },
  "builders": [
    {
      "type": "hcloud",
      "token": "{{user `hcloud_token`}}",
      "image": "ubuntu-18.04",
      "location": "nbg1",
      "server_type": "cx11",
      "ssh_keys": [
        "vlad"
      ],
      "snapshot_name": "nginx-php",
      "snapshot_labels": {
        "test": "label",
        "shell": "bash",
        "python": "3"
      },
      "user_data_file": "ubuntu_deps.sh",
      "communicator": "ssh",
      "ssh_username": "root",
      "pause_before_connecting": "1m"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "script": "ubuntu_deps.sh"
    },
    {
      "type": "shell",
      "inline": [
        "sudo apt-get install -y php-mysql php-pgsql mysql-server postgresql-10"
      ]
    }
  ]
}

Для работы с апи хецнера требуется токен, который прописывается в виде переменной. Переменным значения можно не передавать, просто захардкодив их, или можно передать через переменные окружения. А можно брать вообще из Vault или Consul, в документации отлично рассказано про всё это. В моем примере я передаю их через командную строку при команде build, которая необходима для старта сборки образа. Такой подход позволяет лучше автоматизировать процесс сборки, т.к. json файл будет являться по сути шаблоном, в который ваша CI подставляет необходимые значения.

packer build -var 'hcloud_token=DF23J2LK35J23KJ2LK352GHJF2HGFD23HG' hetzner.json

После начала сборки в панели управления облаком вы увидите, что поднялась новая виртуальная машина заданного типа в которую устанавливаются все указанные пакеты. По окончании сборки с виртуальной машины снимется образ, который будет виден в разделе Snapshots. Теперь из этого образа можно поднимать огромное количество нод и их тип совсем не ограничен той, которая была прописана в server_type.

Я думаю вы с легкостью найдете применение этой замечательной утилите. Когда закончите изучение этой обратите внимание на другую крутую штуку Vagrant, которая помогает управлять виртуальными машинами.

Репозиторий с примером https://git.blindage.org/21h/packer-hetzner-sample

Нет комментариев »

Warm Image operator for Kubernetes

№ 11010 В разделе "Sysadmin" от May 28th, 2020,
В подшивках: , , ,

For example, you have huge image with your software and running POD on node. When POD moving to another node your image downloads to new node minute or two. This operator forces nodes to download image before rescheduling, so POD starts faster.

It runs /bin/sh with infinite loop on specified image as DaemonSet with additional options like NodeSelector, Affinity or resource limits. You can specify custom command if your image not contains /bin/sh interpreter or you want to run own script.

Your first warmer:

apiVersion: blindage.org/v1alpha1
kind: WarmImage
metadata:
  name: mongo4
spec:
  image: mongo
  version: "4"
  nodeSelector:
    node-role.kubernetes.io/master: ""

Now you warmed mongo:4 on all master nodes.

Repository here https://git.blindage.org/21h/warm-image-operator

Нет комментариев »

Простой способ подготовки библиотеки на golang к тестированию

№ 11006 В разделе "Programming" от May 26th, 2020,

Чтобы без проблем тестировать программы, написанные с использованием вашей библиотеки ее необходимо подготовить для этого. Делаем интерфейс, который будет использоваться в тестах, где ваши реальные функции будут заменены функциями с тестовыми данными.

package main

import "fmt"

// library 

type FooAdapter interface {
	Read() string
}

type Foo struct {
	mvar    string
}

func NewFoo(v string) FooAdapter {
	return &Foo{mvar:v}
}

func (a *Foo) Read() string {
	return "orig: " + a.mvar
}

// test 

func NewFooStub(v string) FooAdapter {
	return &FooStub{mvar: v}
}

type FooStub struct {
	mvar string
}

func (s *FooStub) Read() string {
	return "stub: " + s.mvar
}

func main() {
	z := NewFoo("o")
	fmt.Println("Read", z.Read())
	m := NewFooStub("s")
	fmt.Println("Read", m.Read())
}

https://play.golang.org/p/9utaWeDjNjo

Нет комментариев »

Яндекс.Метрика

Fortune cookie: One who does not know a burro from a burrow does not know his ass from a hole in the ground!