1// Copyright 2016 The Prometheus Authors 2// Licensed under the Apache License, Version 2.0 (the "License"); 3// you may not use this file except in compliance with the License. 4// You may obtain a copy of the License at 5// 6// http://www.apache.org/licenses/LICENSE-2.0 7// 8// Unless required by applicable law or agreed to in writing, software 9// distributed under the License is distributed on an "AS IS" BASIS, 10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11// See the License for the specific language governing permissions and 12// limitations under the License. 13 14package triton 15 16import ( 17 "context" 18 "fmt" 19 "net" 20 "net/http" 21 "net/http/httptest" 22 "net/url" 23 "strconv" 24 "strings" 25 "testing" 26 27 "github.com/prometheus/common/config" 28 "github.com/prometheus/common/model" 29 "github.com/stretchr/testify/require" 30) 31 32var ( 33 conf = SDConfig{ 34 Account: "testAccount", 35 Role: "container", 36 DNSSuffix: "triton.example.com", 37 Endpoint: "127.0.0.1", 38 Port: 443, 39 Version: 1, 40 RefreshInterval: 1, 41 TLSConfig: config.TLSConfig{InsecureSkipVerify: true}, 42 } 43 badconf = SDConfig{ 44 Account: "badTestAccount", 45 Role: "container", 46 DNSSuffix: "bad.triton.example.com", 47 Endpoint: "127.0.0.1", 48 Port: 443, 49 Version: 1, 50 RefreshInterval: 1, 51 TLSConfig: config.TLSConfig{ 52 InsecureSkipVerify: false, 53 KeyFile: "shouldnotexist.key", 54 CAFile: "shouldnotexist.ca", 55 CertFile: "shouldnotexist.cert", 56 }, 57 } 58 groupsconf = SDConfig{ 59 Account: "testAccount", 60 Role: "container", 61 DNSSuffix: "triton.example.com", 62 Endpoint: "127.0.0.1", 63 Groups: []string{"foo", "bar"}, 64 Port: 443, 65 Version: 1, 66 RefreshInterval: 1, 67 TLSConfig: config.TLSConfig{InsecureSkipVerify: true}, 68 } 69 cnconf = SDConfig{ 70 Account: "testAccount", 71 Role: "cn", 72 DNSSuffix: "triton.example.com", 73 Endpoint: "127.0.0.1", 74 Port: 443, 75 Version: 1, 76 RefreshInterval: 1, 77 TLSConfig: config.TLSConfig{InsecureSkipVerify: true}, 78 } 79) 80 81func newTritonDiscovery(c SDConfig) (*Discovery, error) { 82 return New(nil, &c) 83} 84 85func TestTritonSDNew(t *testing.T) { 86 td, err := newTritonDiscovery(conf) 87 require.NoError(t, err) 88 require.NotNil(t, td) 89 require.NotNil(t, td.client) 90 require.NotZero(t, td.interval) 91 require.NotNil(t, td.sdConfig) 92 require.Equal(t, conf.Account, td.sdConfig.Account) 93 require.Equal(t, conf.DNSSuffix, td.sdConfig.DNSSuffix) 94 require.Equal(t, conf.Endpoint, td.sdConfig.Endpoint) 95 require.Equal(t, conf.Port, td.sdConfig.Port) 96} 97 98func TestTritonSDNewBadConfig(t *testing.T) { 99 td, err := newTritonDiscovery(badconf) 100 require.Error(t, err) 101 require.Nil(t, td) 102} 103 104func TestTritonSDNewGroupsConfig(t *testing.T) { 105 td, err := newTritonDiscovery(groupsconf) 106 require.NoError(t, err) 107 require.NotNil(t, td) 108 require.NotNil(t, td.client) 109 require.NotZero(t, td.interval) 110 require.NotNil(t, td.sdConfig) 111 require.Equal(t, groupsconf.Account, td.sdConfig.Account) 112 require.Equal(t, groupsconf.DNSSuffix, td.sdConfig.DNSSuffix) 113 require.Equal(t, groupsconf.Endpoint, td.sdConfig.Endpoint) 114 require.Equal(t, groupsconf.Groups, td.sdConfig.Groups) 115 require.Equal(t, groupsconf.Port, td.sdConfig.Port) 116} 117 118func TestTritonSDNewCNConfig(t *testing.T) { 119 td, err := newTritonDiscovery(cnconf) 120 require.NoError(t, err) 121 require.NotNil(t, td) 122 require.NotNil(t, td.client) 123 require.NotZero(t, td.interval) 124 require.NotZero(t, td.sdConfig) 125 require.Equal(t, cnconf.Role, td.sdConfig.Role) 126 require.Equal(t, cnconf.Account, td.sdConfig.Account) 127 require.Equal(t, cnconf.DNSSuffix, td.sdConfig.DNSSuffix) 128 require.Equal(t, cnconf.Endpoint, td.sdConfig.Endpoint) 129 require.Equal(t, cnconf.Port, td.sdConfig.Port) 130} 131 132func TestTritonSDRefreshNoTargets(t *testing.T) { 133 tgts := testTritonSDRefresh(t, conf, "{\"containers\":[]}") 134 require.Nil(t, tgts) 135} 136 137func TestTritonSDRefreshMultipleTargets(t *testing.T) { 138 var ( 139 dstr = `{"containers":[ 140 { 141 "groups":["foo","bar","baz"], 142 "server_uuid":"44454c4c-5000-104d-8037-b7c04f5a5131", 143 "vm_alias":"server01", 144 "vm_brand":"lx", 145 "vm_image_uuid":"7b27a514-89d7-11e6-bee6-3f96f367bee7", 146 "vm_uuid":"ad466fbf-46a2-4027-9b64-8d3cdb7e9072" 147 }, 148 { 149 "server_uuid":"a5894692-bd32-4ca1-908a-e2dda3c3a5e6", 150 "vm_alias":"server02", 151 "vm_brand":"kvm", 152 "vm_image_uuid":"a5894692-bd32-4ca1-908a-e2dda3c3a5e6", 153 "vm_uuid":"7b27a514-89d7-11e6-bee6-3f96f367bee7" 154 }] 155 }` 156 ) 157 158 tgts := testTritonSDRefresh(t, conf, dstr) 159 require.NotNil(t, tgts) 160 require.Equal(t, 2, len(tgts)) 161} 162 163func TestTritonSDRefreshNoServer(t *testing.T) { 164 var ( 165 td, _ = newTritonDiscovery(conf) 166 ) 167 168 _, err := td.refresh(context.Background()) 169 require.Error(t, err) 170 require.Equal(t, strings.Contains(err.Error(), "an error occurred when requesting targets from the discovery endpoint"), true) 171} 172 173func TestTritonSDRefreshCancelled(t *testing.T) { 174 var ( 175 td, _ = newTritonDiscovery(conf) 176 ) 177 178 ctx, cancel := context.WithCancel(context.Background()) 179 cancel() 180 _, err := td.refresh(ctx) 181 require.Error(t, err) 182 require.Equal(t, strings.Contains(err.Error(), context.Canceled.Error()), true) 183} 184 185func TestTritonSDRefreshCNsUUIDOnly(t *testing.T) { 186 var ( 187 dstr = `{"cns":[ 188 { 189 "server_uuid":"44454c4c-5000-104d-8037-b7c04f5a5131" 190 }, 191 { 192 "server_uuid":"a5894692-bd32-4ca1-908a-e2dda3c3a5e6" 193 }] 194 }` 195 ) 196 197 tgts := testTritonSDRefresh(t, cnconf, dstr) 198 require.NotNil(t, tgts) 199 require.Equal(t, 2, len(tgts)) 200} 201 202func TestTritonSDRefreshCNsWithHostname(t *testing.T) { 203 var ( 204 dstr = `{"cns":[ 205 { 206 "server_uuid":"44454c4c-5000-104d-8037-b7c04f5a5131", 207 "server_hostname": "server01" 208 }, 209 { 210 "server_uuid":"a5894692-bd32-4ca1-908a-e2dda3c3a5e6", 211 "server_hostname": "server02" 212 }] 213 }` 214 ) 215 216 tgts := testTritonSDRefresh(t, cnconf, dstr) 217 require.NotNil(t, tgts) 218 require.Equal(t, 2, len(tgts)) 219} 220 221func testTritonSDRefresh(t *testing.T, c SDConfig, dstr string) []model.LabelSet { 222 var ( 223 td, _ = newTritonDiscovery(c) 224 s = httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 225 fmt.Fprintln(w, dstr) 226 })) 227 ) 228 229 defer s.Close() 230 231 u, err := url.Parse(s.URL) 232 require.NoError(t, err) 233 require.NotNil(t, u) 234 235 host, strport, err := net.SplitHostPort(u.Host) 236 require.NoError(t, err) 237 require.NotEmpty(t, host) 238 require.NotEmpty(t, strport) 239 240 port, err := strconv.Atoi(strport) 241 require.NoError(t, err) 242 require.NotZero(t, port) 243 244 td.sdConfig.Port = port 245 246 tgs, err := td.refresh(context.Background()) 247 require.NoError(t, err) 248 require.Equal(t, 1, len(tgs)) 249 tg := tgs[0] 250 require.NotNil(t, tg) 251 252 return tg.Targets 253} 254