blob: d61606067b566e6f7fe5b56454f4b1879aaa6d0a [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"bytes"
"flag"
"fmt"
"go/format"
"log"
"os"
"path/filepath"
"sort"
"strings"
"text/template"
"google.golang.org/protobuf/reflect/protoreflect"
"google.golang.org/protobuf/reflect/protoregistry"
_ "github.com/apache/dubbo-admin/api/mesh/v1alpha1"
)
// resourceTemplate for creating a Dubbo Resource.
var resourceTemplate = template.Must(template.New("dubbo-resource").Parse(`
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Generated by tools/resourcegen
// Run "make generate" to update this file.
{{ $pkg := printf "%sproto" .Package }}
{{ $tk := "` + "`" + `" }}
// nolint:whitespace
package v1alpha1
import (
"encoding/json"
"google.golang.org/protobuf/proto"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
k8sruntime "k8s.io/apimachinery/pkg/runtime"
{{ $pkg }} "github.com/apache/dubbo-admin/api/{{ .Package }}/v1alpha1"
"github.com/apache/dubbo-admin/pkg/core/logger"
coremodel "github.com/apache/dubbo-admin/pkg/core/resource/model"
)
{{range .Resources}}
const {{.Name}}Kind coremodel.ResourceKind = "{{.Name}}"
func init() {
coremodel.RegisterResourceSchema({{.Name}}Kind, New{{.Name}}Resource)
}
type {{.Name}}Resource struct {
metav1.TypeMeta {{ $tk }}json:",inline"{{ $tk }}
metav1.ObjectMeta {{ $tk }}json:"metadata,omitempty"{{ $tk }}
// Mesh is the name of the dubbo mesh this resource belongs to.
// It may be omitted for cluster-scoped resources.
Mesh string {{ $tk }}json:"mesh,omitempty"{{ $tk }}
// Spec is the specification of the Dubbo {{ .ProtoType }} resource.
Spec *{{$pkg}}.{{.Name}} {{ $tk }}json:"spec,omitempty"{{ $tk }}
// Status is the status of the Dubbo {{.Name}} resource.
Status {{.Name}}ResourceStatus {{ $tk }}json:"status,omitempty"{{ $tk }}
}
type {{.Name}}ResourceStatus struct {
// define resource-specific status here
}
type {{.Name}}ResourceList struct {
metav1.TypeMeta {{ $tk }}json:",inline"{{ $tk }}
metav1.ListMeta {{ $tk }}json:"metadata,omitempty"{{ $tk }}
Items []{{.Name}}Resource {{ $tk }}json:"items"{{ $tk }}
}
func (r *{{.Name}}Resource) ResourceKind() coremodel.ResourceKind {
return {{.Name}}Kind
}
func (r *{{.Name}}Resource) MeshName() string {
return r.Mesh
}
func (r *{{.Name}}Resource) ResourceKey() string {
return coremodel.BuildResourceKey(r.Mesh, r.Name)
}
func (r *{{.Name}}Resource) ResourceMeta() metav1.ObjectMeta {
return r.ObjectMeta
}
func (r *{{.Name}}Resource) ResourceSpec() coremodel.ResourceSpec {
return r.Spec
}
func (r *{{.Name}}Resource) DeepCopyObject() k8sruntime.Object {
if r == nil {
return nil
}
out := &{{.Name}}Resource{
TypeMeta: r.TypeMeta,
Mesh: r.Mesh,
Status: r.Status,
}
r.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
if r.Spec != nil {
spec, ok := proto.Clone(r.Spec).(*{{ $pkg }}.{{.Name}})
if !ok {
logger.Warnf("failed to clone spec %v, spec is not conformed to %s", r.Spec, r.ResourceKind())
return out
}
out.Spec = spec
}
return out
}
func (r *{{.Name}}Resource) String() string {
jsonStr, err := json.Marshal(r)
if err != nil {
logger.Errorf("failed to encode {{.Name}}Resource: %s to json, err: %w", r.ResourceKey(), err)
return ""
}
return string(jsonStr)
}
func New{{.Name}}ResourceWithAttributes(name string, mesh string) *{{.Name}}Resource{
return &{{.Name}}Resource{
TypeMeta: metav1.TypeMeta{
Kind: string({{.Name}}Kind),
APIVersion: "v1alpha1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
Labels: map[string]string{},
},
Mesh: mesh,
}
}
func New{{.Name}}Resource() coremodel.Resource {
return &{{.Name}}Resource{
TypeMeta: metav1.TypeMeta{
Kind: string({{.Name}}Kind),
APIVersion: "v1alpha1",
},
}
}
{{- end }} {{/* Resources */}}
`))
// ProtoMessageFunc ...
type ProtoMessageFunc func(protoreflect.MessageType) bool
// OnDubboResourceMessage ...
func OnDubboResourceMessage(pkg string, f ProtoMessageFunc) ProtoMessageFunc {
return func(m protoreflect.MessageType) bool {
r := DubboResourceForMessage(m.Descriptor())
if r == nil {
return true
}
fullname := string(m.Descriptor().FullName())
if strings.Contains(fullname, "legacy") {
log.Printf("Skipping message: %s", fullname)
return true
}
if r.Package == pkg {
return f(m)
}
return true
}
}
func main() {
var pkg string
var outputDir string
flag.StringVar(&pkg, "package", "", "the name of the package to generate: (mesh, system)")
flag.StringVar(&outputDir, "output", "", "the directory to write generated files")
flag.Parse()
switch pkg {
case "mesh", "system":
default:
log.Fatalf("package %s is not supported", pkg)
}
if err := os.MkdirAll(outputDir, 0755); err != nil {
log.Fatalf("failed to create output dir: %v", err)
}
var types []protoreflect.MessageType
protoregistry.GlobalTypes.RangeMessages(
OnDubboResourceMessage(pkg, func(m protoreflect.MessageType) bool {
types = append(types, m)
return true
}))
// Sort by name so the output is deterministic.
sort.Slice(types, func(i, j int) bool {
return types[i].Descriptor().FullName() < types[j].Descriptor().FullName()
})
var resources []ResourceInfo
for _, t := range types {
resourceInfo := ToResourceInfo(t.Descriptor())
resources = append(resources, resourceInfo)
}
for _, resource := range resources {
var buf bytes.Buffer
if err := resourceTemplate.Execute(&buf, struct {
Package string
Resources []ResourceInfo
}{
Package: pkg,
Resources: []ResourceInfo{resource},
}); err != nil {
log.Fatalf("template error for %s: %s", resource.Name, err)
}
out, err := format.Source(buf.Bytes())
if err != nil {
log.Fatalf("format error for %s: %s", resource.Name, err)
}
filename := filepath.Join(outputDir, fmt.Sprintf("%s_types.go", strings.ToLower(resource.Name)))
if err := os.WriteFile(filename, out, 0644); err != nil {
log.Fatalf("write file error for %s: %s", filename, err)
}
log.Printf("Generated: %s", filename)
}
}