Как использовать сокет домена 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")
Другие вопросы по тегам