mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #48243 from brendandburns/imds
Automatic merge from submit-queue (batch tested with PRs 48594, 47042, 48801, 48641, 48243) Add initial support for the Azure instance metadata service. Part of fixing #46632 @colemickens @rootfs @jdumars @kris-nova
This commit is contained in:
commit
d230956280
@ -15,6 +15,7 @@ go_library(
|
||||
"azure_backoff.go",
|
||||
"azure_blob.go",
|
||||
"azure_file.go",
|
||||
"azure_instance_metadata.go",
|
||||
"azure_instances.go",
|
||||
"azure_loadbalancer.go",
|
||||
"azure_routes.go",
|
||||
|
@ -104,6 +104,9 @@ type Config struct {
|
||||
CloudProviderRateLimitQPS float32 `json:"cloudProviderRateLimitQPS" yaml:"cloudProviderRateLimitQPS"`
|
||||
// Rate limit Bucket Size
|
||||
CloudProviderRateLimitBucket int `json:"cloudProviderRateLimitBucket" yaml:"cloudProviderRateLimitBucket"`
|
||||
|
||||
// Use instance metadata service where possible
|
||||
UseInstanceMetadata bool `json:"useInstanceMetadata" yaml:"useInstanceMetadata"`
|
||||
}
|
||||
|
||||
// Cloud holds the config and clients
|
||||
|
103
pkg/cloudprovider/providers/azure/azure_instance_metadata.go
Normal file
103
pkg/cloudprovider/providers/azure/azure_instance_metadata.go
Normal file
@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright 2016 The Kubernetes Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package azure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// This is just for tests injection
|
||||
var metadataURL = "http://169.254.169.254/metadata"
|
||||
|
||||
// SetMetadataURLForTesting is used to modify the URL used for
|
||||
// accessing the metadata server. Should only be used for testing!
|
||||
func SetMetadataURLForTesting(url string) {
|
||||
metadataURL = url
|
||||
}
|
||||
|
||||
// NetworkMetadata contains metadata about an instance's network
|
||||
type NetworkMetadata struct {
|
||||
Interface []NetworkInterface `json:"interface"`
|
||||
}
|
||||
|
||||
// NetworkInterface represents an instances network interface.
|
||||
type NetworkInterface struct {
|
||||
IPV4 NetworkData `json:"ipv4"`
|
||||
IPV6 NetworkData `json:"ipv6"`
|
||||
MAC string `json:"macAddress"`
|
||||
}
|
||||
|
||||
// NetworkData contains IP information for a network.
|
||||
type NetworkData struct {
|
||||
IPAddress []IPAddress `json:"ipAddress"`
|
||||
Subnet []Subnet `json:"subnet"`
|
||||
}
|
||||
|
||||
// IPAddress represents IP address information.
|
||||
type IPAddress struct {
|
||||
PrivateIP string `json:"privateIPAddress"`
|
||||
PublicIP string `json:"publicIPAddress"`
|
||||
}
|
||||
|
||||
// Subnet represents subnet information.
|
||||
type Subnet struct {
|
||||
Address string `json:"address"`
|
||||
Prefix string `json:"prefix"`
|
||||
}
|
||||
|
||||
// QueryMetadataJSON queries the metadata server and populates the passed in object
|
||||
func QueryMetadataJSON(path string, obj interface{}) error {
|
||||
data, err := queryMetadataBytes(path, "json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return json.Unmarshal(data, obj)
|
||||
}
|
||||
|
||||
// QueryMetadataText queries the metadata server and returns the corresponding text
|
||||
func QueryMetadataText(path string) (string, error) {
|
||||
data, err := queryMetadataBytes(path, "text")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(data), err
|
||||
}
|
||||
|
||||
func queryMetadataBytes(path, format string) ([]byte, error) {
|
||||
client := &http.Client{}
|
||||
|
||||
req, err := http.NewRequest("GET", metadataURL+path, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("Metadata", "True")
|
||||
|
||||
q := req.URL.Query()
|
||||
q.Add("format", format)
|
||||
q.Add("api-version", "2017-04-02")
|
||||
req.URL.RawQuery = q.Encode()
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
return ioutil.ReadAll(resp.Body)
|
||||
}
|
@ -29,6 +29,16 @@ import (
|
||||
|
||||
// NodeAddresses returns the addresses of the specified instance.
|
||||
func (az *Cloud) NodeAddresses(name types.NodeName) ([]v1.NodeAddress, error) {
|
||||
if az.UseInstanceMetadata {
|
||||
text, err := QueryMetadataText("instance/network/interface/0/ipv4/ipAddress/0/privateIpAddress")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return []v1.NodeAddress{
|
||||
{Type: v1.NodeInternalIP, Address: text},
|
||||
{Type: v1.NodeHostName, Address: string(name)},
|
||||
}, nil
|
||||
}
|
||||
ip, err := az.getIPForMachine(name)
|
||||
if err != nil {
|
||||
glog.Errorf("error: az.NodeAddresses, az.getIPForMachine(%s), err=%v", name, err)
|
||||
|
@ -17,7 +17,11 @@ limitations under the License.
|
||||
package azure
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@ -816,3 +820,60 @@ func TestSplitProviderID(t *testing.T) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func TestMetadataParsing(t *testing.T) {
|
||||
data := `
|
||||
{
|
||||
"interface": [
|
||||
{
|
||||
"ipv4": {
|
||||
"ipAddress": [
|
||||
{
|
||||
"privateIpAddress": "10.0.1.4",
|
||||
"publicIpAddress": "X.X.X.X"
|
||||
}
|
||||
],
|
||||
"subnet": [
|
||||
{
|
||||
"address": "10.0.1.0",
|
||||
"prefix": "24"
|
||||
}
|
||||
]
|
||||
},
|
||||
"ipv6": {
|
||||
"ipAddress": [
|
||||
|
||||
]
|
||||
},
|
||||
"macAddress": "002248020E1E"
|
||||
}
|
||||
]
|
||||
}
|
||||
`
|
||||
|
||||
network := NetworkMetadata{}
|
||||
if err := json.Unmarshal([]byte(data), &network); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
ip := network.Interface[0].IPV4.IPAddress[0].PrivateIP
|
||||
if ip != "10.0.1.4" {
|
||||
t.Errorf("Unexpected value: %s, expected 10.0.1.4", ip)
|
||||
}
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintln(w, data)
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
SetMetadataURLForTesting(server.URL)
|
||||
|
||||
networkJSON := NetworkMetadata{}
|
||||
if err := QueryMetadataJSON("/some/path", &networkJSON); err != nil {
|
||||
t.Errorf("Unexpected error: %v", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(network, networkJSON) {
|
||||
t.Errorf("Unexpected inequality:\n%#v\nvs\n%#v", network, networkJSON)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user