Skip to content

Commit 1edd3d2

Browse files
authored
Add generating CRD from URL (#62)
1 parent 77eaa5b commit 1edd3d2

File tree

3 files changed

+78
-14
lines changed

3 files changed

+78
-14
lines changed

cmd/root.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ CustomResourceDefinition YAML schema.`
5555
const example = `crd2pulumi --nodejs crontabs.yaml
5656
crd2pulumi -dgnp crd-certificates.yaml crd-issuers.yaml crd-challenges.yaml
5757
crd2pulumi --pythonPath=crds/python/istio --nodejsPath=crds/nodejs/istio crd-all.gen.yaml crd-mixer.yaml crd-operator.yaml
58+
crd2pulumi --pythonPath=crds/python/gke https://raw.githubusercontent.com/GoogleCloudPlatform/gke-managed-certs/master/deploy/managedcertificates-crd.yaml
5859
5960
Notice that by just setting a language-specific output path (--pythonPath, --nodejsPath, etc) the code will
6061
still get generated, so setting -p, -n, etc becomes unnecessary.
@@ -117,7 +118,7 @@ func NewLanguageSettings(flags *pflag.FlagSet) (gen.LanguageSettings, []string)
117118
if golang {
118119
notices = append(notices, "-g is not necessary if --goPath is already set")
119120
}
120-
} else if golang || goName != gen.DefaultName{
121+
} else if golang || goName != gen.DefaultName {
121122
path := filepath.Join(defaultOutputPath, Go)
122123
ls.GoPath = &path
123124
}

