// TODO: Merge this into startMasterOrDie. func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) { etcdClient := NewEtcdClient() etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, testapi.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", ExpAPIPrefix: "/experimental", EnableExp: true, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), }) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) return m, s }
func newEtcd(etcdConfigFile string, etcdServerList util.StringList, interfacesFunc meta.VersionInterfacesFunc, defaultVersion, storageVersion, pathPrefix string) (etcdStorage storage.Interface, err error) { var client tools.EtcdClient if etcdConfigFile != "" { client, err = etcd.NewClientFromFile(etcdConfigFile) if err != nil { return nil, err } } else { etcdClient := etcd.NewClient(etcdServerList) transport := &http.Transport{ Dial: forked.Dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, MaxIdleConnsPerHost: 500, } etcdClient.SetTransport(transport) client = etcdClient } if storageVersion == "" { storageVersion = defaultVersion } return master.NewEtcdStorage(client, interfacesFunc, storageVersion, pathPrefix) }
func newEtcd(etcdConfigFile string, etcdServerList []string, interfacesFunc meta.VersionInterfacesFunc, storageVersion, pathPrefix string) (etcdStorage storage.Interface, err error) { if storageVersion == "" { return etcdStorage, fmt.Errorf("storageVersion is required to create a etcd storage") } var client tools.EtcdClient if etcdConfigFile != "" { client, err = etcd.NewClientFromFile(etcdConfigFile) if err != nil { return nil, err } } else { etcdClient := etcd.NewClient(etcdServerList) transport := &http.Transport{ Dial: forked.Dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, MaxIdleConnsPerHost: 500, } etcdClient.SetTransport(transport) client = etcdClient } etcdStorage, err = master.NewEtcdStorage(client, interfacesFunc, storageVersion, pathPrefix) return etcdStorage, err }
func runAMaster(t *testing.T) (*master.Master, *httptest.Server) { etcdStorage, err := master.NewEtcdStorage(newEtcdClient(), latest.GroupOrDie("").InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } m := master.New(&master.Config{ DatabaseStorage: etcdStorage, KubeletClient: client.FakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), StorageVersions: map[string]string{"": testapi.Default.Version()}, }) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) return m, s }
// startMasterOrDie starts a kubernetes master and an httpserver to handle api requests func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Server, storage.Interface) { var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) var etcdStorage storage.Interface var err error if masterConfig == nil { etcdClient := NewEtcdClient() storageVersions := make(map[string]string) etcdStorage, err = master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, latest.GroupOrDie("").Version, etcdtest.PathPrefix()) storageVersions[""] = latest.GroupOrDie("").Version if err != nil { glog.Fatalf("Failed to create etcd storage for master %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("experimental").InterfacesFor, latest.GroupOrDie("experimental").Version, etcdtest.PathPrefix()) storageVersions["experimental"] = latest.GroupOrDie("experimental").Version if err != nil { glog.Fatalf("Failed to create etcd storage for master %v", err) } masterConfig = &master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, StorageVersions: storageVersions, KubeletClient: client.FakeKubeletClient{}, EnableExp: true, EnableLogsSupport: false, EnableProfiling: true, EnableSwaggerSupport: true, EnableUISupport: false, APIPrefix: "/api", APIGroupPrefix: "/apis", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), } } else { etcdStorage = masterConfig.DatabaseStorage } m = master.New(masterConfig) return m, s, etcdStorage }
func newEtcd(client tools.EtcdClient, interfacesFunc meta.VersionInterfacesFunc, defaultVersion, storageVersion, pathPrefix string) (etcdStorage storage.Storage, err error) { if storageVersion == "" { storageVersion = defaultVersion } master.NewEtcdStorage(client, interfacesFunc, storageVersion, pathPrefix) simpleCodec := conversion.NewSimpleCodec() simpleCodec.AddKnownTypes(®istry.VMTEvent{}) simpleCodec.AddKnownTypes(®istry.VMTEventList{}) return etcdhelper.NewEtcdStorage(client, simpleCodec, pathPrefix), nil }
// TODO: Merge this into startMasterOrDie. func RunAMaster(t *testing.T) (*master.Master, *httptest.Server) { etcdClient := NewEtcdClient() storageVersions := make(map[string]string) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, testapi.Default.GroupAndVersion(), etcdtest.PathPrefix()) storageVersions[""] = testapi.Default.Version() if err != nil { t.Fatalf("unexpected error: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("extensions").InterfacesFor, testapi.Extensions.GroupAndVersion(), etcdtest.PathPrefix()) storageVersions["extensions"] = testapi.Extensions.GroupAndVersion() if err != nil { t.Fatalf("unexpected error: %v", err) } storageDestinations := master.NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdStorage) storageDestinations.AddAPIGroup("extensions", expEtcdStorage) m := master.New(&master.Config{ StorageDestinations: storageDestinations, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableUISupport: false, APIPrefix: "/api", APIGroupPrefix: "/apis", EnableExp: true, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), StorageVersions: storageVersions, }) s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) return m, s }
func newServiceAccountTokenGetter(options configapi.MasterConfig, client *etcdclient.Client) (serviceaccount.ServiceAccountTokenGetter, error) { var tokenGetter serviceaccount.ServiceAccountTokenGetter if options.KubernetesMasterConfig == nil { // When we're running against an external Kubernetes, use the external kubernetes client to validate service account tokens // This prevents infinite auth loops if the privilegedLoopbackKubeClient authenticates using a service account token kubeClient, _, err := configapi.GetKubeClient(options.MasterClients.ExternalKubernetesKubeConfig) if err != nil { return nil, err } tokenGetter = serviceaccount.NewGetterFromClient(kubeClient) } else { // When we're running in-process, go straight to etcd (using the KubernetesStorageVersion/KubernetesStoragePrefix, since service accounts are kubernetes objects) ketcdHelper, err := master.NewEtcdStorage(client, kapilatest.InterfacesFor, options.EtcdStorageConfig.KubernetesStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) } tokenGetter = serviceaccount.NewGetterFromStorageInterface(ketcdHelper) } return tokenGetter, nil }
// startMasterOrDie starts a kubernetes master and an httpserver to handle api requests func startMasterOrDie(masterConfig *master.Config) (*master.Master, *httptest.Server) { var m *master.Master s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) if masterConfig == nil { etcdClient := NewEtcdClient() storageVersions := make(map[string]string) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, latest.GroupOrDie("").GroupVersion, etcdtest.PathPrefix()) storageVersions[""] = latest.GroupOrDie("").GroupVersion if err != nil { glog.Fatalf("Failed to create etcd storage for master %v", err) } expEtcdStorage, err := NewExtensionsEtcdStorage(etcdClient) storageVersions["extensions"] = testapi.Extensions.GroupAndVersion() if err != nil { glog.Fatalf("Failed to create etcd storage for master %v", err) } storageDestinations := master.NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdStorage) storageDestinations.AddAPIGroup("extensions", expEtcdStorage) masterConfig = &master.Config{ StorageDestinations: storageDestinations, StorageVersions: storageVersions, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableProfiling: true, EnableSwaggerSupport: true, EnableUISupport: false, APIPrefix: "/api", APIGroupPrefix: "/apis", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), } } m = master.New(masterConfig) return m, s }
func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*MasterConfig, error) { if options.KubernetesMasterConfig == nil { return nil, errors.New("insufficient information to build KubernetesMasterConfig") } // Connect and setup etcd interfaces etcdClient, err := etcd.EtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } kubeletClientConfig := configapi.GetKubeletClientConfig(options) kubeletClient, err := kclient.NewKubeletClient(kubeletClientConfig) if err != nil { return nil, fmt.Errorf("unable to configure Kubelet client: %v", err) } // in-order list of plug-ins that should intercept admission decisions // TODO: Push node environment support to upstream in future _, portString, err := net.SplitHostPort(options.ServingInfo.BindAddress) if err != nil { return nil, err } port, err := strconv.Atoi(portString) if err != nil { return nil, err } portRange, err := util.ParsePortRange(options.KubernetesMasterConfig.ServicesNodePortRange) if err != nil { return nil, err } podEvictionTimeout, err := time.ParseDuration(options.KubernetesMasterConfig.PodEvictionTimeout) if err != nil { return nil, fmt.Errorf("unable to parse PodEvictionTimeout: %v", err) } server := app.NewAPIServer() server.EventTTL = 2 * time.Hour server.ServiceClusterIPRange = net.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet)) server.ServiceNodePortRange = *portRange server.AdmissionControl = strings.Join(AdmissionPlugins, ",") // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.APIServerArguments, server.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cmserver := cmapp.NewCMServer() cmserver.PodEvictionTimeout = podEvictionTimeout // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.ControllerArguments, cmserver.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cloud, err := cloudprovider.InitCloudProvider(cmserver.CloudProvider, cmserver.CloudConfigFile) if err != nil { return nil, err } if cloud != nil { glog.V(2).Infof("Successfully initialized cloud provider: %q from the config file: %q\n", server.CloudProvider, server.CloudConfigFile) } plugins := []admission.Interface{} for _, pluginName := range strings.Split(server.AdmissionControl, ",") { switch pluginName { case saadmit.PluginName: // we need to set some custom parameters on the service account admission controller, so create that one by hand saAdmitter := saadmit.NewServiceAccount(kubeClient) saAdmitter.LimitSecretReferences = options.ServiceAccountConfig.LimitSecretReferences saAdmitter.Run() plugins = append(plugins, saAdmitter) default: plugin := admission.InitPlugin(pluginName, kubeClient, server.AdmissionControlConfigFile) if plugin != nil { plugins = append(plugins, plugin) } } } admissionController := admission.NewChainHandler(plugins...) var proxyClientCerts []tls.Certificate if len(options.KubernetesMasterConfig.ProxyClientInfo.CertFile) > 0 { clientCert, err := tls.LoadX509KeyPair( options.KubernetesMasterConfig.ProxyClientInfo.CertFile, options.KubernetesMasterConfig.ProxyClientInfo.KeyFile, ) if err != nil { return nil, err } proxyClientCerts = append(proxyClientCerts, clientCert) } // TODO you have to know every APIGroup you're enabling or upstream will panic. It's alternative to panicing is Fataling // It needs a refactor to return errors storageDestinations := master.NewStorageDestinations() // storageVersions is a map from API group to allowed versions that must be a version exposed by the REST API or it breaks. // We need to fix the upstream to stop using the storage version as a preferred api version. storageVersions := map[string]string{} enabledKubeVersions := configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupKube) enabledKubeVersionSet := sets.NewString(enabledKubeVersions...) if len(enabledKubeVersions) > 0 { databaseStorage, err := master.NewEtcdStorage(etcdClient, kapilatest.InterfacesForLegacyGroup, options.EtcdStorageConfig.KubernetesStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) } storageDestinations.AddAPIGroup(configapi.APIGroupKube, databaseStorage) storageVersions[configapi.APIGroupKube] = options.EtcdStorageConfig.KubernetesStorageVersion } enabledExtensionsVersions := configapi.GetEnabledAPIVersionsForGroup(*options.KubernetesMasterConfig, configapi.APIGroupExtensions) if len(enabledExtensionsVersions) > 0 { groupMeta, err := kapilatest.Group(configapi.APIGroupExtensions) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes extensions server storage: %v", err) } // TODO expose storage version options for api groups databaseStorage, err := master.NewEtcdStorage(etcdClient, groupMeta.InterfacesFor, groupMeta.GroupVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes extensions server storage: %v", err) } storageDestinations.AddAPIGroup(configapi.APIGroupExtensions, databaseStorage) storageVersions[configapi.APIGroupExtensions] = enabledExtensionsVersions[0] } m := &master.Config{ PublicAddress: net.ParseIP(options.KubernetesMasterConfig.MasterIP), ReadWritePort: port, StorageDestinations: storageDestinations, StorageVersions: storageVersions, EventTTL: server.EventTTL, //MinRequestTimeout: server.MinRequestTimeout, ServiceClusterIPRange: (*net.IPNet)(&server.ServiceClusterIPRange), ServiceNodePortRange: server.ServiceNodePortRange, RequestContextMapper: requestContextMapper, KubeletClient: kubeletClient, APIPrefix: KubeAPIPrefix, APIGroupPrefix: KubeAPIGroupPrefix, EnableCoreControllers: true, MasterCount: options.KubernetesMasterConfig.MasterCount, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admissionController, EnableExp: len(enabledExtensionsVersions) > 0, DisableV1: !enabledKubeVersionSet.Has("v1"), // Set the TLS options for proxying to pods and services // Proxying to nodes uses the kubeletClient TLS config (so can provide a different cert, and verify the node hostname) ProxyTLSClientConfig: &tls.Config{ // Proxying to pods and services cannot verify hostnames, since they are contacted on randomly allocated IPs InsecureSkipVerify: true, Certificates: proxyClientCerts, }, } // set for consistency -- Origin only used m.EnableExp cmserver.EnableExperimental = m.EnableExp if options.DNSConfig != nil { _, dnsPortStr, err := net.SplitHostPort(options.DNSConfig.BindAddress) if err != nil { return nil, fmt.Errorf("unable to parse DNS bind address %s: %v", options.DNSConfig.BindAddress, err) } dnsPort, err := strconv.Atoi(dnsPortStr) if err != nil { return nil, fmt.Errorf("invalid DNS port: %v", err) } m.ExtraServicePorts = append(m.ExtraServicePorts, kapi.ServicePort{Name: "dns", Port: dnsPort, Protocol: kapi.ProtocolUDP, TargetPort: util.NewIntOrStringFromInt(dnsPort)}, kapi.ServicePort{Name: "dns-tcp", Port: dnsPort, Protocol: kapi.ProtocolTCP, TargetPort: util.NewIntOrStringFromInt(dnsPort)}, ) m.ExtraEndpointPorts = append(m.ExtraEndpointPorts, kapi.EndpointPort{Name: "dns", Port: dnsPort, Protocol: kapi.ProtocolUDP}, kapi.EndpointPort{Name: "dns-tcp", Port: dnsPort, Protocol: kapi.ProtocolTCP}, ) } kmaster := &MasterConfig{ Options: *options.KubernetesMasterConfig, KubeClient: kubeClient, Master: m, ControllerManager: cmserver, CloudProvider: cloud, } return kmaster, nil }
func startComponents(firstManifestURL, secondManifestURL, apiVersion string) (string, string) { // Setup servers := []string{} glog.Infof("Creating etcd client pointing to %v", servers) handler := delegateHandler{} apiServer := httptest.NewServer(&handler) etcdClient := etcd.NewClient(servers) sleep := 4 * time.Second ok := false for i := 0; i < 3; i++ { keys, err := etcdClient.Get("/", false, false) if err != nil { glog.Warningf("Unable to list root etcd keys: %v", err) if i < 2 { time.Sleep(sleep) sleep = sleep * sleep } continue } for _, node := range keys.Node.Nodes { if _, err := etcdClient.Delete(node.Key, true); err != nil { glog.Fatalf("Unable delete key: %v", err) } } ok = true break } if !ok { glog.Fatalf("Failed to connect to etcd") } cl := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: apiVersion}) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Unable to get etcd storage: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, explatest.InterfacesFor, explatest.Version, etcdtest.PathPrefix()) if err != nil { glog.Fatalf("Unable to get etcd storage for experimental: %v", err) } // Master host, port, err := net.SplitHostPort(strings.TrimLeft(apiServer.URL, "http://")) if err != nil { glog.Fatalf("Unable to parse URL '%v': %v", apiServer.URL, err) } portNumber, err := strconv.Atoi(port) if err != nil { glog.Fatalf("Nonnumeric port? %v", err) } publicAddress := net.ParseIP(host) if publicAddress == nil { glog.Fatalf("no public address for %s", host) } // Create a master and install handlers into mux. m := master.New(&master.Config{ DatabaseStorage: etcdStorage, ExpDatabaseStorage: expEtcdStorage, KubeletClient: fakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableProfiling: true, APIPrefix: "/api", ExpAPIPrefix: "/experimental", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), ReadWritePort: portNumber, PublicAddress: publicAddress, CacheTimeout: 2 * time.Second, }) handler.delegate = m.Handler // Scheduler schedulerConfigFactory := factory.NewConfigFactory(cl, nil) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { glog.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}) eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(cl.Events("")) scheduler.New(schedulerConfig).Run() endpoints := endpointcontroller.NewEndpointController(cl) // ensure the service endpoints are sync'd several times within the window that the integration tests wait go endpoints.Run(3, util.NeverStop) controllerManager := replicationControllerPkg.NewReplicationManager(cl, replicationControllerPkg.BurstReplicas) // TODO: Write an integration test for the replication controllers watch. go controllerManager.Run(3, util.NeverStop) nodeController := nodecontroller.NewNodeController(nil, cl, 5*time.Minute, util.NewFakeRateLimiter(), 40*time.Second, 60*time.Second, 5*time.Second, nil, false) nodeController.Run(5 * time.Second) cadvisorInterface := new(cadvisor.Fake) // Kubelet (localhost) testRootDir := makeTempDirOrDie("kubelet_integ_1.", "") configFilePath := makeTempDirOrDie("config", testRootDir) glog.Infof("Using %s as root dir for kubelet #1", testRootDir) fakeDocker1.VersionInfo = docker.Env{"ApiVersion=1.15"} kcfg := kubeletapp.SimpleKubelet(cl, &fakeDocker1, "localhost", testRootDir, firstManifestURL, "127.0.0.1", 10250, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, configFilePath, nil, kubecontainer.FakeOS{}) kubeletapp.RunKubelet(kcfg, nil) // Kubelet (machine) // Create a second kubelet so that the guestbook example's two redis slaves both // have a place they can schedule. testRootDir = makeTempDirOrDie("kubelet_integ_2.", "") glog.Infof("Using %s as root dir for kubelet #2", testRootDir) fakeDocker2.VersionInfo = docker.Env{"ApiVersion=1.15"} kcfg = kubeletapp.SimpleKubelet(cl, &fakeDocker2, "127.0.0.1", testRootDir, secondManifestURL, "127.0.0.1", 10251, api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, "", nil, kubecontainer.FakeOS{}) kubeletapp.RunKubelet(kcfg, nil) return apiServer.URL, configFilePath }
func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*MasterConfig, error) { if options.KubernetesMasterConfig == nil { return nil, errors.New("insufficient information to build KubernetesMasterConfig") } // Connect and setup etcd interfaces etcdClient, err := etcd.EtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } databaseStorage, err := master.NewEtcdStorage(etcdClient, kapilatest.InterfacesFor, options.EtcdStorageConfig.KubernetesStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) } kubeletClientConfig := configapi.GetKubeletClientConfig(options) kubeletClient, err := kclient.NewKubeletClient(kubeletClientConfig) if err != nil { return nil, fmt.Errorf("unable to configure Kubelet client: %v", err) } // in-order list of plug-ins that should intercept admission decisions // TODO: Push node environment support to upstream in future _, portString, err := net.SplitHostPort(options.ServingInfo.BindAddress) if err != nil { return nil, err } port, err := strconv.Atoi(portString) if err != nil { return nil, err } portRange, err := util.ParsePortRange(options.KubernetesMasterConfig.ServicesNodePortRange) if err != nil { return nil, err } podEvictionTimeout, err := time.ParseDuration(options.KubernetesMasterConfig.PodEvictionTimeout) if err != nil { return nil, fmt.Errorf("unable to parse PodEvictionTimeout: %v", err) } server := app.NewAPIServer() server.EventTTL = 2 * time.Hour server.ServiceClusterIPRange = net.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet)) server.ServiceNodePortRange = *portRange server.AdmissionControl = strings.Join(AdmissionPlugins, ",") // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.APIServerArguments, server.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cmserver := cmapp.NewCMServer() cmserver.PodEvictionTimeout = podEvictionTimeout // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.ControllerArguments, cmserver.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cloud, err := cloudprovider.InitCloudProvider(cmserver.CloudProvider, cmserver.CloudConfigFile) if err != nil { return nil, err } plugins := []admission.Interface{} for _, pluginName := range strings.Split(server.AdmissionControl, ",") { switch pluginName { case saadmit.PluginName: // we need to set some custom parameters on the service account admission controller, so create that one by hand saAdmitter := saadmit.NewServiceAccount(kubeClient) saAdmitter.LimitSecretReferences = options.ServiceAccountConfig.LimitSecretReferences saAdmitter.Run() plugins = append(plugins, saAdmitter) default: plugin := admission.InitPlugin(pluginName, kubeClient, server.AdmissionControlConfigFile) if plugin != nil { plugins = append(plugins, plugin) } } } admissionController := admission.NewChainHandler(plugins...) var proxyClientCerts []tls.Certificate if len(options.KubernetesMasterConfig.ProxyClientInfo.CertFile) > 0 { clientCert, err := tls.LoadX509KeyPair( options.KubernetesMasterConfig.ProxyClientInfo.CertFile, options.KubernetesMasterConfig.ProxyClientInfo.KeyFile, ) if err != nil { return nil, err } proxyClientCerts = append(proxyClientCerts, clientCert) } m := &master.Config{ PublicAddress: net.ParseIP(options.KubernetesMasterConfig.MasterIP), ReadWritePort: port, DatabaseStorage: databaseStorage, ExpDatabaseStorage: databaseStorage, EventTTL: server.EventTTL, //MinRequestTimeout: server.MinRequestTimeout, ServiceClusterIPRange: (*net.IPNet)(&server.ServiceClusterIPRange), ServiceNodePortRange: server.ServiceNodePortRange, RequestContextMapper: requestContextMapper, KubeletClient: kubeletClient, APIPrefix: KubeAPIPrefix, EnableCoreControllers: true, MasterCount: options.KubernetesMasterConfig.MasterCount, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admissionController, EnableV1Beta3: configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1beta3"), DisableV1: !configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1"), // Set the TLS options for proxying to pods and services // Proxying to nodes uses the kubeletClient TLS config (so can provide a different cert, and verify the node hostname) ProxyTLSClientConfig: &tls.Config{ // Proxying to pods and services cannot verify hostnames, since they are contacted on randomly allocated IPs InsecureSkipVerify: true, Certificates: proxyClientCerts, }, } kmaster := &MasterConfig{ Options: *options.KubernetesMasterConfig, KubeClient: kubeClient, Master: m, ControllerManager: cmserver, CloudProvider: cloud, } return kmaster, nil }
func TestAuthProxyOnAuthorize(t *testing.T) { testutil.DeleteAllEtcdKeys() // setup etcdClient := testutil.NewEtcdClient() etcdHelper, _ := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) accessTokenStorage := accesstokenetcd.NewREST(etcdHelper) accessTokenRegistry := accesstokenregistry.NewRegistry(accessTokenStorage) authorizeTokenStorage := authorizetokenetcd.NewREST(etcdHelper) authorizeTokenRegistry := authorizetokenregistry.NewRegistry(authorizeTokenStorage) clientStorage := clientetcd.NewREST(etcdHelper) clientRegistry := clientregistry.NewRegistry(clientStorage) clientAuthStorage := clientauthetcd.NewREST(etcdHelper) clientAuthRegistry := clientauthregistry.NewRegistry(clientAuthStorage) userStorage := useretcd.NewREST(etcdHelper) userRegistry := userregistry.NewRegistry(userStorage) identityStorage := identityetcd.NewREST(etcdHelper) identityRegistry := identityregistry.NewRegistry(identityStorage) identityMapper, err := identitymapper.NewIdentityUserMapper(identityRegistry, userRegistry, identitymapper.MappingMethodGenerate) if err != nil { t.Fatal(err) } // this auth request handler is the one that is supposed to recognize information from a front proxy authRequestHandler := headerrequest.NewAuthenticator("front-proxy-test", headerrequest.NewDefaultConfig(), identityMapper) authHandler := &oauthhandlers.EmptyAuth{} storage := registrystorage.New(accessTokenRegistry, authorizeTokenRegistry, clientRegistry, oauthregistry.NewUserConversion()) config := osinserver.NewDefaultServerConfig() grantChecker := oauthregistry.NewClientAuthorizationGrantChecker(clientAuthRegistry) grantHandler := oauthhandlers.NewAutoGrant() server := osinserver.New( config, storage, osinserver.AuthorizeHandlers{ oauthhandlers.NewAuthorizeAuthenticator( authRequestHandler, authHandler, oauthhandlers.EmptyError{}, ), oauthhandlers.NewGrantCheck( grantChecker, grantHandler, oauthhandlers.EmptyError{}, ), }, osinserver.AccessHandlers{ oauthhandlers.NewDenyAccessAuthenticator(), }, osinserver.NewDefaultErrorHandler(), ) mux := http.NewServeMux() server.Install(mux, origin.OpenShiftOAuthAPIPrefix) oauthServer := httptest.NewServer(http.Handler(mux)) defer oauthServer.Close() t.Logf("oauth server is on %v\n", oauthServer.URL) // set up a front proxy guarding the oauth server proxyHTTPHandler := NewBasicAuthChallenger("TestRegistryAndServer", validUsers, NewXRemoteUserProxyingHandler(oauthServer.URL)) proxyServer := httptest.NewServer(proxyHTTPHandler) defer proxyServer.Close() t.Logf("proxy server is on %v\n", proxyServer.URL) // need to prime clients so that we can get back a code. the client must be valid createClient(t, clientRegistry, &oauthapi.OAuthClient{ObjectMeta: kapi.ObjectMeta{Name: "test"}, Secret: "secret", RedirectURIs: []string{oauthServer.URL}}) // our simple URL to get back a code. We want to go through the front proxy rawAuthorizeRequest := proxyServer.URL + origin.OpenShiftOAuthAPIPrefix + "/authorize?response_type=code&client_id=test" // the first request we make to the front proxy should challenge us for authentication info shouldBeAChallengeResponse, err := http.Get(rawAuthorizeRequest) if err != nil { t.Errorf("Unexpected error: %v", err) } if shouldBeAChallengeResponse.StatusCode != http.StatusUnauthorized { t.Errorf("Expected Unauthorized, but got %v", shouldBeAChallengeResponse.StatusCode) } // create an http.Client to make our next request. We need a custom Transport to authenticate us through our front proxy // and a custom CheckRedirect so that we can keep track of the redirect responses we're getting // OAuth requests a few redirects that we don't really care about checking, so this simpler than using a round tripper // and manually handling redirects and setting our auth information every time for the front proxy redirectedUrls := make([]url.URL, 10) httpClient := http.Client{ CheckRedirect: getRedirectMethod(t, &redirectedUrls), Transport: kclient.NewBasicAuthRoundTripper("sanefarmer", "who?", http.DefaultTransport), } // make our authorize request again, but this time our transport has properly set the auth info for the front proxy req, err := http.NewRequest("GET", rawAuthorizeRequest, nil) _, err = httpClient.Do(req) if err != nil { t.Errorf("Unexpected error: %v", err) } // check the last redirect and see if we got a code foundCode := "" if len(redirectedUrls) > 0 { foundCode = redirectedUrls[len(redirectedUrls)-1].Query().Get("code") } if len(foundCode) == 0 { t.Errorf("Did not find code in any redirect: %v", redirectedUrls) } else { t.Logf("Found code %v\n", foundCode) } }
// startServiceAccountTestServer returns a started server // It is the responsibility of the caller to ensure the returned stopFunc is called func startServiceAccountTestServer(t *testing.T) (*client.Client, client.Config, func()) { deleteAllEtcdKeys() // Etcd etcdStorage, err := master.NewEtcdStorage(newEtcdClient(), latest.InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix()) if err != nil { t.Fatalf("unexpected error: %v", err) } // Listener var m *master.Master apiServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { m.Handler.ServeHTTP(w, req) })) // Anonymous client config clientConfig := client.Config{Host: apiServer.URL, Version: testapi.Default.Version()} // Root client rootClient := client.NewOrDie(&client.Config{Host: apiServer.URL, Version: testapi.Default.Version(), BearerToken: rootToken}) // Set up two authenticators: // 1. A token authenticator that maps the rootToken to the "root" user // 2. A ServiceAccountToken authenticator that validates ServiceAccount tokens rootTokenAuth := authenticator.TokenFunc(func(token string) (user.Info, bool, error) { if token == rootToken { return &user.DefaultInfo{rootUserName, "", []string{}}, true, nil } return nil, false, nil }) serviceAccountKey, err := rsa.GenerateKey(rand.Reader, 2048) serviceAccountTokenGetter := serviceaccount.NewGetterFromClient(rootClient) serviceAccountTokenAuth := serviceaccount.JWTTokenAuthenticator([]*rsa.PublicKey{&serviceAccountKey.PublicKey}, true, serviceAccountTokenGetter) authenticator := union.New( bearertoken.New(rootTokenAuth), bearertoken.New(serviceAccountTokenAuth), ) // Set up a stub authorizer: // 1. The "root" user is allowed to do anything // 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace // 3. ServiceAccounts named "rw" are allowed any operation in their namespace authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) error { username := attrs.GetUserName() ns := attrs.GetNamespace() // If the user is "root"... if username == rootUserName { // allow them to do anything return nil } // If the user is a service account... if serviceAccountNamespace, serviceAccountName, err := serviceaccount.SplitUsername(username); err == nil { // Limit them to their own namespace if serviceAccountNamespace == ns { switch serviceAccountName { case readOnlyServiceAccountName: if attrs.IsReadOnly() { return nil } case readWriteServiceAccountName: return nil } } } return fmt.Errorf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()) }) // Set up admission plugin to auto-assign serviceaccounts to pods serviceAccountAdmission := serviceaccountadmission.NewServiceAccount(rootClient) // Create a master and install handlers into mux. m = master.New(&master.Config{ DatabaseStorage: etcdStorage, KubeletClient: client.FakeKubeletClient{}, EnableLogsSupport: false, EnableUISupport: false, EnableIndex: true, APIPrefix: "/api", Authenticator: authenticator, Authorizer: authorizer, AdmissionControl: serviceAccountAdmission, }) // Start the service account and service account token controllers tokenController := serviceaccount.NewTokensController(rootClient, serviceaccount.TokensControllerOptions{TokenGenerator: serviceaccount.JWTTokenGenerator(serviceAccountKey)}) tokenController.Run() serviceAccountController := serviceaccount.NewServiceAccountsController(rootClient, serviceaccount.DefaultServiceAccountsControllerOptions()) serviceAccountController.Run() // Start the admission plugin reflectors serviceAccountAdmission.Run() stop := func() { tokenController.Stop() serviceAccountController.Stop() serviceAccountAdmission.Stop() apiServer.Close() } return rootClient, clientConfig, stop }
func startComponents(firstManifestURL, secondManifestURL string) (string, string) { // Setup servers := []string{} glog.Infof("Creating etcd client pointing to %v", servers) handler := delegateHandler{} apiServer := httptest.NewServer(&handler) etcdClient := etcd.NewClient(servers) sleep := 4 * time.Second ok := false for i := 0; i < 3; i++ { keys, err := etcdClient.Get("/", false, false) if err != nil { glog.Warningf("Unable to list root etcd keys: %v", err) if i < 2 { time.Sleep(sleep) sleep = sleep * sleep } continue } for _, node := range keys.Node.Nodes { if _, err := etcdClient.Delete(node.Key, true); err != nil { glog.Fatalf("Unable delete key: %v", err) } } ok = true break } if !ok { glog.Fatalf("Failed to connect to etcd") } cl := client.NewOrDie(&client.Config{Host: apiServer.URL, GroupVersion: testapi.Default.GroupVersion()}) // TODO: caesarxuchao: hacky way to specify version of Experimental client. // We will fix this by supporting multiple group versions in Config cl.ExtensionsClient = client.NewExtensionsOrDie(&client.Config{Host: apiServer.URL, GroupVersion: testapi.Extensions.GroupVersion()}) storageVersions := make(map[string]string) etcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("").InterfacesFor, testapi.Default.GroupAndVersion(), etcdtest.PathPrefix()) storageVersions[""] = testapi.Default.GroupAndVersion() if err != nil { glog.Fatalf("Unable to get etcd storage: %v", err) } expEtcdStorage, err := master.NewEtcdStorage(etcdClient, latest.GroupOrDie("extensions").InterfacesFor, testapi.Extensions.GroupAndVersion(), etcdtest.PathPrefix()) storageVersions["extensions"] = testapi.Extensions.GroupAndVersion() if err != nil { glog.Fatalf("Unable to get etcd storage for experimental: %v", err) } storageDestinations := master.NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdStorage) storageDestinations.AddAPIGroup("extensions", expEtcdStorage) // Master host, port, err := net.SplitHostPort(strings.TrimLeft(apiServer.URL, "http://")) if err != nil { glog.Fatalf("Unable to parse URL '%v': %v", apiServer.URL, err) } portNumber, err := strconv.Atoi(port) if err != nil { glog.Fatalf("Nonnumeric port? %v", err) } publicAddress := net.ParseIP(host) if publicAddress == nil { glog.Fatalf("No public address for %s", host) } // The caller of master.New should guarantee pulicAddress is properly set hostIP, err := util.ValidPublicAddrForMaster(publicAddress) if err != nil { glog.Fatalf("Unable to find suitable network address.error='%v' . "+ "Fail to get a valid public address for master.", err) } // Create a master and install handlers into mux. m := master.New(&master.Config{ StorageDestinations: storageDestinations, KubeletClient: fakeKubeletClient{}, EnableCoreControllers: true, EnableLogsSupport: false, EnableProfiling: true, APIPrefix: "/api", APIGroupPrefix: "/apis", Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admit.NewAlwaysAdmit(), ReadWritePort: portNumber, PublicAddress: hostIP, CacheTimeout: 2 * time.Second, StorageVersions: storageVersions, }) handler.delegate = m.Handler // Scheduler schedulerConfigFactory := factory.NewConfigFactory(cl, nil) schedulerConfig, err := schedulerConfigFactory.Create() if err != nil { glog.Fatalf("Couldn't create scheduler config: %v", err) } eventBroadcaster := record.NewBroadcaster() schedulerConfig.Recorder = eventBroadcaster.NewRecorder(api.EventSource{Component: "scheduler"}) eventBroadcaster.StartLogging(glog.Infof) eventBroadcaster.StartRecordingToSink(cl.Events("")) scheduler.New(schedulerConfig).Run() // ensure the service endpoints are sync'd several times within the window that the integration tests wait go endpointcontroller.NewEndpointController(cl, controller.NoResyncPeriodFunc). Run(3, util.NeverStop) // TODO: Write an integration test for the replication controllers watch. go replicationcontroller.NewReplicationManager(cl, controller.NoResyncPeriodFunc, replicationcontroller.BurstReplicas). Run(3, util.NeverStop) nodeController := nodecontroller.NewNodeController(nil, cl, 5*time.Minute, util.NewFakeRateLimiter(), util.NewFakeRateLimiter(), 40*time.Second, 60*time.Second, 5*time.Second, nil, false) nodeController.Run(5 * time.Second) cadvisorInterface := new(cadvisor.Fake) // Kubelet (localhost) testRootDir := integration.MakeTempDirOrDie("kubelet_integ_1.", "") configFilePath := integration.MakeTempDirOrDie("config", testRootDir) glog.Infof("Using %s as root dir for kubelet #1", testRootDir) fakeDocker1.VersionInfo = docker.Env{"ApiVersion=1.20"} cm := cm.NewStubContainerManager() kcfg := kubeletapp.SimpleKubelet( cl, fakeDocker1, "localhost", testRootDir, firstManifestURL, "127.0.0.1", 10250, /* KubeletPort */ 0, /* ReadOnlyPort */ api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, configFilePath, nil, kubecontainer.FakeOS{}, 1*time.Second, /* FileCheckFrequency */ 1*time.Second, /* HTTPCheckFrequency */ 10*time.Second, /* MinimumGCAge */ 3*time.Second, /* NodeStatusUpdateFrequency */ 10*time.Second, /* SyncFrequency */ 40, /* MaxPods */ cm) kubeletapp.RunKubelet(kcfg) // Kubelet (machine) // Create a second kubelet so that the guestbook example's two redis slaves both // have a place they can schedule. testRootDir = integration.MakeTempDirOrDie("kubelet_integ_2.", "") glog.Infof("Using %s as root dir for kubelet #2", testRootDir) fakeDocker2.VersionInfo = docker.Env{"ApiVersion=1.20"} kcfg = kubeletapp.SimpleKubelet( cl, fakeDocker2, "127.0.0.1", testRootDir, secondManifestURL, "127.0.0.1", 10251, /* KubeletPort */ 0, /* ReadOnlyPort */ api.NamespaceDefault, empty_dir.ProbeVolumePlugins(), nil, cadvisorInterface, "", nil, kubecontainer.FakeOS{}, 1*time.Second, /* FileCheckFrequency */ 1*time.Second, /* HTTPCheckFrequency */ 10*time.Second, /* MinimumGCAge */ 3*time.Second, /* NodeStatusUpdateFrequency */ 10*time.Second, /* SyncFrequency */ 40, /* MaxPods */ cm) kubeletapp.RunKubelet(kcfg) return apiServer.URL, configFilePath }
func NewTestDeployOpenshift(t *testing.T) *testDeployOpenshift { t.Logf("Starting test openshift") openshift := &testDeployOpenshift{ stop: make(chan struct{}), } openshift.lock.Lock() defer openshift.lock.Unlock() etcdClient := testutil.NewEtcdClient() etcdHelper, _ := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) osMux := http.NewServeMux() openshift.server = httptest.NewServer(osMux) kubeClient := kclient.NewOrDie(&kclient.Config{Host: openshift.server.URL, Version: klatest.DefaultVersionForLegacyGroup()}) osClient := osclient.NewOrDie(&kclient.Config{Host: openshift.server.URL, Version: latest.Version}) openshift.Client = osClient openshift.KubeClient = kubeClient kubeletClient, err := kclient.NewKubeletClient(&kclient.KubeletConfig{Port: 10250}) if err != nil { t.Fatalf("Unable to configure Kubelet client: %v", err) } handlerContainer := master.NewHandlerContainer(osMux) storageDestinations := master.NewStorageDestinations() storageDestinations.AddAPIGroup("", etcdHelper) _ = master.New(&master.Config{ StorageDestinations: storageDestinations, KubeletClient: kubeletClient, APIPrefix: "/api", AdmissionControl: admit.NewAlwaysAdmit(), RestfulContainer: handlerContainer, DisableV1: false, }) interfaces, _ := latest.InterfacesFor(latest.Version) imageStorage := imageetcd.NewREST(etcdHelper) imageRegistry := image.NewRegistry(imageStorage) imageStreamStorage, imageStreamStatus, internalStorage := imagestreametcd.NewREST( etcdHelper, imagestream.DefaultRegistryFunc(func() (string, bool) { return "registry:3000", true }), &fakeSubjectAccessReviewRegistry{}, ) imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatus, internalStorage) imageStreamMappingStorage := imagestreammapping.NewREST(imageRegistry, imageStreamRegistry) imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry) //imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage) imageStreamTagStorage := imagestreamtag.NewREST(imageRegistry, imageStreamRegistry) //imageStreamTagRegistry := imagestreamtag.NewRegistry(imageStreamTagStorage) deployConfigStorage := deployconfigetcd.NewStorage(etcdHelper, kubeClient) deployConfigRegistry := deployconfigregistry.NewRegistry(deployConfigStorage.DeploymentConfig) deployConfigGenerator := &deployconfiggenerator.DeploymentConfigGenerator{ Client: deployconfiggenerator.Client{ DCFn: deployConfigRegistry.GetDeploymentConfig, ISFn: imageStreamRegistry.GetImageStream, LISFn2: imageStreamRegistry.ListImageStreams, }, } storage := map[string]rest.Storage{ "images": imageStorage, "imageStreams": imageStreamStorage, "imageStreamImages": imageStreamImageStorage, "imageStreamMappings": imageStreamMappingStorage, "imageStreamTags": imageStreamTagStorage, "deploymentConfigs": deployConfigStorage.DeploymentConfig, "generateDeploymentConfigs": deployconfiggenerator.NewREST(deployConfigGenerator, latest.Codec), } for k, v := range storage { storage[strings.ToLower(k)] = v } version := &apiserver.APIGroupVersion{ Root: "/oapi", Version: "v1", Storage: storage, Codec: latest.Codec, Mapper: latest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: interfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := version.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } dccFactory := deployconfigcontroller.DeploymentConfigControllerFactory{ Client: osClient, KubeClient: kubeClient, Codec: latest.Codec, } dccFactory.Create().Run() cccFactory := configchangecontroller.DeploymentConfigChangeControllerFactory{ Client: osClient, KubeClient: kubeClient, Codec: latest.Codec, } cccFactory.Create().Run() iccFactory := imagechangecontroller.ImageChangeControllerFactory{ Client: osClient, } iccFactory.Create().Run() return openshift }
func NewTestBuildOpenshift(t *testing.T) *testBuildOpenshift { openshift := &testBuildOpenshift{ stop: make(chan struct{}), } openshift.lock.Lock() defer openshift.lock.Unlock() etcdClient := testutil.NewEtcdClient() etcdHelper, _ := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) osMux := http.NewServeMux() openshift.server = httptest.NewServer(osMux) kubeClient := client.NewOrDie(&client.Config{Host: openshift.server.URL, Version: klatest.Version}) osClient := osclient.NewOrDie(&client.Config{Host: openshift.server.URL, Version: latest.Version}) openshift.Client = osClient openshift.KubeClient = kubeClient kubeletClient, err := kclient.NewKubeletClient(&kclient.KubeletConfig{Port: 10250}) if err != nil { t.Fatalf("Unable to configure Kubelet client: %v", err) } handlerContainer := master.NewHandlerContainer(osMux) _ = master.New(&master.Config{ DatabaseStorage: etcdHelper, KubeletClient: kubeletClient, APIPrefix: "/api", AdmissionControl: admit.NewAlwaysAdmit(), RestfulContainer: handlerContainer, DisableV1: false, }) interfaces, _ := latest.InterfacesFor(latest.Version) buildStorage := buildetcd.NewStorage(etcdHelper) buildRegistry := buildregistry.NewRegistry(buildStorage) buildConfigStorage := buildconfigetcd.NewStorage(etcdHelper) buildConfigRegistry := buildconfigregistry.NewRegistry(buildConfigStorage) imageStorage := imageetcd.NewREST(etcdHelper) imageRegistry := image.NewRegistry(imageStorage) imageStreamStorage, imageStreamStatus := imagestreametcd.NewREST( etcdHelper, imagestream.DefaultRegistryFunc(func() (string, bool) { return "registry:3000", true }), &fakeSubjectAccessReviewRegistry{}, ) imageStreamRegistry := imagestream.NewRegistry(imageStreamStorage, imageStreamStatus) imageStreamImageStorage := imagestreamimage.NewREST(imageRegistry, imageStreamRegistry) imageStreamImageRegistry := imagestreamimage.NewRegistry(imageStreamImageStorage) imageStreamTagStorage := imagestreamtag.NewREST(imageRegistry, imageStreamRegistry) imageStreamTagRegistry := imagestreamtag.NewRegistry(imageStreamTagStorage) buildGenerator := &buildgenerator.BuildGenerator{ Client: buildgenerator.Client{ GetBuildConfigFunc: buildConfigRegistry.GetBuildConfig, UpdateBuildConfigFunc: buildConfigRegistry.UpdateBuildConfig, GetBuildFunc: buildRegistry.GetBuild, CreateBuildFunc: buildRegistry.CreateBuild, GetImageStreamFunc: imageStreamRegistry.GetImageStream, GetImageStreamImageFunc: imageStreamImageRegistry.GetImageStreamImage, GetImageStreamTagFunc: imageStreamTagRegistry.GetImageStreamTag, }, } buildConfigWebHooks := buildconfigregistry.NewWebHookREST( buildConfigRegistry, buildclient.NewOSClientBuildConfigInstantiatorClient(osClient), map[string]webhook.Plugin{ "generic": generic.New(), "github": github.New(), }, ) storage := map[string]rest.Storage{ "builds": buildStorage, "buildConfigs": buildConfigStorage, "buildConfigs/webhooks": buildConfigWebHooks, "builds/clone": buildclonestorage.NewStorage(buildGenerator), "buildConfigs/instantiate": buildinstantiatestorage.NewStorage(buildGenerator), "imageStreams": imageStreamStorage, "imageStreams/status": imageStreamStatus, "imageStreamTags": imageStreamTagStorage, "imageStreamImages": imageStreamImageStorage, } for k, v := range storage { storage[strings.ToLower(k)] = v } version := &apiserver.APIGroupVersion{ Root: "/oapi", Version: "v1", Storage: storage, Codec: latest.Codec, Mapper: latest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: interfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := version.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } bcFactory := buildcontrollerfactory.BuildControllerFactory{ OSClient: osClient, KubeClient: kubeClient, BuildUpdater: buildclient.NewOSClientBuildClient(osClient), DockerBuildStrategy: &buildstrategy.DockerBuildStrategy{ Image: "test-docker-builder", Codec: latest.Codec, }, SourceBuildStrategy: &buildstrategy.SourceBuildStrategy{ Image: "test-sti-builder", TempDirectoryCreator: buildstrategy.STITempDirectoryCreator, Codec: latest.Codec, }, Stop: openshift.stop, } bcFactory.Create().Run() bpcFactory := buildcontrollerfactory.BuildPodControllerFactory{ OSClient: osClient, KubeClient: kubeClient, BuildUpdater: buildclient.NewOSClientBuildClient(osClient), Stop: openshift.stop, } bpcFactory.Create().Run() return openshift }
func NewExtensionsEtcdStorage(client *etcd.Client) (storage.Interface, error) { if client == nil { client = NewEtcdClient() } return master.NewEtcdStorage(client, latest.GroupOrDie("extensions").InterfacesFor, testapi.Extensions.GroupAndVersion(), etcdtest.PathPrefix()) }
func NewEtcdStorage() (storage.Interface, error) { return master.NewEtcdStorage(NewEtcdClient(), latest.GroupOrDie("").InterfacesFor, testapi.Default.Version(), etcdtest.PathPrefix()) }
func TestCLIGetToken(t *testing.T) { testutil.DeleteAllEtcdKeys() // setup etcdClient := testutil.NewEtcdClient() etcdHelper, _ := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, latest.Version, etcdtest.PathPrefix()) accessTokenStorage := accesstokenetcd.NewREST(etcdHelper) accessTokenRegistry := accesstokenregistry.NewRegistry(accessTokenStorage) authorizeTokenStorage := authorizetokenetcd.NewREST(etcdHelper) authorizeTokenRegistry := authorizetokenregistry.NewRegistry(authorizeTokenStorage) clientStorage := clientetcd.NewREST(etcdHelper) clientRegistry := clientregistry.NewRegistry(clientStorage) clientAuthStorage := clientauthetcd.NewREST(etcdHelper) clientAuthRegistry := clientauthregistry.NewRegistry(clientAuthStorage) userStorage := useretcd.NewREST(etcdHelper) userRegistry := userregistry.NewRegistry(userStorage) identityStorage := identityetcd.NewREST(etcdHelper) identityRegistry := identityregistry.NewRegistry(identityStorage) identityMapper := identitymapper.NewAlwaysCreateUserIdentityToUserMapper(identityRegistry, userRegistry) authRequestHandler := basicauthrequest.NewBasicAuthAuthentication(allowanypassword.New("get-token-test", identityMapper), true) authHandler := oauthhandlers.NewUnionAuthenticationHandler( map[string]oauthhandlers.AuthenticationChallenger{"login": passwordchallenger.NewBasicAuthChallenger("openshift")}, nil, nil) storage := registrystorage.New(accessTokenRegistry, authorizeTokenRegistry, clientRegistry, oauthregistry.NewUserConversion()) config := osinserver.NewDefaultServerConfig() grantChecker := oauthregistry.NewClientAuthorizationGrantChecker(clientAuthRegistry) grantHandler := oauthhandlers.NewAutoGrant() server := osinserver.New( config, storage, osinserver.AuthorizeHandlers{ oauthhandlers.NewAuthorizeAuthenticator( authRequestHandler, authHandler, oauthhandlers.EmptyError{}, ), oauthhandlers.NewGrantCheck( grantChecker, grantHandler, oauthhandlers.EmptyError{}, ), }, osinserver.AccessHandlers{ oauthhandlers.NewDenyAccessAuthenticator(), }, osinserver.NewDefaultErrorHandler(), ) mux := http.NewServeMux() server.Install(mux, origin.OpenShiftOAuthAPIPrefix) oauthServer := httptest.NewServer(http.Handler(mux)) defer oauthServer.Close() t.Logf("oauth server is on %v\n", oauthServer.URL) // create the default oauth clients with redirects to our server origin.CreateOrUpdateDefaultOAuthClients(oauthServer.URL, []string{oauthServer.URL}, clientRegistry) flags := pflag.NewFlagSet("test-flags", pflag.ContinueOnError) clientCfg := clientcmd.NewConfig() clientCfg.Bind(flags) flags.Parse(strings.Split("--master="+oauthServer.URL, " ")) reader := bytes.NewBufferString("user\npass") accessToken, err := tokencmd.RequestToken(clientCfg.OpenShiftConfig(), reader, "", "") if err != nil { t.Errorf("Unexpected error: %v", err) } if len(accessToken) == 0 { t.Error("Expected accessToken, but did not get one") } // lets see if this access token is any good token, err := accessTokenRegistry.GetAccessToken(kapi.NewContext(), accessToken) if err != nil { t.Errorf("Unexpected error: %v", err) } if token.UserName != "user" { t.Errorf("Expected token for \"user\", but got: %#v", token) } }
// TestProjectIsNamespace verifies that a project is a namespace, and a namespace is a project func TestProjectIsNamespace(t *testing.T) { testutil.DeleteAllEtcdKeys() etcdClient := testutil.NewEtcdClient() etcdHelper, err := master.NewEtcdStorage(etcdClient, latest.InterfacesFor, "v1", etcdtest.PathPrefix()) if err != nil { t.Fatalf("Unexpected error: %v", err) } // create a kube and its client kubeInterfaces, _ := klatest.InterfacesFor(klatest.Version) namespaceStorage, _, _ := namespaceetcd.NewStorage(etcdHelper) kubeStorage := map[string]rest.Storage{ "namespaces": namespaceStorage, } osMux := http.NewServeMux() server := httptest.NewServer(osMux) defer server.Close() handlerContainer := master.NewHandlerContainer(osMux) version := &apiserver.APIGroupVersion{ Root: "/api", Version: "v1beta3", Storage: kubeStorage, Codec: kv1beta3.Codec, Mapper: klatest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: kubeInterfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := version.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } kubeClient, err := kclient.New(&kclient.Config{Host: server.URL, Version: "v1beta3"}) if err != nil { t.Fatalf("Unexpected error: %v", err) } // create an origin originInterfaces, _ := latest.InterfacesFor(latest.Version) originStorage := map[string]rest.Storage{ "projects": projectregistry.NewREST(kubeClient.Namespaces(), nil), } osVersion := &apiserver.APIGroupVersion{ Root: "/oapi", Version: "v1", Storage: originStorage, Codec: latest.Codec, Mapper: latest.RESTMapper, Creater: kapi.Scheme, Typer: kapi.Scheme, Convertor: kapi.Scheme, Linker: originInterfaces.MetadataAccessor, Admit: admit.NewAlwaysAdmit(), Context: kapi.NewRequestContextMapper(), } if err := osVersion.InstallREST(handlerContainer); err != nil { t.Fatalf("unable to install REST: %v", err) } originClient, err := client.New(&kclient.Config{Host: server.URL}) if err != nil { t.Fatalf("unexpected error: %v", err) } // create a namespace namespace := &kapi.Namespace{ ObjectMeta: kapi.ObjectMeta{Name: "integration-test"}, } namespaceResult, err := kubeClient.Namespaces().Create(namespace) if err != nil { t.Fatalf("unexpected error: %v", err) } // now try to get the project with the same name and ensure it is our namespace project, err := originClient.Projects().Get(namespaceResult.Name) if err != nil { t.Fatalf("unexpected error: %v", err) } if project.Name != namespace.Name { t.Fatalf("Project name did not match namespace name, project %v, namespace %v", project.Name, namespace.Name) } // now create a project project = &projectapi.Project{ ObjectMeta: kapi.ObjectMeta{ Name: "new-project", Annotations: map[string]string{ "openshift.io/display-name": "Hello World", "openshift.io/node-selector": "env=test", }, }, } projectResult, err := originClient.Projects().Create(project) if err != nil { t.Fatalf("unexpected error: %v", err) } // now get the namespace for that project namespace, err = kubeClient.Namespaces().Get(projectResult.Name) if err != nil { t.Fatalf("unexpected error: %v", err) } if project.Name != namespace.Name { t.Fatalf("Project name did not match namespace name, project %v, namespace %v", project.Name, namespace.Name) } if project.Annotations["openshift.io/display-name"] != namespace.Annotations["openshift.io/display-name"] { t.Fatalf("Project display name did not match namespace annotation, project %v, namespace %v", project.Annotations["openshift.io/display-name"], namespace.Annotations["openshift.io/display-name"]) } if project.Annotations["openshift.io/node-selector"] != namespace.Annotations["openshift.io/node-selector"] { t.Fatalf("Project node selector did not match namespace node selector, project %v, namespace %v", project.Annotations["openshift.io/node-selector"], namespace.Annotations["openshift.io/node-selector"]) } }
func BuildKubernetesMasterConfig(options configapi.MasterConfig, requestContextMapper kapi.RequestContextMapper, kubeClient *kclient.Client) (*MasterConfig, error) { if options.KubernetesMasterConfig == nil { return nil, errors.New("insufficient information to build KubernetesMasterConfig") } // Connect and setup etcd interfaces etcdClient, err := etcd.GetAndTestEtcdClient(options.EtcdClientInfo) if err != nil { return nil, err } databaseStorage, err := master.NewEtcdStorage(etcdClient, kapilatest.InterfacesFor, options.EtcdStorageConfig.KubernetesStorageVersion, options.EtcdStorageConfig.KubernetesStoragePrefix) if err != nil { return nil, fmt.Errorf("Error setting up Kubernetes server storage: %v", err) } kubeletClientConfig := configapi.GetKubeletClientConfig(options) kubeletClient, err := kclient.NewKubeletClient(kubeletClientConfig) if err != nil { return nil, fmt.Errorf("unable to configure Kubelet client: %v", err) } // in-order list of plug-ins that should intercept admission decisions // TODO: Push node environment support to upstream in future _, portString, err := net.SplitHostPort(options.ServingInfo.BindAddress) if err != nil { return nil, err } port, err := strconv.Atoi(portString) if err != nil { return nil, err } portRange, err := util.ParsePortRange(options.KubernetesMasterConfig.ServicesNodePortRange) if err != nil { return nil, err } podEvictionTimeout, err := time.ParseDuration(options.KubernetesMasterConfig.PodEvictionTimeout) if err != nil { return nil, fmt.Errorf("unable to parse PodEvictionTimeout: %v", err) } server := app.NewAPIServer() server.EventTTL = 2 * time.Hour server.ServiceClusterIPRange = util.IPNet(flagtypes.DefaultIPNet(options.KubernetesMasterConfig.ServicesSubnet)) server.ServiceNodePortRange = *portRange server.AdmissionControl = strings.Join([]string{ "NamespaceExists", "NamespaceLifecycle", "OriginPodNodeEnvironment", "LimitRanger", "ServiceAccount", "SecurityContextConstraint", "ResourceQuota", }, ",") // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.APIServerArguments, server.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cmserver := cmapp.NewCMServer() cmserver.PodEvictionTimeout = podEvictionTimeout // resolve extended arguments // TODO: this should be done in config validation (along with the above) so we can provide // proper errors if err := cmdflags.Resolve(options.KubernetesMasterConfig.ControllerArguments, cmserver.AddFlags); len(err) > 0 { return nil, kerrors.NewAggregate(err) } cloud, err := cloudprovider.InitCloudProvider(cmserver.CloudProvider, cmserver.CloudConfigFile) if err != nil { return nil, err } admissionController := admission.NewFromPlugins(kubeClient, strings.Split(server.AdmissionControl, ","), server.AdmissionControlConfigFile) m := &master.Config{ PublicAddress: net.ParseIP(options.KubernetesMasterConfig.MasterIP), ReadWritePort: port, DatabaseStorage: databaseStorage, ExpDatabaseStorage: databaseStorage, EventTTL: server.EventTTL, //MinRequestTimeout: server.MinRequestTimeout, ServiceClusterIPRange: (*net.IPNet)(&server.ServiceClusterIPRange), ServiceNodePortRange: server.ServiceNodePortRange, RequestContextMapper: requestContextMapper, KubeletClient: kubeletClient, APIPrefix: KubeAPIPrefix, EnableCoreControllers: true, MasterCount: options.KubernetesMasterConfig.MasterCount, Authorizer: apiserver.NewAlwaysAllowAuthorizer(), AdmissionControl: admissionController, EnableV1Beta3: configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1beta3"), DisableV1: !configapi.HasKubernetesAPILevel(*options.KubernetesMasterConfig, "v1"), } kmaster := &MasterConfig{ Options: *options.KubernetesMasterConfig, KubeClient: kubeClient, Master: m, ControllerManager: cmserver, CloudProvider: cloud, } return kmaster, nil }