├── README.md
├── .gitignore
├── static
├── favicon.ico
├── twitter.jpg
└── root.css
├── template
├── head-doc.html
├── new.html
├── navbar-doc.html
├── _scripts.html
├── _navbar.html
├── _footer.html
├── layout.html
├── _head.html
├── home.html
├── org.html
└── doc.html
├── Makefile
├── deploy
├── redis.yaml
├── infra
│ └── cloudsql.yaml
├── gitter.yaml
├── config.yaml
├── doc.yaml
├── gitter.Dockerfile
└── doc.Dockerfile
├── schema
└── crds_up.sql
├── pkg
├── models
│ └── repo.go
└── crd
│ ├── crd.go
│ └── crd_test.go
├── go.mod
├── DEVELOPING.md
├── cmd
├── gitter
│ └── main.go
└── doc
│ └── main.go
├── LICENSE
└── go.sum
/README.md:
--------------------------------------------------------------------------------
1 | # Doc
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | deploy/dns
2 | *.rdb
3 | cloudsql.json
4 |
--------------------------------------------------------------------------------
/static/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crdsdev/doc/HEAD/static/favicon.ico
--------------------------------------------------------------------------------
/static/twitter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/crdsdev/doc/HEAD/static/twitter.jpg
--------------------------------------------------------------------------------
/template/head-doc.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/template/new.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Oops! Looks like we haven't indexed this version of this repo yet. We are working on that now...
4 |
5 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Set the shell to bash always
2 | SHELL := /bin/bash
3 |
4 | build-doc:
5 | docker build . -f deploy/doc.Dockerfile -t crdsdev/doc:latest
6 |
7 | build-gitter:
8 | docker build . -f deploy/gitter.Dockerfile -t crdsdev/doc-gitter:latest
9 |
10 | .PHONY: build-doc build-gitter
--------------------------------------------------------------------------------
/deploy/redis.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: cache.crossplane.io/v1alpha1
2 | kind: RedisCluster
3 | metadata:
4 | name: doc-redis
5 | namespace: crdsdev
6 | spec:
7 | classSelector:
8 | matchLabels:
9 | app: doc
10 | writeConnectionSecretToRef:
11 | name: doc-redis
12 | engineVersion: "4.0"
--------------------------------------------------------------------------------
/template/navbar-doc.html:
--------------------------------------------------------------------------------
1 |
14 |
15 | {{ if not .Page.DisableNavBar }}
16 | {{ template "_navbar" . }}
17 | {{ end }}
18 | {{ yield }}
19 |
20 | {{ template "_footer" . }}
21 |
22 |
23 |
--------------------------------------------------------------------------------
/deploy/gitter.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: batch/v1beta1
2 | kind: CronJob
3 | metadata:
4 | name: gitter
5 | namespace: crdsdev
6 | labels:
7 | app: doc
8 | spec:
9 | schedule: "@hourly"
10 | jobTemplate:
11 | spec:
12 | backoffLimit: 0
13 | template:
14 | spec:
15 | containers:
16 | - name: gitter
17 | image: crdsdev/doc-gitter:latest
18 | env:
19 | - name: REDIS_HOST
20 | valueFrom:
21 | secretKeyRef:
22 | name: doc-redis
23 | key: endpoint
24 | - name: REPOS
25 | valueFrom:
26 | configMapKeyRef:
27 | name: doc-repos
28 | key: repos
29 | restartPolicy: Never
--------------------------------------------------------------------------------
/deploy/config.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Namespace
3 | metadata:
4 | name: crdsdev
5 | ---
6 | apiVersion: v1
7 | kind: ConfigMap
8 | metadata:
9 | name: doc-repos
10 | namespace: crdsdev
11 | data:
12 | repos: |
13 | crossplane/crossplane,
14 | crossplane/provider-alibaba,
15 | crossplane/provider-aws,
16 | crossplane/provider-azure,
17 | crossplane/provider-gcp,
18 | crossplane/provider-rook,
19 | crossplane/oam-kubernetes-runtime,
20 | crossplane-contrib/provider-helm,
21 | jetstack/cert-manager,
22 | kubernetes-sigs/cluster-api,
23 | kubernetes-sigs/cluster-api-provider-packet,
24 | kubernetes-sigs/security-profiles-operator,
25 | packethost/crossplane-provider-packet,
26 | projectcontour/contour,
27 | schemahero/schemahero
--------------------------------------------------------------------------------
/static/root.css:
--------------------------------------------------------------------------------
1 | @import url("https://unpkg.com/halfmoon@1.1.1/css/halfmoon-variables.min.css");
2 |
3 | :root {
4 | --primary-color: var(--indigo-color);
5 | --primary-color-light: var(--indigo-color-light);
6 | --primary-color-very-light: var(--indigo-color-very-light);
7 | --primary-color-dark: var(--indigo-color-dark);
8 | --primary-color-very-dark: var(--indigo-color-very-dark);
9 | --primary-box-shadow-color: var(--indigo-box-shadow-color);
10 | --primary-box-shadow-color-darker: var(--indigo-box-shadow-color-darker);
11 | --text-color-on-primary-color-bg: var(--text-color-on-indigo-color-bg);
12 | --dm-link-text-color: var(--indigo-color-light);
13 | }
14 |
15 | @media (max-width: 576px) {
16 | body .content-wrapper > div {
17 | padding-left: 1.5rem;
18 | padding-right: 1.5rem;
19 | }
20 | }
21 |
22 | body .content-wrapper {
23 | padding-bottom: 2rem;
24 | }
--------------------------------------------------------------------------------
/deploy/doc.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: apps/v1
2 | kind: Deployment
3 | metadata:
4 | name: doc
5 | namespace: crdsdev
6 | labels:
7 | app: doc
8 | spec:
9 | selector:
10 | matchLabels:
11 | app: doc
12 | template:
13 | metadata:
14 | labels:
15 | app: doc
16 | spec:
17 | containers:
18 | - name: doc
19 | image: crdsdev/doc:latest
20 | env:
21 | - name: REDIS_HOST
22 | valueFrom:
23 | secretKeyRef:
24 | name: doc-redis
25 | key: endpoint
26 | - name: ANALYTICS
27 | value: "true"
28 | ports:
29 | - containerPort: 5000
30 | name: doc
31 | ---
32 | apiVersion: v1
33 | kind: Service
34 | metadata:
35 | name: doc
36 | namespace: crdsdev
37 | labels:
38 | app: doc
39 | spec:
40 | ports:
41 | - port: 80
42 | targetPort: 5000
43 | selector:
44 | app: doc
45 | type: NodePort
--------------------------------------------------------------------------------
/deploy/gitter.Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the official Golang image to create a build artifact.
2 | # This is based on Debian and sets the GOPATH to /go.
3 | # https://hub.docker.com/_/golang
4 | FROM golang:1.13 as builder
5 |
6 | WORKDIR app/
7 |
8 | # Copy internal libraries.
9 | COPY . .
10 |
11 | # Retrieve application dependencies.
12 | # This allows the container build to reuse cached dependencies.
13 | RUN go mod download
14 |
15 | # Build the binary.
16 | RUN CGO_ENABLED=0 GOOS=linux go build -o gitter -mod=readonly -v ./cmd/gitter/main.go
17 |
18 | # Use the official Alpine image for a lean production container.
19 | # https://hub.docker.com/_/alpine
20 | # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
21 | FROM alpine:3
22 | RUN apk add --no-cache ca-certificates
23 |
24 | # Copy the binary to the production image from the builder stage.
25 | COPY --from=builder go/app/gitter ./
26 |
27 | # Run the web service on container startup.
28 | ENTRYPOINT ["/gitter"]
--------------------------------------------------------------------------------
/pkg/models/repo.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2020 The CRDS Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package models
18 |
19 | // RepoCRD is a CRD and data about its location in a repository.
20 | type RepoCRD struct {
21 | Path string
22 | Filename string
23 | Group string
24 | Version string
25 | Kind string
26 | CRD []byte
27 | }
28 |
29 | // GitterRepo is the repo for gitter to index.
30 | type GitterRepo struct {
31 | Org string
32 | Repo string
33 | Tag string
34 | }
35 |
--------------------------------------------------------------------------------
/deploy/doc.Dockerfile:
--------------------------------------------------------------------------------
1 | # Use the official Golang image to create a build artifact.
2 | # This is based on Debian and sets the GOPATH to /go.
3 | # https://hub.docker.com/_/golang
4 | FROM golang:1.13 as builder
5 |
6 | WORKDIR app/
7 |
8 | # Copy internal libraries.
9 | COPY . .
10 |
11 | # Retrieve application dependencies.
12 | # This allows the container build to reuse cached dependencies.
13 | RUN go mod download
14 |
15 | # Build the binary.
16 | RUN CGO_ENABLED=0 GOOS=linux go build -o doc -mod=readonly -v ./cmd/doc/main.go
17 |
18 | # Use the official Alpine image for a lean production container.
19 | # https://hub.docker.com/_/alpine
20 | # https://docs.docker.com/develop/develop-images/multistage-build/#use-multi-stage-builds
21 | FROM alpine:3
22 | RUN apk add --no-cache ca-certificates
23 |
24 | # Copy the binary to the production image from the builder stage.
25 | COPY --from=builder go/app/doc ./
26 | COPY ./template ./template
27 | COPY ./static ./static
28 |
29 | # Run the web service on container startup.
30 | ENTRYPOINT ["/doc"]
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module github.com/crdsdev/doc
2 |
3 | go 1.13
4 |
5 | require (
6 | github.com/go-git/go-git/v5 v5.0.0
7 | github.com/go-openapi/spec v0.19.5 // indirect
8 | github.com/golang/protobuf v1.4.3 // indirect
9 | github.com/google/go-cmp v0.5.2 // indirect
10 | github.com/google/uuid v1.1.2
11 | github.com/gorilla/mux v1.7.4
12 | github.com/hashicorp/golang-lru v0.5.3 // indirect
13 | github.com/imdario/mergo v0.3.7 // indirect
14 | github.com/jackc/pgx/v4 v4.10.1
15 | github.com/lib/pq v1.9.0 // indirect
16 | github.com/pkg/errors v0.9.1
17 | github.com/prometheus/client_golang v1.1.0 // indirect
18 | github.com/spf13/pflag v1.0.5
19 | github.com/unrolled/render v1.0.3
20 | golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb // indirect
21 | golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58 // indirect
22 | golang.org/x/text v0.3.4 // indirect
23 | google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb // indirect
24 | google.golang.org/grpc v1.33.2 // indirect
25 | gopkg.in/square/go-jose.v2 v2.2.2
26 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
27 | k8s.io/apiextensions-apiserver v0.18.2
28 | k8s.io/apimachinery v0.18.2
29 | sigs.k8s.io/yaml v1.2.0
30 | )
31 |
--------------------------------------------------------------------------------
/template/_head.html:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
doc.crds.dev
9 |
10 |
doc.crds.dev is and always will be free and open source .
11 |
12 |
To find a repo, search github.com/{org}/{repo} . You may optionally append @{version} to view documentation for a specific version of the project. For example: github.com/crossplane/crossplane@v0.10.0 . If you do not include a tag, the latest indexed tag will be served.
13 |
14 |
15 |
16 | {{ template "_scripts" . }}
17 |
60 |
61 |
91 |
--------------------------------------------------------------------------------
/template/org.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
12 | {{ $actual := .Tag }}{{ $repo := .Repo }}{{ range $name := .Tags }}
13 | {{ if eq $name $actual }}
14 | {{ $name }}
15 | {{ else }}
16 | {{ $name }}
17 | {{ end }}
18 | {{ end }}
19 |
20 |
CRDs discovered: {{ .Total }}
21 |
22 |
23 |
24 |
25 | {{ template "_scripts" . }}
26 |
32 |
33 |
115 |
--------------------------------------------------------------------------------
/pkg/crd/crd.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2020 The CRDS Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package crd
18 |
19 | import (
20 | "encoding/json"
21 | "errors"
22 | "fmt"
23 |
24 | "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
25 | servervalidation "k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
26 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27 | "k8s.io/apimachinery/pkg/runtime/schema"
28 |
29 | v1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
30 | "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
31 | "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
32 | "sigs.k8s.io/yaml"
33 | )
34 |
35 | const (
36 | getStoredGVKErr = "unable to determind stored gvk"
37 | createSchemaValidatorErr = "could not create schema validator"
38 | yamlToJSONErr = "could not convert yaml to json"
39 | getTypeMetaErr = "could not get type metadata for crd instance"
40 | wrongGVKErr = "crd instance was not of correct group version kind"
41 | instanceConversionErr = "could not convert crd instance json to instance"
42 | )
43 |
44 | // CRDer generates instances of a CustomResourceDefinition.
45 | type CRDer struct {
46 | CRD *apiextensions.CustomResourceDefinition
47 | GVK *schema.GroupVersionKind
48 | }
49 |
50 | // NewCRDer returns a new CRDer type.
51 | func NewCRDer(data []byte, m ...Modifier) (*CRDer, error) {
52 | internal := &apiextensions.CustomResourceDefinition{}
53 | if errV1Beta1 := convertV1Beta1ToInternal(data, internal, m...); errV1Beta1 != nil {
54 | if errV1 := convertV1ToInternal(data, internal, m...); errV1 != nil {
55 | return nil, fmt.Errorf("conversion unsuccessful: %s, %s", errV1Beta1, errV1)
56 | }
57 | }
58 |
59 | gvk := GetStoredGVK(internal)
60 | if gvk == nil {
61 | return nil, errors.New(getStoredGVKErr)
62 | }
63 |
64 | return &CRDer{CRD: internal, GVK: gvk}, nil
65 | }
66 |
67 | // Validate returns true if CRD instance is valid.
68 | func (c *CRDer) Validate(data []byte) error {
69 | sv := getStoredSchema(c.CRD.Spec)
70 |
71 | s, _, err := servervalidation.NewSchemaValidator(sv)
72 | if err != nil {
73 | return errors.New(createSchemaValidatorErr)
74 | }
75 |
76 | j, err := yaml.YAMLToJSONStrict(data)
77 | if err != nil {
78 | return errors.New(yamlToJSONErr)
79 | }
80 |
81 | meta := &metav1.TypeMeta{}
82 | if err := json.Unmarshal(j, meta); err != nil {
83 | return errors.New(getTypeMetaErr)
84 | }
85 |
86 | if !isStoredGVK(meta, c.GVK) {
87 | return errors.New(wrongGVKErr)
88 | }
89 |
90 | var instance interface{}
91 | if err := json.Unmarshal(j, &instance); err != nil {
92 | return errors.New(instanceConversionErr)
93 | }
94 |
95 | res := servervalidation.ValidateCustomResource(nil, instance, s)
96 | if len(res) > 0 {
97 | return errors.New(res.ToAggregate().Error())
98 | }
99 | return nil
100 | }
101 |
102 | func convertV1ToInternal(data []byte, internal *apiextensions.CustomResourceDefinition, mods ...Modifier) error {
103 | crd := &v1.CustomResourceDefinition{}
104 | if err := yaml.Unmarshal(data, crd); err != nil {
105 | return err
106 | }
107 | v1.SetDefaults_CustomResourceDefinition(crd)
108 | if err := v1.Convert_v1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition(crd, internal, nil); err != nil {
109 | return err
110 | }
111 | for _, m := range mods {
112 | m(internal)
113 | }
114 | errList := validation.ValidateCustomResourceDefinition(internal, v1.SchemeGroupVersion)
115 | if len(errList) > 0 {
116 | return errors.New(errList.ToAggregate().Error())
117 | }
118 |
119 | return nil
120 | }
121 |
122 | func convertV1Beta1ToInternal(data []byte, internal *apiextensions.CustomResourceDefinition, mods ...Modifier) error {
123 | crd := &v1beta1.CustomResourceDefinition{}
124 | if err := yaml.Unmarshal(data, crd); err != nil {
125 | return err
126 | }
127 | v1beta1.SetObjectDefaults_CustomResourceDefinition(crd)
128 | if err := v1beta1.Convert_v1beta1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition(crd, internal, nil); err != nil {
129 | return err
130 | }
131 | for _, m := range mods {
132 | m(internal)
133 | }
134 | errList := validation.ValidateCustomResourceDefinition(internal, v1beta1.SchemeGroupVersion)
135 | if len(errList) > 0 {
136 | return errors.New(errList.ToAggregate().Error())
137 | }
138 |
139 | return nil
140 | }
141 |
142 | func getStoredSchema(spec apiextensions.CustomResourceDefinitionSpec) *apiextensions.CustomResourceValidation {
143 | if spec.Validation != nil {
144 | return spec.Validation
145 | }
146 | for _, v := range spec.Versions {
147 | if v.Storage {
148 | return v.Schema
149 | }
150 | }
151 | return nil
152 | }
153 |
154 | func GetStoredGVK(crd *apiextensions.CustomResourceDefinition) *schema.GroupVersionKind {
155 | for _, v := range crd.Spec.Versions {
156 | if v.Storage {
157 | return &schema.GroupVersionKind{
158 | Group: crd.Spec.Group,
159 | Version: v.Name,
160 | Kind: crd.Spec.Names.Kind,
161 | }
162 | }
163 | }
164 |
165 | return nil
166 | }
167 |
168 | func isStoredGVK(meta *metav1.TypeMeta, gvk *schema.GroupVersionKind) bool {
169 | if meta.GroupVersionKind() == *gvk {
170 | return true
171 | }
172 |
173 | return false
174 | }
175 |
176 | // A Modifier specifies how to modify a CRD prior to conversion to internal
177 | // representation
178 | type Modifier func(crd *apiextensions.CustomResourceDefinition)
179 |
180 | // StripLabels removes labels from a CRD's metadata
181 | func StripLabels() Modifier {
182 | return func(crd *apiextensions.CustomResourceDefinition) {
183 | crd.SetLabels(map[string]string{})
184 | }
185 | }
186 |
187 | // StripAnnotations removes annotations from a CRD's metadata
188 | func StripAnnotations() Modifier {
189 | return func(crd *apiextensions.CustomResourceDefinition) {
190 | crd.SetAnnotations(map[string]string{})
191 | }
192 | }
193 |
194 | // StripConversion removes conversion from a CRD's spec
195 | func StripConversion() Modifier {
196 | return func(crd *apiextensions.CustomResourceDefinition) {
197 | crd.Spec.Conversion = nil
198 | }
199 | }
200 |
201 | // PrettyGVK returns a group, version, kind representation in order of
202 | // specificity.
203 | func PrettyGVK(gvk *schema.GroupVersionKind) string {
204 | return fmt.Sprintf("%s/%s/%s", gvk.Group, gvk.Kind, gvk.Version)
205 | }
206 |
--------------------------------------------------------------------------------
/template/doc.html:
--------------------------------------------------------------------------------
1 |
7 |