Skip to content

Commit e60ebd1

Browse files
committed
Implements InstanceFirewaller on OCI instance using SSH-based instance configurator, which manipulates iptables directly.
1 parent 7cb330c commit e60ebd1

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

provider/common/instance_configurator.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,6 @@ func ConfigureExternalIpAddressCommands(apiPort int) []string {
116116
func (c *sshInstanceConfigurator) ConfigureExternalIpAddress(apiPort int) error {
117117
cmds := ConfigureExternalIpAddressCommands(apiPort)
118118
output, err := c.runCommand(strings.Join(cmds, "\n"))
119-
if err != nil {
120-
return errors.Errorf("failed to drop all ports: %s", output)
121-
}
122119
if err != nil {
123120
return errors.Errorf("failed to allocate external IP address: %s", output)
124121
}
@@ -139,7 +136,7 @@ func (c *sshInstanceConfigurator) ChangeIngressRules(ipAddress string, insert bo
139136

140137
output, err := c.runCommand(strings.Join(cmds, "\n"))
141138
if err != nil {
142-
return errors.Errorf("failed to configure ports on external network: %s", output)
139+
return errors.Annotatef(err, "configuring ports for address %q: %s", ipAddress, output)
143140
}
144141
logger.Tracef("change ports output: %s", output)
145142
return nil

provider/oci/instance.go

Lines changed: 76 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ import (
1212

1313
"github.com/juju/errors"
1414
"github.com/juju/juju/core/status"
15+
ociCore "github.com/oracle/oci-go-sdk/core"
1516

1617
envcontext "github.com/juju/juju/environs/context"
1718
"github.com/juju/juju/environs/instances"
1819
"github.com/juju/juju/instance"
1920
"github.com/juju/juju/network"
20-
"github.com/juju/juju/provider/oci/common"
21-
22-
ociCore "github.com/oracle/oci-go-sdk/core"
21+
"github.com/juju/juju/provider/common"
22+
ocicommon "github.com/juju/juju/provider/oci/common"
2323
)
2424

2525
const (
@@ -46,9 +46,9 @@ type vnicWithIndex struct {
4646

4747
var _ instance.Instance = (*ociInstance)(nil)
4848
var maxPollIterations = 30
49-
var pollTime time.Duration = 10 * time.Second
49+
var pollTime = 10 * time.Second
5050

51-
var statusMap map[ociCore.InstanceLifecycleStateEnum]status.Status = map[ociCore.InstanceLifecycleStateEnum]status.Status{
51+
var statusMap = map[ociCore.InstanceLifecycleStateEnum]status.Status{
5252
ociCore.InstanceLifecycleStateProvisioning: status.Provisioning,
5353
ociCore.InstanceLifecycleStateRunning: status.Running,
5454
ociCore.InstanceLifecycleStateStarting: status.Provisioning,
@@ -66,13 +66,12 @@ func newInstance(raw ociCore.Instance, env *Environ) (*ociInstance, error) {
6666
"Instance response does not contain an ID",
6767
)
6868
}
69-
instance := &ociInstance{
69+
70+
return &ociInstance{
7071
raw: raw,
7172
env: env,
7273
arch: "amd64",
73-
}
74-
75-
return instance, nil
74+
}, nil
7675
}
7776

7877
// SetInstance sets the raw property of ociInstance{}
@@ -93,7 +92,7 @@ func (o *ociInstance) Id() instance.Id {
9392
// Status implements instance.Instance
9493
func (o *ociInstance) Status(ctx envcontext.ProviderCallContext) instance.InstanceStatus {
9594
if err := o.refresh(); err != nil {
96-
common.HandleCredentialError(err, ctx)
95+
ocicommon.HandleCredentialError(err, ctx)
9796
return instance.InstanceStatus{}
9897
}
9998
state, ok := statusMap[o.raw.LifecycleState]
@@ -135,8 +134,8 @@ func (o *ociInstance) getAddresses() ([]network.Address, error) {
135134
if err != nil {
136135
return nil, errors.Trace(err)
137136
}
138-
addresses := []network.Address{}
139137

138+
var addresses []network.Address
140139
for _, val := range vnics {
141140
if val.Vnic.PrivateIp != nil {
142141
privateAddress := network.Address{
@@ -161,7 +160,7 @@ func (o *ociInstance) getAddresses() ([]network.Address, error) {
161160
// Addresses implements instance.Instance
162161
func (o *ociInstance) Addresses(ctx envcontext.ProviderCallContext) ([]network.Address, error) {
163162
addresses, err := o.getAddresses()
164-
common.HandleCredentialError(err, ctx)
163+
ocicommon.HandleCredentialError(err, ctx)
165164
return addresses, err
166165
}
167166

@@ -180,7 +179,7 @@ func (o *ociInstance) waitForPublicIP(ctx envcontext.ProviderCallContext) error
180179
for {
181180
addresses, err := o.Addresses(ctx)
182181
if err != nil {
183-
common.HandleCredentialError(err, ctx)
182+
ocicommon.HandleCredentialError(err, ctx)
184183
return errors.Trace(err)
185184
}
186185
if iteration >= maxPollIterations {
@@ -217,7 +216,7 @@ func (o *ociInstance) deleteInstance(ctx envcontext.ProviderCallContext) error {
217216
}
218217
response, err := o.env.Compute.TerminateInstance(context.Background(), request)
219218
if err != nil && !o.env.isNotFound(response.RawResponse) {
220-
common.HandleCredentialError(err, ctx)
219+
ocicommon.HandleCredentialError(err, ctx)
221220
return err
222221
}
223222
iteration := 0
@@ -226,7 +225,7 @@ func (o *ociInstance) deleteInstance(ctx envcontext.ProviderCallContext) error {
226225
if errors.IsNotFound(err) {
227226
break
228227
}
229-
common.HandleCredentialError(err, ctx)
228+
ocicommon.HandleCredentialError(err, ctx)
230229
return err
231230
}
232231
logger.Infof("Waiting for machine to transition to Terminating: %s", o.raw.LifecycleState)
@@ -304,3 +303,65 @@ func (o *ociInstance) refresh() error {
304303
o.raw = response.Instance
305304
return nil
306305
}
306+
307+
// OpenPorts (InstanceFirewaller) ensures that the input ingress rule is
308+
// permitted for machine with the input ID.
309+
func (o *ociInstance) OpenPorts(
310+
ctx envcontext.ProviderCallContext, _ string, rules []network.IngressRule,
311+
) error {
312+
client, err := o.getInstanceConfigurator(ctx)
313+
if err != nil {
314+
return errors.Trace(err)
315+
}
316+
return errors.Trace(client.ChangeIngressRules("", true, rules))
317+
}
318+
319+
// OpenPorts (InstanceFirewaller) ensures that the input ingress rule is
320+
// restricted for machine with the input ID.
321+
func (o *ociInstance) ClosePorts(
322+
ctx envcontext.ProviderCallContext, _ string, rules []network.IngressRule,
323+
) error {
324+
client, err := o.getInstanceConfigurator(ctx)
325+
if err != nil {
326+
return errors.Trace(err)
327+
}
328+
return errors.Trace(client.ChangeIngressRules("", false, rules))
329+
}
330+
331+
// IngressRules (InstanceFirewaller) returns the ingress rules that have been
332+
// applied to the input machine ID.
333+
func (o *ociInstance) IngressRules(
334+
ctx envcontext.ProviderCallContext, _ string,
335+
) ([]network.IngressRule, error) {
336+
client, err := o.getInstanceConfigurator(ctx)
337+
if err != nil {
338+
return nil, errors.Trace(err)
339+
}
340+
341+
rules, err := client.FindIngressRules()
342+
return rules, errors.Trace(err)
343+
}
344+
345+
func (o *ociInstance) getInstanceConfigurator(
346+
ctx envcontext.ProviderCallContext,
347+
) (common.InstanceConfigurator, error) {
348+
addresses, err := o.Addresses(ctx)
349+
if err != nil {
350+
return nil, errors.Trace(err)
351+
}
352+
if len(addresses) == 0 {
353+
return nil, errors.NotFoundf("addresses for instance %q", o.Id())
354+
}
355+
356+
// Try to find a public address.
357+
// Different models use different VCNs (and therefore subnets),
358+
// so the cloud-local IPs are no good if a controller is trying to
359+
// configure an instance in another model.
360+
for _, addr := range addresses {
361+
if addr.Scope == network.ScopePublic {
362+
return common.NewSshInstanceConfigurator(addr.Value), nil
363+
}
364+
}
365+
366+
return nil, errors.NotFoundf("public address for instance %q", o.Id())
367+
}

0 commit comments

Comments
 (0)