gen/generate.go

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ import (
1818
"bytes"
1919
"fmt"
2020
"io/ioutil"
21+
"net/http"
22+
"net/url"
2123
"os"
2224
"path/filepath"
25+
"regexp"
2326
"strings"
2427
"unicode"
2528

@@ -41,6 +44,10 @@ const (
4144
v1 string = "apiextensions.k8s.io/v1"
4245
)
4346

47+
// fetchUrlRe is a regex to determine whether the requested file should
48+
// be fetched from a remote or read from the filesystem
49+
var fetchUrlRe = regexp.MustCompile(`^\w+://`)
50+
4451
// Version specifies the crd2pulumi version. It should be set by the linker via LDFLAGS. This defaults to dev
4552
var Version string = "dev"
4653

@@ -123,6 +130,27 @@ type PackageGenerator struct {
123130
schemaPackageWithObjectMetaType *pschema.Package
124131
}
125132

133+
func FetchFile(u *url.URL) ([]byte, error) {
134+
req, err := http.NewRequest("GET", u.String(), nil)
135+
if err != nil {
136+
return nil, err
137+
}
138+
req.Header.Add("Accept", "application/x-yaml")
139+
req.Header.Add("Accept", "text/yaml")
140+
141+
resp, err := http.DefaultClient.Do(req)
142+
if err != nil {
143+
return nil, fmt.Errorf("failed to connect to HTTP server: %s", err)
144+
}
145+
146+
if resp.StatusCode != http.StatusOK {
147+
return nil, fmt.Errorf("error getting CRD. Status=%d", resp.StatusCode)
148+
}
149+
150+
defer resp.Body.Close()
151+
return ioutil.ReadAll(resp.Body)
152+
}
153+
126154
// Read contents of file, with special case for stdin '-'
127155
func ReadFileOrStdin(path string) ([]byte, error) {
128156
if path == "-" {
@@ -132,11 +160,30 @@ func ReadFileOrStdin(path string) ([]byte, error) {
132160
}
133161
}
134162

163+
func LoadCRD(pathOrUrl string) ([]byte, error) {
164+
if fetchUrlRe.MatchString(pathOrUrl) {
165+
u, err := url.Parse(pathOrUrl)
166+
if err != nil {
167+
return nil, err
168+
}
169+
170+
switch u.Scheme {
171+
case "https", "http":
172+
return FetchFile(u)
173+
default:
174+
return nil, fmt.Errorf("scheme %q is not supported", u.Scheme)
175+
}
176+
}
177+
178+
// If it isn't a http/s scheme, try it as a file
179+
return ReadFileOrStdin(pathOrUrl)
180+
}
181+
135182
func NewPackageGenerator(yamlPaths []string) (PackageGenerator, error) {
136183
yamlFiles := make([][]byte, 0, len(yamlPaths))
137184

138185
for _, yamlPath := range yamlPaths {
139-
yamlFile, err := ReadFileOrStdin(yamlPath)
186+
yamlFile, err := LoadCRD(yamlPath)
140187
if err != nil {
141188
return PackageGenerator{}, errors.Wrapf(err, "could not read file %s", yamlPath)
142189
}

tests/crds_test.go

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,38 @@ import (
2525
"github.com/stretchr/testify/assert"
2626
)
2727

28-
// TestCRDs enumerates all CRD YAML files, and generates them in each language.
29-
func TestCRDs(t *testing.T) {
28+
var languages = []string{"dotnet", "go", "nodejs", "python"}
29+
30+
const gkeManagedCertsUrl = "https://raw.githubusercontent.com/GoogleCloudPlatform/gke-managed-certs/master/deploy/managedcertificates-crd.yaml"
31+
32+
// execCrd2Pulumi runs the crd2pulumi binary in a temporary directory
33+
func execCrd2Pulumi(t *testing.T, lang, path string) {
34+
tmpdir, err := ioutil.TempDir("", "")
35+
assert.Nil(t, err, "expected to create a temp dir for the CRD output")
36+
defer os.RemoveAll(tmpdir)
37+
langFlag := "--" + lang + "Path"
38+
t.Logf("crd2pulumi %s=%s %s: running", langFlag, tmpdir, path)
39+
crdCmd := exec.Command("crd2pulumi", langFlag, tmpdir, "--force", path)
40+
crdOut, err := crdCmd.CombinedOutput()
41+
t.Logf("crd2pulumi %s=%s %s: output=\n%s", langFlag, tmpdir, path, crdOut)
42+
assert.Nil(t, err, "expected crd2pulumi for '%s=%s %s' to succeed", langFlag, tmpdir, path)
43+
}
44+
45+
// TestCRDsFromFile enumerates all CRD YAML files, and generates them in each language.
46+
func TestCRDsFromFile(t *testing.T) {
3047
filepath.WalkDir("crds", func(path string, d fs.DirEntry, err error) error {
3148
if !d.IsDir() && (filepath.Ext(path) == ".yml" || filepath.Ext(path) == ".yaml") {
32-
for _, lang := range []string{"dotnet", "go", "nodejs", "python"} {
33-
tmpdir, err := ioutil.TempDir("", "")
34-
assert.Nil(t, err, "expected to create a temp dir for the CRD output")
35-
defer os.RemoveAll(tmpdir)
36-
langFlag := "--" + lang + "Path"
37-
t.Logf("crd2pulumi %s=%s %s: running", langFlag, tmpdir, path)
38-
crdCmd := exec.Command("crd2pulumi", langFlag, tmpdir, "--force", path)
39-
crdOut, err := crdCmd.CombinedOutput()
40-
t.Logf("crd2pulumi %s=%s %s: output=\n%s", langFlag, tmpdir, path, crdOut)
41-
assert.Nil(t, err, "expected crd2pulumi for '%s=%s %s' to succeed", langFlag, tmpdir, path)
49+
for _, lang := range languages {
50+
execCrd2Pulumi(t, lang, path)
4251
}
4352
}
4453
return nil
4554
})
4655
}
56+
57+
// TestCRDsFromUrl pulls the CRD YAML file from a URL and generates it in each language
58+
func TestCRDsFromUrl(t *testing.T) {
59+
for _, lang := range languages {
60+
execCrd2Pulumi(t, lang, gkeManagedCertsUrl)
61+
}
62+
}

0 commit comments

Comments
 (0)