func init() { kubeTestAPI := os.Getenv("KUBE_TEST_API") if kubeTestAPI != "" { testGroupVersions := strings.Split(kubeTestAPI, ",") for _, gvString := range testGroupVersions { groupVersion := unversioned.ParseGroupVersionOrDie(gvString) Groups[groupVersion.Group] = TestGroup{ externalGroupVersion: groupVersion, internalGroupVersion: unversioned.GroupVersion{Group: groupVersion.Group}, } } } if _, ok := Groups[api.SchemeGroupVersion.Group]; !ok { Groups[api.SchemeGroupVersion.Group] = TestGroup{ externalGroupVersion: unversioned.GroupVersion{Group: api.SchemeGroupVersion.Group, Version: latest.GroupOrDie(api.SchemeGroupVersion.Group).GroupVersion.Version}, internalGroupVersion: api.SchemeGroupVersion, } } if _, ok := Groups[extensions.SchemeGroupVersion.Group]; !ok { Groups[extensions.SchemeGroupVersion.Group] = TestGroup{ externalGroupVersion: unversioned.GroupVersion{Group: extensions.SchemeGroupVersion.Group, Version: latest.GroupOrDie(extensions.SchemeGroupVersion.Group).GroupVersion.Version}, internalGroupVersion: extensions.SchemeGroupVersion, } } Default = Groups[api.SchemeGroupVersion.Group] Extensions = Groups[extensions.SchemeGroupVersion.Group] }
func (m *Master) thirdpartyapi(group, kind, version string) *apiserver.APIGroupVersion { resourceStorage := thirdpartyresourcedataetcd.NewREST(m.thirdPartyStorage, generic.UndecoratedStorage, group, kind) apiRoot := makeThirdPartyPath("") storage := map[string]rest.Storage{ strings.ToLower(kind) + "s": resourceStorage, } serverGroupVersion := unversioned.ParseGroupVersionOrDie(latest.GroupOrDie("").GroupVersion) return &apiserver.APIGroupVersion{ Root: apiRoot, GroupVersion: unversioned.GroupVersion{Group: group, Version: version}, RequestInfoResolver: m.newRequestInfoResolver(), Creater: thirdpartyresourcedata.NewObjectCreator(group, version, api.Scheme), Convertor: api.Scheme, Typer: api.Scheme, Mapper: thirdpartyresourcedata.NewMapper(latest.GroupOrDie("extensions").RESTMapper, kind, version, group), Codec: thirdpartyresourcedata.NewCodec(latest.GroupOrDie("extensions").Codec, kind), Linker: latest.GroupOrDie("extensions").SelfLinker, Storage: storage, ServerGroupVersion: &serverGroupVersion, Context: m.requestContextMapper, MinRequestTimeout: m.minRequestTimeout, } }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) flag.Parse() var funcOut io.Writer if *functionDest == "-" { funcOut = os.Stdout } else { file, err := os.Create(*functionDest) if err != nil { glog.Fatalf("Couldn't open %v: %v", *functionDest, err) } defer file.Close() funcOut = file } data := new(bytes.Buffer) gv := unversioned.ParseGroupVersionOrDie(*groupVersion) _, err := data.WriteString(fmt.Sprintf("package %v\n", gv.Version)) if err != nil { glog.Fatalf("Error while writing package line: %v", err) } versionPath := pkgPath(gv.Group, gv.Version) generator := kruntime.NewConversionGenerator(api.Scheme.Raw(), versionPath) apiShort := generator.AddImport(path.Join(pkgBase, "api")) generator.AddImport(path.Join(pkgBase, "api/resource")) // TODO(wojtek-t): Change the overwrites to a flag. generator.OverwritePackage(gv.Version, "") for _, knownType := range api.Scheme.KnownTypes(gv) { if knownType.PkgPath() != versionPath { continue } if err := generator.GenerateConversionsForType(gv, knownType); err != nil { glog.Errorf("Error while generating conversion functions for %v: %v", knownType, err) } } generator.RepackImports(sets.NewString()) if err := generator.WriteImports(data); err != nil { glog.Fatalf("Error while writing imports: %v", err) } if err := generator.WriteConversionFunctions(data); err != nil { glog.Fatalf("Error while writing conversion functions: %v", err) } if err := generator.RegisterConversionFunctions(data, fmt.Sprintf("%s.Scheme", apiShort)); err != nil { glog.Fatalf("Error while writing conversion functions: %v", err) } b, err := imports.Process("", data.Bytes(), nil) if err != nil { glog.Fatalf("Error while update imports: %v", err) } if _, err := funcOut.Write(b); err != nil { glog.Fatalf("Error while writing out the resulting file: %v", err) } }
func (m *DefaultRESTMapper) Add(scope RESTScope, kind string, gvString string, mixedCase bool) { gv := unversioned.ParseGroupVersionOrDie(gvString) plural, singular := KindToResource(kind, mixedCase) m.plurals[singular] = plural m.singulars[plural] = singular meta := typeMeta{APIVersion: gv.String(), Kind: kind} _, ok1 := m.mapping[plural] _, ok2 := m.mapping[strings.ToLower(plural)] if !ok1 && !ok2 { m.mapping[plural] = meta m.mapping[singular] = meta if strings.ToLower(plural) != plural { m.mapping[strings.ToLower(plural)] = meta m.mapping[strings.ToLower(singular)] = meta } } m.reverse[meta] = plural m.scopes[meta] = scope }
// NewDefaultRESTMapper initializes a mapping between Kind and APIVersion // to a resource name and back based on the objects in a runtime.Scheme // and the Kubernetes API conventions. Takes a group name, a priority list of the versions // to search when an object has no default version (set empty to return an error), // and a function that retrieves the correct codec and metadata for a given version. // TODO remove group when this API is fixed. It is no longer used. // The external API for a RESTMapper is cross-version and this is currently called using // group/version tuples. In the end, the structure may be easier to understand with // a GroupRESTMapper and CrossGroupRESTMapper, but for now, this one is constructed and // used a CrossGroupRESTMapper. func NewDefaultRESTMapper(group string, gvStrings []string, f VersionInterfacesFunc) *DefaultRESTMapper { mapping := make(map[string]typeMeta) reverse := make(map[typeMeta]string) scopes := make(map[typeMeta]RESTScope) plurals := make(map[string]string) singulars := make(map[string]string) // TODO: verify name mappings work correctly when versions differ gvs := []unversioned.GroupVersion{} for _, gvString := range gvStrings { gvs = append(gvs, unversioned.ParseGroupVersionOrDie(gvString)) } return &DefaultRESTMapper{ mapping: mapping, reverse: reverse, scopes: scopes, groupVersions: gvs, plurals: plurals, singulars: singulars, interfacesFunc: f, } }
// UpdateResource returns a function that will handle a resource update func UpdateResource(r rest.Updater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { w := res.ResponseWriter // TODO: we either want to remove timeout or document it (if we document, move timeout out of this function and declare it in api_installer) timeout := parseTimeout(req.Request.URL.Query().Get("timeout")) namespace, name, err := scope.Namer.Name(req) if err != nil { errorJSON(err, scope.Codec, w) return } ctx := scope.ContextFunc(req) ctx = api.WithNamespace(ctx, namespace) body, err := readBody(req.Request) if err != nil { errorJSON(err, scope.Codec, w) return } obj := r.New() if err := scope.Codec.DecodeIntoWithSpecifiedVersionKind(body, obj, unversioned.ParseGroupVersionOrDie(scope.APIVersion).WithKind(scope.Kind)); err != nil { err = transformDecodeError(typer, err, obj, body) errorJSON(err, scope.Codec, w) return } if err := checkName(obj, name, namespace, scope.Namer); err != nil { errorJSON(err, scope.Codec, w) return } if admit != nil && admit.Handles(admission.Update) { userInfo, _ := api.UserFrom(ctx) err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Update, userInfo)) if err != nil { errorJSON(err, scope.Codec, w) return } } wasCreated := false result, err := finishRequest(timeout, func() (runtime.Object, error) { obj, created, err := r.Update(ctx, obj) wasCreated = created return obj, err }) if err != nil { errorJSON(err, scope.Codec, w) return } if err := setSelfLink(result, req, scope.Namer); err != nil { errorJSON(err, scope.Codec, w) return } status := http.StatusOK if wasCreated { status = http.StatusCreated } writeJSON(status, scope.Codec, result, w, isPrettyPrint(req.Request)) } }
func createHandler(r rest.NamedCreater, scope RequestScope, typer runtime.ObjectTyper, admit admission.Interface, includeName bool) restful.RouteFunction { return func(req *restful.Request, res *restful.Response) { w := res.ResponseWriter // TODO: we either want to remove timeout or document it (if we document, move timeout out of this function and declare it in api_installer) timeout := parseTimeout(req.Request.URL.Query().Get("timeout")) var ( namespace, name string err error ) if includeName { namespace, name, err = scope.Namer.Name(req) } else { namespace, err = scope.Namer.Namespace(req) } if err != nil { errorJSON(err, scope.Codec, w) return } ctx := scope.ContextFunc(req) ctx = api.WithNamespace(ctx, namespace) body, err := readBody(req.Request) if err != nil { errorJSON(err, scope.Codec, w) return } obj := r.New() // TODO this cleans up with proper typing if err := scope.Codec.DecodeIntoWithSpecifiedVersionKind(body, obj, unversioned.ParseGroupVersionOrDie(scope.APIVersion).WithKind(scope.Kind)); err != nil { err = transformDecodeError(typer, err, obj, body) errorJSON(err, scope.Codec, w) return } if admit != nil && admit.Handles(admission.Create) { userInfo, _ := api.UserFrom(ctx) err = admit.Admit(admission.NewAttributesRecord(obj, scope.Kind, namespace, name, scope.Resource, scope.Subresource, admission.Create, userInfo)) if err != nil { errorJSON(err, scope.Codec, w) return } } result, err := finishRequest(timeout, func() (runtime.Object, error) { out, err := r.Create(ctx, name, obj) if status, ok := out.(*unversioned.Status); ok && err == nil && status.Code == 0 { status.Code = http.StatusCreated } return out, err }) if err != nil { errorJSON(err, scope.Codec, w) return } if err := setSelfLink(result, req, scope.Namer); err != nil { errorJSON(err, scope.Codec, w) return } write(http.StatusCreated, scope.APIVersion, scope.Codec, result, w, req.Request) } }
// experimental returns the resources and codec for the experimental api func (m *Master) experimental(c *Config) *apiserver.APIGroupVersion { // All resources except these are disabled by default. enabledResources := sets.NewString("jobs", "horizontalpodautoscalers", "ingresses") resourceOverrides := m.apiGroupVersionOverrides["extensions/v1beta1"].ResourceOverrides isEnabled := func(resource string) bool { // Check if the resource has been overriden. enabled, ok := resourceOverrides[resource] if !ok { return enabledResources.Has(resource) } return enabled } storageDecorator := c.storageDecorator() dbClient := func(resource string) storage.Interface { return c.StorageDestinations.get("extensions", resource) } storage := map[string]rest.Storage{} if isEnabled("horizontalpodautoscalers") { autoscalerStorage, autoscalerStatusStorage := horizontalpodautoscaleretcd.NewREST(dbClient("horizontalpodautoscalers"), storageDecorator) storage["horizontalpodautoscalers"] = autoscalerStorage storage["horizontalpodautoscalers/status"] = autoscalerStatusStorage controllerStorage := expcontrolleretcd.NewStorage(c.StorageDestinations.get("", "replicationControllers"), storageDecorator) storage["replicationcontrollers"] = controllerStorage.ReplicationController storage["replicationcontrollers/scale"] = controllerStorage.Scale } if isEnabled("thirdpartyresources") { thirdPartyResourceStorage := thirdpartyresourceetcd.NewREST(dbClient("thirdpartyresources"), storageDecorator) thirdPartyControl := ThirdPartyController{ master: m, thirdPartyResourceRegistry: thirdPartyResourceStorage, } go func() { util.Forever(func() { if err := thirdPartyControl.SyncResources(); err != nil { glog.Warningf("third party resource sync failed: %v", err) } }, 10*time.Second) }() storage["thirdpartyresources"] = thirdPartyResourceStorage } if isEnabled("daemonsets") { daemonSetStorage, daemonSetStatusStorage := daemonetcd.NewREST(dbClient("daemonsets"), storageDecorator) storage["daemonsets"] = daemonSetStorage storage["daemonsets/status"] = daemonSetStatusStorage } if isEnabled("deployments") { deploymentStorage := deploymentetcd.NewStorage(dbClient("deployments"), storageDecorator) storage["deployments"] = deploymentStorage.Deployment storage["deployments/status"] = deploymentStorage.Status storage["deployments/scale"] = deploymentStorage.Scale } if isEnabled("jobs") { jobStorage, jobStatusStorage := jobetcd.NewREST(dbClient("jobs"), storageDecorator) storage["jobs"] = jobStorage storage["jobs/status"] = jobStatusStorage } if isEnabled("ingresses") { ingressStorage, ingressStatusStorage := ingressetcd.NewREST(dbClient("ingresses"), storageDecorator) storage["ingresses"] = ingressStorage storage["ingresses/status"] = ingressStatusStorage } extensionsGroup := latest.GroupOrDie("extensions") serverGroupVersion := unversioned.ParseGroupVersionOrDie(latest.GroupOrDie("").GroupVersion) return &apiserver.APIGroupVersion{ Root: m.apiGroupPrefix, RequestInfoResolver: m.newRequestInfoResolver(), Creater: api.Scheme, Convertor: api.Scheme, Typer: api.Scheme, Mapper: extensionsGroup.RESTMapper, Codec: extensionsGroup.Codec, Linker: extensionsGroup.SelfLinker, Storage: storage, GroupVersion: unversioned.ParseGroupVersionOrDie(extensionsGroup.GroupVersion), ServerGroupVersion: &serverGroupVersion, Admit: m.admissionControl, Context: m.requestContextMapper, MinRequestTimeout: m.minRequestTimeout, } }
func main() { runtime.GOMAXPROCS(runtime.NumCPU()) flag.Parse() var funcOut io.Writer if *functionDest == "-" { funcOut = os.Stdout } else { file, err := os.Create(*functionDest) if err != nil { glog.Fatalf("Couldn't open %v: %v", *functionDest, err) } defer file.Close() funcOut = file } data := new(bytes.Buffer) gv := unversioned.ParseGroupVersionOrDie(*groupVersion) registerTo := destScheme(gv) var pkgname string if gv.Group == "" { // the internal version of v1 is registered in package api pkgname = "api" } else { pkgname = gv.Group } if len(gv.Version) != 0 { pkgname = gv.Version } _, err := data.WriteString(fmt.Sprintf("package %s\n", pkgname)) if err != nil { glog.Fatalf("Error while writing package line: %v", err) } versionPath := pkgPath(gv.Group, gv.Version) generator := kruntime.NewDeepCopyGenerator(api.Scheme.Raw(), versionPath, sets.NewString("k8s.io/kubernetes")) generator.AddImport(path.Join(pkgBase, "api")) if len(*overwrites) > 0 { for _, overwrite := range strings.Split(*overwrites, ",") { if !strings.Contains(overwrite, "=") { glog.Fatalf("Invalid overwrite syntax: %s", overwrite) } vals := strings.Split(overwrite, "=") generator.OverwritePackage(vals[0], vals[1]) } } for _, knownType := range api.Scheme.KnownTypes(gv) { if knownType.PkgPath() != versionPath { continue } if err := generator.AddType(knownType); err != nil { glog.Errorf("Error while generating deep copy functions for %v: %v", knownType, err) } } generator.RepackImports() if err := generator.WriteImports(data); err != nil { glog.Fatalf("Error while writing imports: %v", err) } if err := generator.WriteDeepCopyFunctions(data); err != nil { glog.Fatalf("Error while writing deep copy functions: %v", err) } if err := generator.RegisterDeepCopyFunctions(data, registerTo); err != nil { glog.Fatalf("Error while registering deep copy functions: %v", err) } b, err := imports.Process("", data.Bytes(), nil) if err != nil { glog.Fatalf("Error while update imports: %v", err) } if _, err := funcOut.Write(b); err != nil { glog.Fatalf("Error while writing out the resulting file: %v", err) } }
func (s *Scheme) EncodeToVersionStream(obj interface{}, destVersion string, stream io.Writer) error { obj = maybeCopy(obj) v, _ := EnforcePtr(obj) // maybeCopy guarantees a pointer // Don't encode an object defined in the unversioned package, unless if the // destVersion is v1, encode it to v1 for backward compatibility. pkg := path.Base(v.Type().PkgPath()) if pkg == "unversioned" && destVersion != "v1" { // TODO: convert this to streaming too data, err := s.encodeUnversionedObject(obj) if err != nil { return err } _, err = stream.Write(data) return err } if _, registered := s.typeToGVK[v.Type()]; !registered { return fmt.Errorf("type %v is not registered for %q and it will be impossible to Decode it, therefore Encode will refuse to encode it.", v.Type(), destVersion) } objGVK, err := s.ObjectKind(obj) if err != nil { return err } // Perform a conversion if necessary. if objGVK.GroupVersion().String() != destVersion { objOut, err := s.NewObject(destVersion, objGVK.Kind) if err != nil { return err } flags, meta := s.generateConvertMeta(objGVK.GroupVersion(), unversioned.ParseGroupVersionOrDie(destVersion), obj) err = s.converter.Convert(obj, objOut, flags, meta) if err != nil { return err } obj = objOut // ensure the output object name comes from the destination type newGroupVersionKind, err := s.ObjectKind(obj) if err != nil { return err } objGVK.Kind = newGroupVersionKind.Kind } // Version and Kind should be set on the wire. err = s.SetVersionAndKind(destVersion, objGVK.Kind, obj) if err != nil { return err } // To add metadata, do some simple surgery on the JSON. encoder := json.NewEncoder(stream) if err := encoder.Encode(obj); err != nil { return err } // Version and Kind should be blank in memory. Reset them, since it's // possible that we modified a user object and not a copy above. err = s.SetVersionAndKind("", "", obj) if err != nil { return err } return nil }