| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | // Copyright 2017 The Prometheus 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 openstack | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2017-10-25 12:21:42 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 	"github.com/go-kit/kit/log" | 
					
						
							|  |  |  | 	"github.com/go-kit/kit/log/level" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	"github.com/gophercloud/gophercloud" | 
					
						
							|  |  |  | 	"github.com/gophercloud/gophercloud/openstack" | 
					
						
							|  |  |  | 	"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/floatingips" | 
					
						
							|  |  |  | 	"github.com/gophercloud/gophercloud/openstack/compute/v2/servers" | 
					
						
							|  |  |  | 	"github.com/gophercloud/gophercloud/pagination" | 
					
						
							| 
									
										
										
										
											2019-03-26 07:01:12 +08:00
										 |  |  | 	"github.com/pkg/errors" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	"github.com/prometheus/common/model" | 
					
						
							| 
									
										
										
										
											2020-10-22 17:00:08 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
											  
											
												Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
											
										 
											2017-12-30 04:01:34 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/discovery/targetgroup" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	"github.com/prometheus/prometheus/util/strutil" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	openstackLabelPrefix         = model.MetaLabelPrefix + "openstack_" | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 	openstackLabelAddressPool    = openstackLabelPrefix + "address_pool" | 
					
						
							| 
									
										
										
										
											2019-04-04 17:02:31 +08:00
										 |  |  | 	openstackLabelInstanceFlavor = openstackLabelPrefix + "instance_flavor" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	openstackLabelInstanceID     = openstackLabelPrefix + "instance_id" | 
					
						
							|  |  |  | 	openstackLabelInstanceName   = openstackLabelPrefix + "instance_name" | 
					
						
							|  |  |  | 	openstackLabelInstanceStatus = openstackLabelPrefix + "instance_status" | 
					
						
							|  |  |  | 	openstackLabelPrivateIP      = openstackLabelPrefix + "private_ip" | 
					
						
							| 
									
										
										
										
											2019-04-04 17:02:31 +08:00
										 |  |  | 	openstackLabelProjectID      = openstackLabelPrefix + "project_id" | 
					
						
							|  |  |  | 	openstackLabelPublicIP       = openstackLabelPrefix + "public_ip" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	openstackLabelTagPrefix      = openstackLabelPrefix + "tag_" | 
					
						
							| 
									
										
										
										
											2019-04-04 17:02:31 +08:00
										 |  |  | 	openstackLabelUserID         = openstackLabelPrefix + "user_id" | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // InstanceDiscovery discovers OpenStack instances.
 | 
					
						
							|  |  |  | type InstanceDiscovery struct { | 
					
						
							| 
									
										
										
										
											2020-07-02 22:17:56 +08:00
										 |  |  | 	provider     *gophercloud.ProviderClient | 
					
						
							|  |  |  | 	authOpts     *gophercloud.AuthOptions | 
					
						
							|  |  |  | 	region       string | 
					
						
							|  |  |  | 	logger       log.Logger | 
					
						
							|  |  |  | 	port         int | 
					
						
							|  |  |  | 	allTenants   bool | 
					
						
							|  |  |  | 	availability gophercloud.Availability | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewInstanceDiscovery returns a new instance discovery.
 | 
					
						
							| 
									
										
										
										
											2019-03-25 18:54:22 +08:00
										 |  |  | func newInstanceDiscovery(provider *gophercloud.ProviderClient, opts *gophercloud.AuthOptions, | 
					
						
							| 
									
										
										
										
											2020-07-02 22:17:56 +08:00
										 |  |  | 	port int, region string, allTenants bool, availability gophercloud.Availability, l log.Logger) *InstanceDiscovery { | 
					
						
							| 
									
										
										
										
											2017-09-09 00:34:20 +08:00
										 |  |  | 	if l == nil { | 
					
						
							|  |  |  | 		l = log.NewNopLogger() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-09-24 22:08:42 +08:00
										 |  |  | 	return &InstanceDiscovery{provider: provider, authOpts: opts, | 
					
						
							| 
									
										
										
										
											2020-07-02 22:17:56 +08:00
										 |  |  | 		region: region, port: port, allTenants: allTenants, availability: availability, logger: l} | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | type floatingIPKey struct { | 
					
						
							|  |  |  | 	id    string | 
					
						
							|  |  |  | 	fixed string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 18:54:22 +08:00
										 |  |  | func (i *InstanceDiscovery) refresh(ctx context.Context) ([]*targetgroup.Group, error) { | 
					
						
							| 
									
										
										
										
											2019-03-12 20:53:03 +08:00
										 |  |  | 	i.provider.Context = ctx | 
					
						
							| 
									
										
										
										
											2019-03-25 18:54:22 +08:00
										 |  |  | 	err := openstack.Authenticate(i.provider, *i.authOpts) | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-03-26 07:01:12 +08:00
										 |  |  | 		return nil, errors.Wrap(err, "could not authenticate to OpenStack") | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-07-02 22:17:56 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-09-24 22:08:42 +08:00
										 |  |  | 	client, err := openstack.NewComputeV2(i.provider, gophercloud.EndpointOpts{ | 
					
						
							| 
									
										
										
										
											2020-07-02 22:17:56 +08:00
										 |  |  | 		Region: i.region, Availability: i.availability, | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2019-03-26 07:01:12 +08:00
										 |  |  | 		return nil, errors.Wrap(err, "could not create OpenStack compute session") | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// OpenStack API reference
 | 
					
						
							|  |  |  | 	// https://developer.openstack.org/api-ref/compute/#list-floating-ips
 | 
					
						
							|  |  |  | 	pagerFIP := floatingips.List(client) | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 	floatingIPList := make(map[floatingIPKey]string) | 
					
						
							|  |  |  | 	floatingIPPresent := make(map[string]struct{}) | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	err = pagerFIP.EachPage(func(page pagination.Page) (bool, error) { | 
					
						
							|  |  |  | 		result, err := floatingips.ExtractFloatingIPs(page) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-03-26 07:01:12 +08:00
										 |  |  | 			return false, errors.Wrap(err, "could not extract floatingips") | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		for _, ip := range result { | 
					
						
							|  |  |  | 			// Skip not associated ips
 | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 			if ip.InstanceID == "" || ip.FixedIP == "" { | 
					
						
							|  |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 			floatingIPList[floatingIPKey{id: ip.InstanceID, fixed: ip.FixedIP}] = ip.IP | 
					
						
							|  |  |  | 			floatingIPPresent[ip.IP] = struct{}{} | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return true, nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// OpenStack API reference
 | 
					
						
							|  |  |  | 	// https://developer.openstack.org/api-ref/compute/#list-servers
 | 
					
						
							| 
									
										
										
										
											2018-10-17 20:01:33 +08:00
										 |  |  | 	opts := servers.ListOpts{ | 
					
						
							|  |  |  | 		AllTenants: i.allTenants, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 	pager := servers.List(client, opts) | 
					
						
							| 
									
										
											  
											
												Refactor SD configuration to remove `config` dependency (#3629)
* refactor: move targetGroup struct and CheckOverflow() to their own package
* refactor: move auth and security related structs to a utility package, fix import error in utility package
* refactor: Azure SD, remove SD struct from config
* refactor: DNS SD, remove SD struct from config into dns package
* refactor: ec2 SD, move SD struct from config into the ec2 package
* refactor: file SD, move SD struct from config to file discovery package
* refactor: gce, move SD struct from config to gce discovery package
* refactor: move HTTPClientConfig and URL into util/config, fix import error in httputil
* refactor: consul, move SD struct from config into consul discovery package
* refactor: marathon, move SD struct from config into marathon discovery package
* refactor: triton, move SD struct from config to triton discovery package, fix test
* refactor: zookeeper, move SD structs from config to zookeeper discovery package
* refactor: openstack, remove SD struct from config, move into openstack discovery package
* refactor: kubernetes, move SD struct from config into kubernetes discovery package
* refactor: notifier, use targetgroup package instead of config
* refactor: tests for file, marathon, triton SD - use targetgroup package instead of config.TargetGroup
* refactor: retrieval, use targetgroup package instead of config.TargetGroup
* refactor: storage, use config util package
* refactor: discovery manager, use targetgroup package instead of config.TargetGroup
* refactor: use HTTPClient and TLS config from configUtil instead of config
* refactor: tests, use targetgroup package instead of config.TargetGroup
* refactor: fix tagetgroup.Group pointers that were removed by mistake
* refactor: openstack, kubernetes: drop prefixes
* refactor: remove import aliases forced due to vscode bug
* refactor: move main SD struct out of config into discovery/config
* refactor: rename configUtil to config_util
* refactor: rename yamlUtil to yaml_config
* refactor: kubernetes, remove prefixes
* refactor: move the TargetGroup package to discovery/
* refactor: fix order of imports
											
										 
											2017-12-30 04:01:34 +08:00
										 |  |  | 	tg := &targetgroup.Group{ | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 		Source: fmt.Sprintf("OS_" + i.region), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	err = pager.EachPage(func(page pagination.Page) (bool, error) { | 
					
						
							| 
									
										
										
										
											2019-03-12 20:53:03 +08:00
										 |  |  | 		if ctx.Err() != nil { | 
					
						
							| 
									
										
										
										
											2019-03-26 07:01:12 +08:00
										 |  |  | 			return false, errors.Wrap(ctx.Err(), "could not extract instances") | 
					
						
							| 
									
										
										
										
											2019-03-12 20:53:03 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 		instanceList, err := servers.ExtractServers(page) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2019-03-26 07:01:12 +08:00
										 |  |  | 			return false, errors.Wrap(err, "could not extract instances") | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, s := range instanceList { | 
					
						
							|  |  |  | 			if len(s.Addresses) == 0 { | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 				level.Info(i.logger).Log("msg", "Got no IP address", "instance", s.ID) | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			labels := model.LabelSet{ | 
					
						
							|  |  |  | 				openstackLabelInstanceID:     model.LabelValue(s.ID), | 
					
						
							|  |  |  | 				openstackLabelInstanceStatus: model.LabelValue(s.Status), | 
					
						
							|  |  |  | 				openstackLabelInstanceName:   model.LabelValue(s.Name), | 
					
						
							| 
									
										
										
										
											2019-04-04 17:02:31 +08:00
										 |  |  | 				openstackLabelProjectID:      model.LabelValue(s.TenantID), | 
					
						
							|  |  |  | 				openstackLabelUserID:         model.LabelValue(s.UserID), | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			id, ok := s.Flavor["id"].(string) | 
					
						
							|  |  |  | 			if !ok { | 
					
						
							|  |  |  | 				level.Warn(i.logger).Log("msg", "Invalid type for flavor id, expected string") | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			labels[openstackLabelInstanceFlavor] = model.LabelValue(id) | 
					
						
							|  |  |  | 			for k, v := range s.Metadata { | 
					
						
							|  |  |  | 				name := strutil.SanitizeLabelName(k) | 
					
						
							|  |  |  | 				labels[openstackLabelTagPrefix+model.LabelName(name)] = model.LabelValue(v) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			for pool, address := range s.Addresses { | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 				md, ok := address.([]interface{}) | 
					
						
							|  |  |  | 				if !ok { | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 					level.Warn(i.logger).Log("msg", "Invalid type for address, expected array") | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if len(md) == 0 { | 
					
						
							| 
									
										
										
										
											2017-08-12 02:45:52 +08:00
										 |  |  | 					level.Debug(i.logger).Log("msg", "Got no IP address", "instance", s.ID) | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2018-10-09 23:17:08 +08:00
										 |  |  | 				for _, address := range md { | 
					
						
							|  |  |  | 					md1, ok := address.(map[string]interface{}) | 
					
						
							|  |  |  | 					if !ok { | 
					
						
							|  |  |  | 						level.Warn(i.logger).Log("msg", "Invalid type for address, expected dict") | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					addr, ok := md1["addr"].(string) | 
					
						
							|  |  |  | 					if !ok { | 
					
						
							|  |  |  | 						level.Warn(i.logger).Log("msg", "Invalid type for address, expected string") | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if _, ok := floatingIPPresent[addr]; ok { | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					lbls := make(model.LabelSet, len(labels)) | 
					
						
							|  |  |  | 					for k, v := range labels { | 
					
						
							|  |  |  | 						lbls[k] = v | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					lbls[openstackLabelAddressPool] = model.LabelValue(pool) | 
					
						
							|  |  |  | 					lbls[openstackLabelPrivateIP] = model.LabelValue(addr) | 
					
						
							|  |  |  | 					if val, ok := floatingIPList[floatingIPKey{id: s.ID, fixed: addr}]; ok { | 
					
						
							|  |  |  | 						lbls[openstackLabelPublicIP] = model.LabelValue(val) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					addr = net.JoinHostPort(addr, fmt.Sprintf("%d", i.port)) | 
					
						
							|  |  |  | 					lbls[model.AddressLabel] = model.LabelValue(addr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					tg.Targets = append(tg.Targets, lbls) | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return true, nil | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-25 18:54:22 +08:00
										 |  |  | 	return []*targetgroup.Group{tg}, nil | 
					
						
							| 
									
										
										
										
											2017-08-22 16:16:01 +08:00
										 |  |  | } |