internal/hostgacommunicator/hostgacommunicator.go (67 lines of code) (raw):

package hostgacommunicator import ( "encoding/json" "io" "net/http" "net/url" "github.com/Azure/run-command-handler-linux/internal/constants" "github.com/Azure/run-command-handler-linux/internal/requesthelper" "github.com/go-kit/kit/log" "github.com/pkg/errors" ) const ( hostGaPluginPort = "32526" WireServerFallbackAddress = "http://168.63.129.16:32526" ) type ResponseData struct { VMSettings *VMImmediateExtensionsGoalState ETag string Modified bool } // Interface for operations available when communicating with HostGAPlugin type IHostGACommunicator interface { GetImmediateVMSettings(ctx *log.Context, eTag string) (*ResponseData, error) } // HostGaCommunicator provides methods for retrieving VMSettings from the HostGAPlugin type HostGACommunicator struct { vmRequestManager IVMSettingsRequestManager } func NewHostGACommunicator(requestManager IVMSettingsRequestManager) HostGACommunicator { return HostGACommunicator{vmRequestManager: requestManager} } type IVMSettingsRequestManager interface { GetVMSettingsRequestManager(ctx *log.Context) (*requesthelper.RequestManager, error) } // GetVMSettings returns the VMSettings for the current machine func (c *HostGACommunicator) GetImmediateVMSettings(ctx *log.Context, eTag string) (*ResponseData, error) { requestManager, err := c.vmRequestManager.GetVMSettingsRequestManager(ctx) if err != nil { return nil, errors.Wrapf(err, "could not create the request manager to get immediate VMsettings") } resp, err := requesthelper.WithRetries(ctx, requestManager, requesthelper.ActualSleep, eTag) if err != nil { return nil, errors.Wrapf(err, "request to retrieve VMSettings failed with retries.") } // If the response is 304 Not Modified or 404 Not Found, return nil VMSettings as there are not new goal states to process if resp.StatusCode == http.StatusNotModified || resp.StatusCode == http.StatusNotFound { return &ResponseData{VMSettings: nil, ETag: eTag, Modified: false}, nil } defer resp.Body.Close() body, err := io.ReadAll(resp.Body) if err != nil { panic(err) } var vmSettings VMImmediateExtensionsGoalState if err := json.Unmarshal(body, &vmSettings); err != nil { return nil, errors.Wrapf(err, "failed to parse immediate VMSettings json") } newETag := resp.Header.Get(constants.ETagHeaderName) if newETag == "" { return nil, errors.New("ETag not found in response header when retrieving immediate VMSettings") } return &ResponseData{VMSettings: &vmSettings, ETag: newETag, Modified: eTag != newETag}, nil } // Gets the URI to use to call the given operation name func getOperationUri(ctx *log.Context, operationName string) (string, error) { // TODO: investigate why other extensions use the env var AZURE_GUEST_AGENT_WIRE_PROTOCOL_ADDRESS // and decide if we want to add that wire protocol address as a potential endpoint to use when provided uri, err := url.Parse(WireServerFallbackAddress) if err != nil { return "", errors.Wrap(err, "could not parse address "+WireServerFallbackAddress) } uri.Path = operationName return uri.String(), nil }