Lookup implements the fs.NodeLookuper interface and returns an index node (inode) for a symlink that points to a Unix domain socket. The Unix domain socket is connected to the requested Cloud SQL instance. Lookup returns a symlink (instead of the socket itself) so that multiple callers all use the s
(_ context.Context, instance string, _ *fuse.EntryOut)
| 100 | // symlink (instead of the socket itself) so that multiple callers all use the |
| 101 | // same Unix socket. |
| 102 | func (c *Client) Lookup(_ context.Context, instance string, _ *fuse.EntryOut) (*fs.Inode, syscall.Errno) { |
| 103 | ctx := context.Background() |
| 104 | if instance == "README" { |
| 105 | return c.NewInode(ctx, &readme{}, fs.StableAttr{}), fs.OK |
| 106 | } |
| 107 | |
| 108 | if _, err := parseConnName(instance); err != nil { |
| 109 | c.logger.Debugf("could not parse instance connection name for %q: %v", instance, err) |
| 110 | return nil, syscall.ENOENT |
| 111 | } |
| 112 | |
| 113 | c.fuseMu.Lock() |
| 114 | defer c.fuseMu.Unlock() |
| 115 | if l, ok := c.fuseSockets[instance]; ok { |
| 116 | c.logger.Debugf("found existing socket for instance %q", instance) |
| 117 | return l.symlink.EmbeddedInode(), fs.OK |
| 118 | } |
| 119 | |
| 120 | c.logger.Debugf("creating new socket for instance %q", instance) |
| 121 | s, err := c.newSocketMount( |
| 122 | ctx, withUnixSocket(*c.conf, c.fuseTempDir), |
| 123 | nil, InstanceConnConfig{Name: instance}, |
| 124 | ) |
| 125 | if err != nil { |
| 126 | c.logger.Errorf("could not create socket for %q: %v", instance, err) |
| 127 | return nil, syscall.ENOENT |
| 128 | } |
| 129 | |
| 130 | c.fuseWg.Add(1) |
| 131 | go func() { |
| 132 | defer c.fuseWg.Done() |
| 133 | sErr := c.serveSocketMount(ctx, s) |
| 134 | if sErr != nil { |
| 135 | c.logger.Debugf("could not serve socket for instance %q: %v", instance, sErr) |
| 136 | c.fuseMu.Lock() |
| 137 | defer c.fuseMu.Unlock() |
| 138 | delete(c.fuseSockets, instance) |
| 139 | select { |
| 140 | // Best effort attempt to send error. |
| 141 | // If this send fails, it means the reading goroutine has |
| 142 | // already pulled a value out of the channel and is no longer |
| 143 | // reading any more values. In other words, we report only the |
| 144 | // first error. |
| 145 | case c.fuseExitCh <- sErr: |
| 146 | default: |
| 147 | return |
| 148 | } |
| 149 | } |
| 150 | }() |
| 151 | |
| 152 | // Return a symlink that points to the actual Unix socket within the |
| 153 | // temporary directory. For Postgres, return a symlink that points to the |
| 154 | // directory which holds the ".s.PGSQL.5432" Unix socket. |
| 155 | sl := &symlink{path: filepath.Join(c.fuseTempDir, instance)} |
| 156 | c.fuseSockets[instance] = socketSymlink{ |
| 157 | socket: s, |
| 158 | symlink: sl, |
| 159 | } |