Skip to content

Commit d075eed

Browse files
allmightyspiffGitHub Enterprise
authored andcommitted
Merge pull request #675 from Edson-Rios/issue673
Added new command - ibmcloud sl cdn origin-add
2 parents 122eb03 + 675c7c0 commit d075eed

7 files changed

Lines changed: 423 additions & 4 deletions

File tree

plugin/commands/cdn/cdn.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ func SetupCobraCommands(sl *metadata.SoftlayerCommand) *cobra.Command {
1919
cobraCmd.AddCommand(NewDetailCommand(sl).Command)
2020
cobraCmd.AddCommand(NewEditCommand(sl).Command)
2121
cobraCmd.AddCommand(NewCreateCommand(sl).Command)
22+
cobraCmd.AddCommand(NewOriginAddCommand(sl).Command)
2223
return cobraCmd
2324
}
2425

plugin/commands/cdn/cdn_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var availableCommands = []string{
2323
"edit",
2424
"list",
2525
"create",
26+
"origin-add",
2627
}
2728

2829
// This test suite exists to make sure commands don't get accidently removed from the actionBindings

plugin/commands/cdn/origin_add.go

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
package cdn
2+
3+
import (
4+
"regexp"
5+
6+
"github.com/IBM-Cloud/ibm-cloud-cli-sdk/bluemix/terminal"
7+
"github.com/softlayer/softlayer-go/datatypes"
8+
"github.com/spf13/cobra"
9+
10+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/errors"
11+
. "github.ibm.com/SoftLayer/softlayer-cli/plugin/i18n"
12+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/managers"
13+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/metadata"
14+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/utils"
15+
)
16+
17+
type OriginAddCommand struct {
18+
*metadata.SoftlayerCommand
19+
CdnManager managers.CdnManager
20+
Command *cobra.Command
21+
Header string
22+
Path string
23+
OriginHost string
24+
OriginType string
25+
Http int
26+
Https int
27+
CacheKey string
28+
Optimize string
29+
DynamicPath string
30+
DynamicPrefetch bool
31+
DynamicCompression bool
32+
BuckeName string
33+
fileExtension string
34+
}
35+
36+
func NewOriginAddCommand(sl *metadata.SoftlayerCommand) *OriginAddCommand {
37+
thisCmd := &OriginAddCommand{
38+
SoftlayerCommand: sl,
39+
CdnManager: managers.NewCdnManager(sl.Session),
40+
}
41+
cobraCmd := &cobra.Command{
42+
Use: "origin-add " + T("IDENTIFIER"),
43+
Short: T("Create an origin path for an existing CDN mapping."),
44+
Long: T(`${COMMAND_NAME} sl cdn origin-add
45+
Example:
46+
${COMMAND_NAME} sl cdn origin-add --origin 123.123.123.123 --path /example/videos --http 80`),
47+
Args: metadata.OneArgs,
48+
RunE: func(cmd *cobra.Command, args []string) error {
49+
return thisCmd.Run(args)
50+
},
51+
}
52+
cobraCmd.Flags().StringVar(&thisCmd.Header, "header", "", T("The edge server uses the host header in the HTTP header to communicate with the Origin host. It defaults to Hostname."))
53+
cobraCmd.Flags().StringVar(&thisCmd.Path, "path", "", T("Give a path relative to the domain provided, which can be used to reach this Origin. For example, 'articles/video' => 'www.example.com/articles/video [required]"))
54+
cobraCmd.Flags().StringVar(&thisCmd.OriginHost, "origin", "", T("Your server IP address or hostname. [required]"))
55+
cobraCmd.Flags().StringVar(&thisCmd.OriginType, "origin-type", "server", T("The origin type. [Permit: server, storage] Note: If OriginType is storage then OriginHost is take as Endpoint."))
56+
cobraCmd.Flags().IntVar(&thisCmd.Http, "http", 0, T("Http port. [http or https is required]"))
57+
cobraCmd.Flags().IntVar(&thisCmd.Https, "https", 0, T("Https port. [http or https is required]"))
58+
cobraCmd.Flags().StringVar(&thisCmd.CacheKey, "cache-key", "include-all", T("Cache query rules with the following formats: 'include-all', 'ignore-all', 'include: <query-names>', 'ignore: <query-names>'. example <query-names> = 'uuid=1234567 issue=important'."))
59+
cobraCmd.Flags().StringVar(&thisCmd.Optimize, "optimize", "web", T("Performance configuration. [Permit: web, video, file, dynamic]"))
60+
cobraCmd.Flags().StringVar(&thisCmd.DynamicPath, "dynamic-path", "", T("The path that Akamai edge servers periodically fetch the test object from. example = /detection-test-object.html"))
61+
cobraCmd.Flags().BoolVar(&thisCmd.DynamicPrefetch, "prefetching", true, T("Enable or disable the embedded object prefetching feature."))
62+
cobraCmd.Flags().BoolVar(&thisCmd.DynamicCompression, "compression", true, T("Enable or disable compression of JPEG images for requests over certain network conditions."))
63+
cobraCmd.Flags().StringVar(&thisCmd.BuckeName, "bucket-name", "", T("Bucket name."))
64+
cobraCmd.Flags().StringVar(&thisCmd.fileExtension, "file-extensions", "", T("Specify the file extensions that can be stored on the CDN service, separated by commas. For example, 'jpg, pdf, jpeg, png' is a valid list. Leave the flag empty to allow all extensions."))
65+
66+
//#nosec G104 -- This is a false positive
67+
cobraCmd.MarkFlagRequired("path")
68+
//#nosec G104 -- This is a false positive
69+
cobraCmd.MarkFlagRequired("origin")
70+
thisCmd.Command = cobraCmd
71+
return thisCmd
72+
}
73+
74+
func (cmd *OriginAddCommand) Run(args []string) error {
75+
uniqueId := args[0]
76+
77+
if cmd.Http == 0 && cmd.Https == 0 {
78+
return errors.NewMissingInputError(T("http or https"))
79+
}
80+
81+
if cmd.OriginType != "server" && cmd.OriginType != "storage" {
82+
return errors.NewInvalidUsageError(T("--origintype"))
83+
}
84+
85+
if cmd.Optimize != "web" && cmd.Optimize != "video" && cmd.Optimize != "file" && cmd.Optimize != "dynamic" {
86+
return errors.NewInvalidUsageError(T("--optimize"))
87+
}
88+
89+
permitCacheKey := regexp.MustCompile(`^(ignore|include): \w+`)
90+
if cmd.CacheKey != "ignore-all" && cmd.CacheKey != "include-all" && !permitCacheKey.MatchString(cmd.CacheKey) {
91+
return errors.NewInvalidUsageError(T("--cache-key"))
92+
}
93+
94+
if cmd.OriginType == "storage" && cmd.BuckeName == "" {
95+
return errors.NewInvalidUsageError(T("--bucket-name can not be empty"))
96+
}
97+
98+
outputFormat := cmd.GetOutputFlag()
99+
100+
newOrigin, err := cmd.CdnManager.OriginAddCdn(uniqueId, cmd.Header, cmd.Path, cmd.OriginHost, cmd.OriginType, cmd.Http, cmd.Https, cmd.CacheKey, cmd.Optimize, cmd.DynamicPath, cmd.DynamicPrefetch, cmd.DynamicCompression, cmd.BuckeName, cmd.fileExtension)
101+
if err != nil {
102+
return errors.NewAPIError(T("Failed to create a Origin."), err.Error(), 2)
103+
}
104+
105+
PrintNewOrigin(cmd.UI, newOrigin, outputFormat)
106+
return nil
107+
}
108+
109+
func PrintNewOrigin(ui terminal.UI, cdn []datatypes.Container_Network_CdnMarketplace_Configuration_Mapping_Path, outputFormat string) {
110+
table := ui.Table([]string{
111+
T("Name"),
112+
T("Value"),
113+
})
114+
if len(cdn) > 0 {
115+
table.Add(T("CDN Unique ID"), utils.FormatStringPointer(cdn[0].MappingUniqueId))
116+
if cdn[0].BucketName != nil {
117+
table.Add(T("Bucket Name"), utils.FormatStringPointer(cdn[0].BucketName))
118+
}
119+
if cdn[0].FileExtension != nil {
120+
table.Add(T("File Extension"), utils.FormatStringPointer(cdn[0].FileExtension))
121+
}
122+
table.Add(T("Header"), utils.FormatStringPointer(cdn[0].Header))
123+
table.Add(T("Path"), utils.FormatStringPointer(cdn[0].Path))
124+
table.Add(T("Origin"), utils.FormatStringPointer(cdn[0].Origin))
125+
table.Add(T("Origin Type"), utils.FormatStringPointer(cdn[0].OriginType))
126+
table.Add(T("Http Port"), utils.FormatIntPointer(cdn[0].HttpPort))
127+
table.Add(T("Https Port"), utils.FormatIntPointer(cdn[0].HttpsPort))
128+
table.Add(T("Cache Key Rule"), utils.FormatStringPointer(cdn[0].CacheKeyQueryRule))
129+
table.Add(T("Performance Configuration"), utils.FormatStringPointer(cdn[0].PerformanceConfiguration))
130+
table.Add(T("Status"), utils.FormatStringPointer(cdn[0].Status))
131+
}
132+
utils.PrintTable(ui, table, outputFormat)
133+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
package cdn_test
2+
3+
import (
4+
"github.com/IBM-Cloud/ibm-cloud-cli-sdk/testhelpers/terminal"
5+
. "github.com/onsi/ginkgo"
6+
. "github.com/onsi/gomega"
7+
"github.com/softlayer/softlayer-go/session"
8+
9+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/commands/cdn"
10+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/metadata"
11+
"github.ibm.com/SoftLayer/softlayer-cli/plugin/testhelpers"
12+
)
13+
14+
var _ = Describe("Cdn origin add", func() {
15+
var (
16+
fakeUI *terminal.FakeUI
17+
cliCommand *cdn.OriginAddCommand
18+
fakeSession *session.Session
19+
slCommand *metadata.SoftlayerCommand
20+
)
21+
BeforeEach(func() {
22+
fakeUI = terminal.NewFakeUI()
23+
fakeSession = testhelpers.NewFakeSoftlayerSession([]string{})
24+
slCommand = metadata.NewSoftlayerCommand(fakeUI, fakeSession)
25+
cliCommand = cdn.NewOriginAddCommand(slCommand)
26+
cliCommand.Command.PersistentFlags().Var(cliCommand.OutputFlag, "output", "--output=JSON for json output.")
27+
})
28+
29+
Describe("Cdn origin add", func() {
30+
Context("Cdn origin add, Invalid Usage", func() {
31+
It("Set command with an invalid output option", func() {
32+
err := testhelpers.RunCobraCommand(cliCommand.Command, "--output=xml")
33+
Expect(err).To(HaveOccurred())
34+
Expect(err.Error()).To(ContainSubstring("Incorrect Usage: Invalid output format, only JSON is supported now."))
35+
})
36+
It("Set command without id", func() {
37+
err := testhelpers.RunCobraCommand(cliCommand.Command)
38+
Expect(err).To(HaveOccurred())
39+
Expect(err.Error()).To(ContainSubstring("Incorrect Usage: This command requires one argument"))
40+
})
41+
It("Set command without flag hostname", func() {
42+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789")
43+
Expect(err).To(HaveOccurred())
44+
Expect(err.Error()).To(ContainSubstring(`required flag(s) "origin", "path" not set`))
45+
})
46+
It("Set command without flag origin", func() {
47+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123")
48+
Expect(err).To(HaveOccurred())
49+
Expect(err.Error()).To(ContainSubstring(`required flag(s) "path" not set`))
50+
})
51+
It("Set command without flag http or https", func() {
52+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123", "--path", "/example/videos")
53+
Expect(err).To(HaveOccurred())
54+
Expect(err.Error()).To(ContainSubstring(`Incorrect Usage: 'http or https' is required`))
55+
})
56+
It("Set command with flag wrong origin-type", func() {
57+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123", "--path", "/example/videos", "--http", "80", "--origin-type", "asdfgh")
58+
Expect(err).To(HaveOccurred())
59+
Expect(err.Error()).To(ContainSubstring(`Incorrect Usage: --origintype`))
60+
})
61+
It("Set command with flag wrong optimize", func() {
62+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123", "--path", "/example/videos", "--http", "80", "--optimize", "notPermit")
63+
Expect(err).To(HaveOccurred())
64+
Expect(err.Error()).To(ContainSubstring(`Incorrect Usage: --optimize`))
65+
})
66+
It("Set command with flag wrong cache-key", func() {
67+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123", "--path", "/example/videos", "--http", "80", "--cache-key", "notPermit")
68+
Expect(err).To(HaveOccurred())
69+
Expect(err.Error()).To(ContainSubstring(`Incorrect Usage: --cache-key`))
70+
})
71+
It("Set command with flag originType like storage and empty bucket-name", func() {
72+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123", "--path", "/example/videos", "--http", "80", "--origin-type", "storage")
73+
Expect(err).To(HaveOccurred())
74+
Expect(err.Error()).To(ContainSubstring(`Incorrect Usage: --bucket-name can not be empty`))
75+
})
76+
})
77+
78+
Context("Cdn origin add, correct use", func() {
79+
It("return cdn origin add", func() {
80+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123","--path", "/example/videos/", "--http", "80", "--origin-type", "storage", "--bucket-name", "bucketName", "--file-extensions", "jpg")
81+
Expect(err).NotTo(HaveOccurred())
82+
Expect(fakeUI.Outputs()).To(ContainSubstring("CDN Unique ID"))
83+
Expect(fakeUI.Outputs()).To(ContainSubstring("354034879028850"))
84+
Expect(fakeUI.Outputs()).To(ContainSubstring("File Extension"))
85+
Expect(fakeUI.Outputs()).To(ContainSubstring("jpg,pdf,jpeg,png"))
86+
Expect(fakeUI.Outputs()).To(ContainSubstring("Header"))
87+
Expect(fakeUI.Outputs()).To(ContainSubstring("header.test.com"))
88+
Expect(fakeUI.Outputs()).To(ContainSubstring("Path"))
89+
Expect(fakeUI.Outputs()).To(ContainSubstring("/example/videos"))
90+
Expect(fakeUI.Outputs()).To(ContainSubstring("Cache Key Rule"))
91+
Expect(fakeUI.Outputs()).To(ContainSubstring("include-all"))
92+
Expect(fakeUI.Outputs()).To(ContainSubstring("Performance Configuration"))
93+
Expect(fakeUI.Outputs()).To(ContainSubstring("General web delivery"))
94+
Expect(fakeUI.Outputs()).To(ContainSubstring("Status"))
95+
Expect(fakeUI.Outputs()).To(ContainSubstring("RUNNING"))
96+
})
97+
It("return cdn in format json", func() {
98+
err := testhelpers.RunCobraCommand(cliCommand.Command, "123456789", "--origin", "123.123.123.123","--path", "/example/videos/", "--http", "80", "--output", "json")
99+
Expect(err).NotTo(HaveOccurred())
100+
Expect(fakeUI.Outputs()).To(ContainSubstring(`"Name": "CDN Unique ID",`))
101+
Expect(fakeUI.Outputs()).To(ContainSubstring(`"Value": "354034879028850"`))
102+
Expect(fakeUI.Outputs()).To(ContainSubstring(`[`))
103+
Expect(fakeUI.Outputs()).To(ContainSubstring(`{`))
104+
Expect(fakeUI.Outputs()).To(ContainSubstring(`}`))
105+
Expect(fakeUI.Outputs()).To(ContainSubstring(`]`))
106+
})
107+
})
108+
})
109+
})

plugin/managers/cdn.go

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,20 @@ type CdnManager interface {
1818
GetUsageMetrics(uniqueId int, history int, mask string) (datatypes.Container_Network_CdnMarketplace_Metrics, error)
1919
EditCDN(uniqueId int, header string, httpPort int, httpsPort int, origin string, respectHeaders string, cache string, cacheDescription string, performanceConfiguration string) (datatypes.Container_Network_CdnMarketplace_Configuration_Mapping, error)
2020
CreateCdn(hostname string, originHost string, originType string, http int, https int, bucketName string, cname string, header string, path string, ssl string) ([]datatypes.Container_Network_CdnMarketplace_Configuration_Mapping, error)
21+
OriginAddCdn(uniqueId string, header string, path string, originHost string, originType string, http int, https int, cacheKey string, optimize string, dynamicPath string, dynamicPrefetch bool, dynamicCompression bool, bucketName string, fileExtension string) ([]datatypes.Container_Network_CdnMarketplace_Configuration_Mapping_Path, error)
2122
}
2223

2324
type cdnManager struct {
24-
CdnService services.Network_CdnMarketplace_Configuration_Mapping
25-
Session *session.Session
25+
CdnService services.Network_CdnMarketplace_Configuration_Mapping
26+
CdnPathService services.Network_CdnMarketplace_Configuration_Mapping_Path
27+
Session *session.Session
2628
}
2729

2830
func NewCdnManager(session *session.Session) *cdnManager {
2931
return &cdnManager{
30-
CdnService: services.GetNetworkCdnMarketplaceConfigurationMappingService(session),
31-
Session: session,
32+
CdnService: services.GetNetworkCdnMarketplaceConfigurationMappingService(session),
33+
CdnPathService: services.GetNetworkCdnMarketplaceConfigurationMappingPathService(session),
34+
Session: session,
3235
}
3336
}
3437

@@ -199,3 +202,54 @@ func (a cdnManager) CreateCdn(hostname string, originHost string, originType str
199202

200203
return a.CdnService.CreateDomainMapping(&NewOrigin)
201204
}
205+
206+
/*
207+
https://sldn.softlayer.com/reference/services/SoftLayer_Network_CdnMarketplace_Configuration_Mapping_Path/createOriginPath/
208+
*/
209+
func (a cdnManager) OriginAddCdn(uniqueId string, header string, path string, originHost string, originType string, http int, https int, cacheKey string, optimize string, dynamicPath string, dynamicPrefetch bool, dynamicCompression bool, bucketName string, fileExtension string) ([]datatypes.Container_Network_CdnMarketplace_Configuration_Mapping_Path, error) {
210+
types := map[string]string{
211+
"server": "HOST_SERVER",
212+
"storage": "OBJECT_STORAGE",
213+
}
214+
performanceConfig := map[string]string{
215+
"web": "General web delivery",
216+
"video": "Video on demand optimization",
217+
"file": "Large file optimization",
218+
"dynamic": "Dynamic content acceleration",
219+
}
220+
221+
NewOrigin := datatypes.Container_Network_CdnMarketplace_Configuration_Input{
222+
UniqueId: sl.String(uniqueId),
223+
Path: sl.String("/" + path),
224+
Origin: sl.String(originHost),
225+
OriginType: sl.String(types[originType]),
226+
CacheKeyQueryRule: sl.String(cacheKey),
227+
PerformanceConfiguration: sl.String(performanceConfig[optimize]),
228+
}
229+
230+
if optimize == "dynamic" {
231+
NewOrigin.DynamicContentAcceleration = &datatypes.Container_Network_CdnMarketplace_Configuration_Performance_DynamicContentAcceleration{
232+
DetectionPath: sl.String("/" + dynamicPath),
233+
PrefetchEnabled: sl.Bool(dynamicPrefetch),
234+
MobileImageCompressionEnabled: sl.Bool(dynamicCompression),
235+
}
236+
}
237+
238+
if originType == "storage" {
239+
NewOrigin.BucketName = sl.String(bucketName)
240+
NewOrigin.FileExtension = sl.String(fileExtension)
241+
NewOrigin.Header = sl.String(originHost)
242+
}
243+
244+
if header != "" {
245+
NewOrigin.Header = sl.String(header)
246+
}
247+
if http != 0 {
248+
NewOrigin.HttpPort = sl.Int(http)
249+
}
250+
if https != 0 {
251+
NewOrigin.HttpsPort = sl.Int(https)
252+
}
253+
254+
return a.CdnPathService.CreateOriginPath(&NewOrigin)
255+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
[
2+
{
3+
"bucketName": "test-bucket-name",
4+
"cacheKeyQueryRule": "include-all",
5+
"fileExtension": "jpg,pdf,jpeg,png",
6+
"header": "header.test.com",
7+
"httpPort": 83,
8+
"httpsPort": null,
9+
"mappingUniqueId": "354034879028850",
10+
"origin": "10.32.12.125",
11+
"originType": "HOST_SERVER",
12+
"path": "\/example\/videos",
13+
"performanceConfiguration": "General web delivery",
14+
"status": "RUNNING"
15+
}
16+
]

0 commit comments

Comments
 (0)