Как использовать сокет домена unix для выполнения запроса при использовании Gin?
Я создаю обертку для фейерверка.
Чтобы запустить виртуальную машину с фейерверком в командной строке, вы должны передать файл сокета вfirecracker
исполняемый. Что-то вроде этого:
firecracker --api-sock /path/to/file.socket
Затем с другого терминала вы можете делать запросы к этому серверу/сокету примерно так:
curl --unix-socket /tmp/firecracker.socket -XPUT 'http://localhost/actions' -d '{"action_type": "SendCtrlAltDel"}'
Я пытаюсь воспроизвести то же самое с сервера Gin.
У меня есть конечная точка, которая выполняет первую работу, то есть запускает сервер. Минимальный код выглядит так:
cmd := exec.Command("firecracker", "--api-sock", "/path/to/file.socket")
err := cmd.Start()
Эта конечная точка запускает сервер и прослушивает любую команду. Проблема в том, что я не знаю, как использовать файл сокета для отправки запроса PUT на этот сервер. Я нашел это в Интернете, но это не имеет для меня особого смысла.
Вот начальный код, который не использует файл сокета.
func BootSource(c *gin.Context) {
var body models.BootSource
c.BindJSON(&body)
bodyJson, _ := json.Marshal(body)
// initialize http client
client := &http.Client{}
// set the HTTP method, url, and request body
req, err := http.NewRequest(http.MethodPut, "http://localhost/boot-source", bytes.NewBuffer(bodyJson))
if err != nil {
panic(err)
}
// set the request header Content-Type for json
_, err = client.Do(req)
if err != nil {
panic(err)
}
}
Как заставить этот запрос PUT использовать файл сокета?
Также обратите внимание, что я использую фреймворк Gin.
2 ответа
Для этого вам нужно переопределить транспорт, используемый вашимhttp.Client
чтобы настроить функцию, которая будет использоваться для создания соединения с сокетом:
client := http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return net.DialContext(ctx, "unix", "/path/to/socket")
}
}
}
Затем вы можете использовать этот клиент, и все запросы, сделанные им, будут использовать это соединение. Обычно для служб HTTP, предоставляемых через сокет, хост, используемый в запросе, не важен, поэтому вы можете просто использовать любое значение, которое имеет для вас смысл, например
client.Get("http://firecracker/some/api/path")
Однако, поскольку вы пытаетесь использовать Firecracker API, почему бы просто не использовать их SDK: https://github.com/firecracker-microvm/firecracker-go-sdk
Это позволит настроить соединение за вас и избавит вас от необходимости вручную обрабатывать все запросы.
Расширяя этот ответ , вы можете сохранить значения http по умолчанию, клонировав транспорт по умолчанию.
defaultTransport, ok := http.DefaultTransport.(*http.Transport)
if !ok {
panic("http.DefaultTransport is not a *http.Transport")
}
unixTransport := defaultTransport.Clone()
defaultDialContext := unixTransport.DialContext
unixTransport.DialContext = func(ctx context.Context, _, _ string) (net.Conn, error) {
return defaultDialContext(ctx, "unix", "/path/to/socket")
}
client := http.Client{Transport: unixTransport}
client.Get("http://example.com")