30380339 |
package api
import (
"crypto/x509"
"fmt" |
2d02cf55 |
"net"
"net/http" |
970f2c0f |
"strings" |
2d02cf55 |
"time" |
30380339 |
|
83c702b4 |
kclient "k8s.io/kubernetes/pkg/client"
"k8s.io/kubernetes/pkg/client/clientcmd"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util" |
30380339 |
"github.com/openshift/origin/pkg/client" |
86e9e5c0 |
cmdutil "github.com/openshift/origin/pkg/cmd/util" |
30380339 |
)
|
642797f7 |
var (
knownOpenShiftFeatureSet map[string]string
)
func init() {
knownOpenShiftFeatureSet = make(map[string]string, len(KnownOpenShiftFeatures))
for _, feature := range KnownOpenShiftFeatures {
knownOpenShiftFeatureSet[strings.ToLower(feature)] = feature
}
}
// Add extends feature list with given valid items. They are appended
// unless already present.
func (fl *FeatureList) Add(items ...string) error {
unknown := []string{}
toAppend := make([]string, 0, len(items))
for _, item := range items {
feature, exists := knownOpenShiftFeatureSet[strings.ToLower(item)]
if !exists {
unknown = append(unknown, item)
continue
}
if fl.Has(feature) {
continue
}
toAppend = append(toAppend, feature)
}
if len(unknown) > 0 {
return fmt.Errorf("unknown features: %s", strings.Join(unknown, ", "))
}
*fl = append(*fl, toAppend...)
return nil
}
// Delete removes given items from feature list while keeping its original
// order.
func (fl *FeatureList) Delete(items ...string) {
if len(*fl) == 0 || len(items) == 0 {
return
}
toDelete := util.NewStringSet()
for _, item := range items {
toDelete.Insert(strings.ToLower(item))
}
newList := []string{}
for _, item := range *fl {
if !toDelete.Has(strings.ToLower(item)) {
newList = append(newList, item)
}
}
*fl = newList
}
// Has returns true if given feature exists in feature list. The check is
// case-insensitive.
func (fl FeatureList) Has(feature string) bool {
lowerCased := strings.ToLower(feature)
for _, item := range fl {
if strings.ToLower(item) == lowerCased {
return true
}
}
return false
}
|
970f2c0f |
// ParseNamespaceAndName returns back the namespace and name (empty if something goes wrong), for a given string.
// This is useful when pointing to a particular resource inside of our config.
func ParseNamespaceAndName(in string) (string, string, error) {
if len(in) == 0 {
return "", "", nil
}
tokens := strings.Split(in, "/")
if len(tokens) != 2 {
return "", "", fmt.Errorf("expected input in the form <namespace>/<resource-name>, not: %v", in)
}
return tokens[0], tokens[1], nil
}
|
86e9e5c0 |
func RelativizeMasterConfigPaths(config *MasterConfig, base string) error { |
8564fdc7 |
return cmdutil.RelativizePathWithNoBacksteps(GetMasterFileReferences(config), base) |
86e9e5c0 |
}
func ResolveMasterConfigPaths(config *MasterConfig, base string) error {
return cmdutil.ResolvePaths(GetMasterFileReferences(config), base)
}
func GetMasterFileReferences(config *MasterConfig) []*string {
refs := []*string{}
refs = append(refs, &config.ServingInfo.ServerCert.CertFile)
refs = append(refs, &config.ServingInfo.ServerCert.KeyFile)
refs = append(refs, &config.ServingInfo.ClientCA)
refs = append(refs, &config.EtcdClientInfo.ClientCert.CertFile)
refs = append(refs, &config.EtcdClientInfo.ClientCert.KeyFile)
refs = append(refs, &config.EtcdClientInfo.CA)
|
53c7aa34 |
refs = append(refs, &config.KubeletClientInfo.ClientCert.CertFile)
refs = append(refs, &config.KubeletClientInfo.ClientCert.KeyFile)
refs = append(refs, &config.KubeletClientInfo.CA)
|
86e9e5c0 |
if config.EtcdConfig != nil {
refs = append(refs, &config.EtcdConfig.ServingInfo.ServerCert.CertFile)
refs = append(refs, &config.EtcdConfig.ServingInfo.ServerCert.KeyFile)
refs = append(refs, &config.EtcdConfig.ServingInfo.ClientCA) |
53c7aa34 |
refs = append(refs, &config.EtcdConfig.PeerServingInfo.ServerCert.CertFile)
refs = append(refs, &config.EtcdConfig.PeerServingInfo.ServerCert.KeyFile)
refs = append(refs, &config.EtcdConfig.PeerServingInfo.ClientCA)
|
86e9e5c0 |
refs = append(refs, &config.EtcdConfig.StorageDir)
}
if config.OAuthConfig != nil { |
4457e6fd |
if config.OAuthConfig.SessionConfig != nil {
refs = append(refs, &config.OAuthConfig.SessionConfig.SessionSecretsFile)
}
|
130758bb |
for _, identityProvider := range config.OAuthConfig.IdentityProviders {
switch provider := identityProvider.Provider.Object.(type) {
case (*RequestHeaderIdentityProvider):
refs = append(refs, &provider.ClientCA)
case (*HTPasswdPasswordIdentityProvider):
refs = append(refs, &provider.File)
|
f3d621f6 |
case (*LDAPPasswordIdentityProvider):
refs = append(refs, &provider.CA)
|
130758bb |
case (*BasicAuthPasswordIdentityProvider):
refs = append(refs, &provider.RemoteConnectionInfo.CA)
refs = append(refs, &provider.RemoteConnectionInfo.ClientCert.CertFile)
refs = append(refs, &provider.RemoteConnectionInfo.ClientCert.KeyFile)
|
a8407292 |
case (*OpenIDIdentityProvider):
refs = append(refs, &provider.CA)
|
130758bb |
}
} |
86e9e5c0 |
}
if config.AssetConfig != nil {
refs = append(refs, &config.AssetConfig.ServingInfo.ServerCert.CertFile)
refs = append(refs, &config.AssetConfig.ServingInfo.ServerCert.KeyFile)
refs = append(refs, &config.AssetConfig.ServingInfo.ClientCA)
}
|
287c3a51 |
if config.KubernetesMasterConfig != nil {
refs = append(refs, &config.KubernetesMasterConfig.SchedulerConfigFile)
}
|
5b4ee6a4 |
refs = append(refs, &config.ServiceAccountConfig.MasterCA) |
878d37a8 |
refs = append(refs, &config.ServiceAccountConfig.PrivateKeyFile)
for i := range config.ServiceAccountConfig.PublicKeyFiles {
refs = append(refs, &config.ServiceAccountConfig.PublicKeyFiles[i])
}
|
86e9e5c0 |
refs = append(refs, &config.MasterClients.OpenShiftLoopbackKubeConfig) |
da1980d3 |
refs = append(refs, &config.MasterClients.ExternalKubernetesKubeConfig) |
86e9e5c0 |
|
287c3a51 |
refs = append(refs, &config.PolicyConfig.BootstrapPolicyFile)
|
86e9e5c0 |
return refs
}
func RelativizeNodeConfigPaths(config *NodeConfig, base string) error { |
8564fdc7 |
return cmdutil.RelativizePathWithNoBacksteps(GetNodeFileReferences(config), base) |
86e9e5c0 |
}
func ResolveNodeConfigPaths(config *NodeConfig, base string) error {
return cmdutil.ResolvePaths(GetNodeFileReferences(config), base)
}
func GetNodeFileReferences(config *NodeConfig) []*string {
refs := []*string{}
refs = append(refs, &config.ServingInfo.ServerCert.CertFile)
refs = append(refs, &config.ServingInfo.ServerCert.KeyFile)
refs = append(refs, &config.ServingInfo.ClientCA)
refs = append(refs, &config.MasterKubeConfig)
refs = append(refs, &config.VolumeDirectory)
|
d25e310c |
if config.PodManifestConfig != nil {
refs = append(refs, &config.PodManifestConfig.Path)
}
|
86e9e5c0 |
return refs
}
|
bb8a2276 |
// TODO: clients should be copied and instantiated from a common client config, tweaked, then
// given to individual controllers and other infrastructure components. |
30380339 |
func GetKubeClient(kubeConfigFile string) (*kclient.Client, *kclient.Config, error) { |
c087f950 |
loadingRules := &clientcmd.ClientConfigLoadingRules{}
loadingRules.ExplicitPath = kubeConfigFile |
30380339 |
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
kubeConfig, err := loader.ClientConfig()
if err != nil {
return nil, nil, err
} |
ee1f59b0 |
|
bb8a2276 |
// This is an internal client which is shared by most controllers, so boost default QPS
// TODO: this should be configured by the caller, not in this method.
kubeConfig.QPS = 100.0
kubeConfig.Burst = 200 |
ee1f59b0 |
|
2d02cf55 |
kubeConfig.WrapTransport = DefaultClientTransport |
30380339 |
kubeClient, err := kclient.New(kubeConfig)
if err != nil {
return nil, nil, err
}
return kubeClient, kubeConfig, nil
}
|
bb8a2276 |
// TODO: clients should be copied and instantiated from a common client config, tweaked, then
// given to individual controllers and other infrastructure components. |
30380339 |
func GetOpenShiftClient(kubeConfigFile string) (*client.Client, *kclient.Config, error) { |
c087f950 |
loadingRules := &clientcmd.ClientConfigLoadingRules{}
loadingRules.ExplicitPath = kubeConfigFile |
30380339 |
loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
kubeConfig, err := loader.ClientConfig()
if err != nil {
return nil, nil, err
} |
bb8a2276 |
// This is an internal client which is shared by most controllers, so boost default QPS
// TODO: this should be configured by the caller, not in this method.
kubeConfig.QPS = 150.0
kubeConfig.Burst = 300
|
2d02cf55 |
kubeConfig.WrapTransport = DefaultClientTransport |
30380339 |
openshiftClient, err := client.New(kubeConfig)
if err != nil {
return nil, nil, err
}
return openshiftClient, kubeConfig, nil
}
|
2d02cf55 |
// DefaultClientTransport sets defaults for a client Transport that are suitable
// for use by infrastructure components.
func DefaultClientTransport(rt http.RoundTripper) http.RoundTripper {
transport := rt.(*http.Transport) |
bb8a2276 |
// TODO: this should be configured by the caller, not in this method. |
2d02cf55 |
dialer := &net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}
transport.Dial = dialer.Dial
// Hold open more internal idle connections |
bb8a2276 |
// TODO: this should be configured by the caller, not in this method.
transport.MaxIdleConnsPerHost = 100 |
2d02cf55 |
return transport
}
|
30380339 |
func UseTLS(servingInfo ServingInfo) bool {
return len(servingInfo.ServerCert.CertFile) > 0
}
// GetAPIClientCertCAPool returns the cert pool used to validate client certificates to the API server
func GetAPIClientCertCAPool(options MasterConfig) (*x509.CertPool, error) { |
3aa6d379 |
return cmdutil.CertPoolFromFile(options.ServingInfo.ClientCA) |
30380339 |
}
// GetClientCertCAPool returns a cert pool containing all client CAs that could be presented (union of API and OAuth)
func GetClientCertCAPool(options MasterConfig) (*x509.CertPool, error) {
roots := x509.NewCertPool()
// Add CAs for OAuth
certs, err := getOAuthClientCertCAs(options)
if err != nil {
return nil, err
}
for _, root := range certs {
roots.AddCert(root)
}
// Add CAs for API
certs, err = getAPIClientCertCAs(options)
if err != nil {
return nil, err
}
for _, root := range certs {
roots.AddCert(root)
}
return roots, nil
}
// GetAPIServerCertCAPool returns the cert pool containing the roots for the API server cert
func GetAPIServerCertCAPool(options MasterConfig) (*x509.CertPool, error) { |
e00edaae |
if !UseTLS(options.ServingInfo.ServingInfo) { |
41dae4d1 |
return x509.NewCertPool(), nil
}
|
3aa6d379 |
return cmdutil.CertPoolFromFile(options.ServingInfo.ClientCA) |
30380339 |
}
func getOAuthClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) { |
e00edaae |
if !UseTLS(options.ServingInfo.ServingInfo) { |
41dae4d1 |
return nil, nil
}
|
130758bb |
allCerts := []*x509.Certificate{}
if options.OAuthConfig != nil {
for _, identityProvider := range options.OAuthConfig.IdentityProviders {
switch provider := identityProvider.Provider.Object.(type) {
case (*RequestHeaderIdentityProvider):
caFile := provider.ClientCA
if len(caFile) == 0 { |
53c7aa34 |
continue |
130758bb |
} |
3aa6d379 |
certs, err := cmdutil.CertificatesFromFile(caFile) |
130758bb |
if err != nil {
return nil, fmt.Errorf("Error reading %s: %s", caFile, err)
}
allCerts = append(allCerts, certs...)
}
} |
30380339 |
} |
130758bb |
return allCerts, nil |
30380339 |
}
func getAPIClientCertCAs(options MasterConfig) ([]*x509.Certificate, error) { |
e00edaae |
if !UseTLS(options.ServingInfo.ServingInfo) { |
41dae4d1 |
return nil, nil
}
|
3aa6d379 |
return cmdutil.CertificatesFromFile(options.ServingInfo.ClientCA) |
53c7aa34 |
}
func GetKubeletClientConfig(options MasterConfig) *kclient.KubeletConfig {
config := &kclient.KubeletConfig{
Port: options.KubeletClientInfo.Port,
}
if len(options.KubeletClientInfo.CA) > 0 {
config.EnableHttps = true
config.CAFile = options.KubeletClientInfo.CA
}
if len(options.KubeletClientInfo.ClientCert.CertFile) > 0 {
config.EnableHttps = true
config.CertFile = options.KubeletClientInfo.ClientCert.CertFile
config.KeyFile = options.KubeletClientInfo.ClientCert.KeyFile |
30380339 |
}
|
53c7aa34 |
return config |
30380339 |
} |
130758bb |
func IsPasswordAuthenticator(provider IdentityProvider) bool { |
e14c2574 |
switch provider.Provider.Object.(type) { |
130758bb |
case
(*BasicAuthPasswordIdentityProvider),
(*AllowAllPasswordIdentityProvider),
(*DenyAllPasswordIdentityProvider), |
f3d621f6 |
(*HTPasswdPasswordIdentityProvider),
(*LDAPPasswordIdentityProvider): |
130758bb |
return true
}
return false
}
func IsIdentityProviderType(provider runtime.EmbeddedObject) bool {
switch provider.Object.(type) {
case
(*RequestHeaderIdentityProvider),
(*BasicAuthPasswordIdentityProvider),
(*AllowAllPasswordIdentityProvider),
(*DenyAllPasswordIdentityProvider), |
e14c2574 |
(*HTPasswdPasswordIdentityProvider), |
f3d621f6 |
(*LDAPPasswordIdentityProvider), |
a8407292 |
(*OpenIDIdentityProvider), |
e14c2574 |
(*GitHubIdentityProvider),
(*GoogleIdentityProvider): |
130758bb |
return true
}
return false
}
|
e14c2574 |
func IsOAuthIdentityProvider(provider IdentityProvider) bool {
switch provider.Provider.Object.(type) { |
130758bb |
case |
a8407292 |
(*OpenIDIdentityProvider), |
e14c2574 |
(*GitHubIdentityProvider),
(*GoogleIdentityProvider): |
130758bb |
return true
}
return false
} |
26c990fe |
func HasOpenShiftAPILevel(config MasterConfig, apiLevel string) bool {
apiLevelSet := util.NewStringSet(config.APILevels...)
return apiLevelSet.Has(apiLevel)
}
func HasKubernetesAPILevel(config KubernetesMasterConfig, apiLevel string) bool {
apiLevelSet := util.NewStringSet(config.APILevels...)
return apiLevelSet.Has(apiLevel)
} |